Skip to content

Commit ed23883

Browse files
authored
Day 15 2024 cleanup (#276)
* extract sumBoxes * refactor out area/directions setup? * last cleanups
1 parent 42ce619 commit ed23883

File tree

1 file changed

+87
-114
lines changed
  • src/main/kotlin/me/peckb/aoc/_2024/calendar/day15

1 file changed

+87
-114
lines changed

src/main/kotlin/me/peckb/aoc/_2024/calendar/day15/Day15.kt

Lines changed: 87 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)