diff --git a/2019/day24/input b/2019/day24/input new file mode 100644 index 0000000..f93af7b --- /dev/null +++ b/2019/day24/input @@ -0,0 +1,5 @@ +##.#. +.#.## +.#... +#..#. +.##.. diff --git a/2019/day24/layout.go b/2019/day24/layout.go new file mode 100644 index 0000000..e9df525 --- /dev/null +++ b/2019/day24/layout.go @@ -0,0 +1,112 @@ +package main + +import ( + "log" + "math" + "strings" + + "io/ioutil" + + h "git.bullercodeworks.com/brian/adventofcode/helpers" +) + +type Layout struct { + Area map[h.Coordinate]bool + BottomRight h.Coordinate + + History map[string]float64 +} + +func NewLayout(filename string) *Layout { + ret := Layout{ + Area: make(map[h.Coordinate]bool), + BottomRight: h.Coordinate{X: 0, Y: 0}, + History: make(map[string]float64), + } + 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.Coordinate{X: x, Y: y}] = lines[y][x] == '#' + } + } + ret.SaveToHistory() + return &ret +} + +func (l Layout) SaveToHistory() { + l.History[l.String()] = l.Rating() +} + +func (l Layout) Rating() float64 { + var rating, pow float64 + for y := 0; y <= l.BottomRight.Y; y++ { + for x := 0; x <= l.BottomRight.X; x++ { + if l.Area[h.Coordinate{X: x, Y: y}] { + rating = rating + math.Pow(2, pow) + } + pow++ + } + } + return rating +} + +func (l Layout) Step() bool { + a := make(map[h.Coordinate]bool) + for k, v := range l.Area { + a[k] = v + } + for y := 0; y <= l.BottomRight.Y; y++ { + for x := 0; x <= l.BottomRight.X; x++ { + c := h.Coordinate{X: x, Y: y} + neighbors := 0 + for _, v := range []h.Coordinate{c.North(), c.East(), c.South(), c.West()} { + if n, ok := l.Area[v]; ok && n { + neighbors++ + } + } + if l.Area[c] { + if neighbors != 1 { + a[c] = false + } + } else { + if neighbors == 1 || neighbors == 2 { + a[c] = true + } + } + } + } + for k, v := range a { + l.Area[k] = v + } + // Finally check/save to history + _, ok := l.History[l.String()] + l.History[l.String()] = l.Rating() + return ok +} + +func (l Layout) String() string { + var ret string + for y := 0; y <= l.BottomRight.Y; y++ { + for x := 0; x <= l.BottomRight.X; x++ { + if l.Area[h.Coordinate{X: x, Y: y}] { + ret = ret + "#" + } else { + ret = ret + "." + } + } + ret = ret + "\n" + } + return ret +} diff --git a/2019/day24/layout3d.go b/2019/day24/layout3d.go new file mode 100644 index 0000000..ddf682a --- /dev/null +++ b/2019/day24/layout3d.go @@ -0,0 +1,215 @@ +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 +} diff --git a/2019/day24/main.go b/2019/day24/main.go new file mode 100644 index 0000000..8f82428 --- /dev/null +++ b/2019/day24/main.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + + h "git.bullercodeworks.com/brian/adventofcode/helpers" +) + +func main() { + filename := "input" + if h.GetArgNumber(1) != "" { + filename = h.GetArgNumber(1) + } + if h.GetArgNumber(2) != "2" { + part1(filename) + } else { + part2(filename) + } +} + +func part1(filename string) { + l := NewLayout(filename) + for !l.Step() { + fmt.Println(h.CLEAR_SCREEN) + fmt.Println(l) + fmt.Println(int(l.Rating())) + } + fmt.Println(h.CLEAR_SCREEN) + fmt.Println(l) + fmt.Println(int(l.Rating())) +} + +func part2(filename string) { + l := NewLayout3d(filename) + for i := 0; i < 200; i++ { + l.Step() + } + fmt.Println("Bugs:", l.CountBugs()) +} diff --git a/2019/day24/testinput b/2019/day24/testinput new file mode 100644 index 0000000..704a112 --- /dev/null +++ b/2019/day24/testinput @@ -0,0 +1,5 @@ +....# +#..#. +#..## +..#.. +#.... diff --git a/helpers/coordinate.go b/helpers/coordinate.go index 943af77..d7457cd 100644 --- a/helpers/coordinate.go +++ b/helpers/coordinate.go @@ -14,6 +14,19 @@ func NewCoordinate(x, y int) *Coordinate { return &Coordinate{x, y} } +func (c *Coordinate) North() Coordinate { + return Coordinate{X: c.X, Y: c.Y - 1} +} +func (c *Coordinate) East() Coordinate { + return Coordinate{X: c.X + 1, Y: c.Y} +} +func (c *Coordinate) South() Coordinate { + return Coordinate{X: c.X, Y: c.Y + 1} +} +func (c *Coordinate) West() Coordinate { + return Coordinate{X: c.X - 1, Y: c.Y} +} + func (c *Coordinate) GetNorthCoord() *Coordinate { return &Coordinate{ X: c.X, diff --git a/helpers/coordinate3d.go b/helpers/coordinate3d.go index 2987b29..665bf8b 100644 --- a/helpers/coordinate3d.go +++ b/helpers/coordinate3d.go @@ -10,6 +10,25 @@ func NewCoordinate3d(x, y, z int) *Coordinate3d { return &Coordinate3d{x, y, z} } +func (c Coordinate3d) North() Coordinate3d { + return Coordinate3d{X: c.X, Y: c.Y - 1, Z: c.Z} +} +func (c Coordinate3d) East() Coordinate3d { + return Coordinate3d{X: c.X + 1, Y: c.Y, Z: c.Z} +} +func (c Coordinate3d) South() Coordinate3d { + return Coordinate3d{X: c.X, Y: c.Y + 1, Z: c.Z} +} +func (c Coordinate3d) West() Coordinate3d { + return Coordinate3d{X: c.X - 1, Y: c.Y, Z: c.Z} +} +func (c Coordinate3d) Up() Coordinate3d { + return Coordinate3d{X: c.X, Y: c.Y, Z: c.Z + 1} +} +func (c Coordinate3d) Down() Coordinate3d { + return Coordinate3d{X: c.X, Y: c.Y, Z: c.Z - 1} +} + func (c *Coordinate3d) GetNorthCoord() *Coordinate3d { return &Coordinate3d{ X: c.X,