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 }