main.go (2604B)
1 package main
2
3 import (
4 "bufio"
5 "fmt"
6 "os"
7 )
8
9 const (
10 FLOOR = '.'
11 EMPTY = 'L'
12 OCCUPIED = '#'
13 )
14
15 type seats struct {
16 width int
17 height int
18 v []rune
19 }
20
21 func (this *seats) val(x, y int) rune {
22 return this.v[x*this.width+y]
23 }
24
25 func (this *seats) valChecked(x, y int) (rune, bool) {
26 if x >= 0 && x < this.height && y >= 0 && y < this.width {
27 return this.v[x*this.width+y], true
28 } else {
29 return 0, false
30 }
31 }
32
33 func (this *seats) set(x, y int, val rune) {
34 this.v[x*this.width+y] = val
35 }
36
37 func (this seats) copy() seats {
38 return seats{this.width, this.height, append([]rune(nil), this.v...)}
39 }
40
41 func readInput(filename string) (res seats) {
42 file, _ := os.Open(filename)
43 defer file.Close()
44 scanner := bufio.NewScanner(file)
45 for scanner.Scan() {
46 row := scanner.Text()
47 res.height += 1
48 res.width = len(row)
49 for _, ch := range row {
50 res.v = append(res.v, ch)
51 }
52 }
53 return
54 }
55
56 func main() {
57 input := readInput("./input.txt")
58 // 2281
59 fmt.Println(part(input, update1))
60 // 2085
61 fmt.Println(part(input, update2))
62 }
63
64 func update1(input seats, x, y int) rune {
65 old := input.val(x, y)
66 if old == FLOOR {
67 return FLOOR
68 }
69 dx := []int{-1, +0, +1, -1, +1, -1, +0, +1}
70 dy := []int{-1, -1, -1, +0, +0, +1, +1, +1}
71 occCount := 0
72 for i := 0; i < len(dx); i++ {
73 val, ok := input.valChecked(x+dx[i], y+dy[i])
74 if ok && val == OCCUPIED {
75 occCount += 1
76 }
77 }
78 if old == EMPTY && occCount == 0 {
79 return OCCUPIED
80 }
81 if old == OCCUPIED && occCount >= 4 {
82 return EMPTY
83 }
84 return old
85 }
86
87 func update2(input seats, x, y int) rune {
88 old := input.val(x, y)
89 if old == FLOOR {
90 return FLOOR
91 }
92 dx := []int{-1, +0, +1, -1, +1, -1, +0, +1}
93 dy := []int{-1, -1, -1, +0, +0, +1, +1, +1}
94 occCount := 0
95 for i := 0; i < len(dx); i++ {
96 xNew, yNew := x, y
97 for val, ok := FLOOR, true; ok; val, ok = input.valChecked(xNew, yNew) {
98 if val == FLOOR {
99 xNew += dx[i]
100 yNew += dy[i]
101 } else {
102 if val == OCCUPIED {
103 occCount += 1
104 }
105 break
106 }
107 }
108 }
109 if old == EMPTY && occCount == 0 {
110 return OCCUPIED
111 }
112 if old == OCCUPIED && occCount >= 5 {
113 return EMPTY
114 }
115 return old
116 }
117
118 func part(input seats, updater func(seats, int, int) rune) (occCount int) {
119 curr := input.copy()
120 next := input.copy()
121 for updated := true; updated; {
122 updated = false
123 for x := 0; x < curr.height; x++ {
124 for y := 0; y < curr.width; y++ {
125 old := next.val(x, y)
126 next.set(x, y, updater(curr, x, y))
127 updated = updated || old != next.val(x, y)
128 }
129 }
130 curr, next = next, curr
131 }
132 for _, v := range curr.v {
133 if v == OCCUPIED {
134 occCount += 1
135 }
136 }
137 return
138 }