Skip to content

Instantly share code, notes, and snippets.

@almendar
Created December 22, 2021 14:59
Show Gist options
  • Save almendar/a0382718e76120c5ecb03912ff63250b to your computer and use it in GitHub Desktop.
Save almendar/a0382718e76120c5ecb03912ff63250b to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"io/ioutil"
"log"
"math"
"strconv"
"strings"
)
type Coord struct{ x, y, z int }
type Range struct{ from, to int }
func (r Range) overlap(or Range) bool {
inTheMiddle := func(xa, x1a, x1b int) bool {
return xa >= x1a && xa <= x1b
}
return inTheMiddle(or.from, r.from, r.to) || inTheMiddle(or.to, r.from, r.to)
}
func (r Range) small() bool {
return r.from >= -50 && r.to <= 50
}
type Region struct {
xRange Range
yRange Range
zRange Range
action bool
}
func (r Region) isOn() bool {
return r.action
}
func (r Region) capacity() int {
signs := 1
if !r.action {
signs = -1
}
return (r.xRange.to - r.xRange.from + 1) * (r.yRange.to - r.yRange.from + 1) * (r.zRange.to - r.zRange.from + 1) * signs
}
func (r Region) clip(or Region) (Region, bool) {
newRegion := Region{}
newRegion.action = r.action
from := math.Max(float64(r.xRange.from), float64(or.xRange.from))
to := math.Min(float64(r.xRange.to), float64(or.xRange.to))
newRegion.xRange = Range{int(from), int(to)}
if from > to {
return newRegion, false
}
from = math.Max(float64(r.yRange.from), float64(or.yRange.from))
to = math.Min(float64(r.yRange.to), float64(or.yRange.to))
newRegion.yRange = Range{int(from), int(to)}
if from > to {
return newRegion, false
}
from = math.Max(float64(r.zRange.from), float64(or.zRange.from))
to = math.Min(float64(r.zRange.to), float64(or.zRange.to))
newRegion.zRange = Range{int(from), int(to)}
if from > to {
return newRegion, false
}
return newRegion, true
}
func readInput(input string) []Region {
bytes, err := ioutil.ReadFile(input)
if err != nil {
log.Fatal(err)
}
lines := strings.Split(string(bytes), "\n")
unsafeAtoi := func(str string) int {
x, err := strconv.Atoi(str)
if err != nil {
log.Fatal(err)
}
return x
}
directives := make([]Region, 0)
for _, line := range lines {
onOff := strings.TrimSpace(line[0:3])
if onOff != "on" && onOff != "off" {
log.Fatal(onOff)
}
coords := strings.Split(strings.TrimSpace(line[3:]), ",")
read := func(str string) Range {
xRange := strings.Split(str[2:], "..")
from := unsafeAtoi(xRange[0])
to := unsafeAtoi(xRange[1])
return Range{from, to}
}
d := Region{}
switch onOff {
case "on":
d.action = true
case "off":
d.action = false
default:
log.Fatal("!")
}
// x
d.xRange = read(coords[0])
// y
d.yRange = read(coords[1])
// z
d.zRange = read(coords[2])
directives = append(directives, d)
}
return directives
}
func task1(input string) int {
directives := readInput(input)
cubes := make(map[Coord]bool)
for _, d := range directives {
xRange := d.xRange
if !xRange.small() {
continue
}
for xi := xRange.from; xi <= xRange.to; xi++ {
yRange := d.yRange
if !yRange.small() {
continue
}
for yi := yRange.from; yi <= yRange.to; yi++ {
zRange := d.zRange
if !zRange.small() {
continue
}
for zi := zRange.from; zi <= zRange.to; zi++ {
if d.action {
cubes[Coord{xi, yi, zi}] = true
} else {
delete(cubes, Coord{xi, yi, zi})
}
}
}
}
}
counter := 0
for range cubes {
counter++
}
fmt.Printf("Day22 task1 %s: %d\n", input, counter)
return counter
}
func task2(input string) int {
regions := readInput(input)
accumulator := make([]Region, 0)
for _, region := range regions {
tmpAcc := make([]Region, 0)
for _, r := range accumulator {
clip, ok := r.clip(region)
if !ok {
continue
}
artificcialRegion := Region{clip.xRange, clip.yRange, clip.zRange, false}
if clip.isOn() && region.isOn() {
artificcialRegion.action = false
} else if !clip.isOn() && !region.isOn() {
artificcialRegion.action = true
} else {
artificcialRegion.action = region.action
}
tmpAcc = append(tmpAcc, artificcialRegion)
}
if region.isOn() {
accumulator = append(accumulator, region)
}
accumulator = append(accumulator, tmpAcc...)
}
counter := 0
for _, r := range accumulator {
counter += r.capacity()
}
fmt.Printf("Day22 task2 %s: %d\n", input, counter)
return counter
}
func main() {
task1("example1.txt")
task2("example1.txt")
task1("example2.txt")
task2("example2.txt")
// task1("input.txt")
task2("input.txt")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment