@@ -9,57 +9,33 @@ class Day15 @Inject constructor(
99 fun partOne (filename : String ) = generatorFactory.forFile(filename).read { input ->
1010 var gx = - 1
1111 var gy = - 1
12- val area = mutableListOf<MutableList <Room >>()
13- val directions = mutableListOf<Direction >()
14-
15- var setupArea = true
16- input.forEachIndexed setup@ { yIndex, line ->
17- if (line.isEmpty()) {
18- setupArea = false
19- return @setup
20- }
21- if (setupArea) {
22- val row = mutableListOf<Room >()
23- line.forEachIndexed { xIndex, c ->
24- when (c) {
25- ' #' -> row.add(Room .WALL )
26- ' .' -> row.add(Room .EMPTY )
27- ' O' -> row.add(Room .BOX )
28- else -> {
29- row.add(Room .GUARD )
30- gx = xIndex
31- gy = yIndex
32- }
33- }
34- }
35- area.add(row)
36- } else {
37- line.forEach { c ->
38- when (c) {
39- ' <' -> directions.add(Direction .W )
40- ' ^' -> directions.add(Direction .N )
41- ' >' -> directions.add(Direction .E )
42- else -> directions.add(Direction .S )
43- }
12+ val (area, directions) = setupArea(input) { c, y, x ->
13+ listOf (
14+ when (c) {
15+ ' #' -> Room .WALL
16+ ' .' -> Room .EMPTY
17+ ' O' -> Room .BOX
18+ else -> Room .GUARD .also { gx = x; gy = y }
4419 }
45- }
20+ )
4621 }
4722
4823 directions.forEach { direction ->
4924 val (yDelta, xDelta) = when (direction) {
50- Direction .N -> - 1 to 0
51- Direction .E -> 0 to 1
52- Direction .S -> 1 to 0
53- Direction .W -> 0 to - 1
25+ Direction .N -> - 1 to 0
26+ Direction .E -> 0 to 1
27+ Direction .S -> 1 to 0
28+ Direction .W -> 0 to - 1
5429 }
5530
56- var boxes = 1
57- var boxEnd = area[gy + (yDelta * boxes)][gx + (xDelta * boxes)]
58- while (boxEnd == Room . BOX ) {
31+ var boxEnd : Room
32+ var boxes = 0
33+ do {
5934 boxes++
6035 boxEnd = area[gy + (yDelta * boxes)][gx + (xDelta * boxes)]
61- }
36+ } while (boxEnd == Room . BOX )
6237 boxes--
38+
6339 if (boxEnd == Room .EMPTY ) {
6440 while (boxes > 0 ) {
6541 area[gy + (yDelta * (boxes + 1 ))][gx + (xDelta * (boxes + 1 ))] = Room .BOX
@@ -72,61 +48,19 @@ class Day15 @Inject constructor(
7248 }
7349 }
7450
75- area.withIndex().sumOf { (y, row) ->
76- row.withIndex().sumOf { (x, room) ->
77- when (room) {
78- Room .BOX -> (100 * y) + x
79- else -> 0
80- }
81- }
82- }
51+ area.sumBoxes { it == Room .BOX }
8352 }
8453
8554 fun partTwo (filename : String ) = generatorFactory.forFile(filename).read { input ->
86- var guard: WideRoom = WideRoom .Guard (- 1 , - 1 )
87- val area = mutableListOf<MutableList <WideRoom >>()
88- val directions = mutableListOf<Direction >()
89-
90- var setupArea = true
91- input.forEachIndexed setup@ { y, line ->
92- if (line.isEmpty()) {
93- setupArea = false
94- return @setup
95- }
96- if (setupArea) {
97- val row = mutableListOf<WideRoom >()
98- line.forEachIndexed { x, c ->
99- val x1 = x* 2
100- val x2 = x* 2 + 1
101- when (c) {
102- ' #' -> {
103- row.add(WideRoom .Wall (y, x1))
104- row.add(WideRoom .Wall (y, x2))
105- }
106- ' .' -> {
107- row.add(WideRoom .Empty (y, x1))
108- row.add(WideRoom .Empty (y, x2))
109- }
110- ' O' -> {
111- row.add(WideRoom .LeftBox (y, x1))
112- row.add(WideRoom .RightBox (y, x2))
113- }
114- else -> {
115- row.add(WideRoom .Guard (y, x1).also { guard = it })
116- row.add(WideRoom .Empty (y, x2))
117- }
118- }
119- }
120- area.add(row)
121- } else {
122- line.forEach { c ->
123- when (c) {
124- ' <' -> directions.add(Direction .W )
125- ' ^' -> directions.add(Direction .N )
126- ' >' -> directions.add(Direction .E )
127- else -> directions.add(Direction .S )
128- }
129- }
55+ lateinit var guard: WideRoom
56+ val (area, directions) = setupArea(input) { c, y, x ->
57+ val x1 = x* 2
58+ val x2 = x1 + 1
59+ when (c) {
60+ ' #' -> listOf (WideRoom .Wall (y, x1), WideRoom .Wall (y, x2))
61+ ' .' -> listOf (WideRoom .Empty (y, x1), WideRoom .Empty (y, x2))
62+ ' O' -> listOf (WideRoom .LeftBox (y, x1), WideRoom .RightBox (y, x2))
63+ else -> listOf (WideRoom .Guard (y, x1), WideRoom .Empty (y, x2)).also { guard = it.first() }
13064 }
13165 }
13266
@@ -138,22 +72,24 @@ class Day15 @Inject constructor(
13872 else -> throw IllegalStateException (" can't move N/S in an E/W block" )
13973 }
14074
141- var boxes = 1
142- var boxEnd = area[guard.y][guard.x + (xDelta * boxes)]
143- while (boxEnd is WideRoom .RightBox || boxEnd is WideRoom .LeftBox ) {
75+ val guardRow = area[guard.y]
76+ var boxEnd: WideRoom
77+ var boxes = 0
78+ do {
14479 boxes++
145- boxEnd = area[guard.y] [guard.x + (xDelta * boxes)]
146- }
80+ boxEnd = guardRow [guard.x + (xDelta * boxes)]
81+ } while (boxEnd is WideRoom . RightBox || boxEnd is WideRoom . LeftBox )
14782 boxes--
83+
14884 if (boxEnd is WideRoom .Empty ) {
14985 while (boxes > 0 ) {
15086 val x = guard.x + (xDelta * (boxes + 1 ))
151- area[guard.y][ x] = area[guard.y] [guard.x + (xDelta * boxes)].also { it.x = x }
87+ guardRow[ x] = guardRow [guard.x + (xDelta * boxes)].also { it.x = x }
15288 boxes--
15389 }
154- area[guard.y] [guard.x] = WideRoom .Empty (guard.y, guard.x)
90+ guardRow [guard.x] = WideRoom .Empty (guard.y, guard.x)
15591 guard.x + = xDelta
156- area[guard.y] [guard.x] = guard
92+ guardRow [guard.x] = guard
15793 }
15894 } else { // N/S Block!
15995 val yDelta = when (direction) {
@@ -164,20 +100,23 @@ class Day15 @Inject constructor(
164100
165101 var allCanMove = true
166102 var doneSearching = false
167- val areasToMove = mutableMapOf<Int , Set <WideRoom >>()
168- areasToMove[guard.y] = setOf (area[guard.y][guard.x])
103+ val areasToMove = mutableMapOf<Int , Set <WideRoom >>().apply {
104+ put(guard.y, setOf (area[guard.y][guard.x]))
105+ }
106+
169107 var currentY = guard.y
170108 while (allCanMove && ! doneSearching) {
171109 areasToMove[currentY]?.forEach { room ->
172- when (val nextArea = area[room.y + yDelta][room.x]) {
110+ val searchY = currentY + yDelta
111+ when (val nextArea = area[searchY][room.x]) {
173112 is WideRoom .Wall -> allCanMove = false
174113 is WideRoom .LeftBox -> {
175- areasToMove.merge(currentY + yDelta , setOf (nextArea)) { a, b -> a + b }
176- areasToMove.merge(currentY + yDelta , setOf (area[room.y + yDelta ][room.x + 1 ])) { a, b -> a + b }
114+ areasToMove.merge(searchY , setOf (nextArea)) { a, b -> a + b }
115+ areasToMove.merge(searchY , setOf (area[searchY ][room.x + 1 ])) { a, b -> a + b }
177116 }
178117 is WideRoom .RightBox -> {
179- areasToMove.merge(currentY + yDelta , setOf (nextArea)) { a, b -> a + b }
180- areasToMove.merge(currentY + yDelta , setOf (area[room.y + yDelta ][room.x - 1 ])) { a, b -> a + b }
118+ areasToMove.merge(searchY , setOf (nextArea)) { a, b -> a + b }
119+ areasToMove.merge(searchY , setOf (area[searchY ][room.x - 1 ])) { a, b -> a + b }
181120 }
182121 else -> { /* ignore empty rooms */ }
183122 }
@@ -191,8 +130,9 @@ class Day15 @Inject constructor(
191130
192131 sortedEntries.forEach { (y, wideRooms) ->
193132 wideRooms.forEach { room ->
194- if (areasToMove[y - yDelta]?.contains(area[room.y - yDelta][room.x]) != true ) {
195- area[room.y][room.x] = WideRoom .Empty (room.y - yDelta, room.x)
133+ val nextY = room.y - yDelta
134+ if (areasToMove[y - yDelta]?.contains(area[nextY][room.x]) != true ) {
135+ area[room.y][room.x] = WideRoom .Empty (nextY, room.x)
196136 }
197137 room.y + = yDelta
198138 area[room.y][room.x] = room
@@ -202,14 +142,47 @@ class Day15 @Inject constructor(
202142 }
203143 }
204144
205- area.withIndex().sumOf { (y, row) ->
145+ area.sumBoxes { it is WideRoom .LeftBox }
146+ }
147+
148+ private fun <T > MutableList<MutableList<T>>.sumBoxes (roomCheck : (T ) -> Boolean ): Int {
149+ return withIndex().sumOf { (y, row) ->
206150 row.withIndex().sumOf { (x, room) ->
207- when (room) {
208- is WideRoom .LeftBox -> (100 * y) + x
209- else -> 0
151+ if (roomCheck(room)) { (100 * y) + x } else { 0 }
152+ }
153+ }
154+ }
155+
156+ private fun <RoomType > setupArea (
157+ input : Sequence <String >,
158+ roomCreator : (Char , Int , Int ) -> List <RoomType >
159+ ): Pair <MutableList <MutableList <RoomType >>, MutableList<Direction>> {
160+ val area = mutableListOf<MutableList <RoomType >>()
161+ val directions = mutableListOf<Direction >()
162+
163+ var setupArea = true
164+ input.forEachIndexed setup@ { y, line ->
165+ if (line.isEmpty()) {
166+ setupArea = false
167+ return @setup
168+ }
169+ if (setupArea) {
170+ val row = mutableListOf<RoomType >()
171+ line.forEachIndexed { x, c -> roomCreator(c, y, x).forEach(row::add) }
172+ area.add(row)
173+ } else {
174+ line.forEach { c ->
175+ when (c) {
176+ ' <' -> directions.add(Direction .W )
177+ ' ^' -> directions.add(Direction .N )
178+ ' >' -> directions.add(Direction .E )
179+ ' v' -> directions.add(Direction .S )
180+ }
210181 }
211182 }
212183 }
184+
185+ return area to directions
213186 }
214187}
215188
0 commit comments