@@ -9,11 +9,6 @@ import (
9
9
)
10
10
11
11
var inputFile = flag .String ("inputFile" , "inputs/day20.input" , "Relative file path to use as input." )
12
- var debug = flag .Bool ("debug" , false , "Whether to print debug output along the way." )
13
-
14
- var SeaMonster = strings .Split (` #
15
- # ## ## ###
16
- # # # # # # ` , "\n " )
17
12
18
13
type Tile [10 ][10 ]bool
19
14
type Edge uint16
@@ -25,71 +20,6 @@ const (
25
20
LEFT
26
21
)
27
22
28
- type Cropped [8 ][8 ]bool
29
-
30
- // This is assumed to be pre-rotated/flipped.
31
- type Mosaic [][]Tile
32
-
33
- func (m Mosaic ) PixelAtCoord (r , c int ) bool {
34
- mosaicRow := r / 8
35
- mosaicCol := c / 8
36
- cropped := m [mosaicRow ][mosaicCol ].Crop ()
37
- row := r % 8
38
- col := c % 8
39
- return cropped [row ][col ]
40
- }
41
-
42
- func (m Mosaic ) FlipX () Mosaic {
43
- var ret Mosaic
44
- for r := range m {
45
- var row []Tile
46
- for c := range m [r ] {
47
- row = append (row , m [len (m )- 1 - r ][c ].FlipX ())
48
- }
49
- ret = append (ret , row )
50
- }
51
- return ret
52
- }
53
-
54
- func (m Mosaic ) RotCW () Mosaic {
55
- var ret Mosaic
56
- for r := range m {
57
- var row []Tile
58
- for c := range m [r ] {
59
- row = append (row , m [len (m [0 ])- 1 - c ][r ].RotCW ())
60
- }
61
- ret = append (ret , row )
62
- }
63
- return ret
64
- }
65
-
66
- func (m Mosaic ) MonsterTopLeftCoord (r , c int ) bool {
67
- for rOffset , row := range SeaMonster {
68
- for cOffset , char := range row {
69
- if char != '#' {
70
- continue
71
- }
72
- if ! m .PixelAtCoord (r + rOffset , c + cOffset ) {
73
- return false
74
- }
75
- }
76
- }
77
- return true
78
- }
79
-
80
- func (m Mosaic ) FindMonsters () int {
81
- // Find the sea monster.
82
- var monstersFound int
83
- for r := 0 ; r + len (SeaMonster ) < 8 * len (m ); r ++ {
84
- for c := 0 ; c + len (SeaMonster [0 ]) < 8 * len (m [0 ]); c ++ {
85
- if m .MonsterTopLeftCoord (r , c ) {
86
- monstersFound ++
87
- }
88
- }
89
- }
90
- return monstersFound
91
- }
92
-
93
23
func (t Tile ) Crop () Cropped {
94
24
var ret Cropped
95
25
for r := 1 ; r < 9 ; r ++ {
@@ -165,6 +95,174 @@ func (e Edge) Flip() Edge {
165
95
return ret
166
96
}
167
97
98
+ type Cropped [8 ][8 ]bool
99
+
100
+ // This is assumed to be pre-rotated/flipped.
101
+ type Mosaic [][]Tile
102
+
103
+ func (m Mosaic ) PixelAtCoord (r , c int ) bool {
104
+ mosaicRow := r / 8
105
+ mosaicCol := c / 8
106
+ cropped := m [mosaicRow ][mosaicCol ].Crop ()
107
+ row := r % 8
108
+ col := c % 8
109
+ return cropped [row ][col ]
110
+ }
111
+
112
+ func (m Mosaic ) FlipX () Mosaic {
113
+ var ret Mosaic
114
+ for r := range m {
115
+ var row []Tile
116
+ for c := range m [r ] {
117
+ row = append (row , m [len (m )- 1 - r ][c ].FlipX ())
118
+ }
119
+ ret = append (ret , row )
120
+ }
121
+ return ret
122
+ }
123
+
124
+ func (m Mosaic ) RotCW () Mosaic {
125
+ var ret Mosaic
126
+ for r := range m {
127
+ var row []Tile
128
+ for c := range m [r ] {
129
+ row = append (row , m [len (m [0 ])- 1 - c ][r ].RotCW ())
130
+ }
131
+ ret = append (ret , row )
132
+ }
133
+ return ret
134
+ }
135
+
136
+ func (m Mosaic ) CheckSingleEdge (t Tile , r , c , dir int ) bool {
137
+ oDir := (dir + 2 ) % 4
138
+ var otherR , otherC int
139
+ switch dir {
140
+ case TOP :
141
+ if r - 1 < 0 {
142
+ return true
143
+ }
144
+ otherC = c
145
+ otherR = r - 1
146
+ case BOTTOM :
147
+ if r + 1 >= len (m ) {
148
+ return true
149
+ }
150
+ otherC = c
151
+ otherR = r + 1
152
+ case LEFT :
153
+ if c - 1 < 0 {
154
+ return true
155
+ }
156
+ otherC = c - 1
157
+ otherR = r
158
+ case RIGHT :
159
+ if c + 1 >= len (m [0 ]) {
160
+ return true
161
+ }
162
+ otherC = c + 1
163
+ otherR = r
164
+ }
165
+ otherTile := m [otherR ][otherC ]
166
+ var empty Tile
167
+ if otherTile == empty {
168
+ return true
169
+ }
170
+ return otherTile .Edges ()[oDir ] == t .Edges ()[dir ].Flip ()
171
+ }
172
+
173
+ func (m Mosaic ) CheckFit (t Tile , r , c int ) bool {
174
+ // Check up, if exists.
175
+ if ! m .CheckSingleEdge (t , r , c , TOP ) {
176
+ return false
177
+ }
178
+ // Check down, if exists.
179
+ if ! m .CheckSingleEdge (t , r , c , BOTTOM ) {
180
+ return false
181
+ }
182
+ // Check left, if exists.
183
+ if ! m .CheckSingleEdge (t , r , c , LEFT ) {
184
+ return false
185
+ }
186
+ // Check right, if exists.
187
+ if ! m .CheckSingleEdge (t , r , c , RIGHT ) {
188
+ return false
189
+ }
190
+
191
+ return true
192
+ }
193
+
194
+ func (m Mosaic ) Traverse (allTiles map [Tile ]int , used map [int ]bool , r , c int , dir int ) int {
195
+ var rIncr , cIncr int
196
+ switch dir {
197
+ case RIGHT :
198
+ cIncr = 1
199
+ case BOTTOM :
200
+ rIncr = 1
201
+ case LEFT :
202
+ cIncr = - 1
203
+ case TOP :
204
+ rIncr = - 1
205
+ }
206
+ i := 1
207
+ outer:
208
+ for ; ; i ++ {
209
+ row := r + rIncr * i
210
+ col := c + cIncr * i
211
+ if row < 0 || row >= len (m ) {
212
+ break
213
+ }
214
+ if row < 0 || col >= len (m [0 ]) {
215
+ break
216
+ }
217
+ for t , s := range allTiles {
218
+ if used [s ] {
219
+ // Don't re-use the same piece twice.
220
+ continue
221
+ }
222
+ if m .CheckFit (t , row , col ) {
223
+ used [s ] = true
224
+ m [row ][col ] = t
225
+ continue outer
226
+ }
227
+ // This piece hasn't matched, continue on to other pieces.
228
+ }
229
+ // We didn't match any pieces, abort.
230
+ return 0
231
+ }
232
+ return i - 1
233
+ }
234
+
235
+ var SeaMonster = strings .Split (` #
236
+ # ## ## ###
237
+ # # # # # # ` , "\n " )
238
+
239
+ func (m Mosaic ) MonsterTopLeftCoord (r , c int ) bool {
240
+ for rOffset , row := range SeaMonster {
241
+ for cOffset , char := range row {
242
+ if char != '#' {
243
+ continue
244
+ }
245
+ if ! m .PixelAtCoord (r + rOffset , c + cOffset ) {
246
+ return false
247
+ }
248
+ }
249
+ }
250
+ return true
251
+ }
252
+
253
+ func (m Mosaic ) FindMonsters () int {
254
+ // Find the sea monster.
255
+ var monstersFound int
256
+ for r := 0 ; r + len (SeaMonster ) < 8 * len (m ); r ++ {
257
+ for c := 0 ; c + len (SeaMonster [0 ]) < 8 * len (m [0 ]); c ++ {
258
+ if m .MonsterTopLeftCoord (r , c ) {
259
+ monstersFound ++
260
+ }
261
+ }
262
+ }
263
+ return monstersFound
264
+ }
265
+
168
266
func main () {
169
267
flag .Parse ()
170
268
bytes , err := ioutil .ReadFile (* inputFile )
@@ -195,16 +293,6 @@ func main() {
195
293
}
196
294
tiles [n ] = tile
197
295
}
198
- if * debug {
199
- for i , t := range tiles {
200
- edges := t .Edges ()
201
- var flipped [4 ]Edge
202
- for i , e := range edges {
203
- flipped [i ] = e .Flip ()
204
- }
205
- fmt .Printf ("Tile %d: %v (flipped: %v)\n " , i , edges , flipped )
206
- }
207
- }
208
296
allEdges := make (map [Edge ][]int )
209
297
for i , t := range tiles {
210
298
edges := t .Edges ()
@@ -235,9 +323,6 @@ func main() {
235
323
}
236
324
}
237
325
fmt .Println (product )
238
- if * debug {
239
- fmt .Printf ("Number of corners found: %d; number of sides found: %d\n " , len (corners ), len (sides ))
240
- }
241
326
242
327
var image Mosaic
243
328
for r := 0 ; r * r < len (tiles ); r ++ {
@@ -276,23 +361,23 @@ func main() {
276
361
}
277
362
278
363
count := image .Traverse (allTiles , used , 0 , 0 , RIGHT )
279
- if count == 0 {
364
+ if count != len ( image [ 0 ]) - 1 {
280
365
fmt .Println ("Failed to traverse right from what should be top left." )
281
366
return
282
367
}
283
368
284
- for c := 0 ; c * c < len (tiles ); c ++ {
369
+ for c := 0 ; c < len (image [ 0 ] ); c ++ {
285
370
count = image .Traverse (allTiles , used , 0 , c , BOTTOM )
286
- if count == 0 {
371
+ if count != len ( image ) - 1 {
287
372
fmt .Printf ("Failed to traverse down column %d\n " , c )
288
373
return
289
374
}
290
375
}
291
376
292
377
var monsterCount int
293
378
outer:
294
- for rot := 0 ; rot < 4 ; rot ++ {
295
- for flip := 0 ; flip < 2 ; flip ++ {
379
+ for flip := 0 ; flip < 2 ; flip ++ {
380
+ for rot := 0 ; rot < 4 ; rot ++ {
296
381
monsterCount = image .FindMonsters ()
297
382
if monsterCount != 0 {
298
383
break outer
@@ -312,47 +397,3 @@ outer:
312
397
}
313
398
fmt .Println (sum - monsterPixels )
314
399
}
315
-
316
- func (m Mosaic ) Traverse (allTiles map [Tile ]int , used map [int ]bool , r , c int , dir int ) int {
317
- loose := m [r ][c ].Edges ()[dir ]
318
- var rIncr , cIncr int
319
- switch dir {
320
- case RIGHT :
321
- cIncr = 1
322
- case BOTTOM :
323
- rIncr = 1
324
- case LEFT :
325
- cIncr = - 1
326
- case TOP :
327
- rIncr = - 1
328
- }
329
- i := 1
330
- outer:
331
- for ; ; i ++ {
332
- row := r + rIncr * i
333
- col := c + cIncr * i
334
- if row < 0 || row >= len (m ) {
335
- break
336
- }
337
- if row < 0 || col >= len (m [0 ]) {
338
- break
339
- }
340
- for t , s := range allTiles {
341
- if used [s ] {
342
- // Don't re-use the same piece twice.
343
- continue
344
- }
345
- edges := t .Edges ()
346
- if loose .Flip () == edges [(dir + 2 )% 4 ] {
347
- used [s ] = true
348
- loose = edges [dir ]
349
- m [row ][col ] = t
350
- continue outer
351
- }
352
- // This piece hasn't matched, continue on to other pieces.
353
- }
354
- // We didn't match any pieces, abort.
355
- return 0
356
- }
357
- return i - 1
358
- }
0 commit comments