@@ -31,19 +31,7 @@ object Day20 {
31
31
def borderLeft : Border = grid.map(_.head)
32
32
def borderRight : Border = grid.map(_.last)
33
33
34
- def rotate : Tile = copy(grid = grid.transpose.reverse)
35
- def flip : Tile = copy(grid = grid.reverse)
36
-
37
- def orientations : Seq [Tile ] = Seq (
38
- this ,
39
- rotate,
40
- rotate.rotate,
41
- rotate.rotate.rotate,
42
- flip,
43
- flip.rotate,
44
- flip.rotate.rotate,
45
- flip.rotate.rotate.rotate,
46
- )
34
+ def orientations : Seq [Tile ] = grid.orientations.map(grid => copy(grid = grid))
47
35
48
36
def innerGrid : Grid [Boolean ] = grid.drop(1 ).dropRight(1 ).map(_.drop(1 ).dropRight(1 ))
49
37
@@ -77,20 +65,14 @@ object Day20 {
77
65
case (border, Seq (tile)) => border -> tile
78
66
})
79
67
80
- edgeBorderTiles
81
- .groupMapReduce(_._2)(p => Set (p._1))(_ ++ _)
68
+ edgeBorderTiles.groupMapReduce(_._2)(p => Set (p._1))(_ ++ _)
82
69
}
83
70
84
71
def findCorners (borderTiles : Map [Border , Seq [Tile ]]): Seq [Tile ] = {
85
- val tileEdgeBorders = getTileEdgeBorders(borderTiles)
86
-
87
- /* for ((a, b) <- edgeBorderTiles)
88
- println(s"$a: $b")
89
-
90
- for ((a, b) <- tileEdgeBorders)
91
- println(s"${a.id}: ${b.size}")*/
92
-
93
- tileEdgeBorders.filter(_._2.size == 4 ).keys.toSeq
72
+ getTileEdgeBorders(borderTiles)
73
+ .filter(_._2.size == 4 )
74
+ .keys
75
+ .toSeq
94
76
}
95
77
96
78
def findCorners (tiles : Seq [Tile ]): Seq [Tile ] = findCorners(getBorderTiles(tiles))
@@ -99,11 +81,6 @@ object Day20 {
99
81
100
82
def solvePuzzle (tiles : Seq [Tile ]): Grid [Tile ] = {
101
83
val borderTiles = getBorderTiles(tiles)
102
- val corners = findCorners(borderTiles)
103
- val cornerTopLeft = corners.head
104
- val cornerTopLeftBorders = getTileEdgeBorders(borderTiles)(cornerTopLeft) // TODO: don't repeat with findCorners
105
- val cornerTopLeftOriented = cornerTopLeft.orientations.find(tile => cornerTopLeftBorders.contains(tile.borderTop) && cornerTopLeftBorders.contains(tile.borderLeft)).get
106
- println(cornerTopLeftOriented)
107
84
108
85
def solveRow (tileLeft : Tile ): Vector [Tile ] = {
109
86
val border = tileLeft.borderRight
@@ -112,76 +89,77 @@ object Day20 {
112
89
if (newTiles.size == 1 ) {
113
90
val newTile = newTiles.head
114
91
val newTileOriented = newTile.orientations.find(_.borderLeft == border).get
115
- newTileOriented +: solveRow (newTileOriented)
92
+ solveRow1 (newTileOriented)
116
93
}
117
94
else if (newTiles.isEmpty) {
118
95
Vector .empty
119
96
}
120
97
else
121
- throw new IllegalArgumentException (" duplicate new tiles " )
98
+ throw new IllegalArgumentException (" ambiguous new tile " )
122
99
}
123
100
101
+ def solveRow1 (tileLeft : Tile ): Vector [Tile ] = tileLeft +: solveRow(tileLeft)
102
+
124
103
def solve (tileTop : Tile ): Grid [Tile ] = {
125
104
val border = tileTop.borderBottom
126
105
// val newTiles = borderTiles(border).toSet - tileLeft
127
106
val newTiles = borderTiles(border).toSet.filterNot(_.id == tileTop.id)
128
107
if (newTiles.size == 1 ) {
129
108
val newTile = newTiles.head
130
109
val newTileOriented = newTile.orientations.find(_.borderTop == border).get
131
- (newTileOriented +: solveRow(newTileOriented)) +: solve (newTileOriented)
110
+ solve1 (newTileOriented)
132
111
}
133
112
else if (newTiles.isEmpty) {
134
113
Vector .empty
135
114
}
136
115
else
137
- throw new IllegalArgumentException (" duplicate new tiles " )
116
+ throw new IllegalArgumentException (" ambiguous new tile " )
138
117
}
139
118
140
- (cornerTopLeftOriented +: solveRow(cornerTopLeftOriented)) +: solve(cornerTopLeftOriented)
141
- }
119
+ def solve1 (tileTop : Tile ): Grid [Tile ] = solveRow1(tileTop) +: solve(tileTop)
142
120
143
- def printGrid ( grid : Grid [ Boolean ]) : Unit = {
144
- for (row <- grid) {
145
- for (cell <- row)
146
- print( if (cell) '#' else '.' )
147
- println()
148
- }
121
+ val corners = findCorners(borderTiles)
122
+ val cornerTopLeft = corners.head
123
+ val cornerTopLeftBorders = getTileEdgeBorders(borderTiles)(cornerTopLeft) // TODO: don't repeat with findCorners
124
+ val cornerTopLeftOriented = cornerTopLeft.orientations.find(tile => cornerTopLeftBorders.contains(tile.borderTop) && cornerTopLeftBorders.contains(tile.borderLeft)).get
125
+
126
+ solve1(cornerTopLeftOriented)
149
127
}
150
128
151
- private val seamonster =
152
- """ #.
129
+ private val seaMonster =
130
+ """ #
153
131
|# ## ## ###
154
132
| # # # # # # """ .stripMargin
155
133
156
134
def checkSeaMonsters (tiles : Seq [Tile ]): Int = {
157
135
val solved = solvePuzzle(tiles)
158
- val grid = solved.mapGrid(_.innerGrid).flattenGrid // TODO: try all orientations
159
- // printGrid(grid)
136
+ val grid = solved.mapGrid(_.innerGrid).flattenGrid
160
137
161
- def grid2PosSet (grid : Grid [Boolean ]): Set [Pos ] = {
138
+ // TODO: move this to library?
139
+ def booleanGrid2Poss (grid : Grid [Boolean ]): Set [Pos ] = {
162
140
(for {
163
141
(row, y) <- grid.view.zipWithIndex
164
142
(cell, x) <- row.view.zipWithIndex
165
143
if cell
166
144
} yield Pos (x, y)).toSet
167
145
}
168
146
169
- val monster = seamonster.linesIterator.map(_.toVector).toVector.mapGrid(_ == '#' )
170
- val monsterPosSet = grid2PosSet(monster)
171
-
172
- def doOrientation (grid : Grid [Boolean ]): Option [Int ] = {
173
- val gridPosSet = grid2PosSet(grid)
147
+ val seaMonsterGrid = seaMonster.linesIterator.map(_.toVector).toVector.mapGrid(_ == '#' )
148
+ val seaMonsterPoss = booleanGrid2Poss(seaMonsterGrid)
149
+ val seaMonsterSize = Pos (seaMonsterGrid.head.length, seaMonsterGrid.length)
174
150
175
- val monsterPosSet2 =
176
- Box (Pos .zero, Pos (grid.head.length - monster.head.length - 1 , grid.length - monster.length - 1 )).iterator
177
- .map(pos => monsterPosSet.map(pos + _))
178
- .filter(_.subsetOf(gridPosSet))
179
- .reduceOption(_ ++ _)
151
+ def checkSeaMonstersGrid (grid : Grid [Boolean ]): Option [Int ] = {
152
+ val gridPoss = booleanGrid2Poss(grid)
153
+ val gridSize = Pos (grid.head.length, grid.length)
180
154
181
- monsterPosSet2.map(s => (gridPosSet -- s).size)
155
+ Box (Pos .zero, gridSize - seaMonsterSize - Pos (1 , 1 )).iterator
156
+ .map(pos => seaMonsterPoss.map(pos + _))
157
+ .filter(_.subsetOf(gridPoss))
158
+ .reduceOption(_ ++ _)
159
+ .map(seaMonsterPoss => (gridPoss -- seaMonsterPoss).size)
182
160
}
183
161
184
- grid.orientations.flatMap(doOrientation ).head
162
+ grid.orientations.flatMap(checkSeaMonstersGrid ).head
185
163
}
186
164
187
165
private val tileIdRegex = """ Tile (\d+):""" .r
0 commit comments