main.go (2402B)
1 package main
2
3 import (
4 "bufio"
5 "fmt"
6 "os"
7 "regexp"
8 )
9
10 const (
11 E = iota
12 SE
13 SW
14 W
15 NW
16 NE
17 WHITE = 0
18 BLACK = 1
19 )
20
21 type pos [2]int
22
23 func (this pos) move(dir int) pos {
24 other := pathToCoord([]int{dir})
25 return pos{this[0] + other[0], this[1] + other[1]}
26 }
27
28 func readInput(filename string) (res [][]int) {
29 file, _ := os.Open(filename)
30 defer file.Close()
31
32 scanner := bufio.NewScanner(file)
33 matcher := regexp.MustCompile(`e|se|sw|w|nw|ne`)
34 dirMap := map[string]int{
35 "e": E, "se": SE, "sw": SW, "w": W, "nw": NW, "ne": NE,
36 }
37 for scanner.Scan() {
38 curr := []int{}
39 for _, dir := range matcher.FindAllStringSubmatch(scanner.Text(), -1) {
40 curr = append(curr, dirMap[dir[0]])
41 }
42 res = append(res, curr)
43 }
44 return
45 }
46
47 func main() {
48 input := readInput("./input.txt")
49 // 382
50 fmt.Println(part1(input))
51 // 3964
52 fmt.Println(part2(input))
53 }
54
55 func pathToCoord(path []int) (coord pos) {
56 // Use E/W axis as x, NW/SE axis as y.
57 for _, dir := range path {
58 switch dir {
59 case E, NE:
60 coord[0] += 1
61 case W, SW:
62 coord[0] -= 1
63 }
64 switch dir {
65 case NW, NE:
66 coord[1] += 1
67 case SE, SW:
68 coord[1] -= 1
69 }
70 }
71 return
72 }
73
74 func part1(input [][]int) (blackCount int) {
75 tileColor := map[pos]int{}
76 for _, path := range input {
77 coord := pathToCoord(path)
78 tileColor[coord] = 1 - tileColor[coord]
79 }
80 for _, v := range tileColor {
81 if v == BLACK {
82 blackCount += 1
83 }
84 }
85 return
86 }
87
88 func flip(tileColor map[pos]int, steps int) map[pos]int {
89 // Same as day 17.
90 curr, next := tileColor, map[pos]int{}
91 for i := 0; i < steps; i++ {
92 // Update neighbor black count.
93 next = map[pos]int{}
94 for p, v := range curr {
95 next[p] = next[p] // ensure key exists
96 for _, dir := range []int{E, SE, SW, W, NW, NE} {
97 next[p.move(dir)] += v
98 }
99 }
100 // Update state.
101 for p, blackCount := range next {
102 switch curr[p] {
103 case BLACK:
104 if blackCount == 0 || blackCount > 2 {
105 next[p] = WHITE
106 } else {
107 next[p] = BLACK
108 }
109 case WHITE:
110 if blackCount == 2 {
111 next[p] = BLACK
112 } else {
113 next[p] = WHITE
114 }
115 }
116 }
117 curr = next
118 }
119 return curr
120 }
121
122 func part2(input [][]int) (blackCount int) {
123 tileColor := map[pos]int{}
124 for _, path := range input {
125 coord := pathToCoord(path)
126 tileColor[coord] = 1 - tileColor[coord]
127 }
128 tileColor = flip(tileColor, 100)
129 for _, v := range tileColor {
130 if v == BLACK {
131 blackCount += 1
132 }
133 }
134 return
135 }