adventofcode/2019/day24/layout3d.go

216 lines
6.2 KiB
Go

package main
import (
"fmt"
"io/ioutil"
"log"
"strings"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
type Layout3d struct {
Area map[h.Coordinate3d]bool
TopLeft h.Coordinate3d
BottomRight h.Coordinate3d
}
func NewLayout3d(filename string) *Layout3d {
ret := Layout3d{
Area: make(map[h.Coordinate3d]bool),
TopLeft: h.Coordinate3d{X: 0, Y: 0, Z: 0},
BottomRight: h.Coordinate3d{X: 0, Y: 0, Z: 0},
}
input, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatal(err.Error())
}
lines := make([]string, 0)
for _, line := range strings.Split(string(input), "\n") {
lines = append(lines, line)
}
for y := 0; y < len(lines); y++ {
if len(lines[y]) < ret.BottomRight.X {
break
}
ret.BottomRight.Y = y
for x := 0; x < len(lines[y]); x++ {
ret.BottomRight.X = x
ret.Area[h.Coordinate3d{X: x, Y: y}] = lines[y][x] == '#'
}
}
return &ret
}
func (l *Layout3d) Step() {
a := make(map[h.Coordinate3d]bool)
for k, v := range l.Area {
a[k] = v
}
middle := h.Coordinate{X: l.BottomRight.X / 2, Y: l.BottomRight.Y / 2}
for z := l.TopLeft.Z - 1; z <= l.BottomRight.Z+1; z++ {
for y := l.TopLeft.Y; y <= l.BottomRight.Y; y++ {
for x := l.TopLeft.X; x <= l.BottomRight.X; x++ {
c := h.Coordinate3d{X: x, Y: y, Z: z}
if x == middle.X && y == middle.Y {
a[c] = false
continue
}
neighbors := l.GetNeighborCount(c)
if l.Area[c] {
if neighbors != 1 {
a[c] = false
}
} else {
if neighbors == 1 || neighbors == 2 {
a[c] = true
// If c is on a new 'z', we need to expand our TopLeft/BottomRight
if c.Z < l.TopLeft.Z {
l.TopLeft.Z = c.Z
} else if c.Z > l.BottomRight.Z {
l.BottomRight.Z = c.Z
}
}
}
}
}
}
for k, v := range a {
l.Area[k] = v
}
}
func (l *Layout3d) GetNeighborCount(c h.Coordinate3d) int {
middle := h.Coordinate3d{X: l.BottomRight.X / 2, Y: l.BottomRight.Y / 2, Z: c.Z}
var neighbors []h.Coordinate3d
if c.Y == l.TopLeft.Y {
neighbors = append(neighbors, middle.Up().North())
neighbors = append(neighbors, c.South())
if c.X == l.TopLeft.X {
neighbors = append(neighbors, middle.Up().West())
neighbors = append(neighbors, c.East())
} else if c.X == l.BottomRight.X {
neighbors = append(neighbors, middle.Up().East())
neighbors = append(neighbors, c.West())
} else {
neighbors = append(neighbors, c.West())
neighbors = append(neighbors, c.East())
}
} else if c.Y == l.BottomRight.Y {
neighbors = append(neighbors, middle.Up().South())
neighbors = append(neighbors, c.North())
if c.X == l.TopLeft.X {
neighbors = append(neighbors, middle.Up().West())
neighbors = append(neighbors, c.East())
} else if c.X == l.BottomRight.X {
neighbors = append(neighbors, middle.Up().East())
neighbors = append(neighbors, c.West())
} else {
neighbors = append(neighbors, c.West())
neighbors = append(neighbors, c.East())
}
} else if c.X == l.TopLeft.X {
neighbors = append(neighbors, middle.Up().West())
neighbors = append(neighbors, c.East())
if c.Y == l.TopLeft.Y {
neighbors = append(neighbors, middle.Up().North())
neighbors = append(neighbors, c.South())
} else if c.Y == l.BottomRight.Y {
neighbors = append(neighbors, middle.Up().South())
neighbors = append(neighbors, c.North())
} else {
neighbors = append(neighbors, c.South())
neighbors = append(neighbors, c.North())
}
} else if c.X == l.BottomRight.X {
neighbors = append(neighbors, middle.Up().East())
neighbors = append(neighbors, c.West())
if c.Y == l.TopLeft.Y {
neighbors = append(neighbors, middle.Up().North())
neighbors = append(neighbors, c.South())
} else if c.Y == l.BottomRight.Y {
neighbors = append(neighbors, middle.Up().South())
neighbors = append(neighbors, c.North())
} else {
neighbors = append(neighbors, c.South())
neighbors = append(neighbors, c.North())
}
} else if c.Y == middle.Y-1 && c.X == middle.X {
neighbors = append(neighbors, c.North())
neighbors = append(neighbors, c.East())
neighbors = append(neighbors, c.West())
// South is the North row of the lower grid
for x := l.TopLeft.X; x <= l.BottomRight.X; x++ {
neighbors = append(neighbors, h.Coordinate3d{X: x, Y: l.TopLeft.Y, Z: c.Down().Z})
}
} else if c.Y == middle.Y+1 && c.X == middle.X {
neighbors = append(neighbors, c.East())
neighbors = append(neighbors, c.South())
neighbors = append(neighbors, c.West())
// North is the South row of the lower grid
for x := l.TopLeft.X; x <= l.BottomRight.X; x++ {
neighbors = append(neighbors, h.Coordinate3d{X: x, Y: l.BottomRight.Y, Z: c.Down().Z})
}
} else if c.X == middle.X-1 && c.Y == middle.Y {
neighbors = append(neighbors, c.North())
neighbors = append(neighbors, c.South())
neighbors = append(neighbors, c.West())
// East is the West row of the lower grid
for y := l.TopLeft.Y; y <= l.BottomRight.Y; y++ {
neighbors = append(neighbors, h.Coordinate3d{X: l.TopLeft.X, Y: y, Z: c.Down().Z})
}
} else if c.X == middle.X+1 && c.Y == middle.Y {
neighbors = append(neighbors, c.North())
neighbors = append(neighbors, c.East())
neighbors = append(neighbors, c.South())
// West is the East row of the lower grid
for y := l.TopLeft.Y; y <= l.BottomRight.Y; y++ {
neighbors = append(neighbors, h.Coordinate3d{X: l.BottomRight.X, Y: y, Z: c.Down().Z})
}
} else {
neighbors = append(neighbors, c.North())
neighbors = append(neighbors, c.East())
neighbors = append(neighbors, c.South())
neighbors = append(neighbors, c.West())
}
ret := 0
for _, v := range neighbors {
if n, ok := l.Area[v]; ok && n {
ret++
}
}
return ret
}
func (l *Layout3d) CountBugs() int {
var ret int
for _, v := range l.Area {
if v {
ret++
}
}
return ret
}
func (l Layout3d) String() string {
var ret string
middle := h.Coordinate{X: l.BottomRight.X / 2, Y: l.BottomRight.Y / 2}
for z := l.TopLeft.Z; z <= l.BottomRight.Z; z++ {
ret = fmt.Sprintf("%s\nDepth %d:\n", ret, z)
for y := l.TopLeft.Y; y <= l.BottomRight.Y; y++ {
for x := l.TopLeft.X; x <= l.BottomRight.X; x++ {
if x == middle.X && y == middle.Y {
ret = ret + "?"
} else if l.Area[h.Coordinate3d{X: x, Y: y, Z: z}] {
ret = ret + "#"
} else {
ret = ret + "."
}
}
ret = ret + "\n"
}
}
return ret
}