@@ -18,39 +18,83 @@ interface Grid {
18
18
val width: Int ;
19
19
val height: Int ;
20
20
val lastPoint: Point ;
21
+ fun isEmpty (): Boolean ;
22
+ fun isNotEmpty (): Boolean ;
21
23
operator fun contains (p : Point ): Boolean ;
22
24
operator fun get (p : Point ): Int? ;
23
25
}
24
26
25
- data class ImmutableGrid (val data : List <List <Int >>) : Grid {
26
- override val height: Int by lazy { data.size }
27
- override val width: Int by lazy { if (data.isNotEmpty()) data[0 ].size else 0 }
27
+ abstract class BaseImmutableGrid : Grid {
28
28
override val lastPoint: Point by lazy { Point (width - 1 , height - 1 ) }
29
29
30
+ override fun isEmpty (): Boolean {
31
+ return width == 0 && height == 0
32
+ }
33
+
34
+ override fun isNotEmpty (): Boolean {
35
+ return ! isEmpty()
36
+ }
37
+
30
38
override operator fun contains (p : Point ): Boolean {
31
39
val insideRowRange = p.row in 0 until height
32
40
val insideColRange = p.col in 0 until width
33
41
return insideRowRange && insideColRange
34
42
}
43
+ }
44
+
45
+ data class ImmutableGrid (val data : List <List <Int >>) : BaseImmutableGrid() {
46
+ override val height: Int by lazy { data.size }
47
+ override val width: Int by lazy { if (data.isNotEmpty()) data[0 ].size else 0 }
35
48
36
49
override fun get (p : Point ): Int? {
37
50
return data[p.row][p.col]
38
51
}
39
52
}
40
53
41
- fun ImmutableGrid .prettyPrint (withPath : Path ? = null) {
54
+ fun Grid .prettyPrint (withPath : Path ? = null) {
42
55
val pointset = withPath?.let { it.toSet() } ? : setOf ()
43
56
val padding = 2 + (withPath?.let { 4 } ? : 0 )
44
- this .data.forEachIndexed { rowIdx, row ->
45
- val s = row.mapIndexed { colIdx, value ->
57
+ ( 0 until height).forEach { rowIdx ->
58
+ val s = ( 0 until width).map { colIdx ->
46
59
val point = Point (colIdx, rowIdx)
60
+ val value = this [point]
47
61
val attr = withPath?.let { if (point in pointset) " {*}" else null }
48
62
" $value${attr?.let { it } ? : " " } " .padEnd(padding)
49
63
}
50
64
println (s.joinToString(" " ))
51
65
}
52
66
}
53
67
68
+ data class TiledGrid (
69
+ val tile : Grid ,
70
+ val widthScale : Int = 1 ,
71
+ val heightScale : Int = 1
72
+ ) : BaseImmutableGrid() {
73
+ constructor (
74
+ data: List <List <Int >>,
75
+ widthScale: Int = 1 ,
76
+ heightScale: Int = 1 ,
77
+ ) : this (ImmutableGrid (data), widthScale, heightScale)
78
+
79
+ override val height: Int by lazy { tile.height * heightScale }
80
+ override val width: Int by lazy { tile.width * widthScale }
81
+
82
+ override fun get (p : Point ): Int? {
83
+ if (p !in this ) {
84
+ return null
85
+ }
86
+
87
+ val colTileIdx = (p.col / tile.width)
88
+ val rowTileIdx = (p.row / tile.height)
89
+ val inColTileIdx = p.col % tile.width
90
+ val inRowTileIdx = p.row % tile.height
91
+ val inTilePoint = Point (inColTileIdx, inRowTileIdx)
92
+ val inTileValue = tile[inTilePoint] ? : throw error(" Invalid point in tile $inTilePoint " )
93
+ val baseValue = inTileValue - 1 + colTileIdx + rowTileIdx
94
+ return (baseValue % 9 ) + 1
95
+ }
96
+ }
97
+
54
98
data class TraversalEntry (val parent : Point ? = null , val cost : Double = 0.0 )
55
99
56
100
object PathFinder {
@@ -96,15 +140,29 @@ object PathFinder {
96
140
97
141
}
98
142
99
- fun main () {
100
- val data = File (" day15/src/main/resources/puzzleInput.txt" )
101
- .readLines()
102
- .map { it.split(" " ).drop(1 ).dropLast(1 ).map(String ::toInt) }
103
-
143
+ fun runSolutionPart1 (data : List <List <Int >>) {
144
+ println (" Day 15 Solution: Part 1\n\n " )
104
145
val grid = ImmutableGrid (data)
105
146
val path = PathFinder .findShortestPath(grid)
106
147
grid.prettyPrint(path)
148
+ val cost = path.drop(1 ).sumOf { grid[it] ? : 0 }
107
149
println ()
150
+ println (" total cost: $cost " )
151
+ }
152
+
153
+ fun runSolutionPart2 (data : List <List <Int >>) {
154
+ println (" Day 15 Solution: Part 2\n " )
155
+ val grid = TiledGrid (data, widthScale = 5 , heightScale = 5 )
156
+ val path = PathFinder .findShortestPath(grid)
108
157
val cost = path.drop(1 ).sumOf { grid[it] ? : 0 }
109
158
println (" total cost: $cost " )
110
159
}
160
+
161
+ fun main () {
162
+ val data = File (" day15/src/main/resources/puzzleInput.txt" )
163
+ .readLines()
164
+ .map { it.split(" " ).drop(1 ).dropLast(1 ).map(String ::toInt) }
165
+
166
+ runSolutionPart1(data)
167
+ // runSolutionPart2(data)
168
+ }
0 commit comments