adventofcode/2021/day22/main.go

180 lines
3.3 KiB
Go

package main
import (
"fmt"
"strings"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
var steps []cuboid
func main() {
inp := h.StdinToStringSlice()
for i := range inp {
pts := strings.Split(inp[i], " ")
c := strings.Split(pts[1], ",")
steps = append(steps, NewCuboid(
pts[0] == "on",
c[0][2:],
c[1][2:],
c[2][2:],
))
}
m := c3dMap{
Field: make(map[h.Coordinate3d]bool),
blfX: -50, trbX: 50,
blfY: -50, trbY: 50,
blfZ: -50, trbZ: 50,
}
initialize(&m)
reboot()
}
func initialize(m *c3dMap) {
fmt.Println("# Part 1")
for i := range steps {
m.doInitialize(steps[i])
}
fmt.Printf("After initialization, %d bits are on.\n", m.count(true))
}
func reboot() {
fmt.Println("# Part 2")
var cuboids []cuboid
var volume int64
for _, s1 := range steps {
adds := make([]cuboid, 0)
if s1.val {
adds = append(adds, s1)
}
for _, s2 := range cuboids {
if i := s1.intersect(s2, !s2.val); i.valid() {
adds = append(adds, i)
}
}
cuboids = append(cuboids, adds...)
}
for _, c := range cuboids {
if c.val {
volume += c.volume()
} else {
volume -= c.volume()
}
}
fmt.Printf("After reboot, %d bits are on.\n", volume)
}
type cuboid struct {
val bool
x1, x2 int
y1, y2 int
z1, z2 int
}
func NewCuboid(val bool, x, y, z string) cuboid {
s := cuboid{val: val}
fmt.Sscanf(x, "%d..%d", &s.x1, &s.x2)
fmt.Sscanf(y, "%d..%d", &s.y1, &s.y2)
fmt.Sscanf(z, "%d..%d", &s.z1, &s.z2)
return s
}
func (s cuboid) volume() int64 {
return int64((h.Abs(s.x2-s.x1) + 1) * (h.Abs(s.y2-s.y1) + 1) * (h.Abs(s.z2-s.z1) + 1))
}
func (s cuboid) valid() bool {
return s.x1 <= s.x2 && s.y1 <= s.y2 && s.z1 <= s.z2
}
func (s cuboid) intersect(t cuboid, val bool) cuboid {
return cuboid{
val: val,
x1: h.Max(s.x1, t.x1),
x2: h.Min(s.x2, t.x2),
y1: h.Max(s.y1, t.y1),
y2: h.Min(s.y2, t.y2),
z1: h.Max(s.z1, t.z1),
z2: h.Min(s.z2, t.z2),
}
}
func (s cuboid) String() string {
return fmt.Sprintf("{%v; x:%d..%d, y:%d..%d, z:%d..%d}", s.val, s.x1, s.x2, s.y1, s.y2, s.z1, s.z2)
}
// Ended up not even using this for part 2
type c3dMap struct {
Field map[h.Coordinate3d]bool
blfX, trbX int
blfY, trbY int
blfZ, trbZ int
}
func (c *c3dMap) count(v bool) int {
var ret int
for x := c.blfX; x <= c.trbX; x++ {
for y := c.blfY; y <= c.trbY; y++ {
for z := c.blfZ; z <= c.trbZ; z++ {
if c.Field[h.Coordinate3d{X: x, Y: y, Z: z}] == v {
ret++
}
}
}
}
return ret
}
func (c *c3dMap) doInitialize(s cuboid) {
if !c.inRange(s) {
return
}
c.do(s)
}
func (c *c3dMap) do(s cuboid) {
for x := s.x1; x <= s.x2; x++ {
if x < c.blfX || x > c.trbX {
continue
}
for y := s.y1; y <= s.y2; y++ {
if y < c.blfY || x > c.trbY {
continue
}
for z := s.z1; z <= s.z2; z++ {
if z < c.blfZ || x > c.trbZ {
continue
}
c.Field[h.Coordinate3d{X: x, Y: y, Z: z}] = s.val
}
}
}
}
func (c *c3dMap) inRange(s cuboid) bool {
if s.x2 < c.blfX {
return false
}
if s.x1 > c.trbX {
return false
}
if s.y2 < c.blfY {
return false
}
if s.y1 > c.trbY {
return false
}
if s.z2 < c.blfZ {
return false
}
if s.z1 > c.trbZ {
return false
}
return true
}
func (c c3dMap) Meta() string {
return fmt.Sprintf(
"{x: %d..%d, y: %d..%d, z: %d..%d}",
c.blfX, c.trbX, c.blfY, c.trbY, c.blfZ, c.trbZ,
)
}