Skip to content

Commit 1a5fdfe

Browse files
committed
Solved day10 part 2
1 parent efe6aa8 commit 1a5fdfe

File tree

3 files changed

+173
-13
lines changed

3 files changed

+173
-13
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44

55
// project meta data
66
group 'de.havox_design.aoc2023'
7-
version '0.9.3'
7+
version '0.9.4'
88

99
// Switch to gradle "all" distribution.
1010
wrapper {

day10/src/main/kotlin/de/havox_design/aoc2023/day10/Day10.kt

Lines changed: 168 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,119 @@ class Day10(private var filename: String) {
88
private val ICON_NORTH_WEST_BEND = 'J'
99
private val ICON_SOUTH_WEST_BEND = '7'
1010
private val ICON_SOUTH_EAST_BEND = 'F'
11-
private val ICON_FREE_GROUND = '.'
1211

1312
fun solvePart1(): Long =
14-
solvePart1(
13+
(computeMazeLoop(
1514
getResourceAsText(filename)
1615
.map { row -> row.toCharArray().toList() }
16+
).size / 2)
17+
.toLong()
18+
19+
fun solvePart2(): Long {
20+
val maze = getResourceAsText(filename)
21+
.map { row -> row.toCharArray().toList() }
22+
23+
return computeEnclosedTiles(
24+
computeMazeLoop(maze),
25+
maze
1726
)
27+
}
28+
29+
@SuppressWarnings("kotlin:S3776")
30+
private fun computeEnclosedTiles(loop: List<Pair<Int, Int>>, maze: List<List<Char>>): Long {
31+
val (startIndex, newStart) = loop
32+
.withIndex()
33+
.minWith(compareBy<IndexedValue<Pair<Int, Int>>> { it.value.first }.thenBy { it.value.second })
34+
35+
val counterClockwise = loop[startIndex + 1].first > newStart.first
36+
|| loop[startIndex + 1].second < newStart.second
37+
38+
val enclosedTiles = loop
39+
.indices
40+
.asSequence()
41+
.flatMap {
42+
val index = (it + startIndex) % loop.size
43+
val currentTile = loop[index]
44+
val prevTile = loop[(index + loop.size - 1) % loop.size]
45+
val adjacentTileDirections = setOf(
46+
currentTile.getDirectionTo(prevTile),
47+
currentTile.getDirectionTo(loop[(index + loop.size + 1) % loop.size])
48+
)
49+
50+
when (adjacentTileDirections) {
51+
setOf(
52+
Direction.NORTH,
53+
Direction.EAST
54+
) -> when {
55+
!counterClockwise && prevTile.first < currentTile.first || counterClockwise && prevTile.second > currentTile.second -> {
56+
left(loop, currentTile, maze).asSequence()
57+
}
58+
else -> {
59+
emptySequence()
60+
}
61+
}
62+
63+
setOf(
64+
Direction.SOUTH,
65+
Direction.WEST
66+
) -> when {
67+
!counterClockwise && prevTile.first > currentTile.first || counterClockwise && prevTile.second < currentTile.second -> {
68+
right(loop, currentTile, maze).asSequence()
69+
}
70+
else -> {
71+
emptySequence()
72+
}
73+
}
74+
75+
setOf(
76+
Direction.SOUTH,
77+
Direction.EAST
78+
) -> when {
79+
!counterClockwise && prevTile.second > currentTile.second || counterClockwise && prevTile.first > currentTile.first -> {
80+
left(loop, currentTile, maze).asSequence()
81+
}
82+
else -> {
83+
emptySequence()
84+
}
85+
}
1886

19-
fun solvePart2(): Long =
20-
0L
87+
setOf(
88+
Direction.NORTH,
89+
Direction.WEST
90+
) -> when {
91+
!counterClockwise && prevTile.second < currentTile.second || counterClockwise && prevTile.first < currentTile.first -> {
92+
right(loop, currentTile, maze).asSequence()
93+
}
94+
else -> {
95+
emptySequence()
96+
}
97+
}
2198

22-
private fun solvePart1(maze: List<List<Char>>): Long {
99+
setOf(Direction.NORTH, Direction.SOUTH) -> {
100+
when {
101+
!counterClockwise == prevTile.first < currentTile.first -> {
102+
left(loop, currentTile, maze).asSequence()
103+
}
104+
!counterClockwise == prevTile.first > currentTile.first -> {
105+
right(loop, currentTile, maze).asSequence()
106+
}
107+
else -> {
108+
emptySequence()
109+
}
110+
}
111+
}
112+
113+
else -> emptySequence()
114+
}
115+
}
116+
.toSet()
117+
118+
return enclosedTiles
119+
.size
120+
.toLong()
121+
}
122+
123+
private fun computeMazeLoop(maze: List<List<Char>>): List<Pair<Int, Int>> {
23124
var start: Pair<Int, Int>? = null
24125

25126
out@ for (row in maze.indices) {
@@ -31,9 +132,7 @@ class Day10(private var filename: String) {
31132
}
32133
}
33134

34-
val loop = getLoop(start!!, maze)
35-
36-
return (loop.size / 2).toLong()
135+
return getLoop(start!!, maze)
37136
}
38137

39138
private fun getLoop(start: Pair<Int, Int>, maze: List<List<Char>>): List<Pair<Int, Int>> {
@@ -106,6 +205,67 @@ class Day10(private var filename: String) {
106205
}
107206
}
108207

208+
private fun left(
209+
loop: List<Pair<Int, Int>>,
210+
currentTile: Pair<Int, Int>,
211+
maze: List<List<Char>>
212+
): List<Pair<Int, Int>> {
213+
val rowTiles = loop
214+
.filter { it.first == currentTile.first && it.second < currentTile.second }
215+
216+
when {
217+
rowTiles.isEmpty() -> {
218+
return emptyList()
219+
}
220+
else -> {
221+
val nextTile = rowTiles
222+
.maxWith(compareBy { it.second })
223+
224+
return maze[currentTile.first]
225+
.withIndex()
226+
.filter { nextTile.second < it.index && it.index < currentTile.second }
227+
.map { Pair(currentTile.first, it.index) }
228+
}
229+
}
230+
}
231+
232+
private fun right(
233+
loop: List<Pair<Int, Int>>,
234+
currentTile: Pair<Int, Int>,
235+
maze: List<List<Char>>
236+
): List<Pair<Int, Int>> {
237+
val rowTiles = loop
238+
.filter { it.first == currentTile.first && it.second > currentTile.second }
239+
240+
when {
241+
rowTiles.isEmpty() -> {
242+
return emptyList()
243+
}
244+
else -> {
245+
val nextTile = rowTiles
246+
.minWith(compareBy { it.second })
247+
248+
return maze[currentTile.first]
249+
.withIndex()
250+
.filter { currentTile.second < it.index && it.index < nextTile.second }
251+
.map { Pair(currentTile.first, it.index) }
252+
}
253+
}
254+
}
255+
256+
private fun Pair<Int, Int>.getDirectionTo(location: Pair<Int, Int>): Direction {
257+
when {
258+
this.first != location.first && this.second != location.second -> throw IllegalArgumentException()
259+
else -> return when {
260+
this.first == location.first && this.second < location.second -> return Direction.EAST
261+
this.first == location.first && this.second > location.second -> return Direction.WEST
262+
this.second == location.second && this.first < location.first -> return Direction.SOUTH
263+
this.second == location.second && this.first > location.first -> return Direction.NORTH
264+
else -> Direction.NONE
265+
}
266+
}
267+
}
268+
109269
private fun getResourceAsText(path: String): List<String> =
110270
this.javaClass.classLoader.getResourceAsStream(path)!!.bufferedReader().readLines()
111271
}

day10/src/test/kotlin/de/havox_design/aoc2023/day10/Day10Test.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ class Day10Test {
3434
@JvmStatic
3535
private fun getDataForTestSolvePart2(): Stream<Arguments> =
3636
Stream.of(
37-
Arguments.of("part2sample1.txt", 0L),
38-
Arguments.of("part2sample2.txt", 0L),
39-
Arguments.of("part2sample3.txt", 0L),
40-
Arguments.of("part2sample4.txt", 0L)
37+
Arguments.of("part2sample1.txt", 4L),
38+
Arguments.of("part2sample2.txt", 4L),
39+
Arguments.of("part2sample3.txt", 8L),
40+
Arguments.of("part2sample4.txt", 10L)
4141
)
4242
}
4343
}

0 commit comments

Comments
 (0)