From f32239d2cb2f85095c44b7c3367291d9c864a1f1 Mon Sep 17 00:00:00 2001 From: alexchao26 Date: Sat, 11 Dec 2021 12:29:05 -0500 Subject: [PATCH] 2021 day11: fun game of life ish thing --- 2021/day11/main.go | 122 ++++++++++++++++++++++++++++++++++++++++ 2021/day11/main_test.go | 57 +++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 2021/day11/main.go create mode 100644 2021/day11/main_test.go diff --git a/2021/day11/main.go b/2021/day11/main.go new file mode 100644 index 0000000..bb3bb9e --- /dev/null +++ b/2021/day11/main.go @@ -0,0 +1,122 @@ +package main + +import ( + _ "embed" + "flag" + "fmt" + "math" + "strings" + + "github.com/alexchao26/advent-of-code-go/cast" + "github.com/alexchao26/advent-of-code-go/util" +) + +//go:embed input.txt +var input string + +func init() { + // do this in init (not main) so test file has same input + input = strings.TrimRight(input, "\n") + if len(input) == 0 { + panic("empty input.txt file") + } +} + +func main() { + var part int + flag.IntVar(&part, "part", 1, "part 1 or 2") + flag.Parse() + fmt.Println("Running part", part) + + ans := flashingOctopiLol(input, part) + util.CopyToClipboard(fmt.Sprintf("%v", ans)) + fmt.Println("Output:", ans) +} + +func flashingOctopiLol(input string, part int) int { + grid := parseInput(input) + + var flashed int + + adjacentDiffs := [][2]int{ + {-1, 0}, + {-1, -1}, + {-1, 1}, + {0, -1}, + {0, 1}, + {1, -1}, + {1, 0}, + {1, 1}, + } + + steps := 100 + if part == 2 { + // assume it'll run in less steps than 2^31-1... + steps = math.MaxInt32 + } + + for s := 0; s < steps; s++ { + // initial increment and store who will flash + var queueToFlash [][2]int + for i, row := range grid { + for j := range row { + grid[i][j]++ + if grid[i][j] > 9 { + queueToFlash = append(queueToFlash, [2]int{i, j}) + } + } + } + + // map tracks who has flashed, bc it's a map it'll also help dedupe and its length will be + // how many flashed on this step + seen := map[[2]int]bool{} + for len(queueToFlash) > 0 { + front := queueToFlash[0] + queueToFlash = queueToFlash[1:] + if seen[front] { + continue + } + seen[front] = true + + // increment neighbors + for _, d := range adjacentDiffs { + r, c := front[0]+d[0], front[1]+d[1] + // check in bounds + if r < 0 || r >= len(grid) || c < 0 || c >= len(grid[0]) { + continue + } + grid[r][c]++ + // check if neighbor should flash, seen map will dedupe so don't safeguard here + if grid[r][c] > 9 { + queueToFlash = append(queueToFlash, [2]int{r, c}) + } + } + } + + // part1, track how many have flashed in total + flashed += len(seen) + // set them all to zero + for c := range seen { + grid[c[0]][c[1]] = 0 + } + + // if all octopi flashed, return the step number (1-indexed) + if part == 2 && len(seen) == len(grid)*len(grid[0]) { + return s + 1 + } + } + + // for part 1 + return flashed +} + +func parseInput(input string) (ans [][]int) { + for _, line := range strings.Split(input, "\n") { + var row []int + for _, char := range strings.Split(line, "") { + row = append(row, cast.ToInt(char)) + } + ans = append(ans, row) + } + return ans +} diff --git a/2021/day11/main_test.go b/2021/day11/main_test.go new file mode 100644 index 0000000..ce48290 --- /dev/null +++ b/2021/day11/main_test.go @@ -0,0 +1,57 @@ +package main + +import ( + "testing" +) + +var example = `5483143223 +2745854711 +5264556173 +6141336146 +6357385478 +4167524645 +2176841721 +6882881134 +4846848554 +5283751526` + +func Test_flashingOctopiLol(t *testing.T) { + tests := []struct { + name string + input string + part int + want int + }{ + { + name: "example", + input: example, + part: 1, + want: 1656, + }, + { + name: "actual", + input: input, + part: 1, + want: 1723, + }, + { + name: "example", + input: example, + part: 2, + want: 195, + }, + { + name: "actual", + input: input, + part: 2, + want: 327, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := flashingOctopiLol(tt.input, tt.part); got != tt.want { + t.Errorf("flashingOctopiLol() = %v, want %v", got, tt.want) + } + }) + } +}