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, ) }