180 lines
3.3 KiB
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,
|
|
)
|
|
}
|