Created
December 22, 2021 14:59
-
-
Save almendar/a0382718e76120c5ecb03912ff63250b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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