Skip to content

Commit

Permalink
Implementation for 24b
Browse files Browse the repository at this point in the history
  • Loading branch information
nlowe committed Jan 1, 2020
1 parent 640f630 commit 60202d7
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 16 deletions.
1 change: 1 addition & 0 deletions challenge/day24/a.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func a(challenge *challenge.Input) int {
}
for {
w.tick()
w.swap()
d := w.biodiversity()

if _, ok := seen[d]; ok {
Expand Down
145 changes: 145 additions & 0 deletions challenge/day24/b.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package day24

import (
"fmt"

"github.com/nlowe/aoc2019/challenge"
"github.com/spf13/cobra"
)

var B = &cobra.Command{
Use: "24b",
Short: "Day 24, Problem B",
Run: func(_ *cobra.Command, _ []string) {
fmt.Printf("Answer: %d\n", b(challenge.FromFile()))
},
}

var iterations = 200

type recursiveWorld struct {
levels map[int]*world
}

func makeRecursive(w *world) *recursiveWorld {
result := &recursiveWorld{levels: map[int]*world{0: w}}

for i := -1; i >= (-1*iterations/2)-1; i-- {
result.createLevel(i)
}

for i := 1; i <= iterations/2+1; i++ {
result.createLevel(i)
}

w.innerRecursiveCounter = result.makeInnerRecursiveCounter(0)
w.outerRecursiveCounter = result.makeOuterRecursiveCounter(0)
return result
}

func (r *recursiveWorld) createLevel(level int) {
w := NewEmptyWorld()
w.innerRecursiveCounter = r.makeInnerRecursiveCounter(level)
w.outerRecursiveCounter = r.makeOuterRecursiveCounter(level)
r.levels[level] = w
}

func (r *recursiveWorld) tickAll() {
// tick all levels
for _, w := range r.levels {
w.tick()
}
}

func (r *recursiveWorld) swapAll() {
for _, w := range r.levels {
w.swap()
}
}

func (r *recursiveWorld) popCount() (result int) {
for _, w := range r.levels {
result += w.count()
}

return
}

func (r *recursiveWorld) makeOuterRecursiveCounter(level int) func(int) int {
return func(direction int) int {
outer, ok := r.levels[level-1]
if !ok {
return 0
}

switch direction {
case directionNorth:
if outer.active[2][1] {
return 1
}
case directionEast:
if outer.active[3][2] {
return 1
}
case directionSouth:
if outer.active[2][3] {
return 1
}
default:
if outer.active[1][2] {
return 1
}
}

return 0
}
}

func (r *recursiveWorld) makeInnerRecursiveCounter(level int) func(int) int {
return func(direction int) (result int) {
inner, ok := r.levels[level+1]
if !ok {
return 0
}

switch direction {
case directionNorth:
for x := 0; x < width; x++ {
if inner.active[x][0] {
result++
}
}
case directionSouth:
for x := 0; x < width; x++ {
if inner.active[x][height-1] {
result++
}
}
case directionEast:
for y := 0; y < height; y++ {
if inner.active[width-1][y] {
result++
}
}
case directionWest:
for y := 0; y < height; y++ {
if inner.active[0][y] {
result++
}
}
}

return
}
}

func b(challenge *challenge.Input) int {
r := makeRecursive(NewWorld(challenge))

for i := 0; i < iterations; i++ {
r.tickAll()
r.swapAll()
}

return r.popCount()
}
21 changes: 21 additions & 0 deletions challenge/day24/b_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package day24

import (
"testing"

"github.com/nlowe/aoc2019/challenge"
"github.com/stretchr/testify/require"
)

func TestB(t *testing.T) {
input := challenge.FromLiteral(`....#
#..#.
#..##
..#..
#....`)

iterations = 10
result := b(input)

require.Equal(t, 99, result)
}
82 changes: 67 additions & 15 deletions challenge/day24/world.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package day24

import (
"fmt"
"math/bits"

"github.com/nlowe/aoc2019/challenge"
)
Expand All @@ -14,8 +15,19 @@ const (
tileBug = '#'
)

const (
directionNorth int = iota
directionEast
directionSouth
directionWest
)

type world struct {
m [][]bool
active [][]bool
next [][]bool

outerRecursiveCounter func(direction int) int
innerRecursiveCounter func(direction int) int
}

func emptyWorld() [][]bool {
Expand All @@ -27,14 +39,18 @@ func emptyWorld() [][]bool {
return m
}

func NewEmptyWorld() *world {
return &world{active: emptyWorld(), next: emptyWorld()}
}

func NewWorld(challenge *challenge.Input) *world {
result := &world{m: emptyWorld()}
result := NewEmptyWorld()

y := 0
for row := range challenge.Lines() {
for x, c := range row {
if c == tileBug {
result.m[x][y] = true
result.active[x][y] = true
}
}

Expand All @@ -58,10 +74,30 @@ func (w *world) countNeighbors(x, y int) (result int) {
dy := y + delta.y

if dx < 0 || dx >= width || dy < 0 || dy >= height {
continue
}
if w.outerRecursiveCounter == nil {
continue
}

if w.m[dx][dy] {
if delta.x == -1 {
result += w.outerRecursiveCounter(directionWest)
} else if delta.x == 1 {
result += w.outerRecursiveCounter(directionEast)
} else if delta.y == -1 {
result += w.outerRecursiveCounter(directionNorth)
} else {
result += w.outerRecursiveCounter(directionSouth)
}
} else if dx == width/2 && dy == height/2 && w.innerRecursiveCounter != nil {
if delta.x == -1 {
result += w.innerRecursiveCounter(directionEast)
} else if delta.x == 1 {
result += w.innerRecursiveCounter(directionWest)
} else if delta.y == -1 {
result += w.innerRecursiveCounter(directionSouth)
} else {
result += w.innerRecursiveCounter(directionNorth)
}
} else if w.active[dx][dy] {
result++
}
}
Expand All @@ -70,29 +106,37 @@ func (w *world) countNeighbors(x, y int) (result int) {
}

func (w *world) tick() {
next := emptyWorld()
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
next[x][y] = w.m[x][y]
if w.innerRecursiveCounter != nil &&
w.outerRecursiveCounter != nil &&
x == width/2 && y == height/2 {
continue
}

w.next[x][y] = w.active[x][y]

n := w.countNeighbors(x, y)
if w.m[x][y] && n != 1 {
next[x][y] = false
} else if !w.m[x][y] && (n == 1 || n == 2) {
next[x][y] = true
if w.active[x][y] && n != 1 {
w.next[x][y] = false
} else if !w.active[x][y] && (n == 1 || n == 2) {
w.next[x][y] = true
}
}
}
}

w.m = next
func (w *world) swap() {
w.active = w.next
w.next = emptyWorld()
}

func (w *world) biodiversity() int {
pow := 1
biodiversity := 0
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
if w.m[x][y] {
if w.active[x][y] {
biodiversity += pow
}
pow <<= 1
Expand All @@ -102,10 +146,18 @@ func (w *world) biodiversity() int {
return biodiversity
}

func (w *world) count() int {
return bits.OnesCount32(uint32(w.biodiversity()))
}

func (w *world) dump() {
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
if w.m[x][y] {
if w.innerRecursiveCounter != nil &&
w.outerRecursiveCounter != nil &&
x == width/2 && y == height/2 {
fmt.Print("?")
} else if w.active[x][y] {
fmt.Print(string(tileBug))
} else {
fmt.Print(string(tileEmpty))
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func init() {
day21.A, day21.B,
day22.A, day22.B,
day23.A, day23.B,
day24.A,
day24.A, day24.B,
)

flags := rootCmd.PersistentFlags()
Expand Down

0 comments on commit 60202d7

Please sign in to comment.