Skip to content

Commit

Permalink
2024 - Day 15 - still part 2 - last check-in more or less worked for …
Browse files Browse the repository at this point in the history
…part 2. Then refactored a bit.
  • Loading branch information
fmmr committed Dec 15, 2024
1 parent c36a9cb commit ec3ca95
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 75 deletions.
6 changes: 1 addition & 5 deletions src/main/kotlin/no/rodland/advent/Cave.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ operator fun Cave.get(pos: Pos): Char {

fun Cave.getOrNull(pos: Pos): Char? = if (pos in this) this[pos] else null

fun Cave.copy() = this.indices.map { y ->
this.indices.map { x ->
this[y][x]
}.toCharArray()
}.toTypedArray<CharArray>()
fun Cave.copy() = this.map { row -> row.map { it }.toCharArray() }.toTypedArray<CharArray>()

fun fromMap(map: Map<Pos, Char>): Cave {
val maxX = map.keys.maxOf { it.x }
Expand Down
130 changes: 66 additions & 64 deletions src/main/kotlin/no/rodland/advent_2024/Day15.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,45 @@ import no.rodland.advent.*
// template generated: 15/12/2024
// Fredrik Rødland 2024

class Day15(val input: List<String>) : Day<Long, Long, Pair<Pair<Pos, Cave>, List<Direction>>> {
class Day15(val input: List<String>) : Day<Int, Int, Pair<Pair<Array<CharArray>, Array<CharArray>>, Pair<Pos, List<Direction>>>> {

private val parsed = input.parse()
private val start = parsed.first.first
private val grid = parsed.first.second
private val directions = parsed.second
private val width = grid[0].size
private val height = grid.size

override fun partOne(): Long {
val gridCopy = grid.copy()
var p = start
directions.forEach { d -> p = gridCopy.move(d, p) }
private val grid = parsed.first.first
private val grid2 = parsed.first.second
private val start = parsed.second.first
private val directions = parsed.second.second
private val boxCorner = setOf('O', '[')

override fun partOne(): Int {
return solve(start, grid.copy())
}

override fun partTwo(): Int {
return solve(Pos(start.x * 2, start.y), grid2.copy())
}

private fun solve(p: Pos, gridCopy: Array<CharArray>): Int {
directions.fold(p) { pos, direction ->
gridCopy.move(direction, pos)
}
return gridCopy
.flatMapIndexed { y, row ->
row.mapIndexed { x, c -> if (c == 'O') 100 * y + x else 0 }
row.mapIndexed { x, c -> if (c in boxCorner) 100 * y + x else 0 }
}
.sum().toLong()
.sum()
}

override fun partTwo(): Long {
return 2
private fun Cave.move(d: Direction, robot: Pos): Pos {
val changes = getAreaToMove(this, d, robot).changes(this, d)
return changes
.mapNotNull { (p, c) ->
this[p] = c
if (c == '@') p else null
}
.firstOrNull() ?: robot
}

private fun getRest(cave: Cave, d: Direction, robot: Pos): Set<Pos> {
private fun getAreaToMove(cave: Cave, d: Direction, robot: Pos): Set<Pos> {
val set = mutableSetOf<Pos>()
val queue = ArrayDeque<Pos>()
queue.add(robot)
Expand All @@ -49,25 +63,25 @@ class Day15(val input: List<String>) : Day<Long, Long, Pair<Pair<Pos, Cave>, Lis
set.add(p)
}

// ']' -> {
// set.add(p)
// val side = Pos(p.x - 1, p.y)
// set.add(side)
// val pnext = p.next(d)
// val sidenext = side.next(d)
// if (pnext !in queue) set.add(pnext)
// if (sidenext !in queue) set.add(sidenext)
// }
//
// '[' -> {
// set.add(p)
// val side = Pos(p.x + 1, p.y)
// set.add(side)
// val pNext = p.next(d)
// val sideNext = side.next(d)
// if (pNext !in queue) set.add(pNext)
// if (sideNext !in queue) set.add(sideNext)
// }
']' -> {
val side = Pos(p.x - 1, p.y)
val pNext = p.next(d)
val sideNext = side.next(d)
if (pNext !in set) queue.add(pNext)
if (sideNext !in set) queue.add(sideNext)
set.add(p)
set.add(side)
}

'[' -> {
val side = Pos(p.x + 1, p.y)
val pNext = p.next(d)
val sideNext = side.next(d)
if (pNext !in set) queue.add(pNext)
if (sideNext !in set) queue.add(sideNext)
set.add(p)
set.add(side)
}

else -> error("Unexpected character: ${cave[p]}")
}
Expand All @@ -76,42 +90,30 @@ class Day15(val input: List<String>) : Day<Long, Long, Pair<Pair<Pos, Cave>, Lis
return if (possible) set else emptySet()
}

private fun Set<Pos>.changes(cave: Cave, d: Direction, robot: Pos): Map<Pos, Char> {

val clearAll = map { p -> p to '.' }.toMap()
val newValues = map { p -> p.next(d) to cave[p] }.toMap()
// XXX probably something I can do here
return clearAll.mapValues { (k, v) -> newValues[k] ?: v }


// val chars = map { cave[it] }
// var i = 0
// val old = if (isEmpty()) {
// emptyMap()
// } else {
// (listOf('.') + (1..<size).map { chars[it - 1] }).associateBy { robot.next(d, i++) }
// }
// return old
private fun Set<Pos>.changes(cave: Cave, d: Direction): Map<Pos, Char> {
val clearAll = associate { p -> p to '.' }
val newValues = associate { p -> p.next(d) to cave[p] }
return (clearAll + newValues).toMap().filterKeys { it in this }
}

private fun Cave.move(d: Direction, robot: Pos): Pos {
val line: Set<Pos> = getRest(this, d, robot)
val changes = line.changes(this, d, robot)
return changes
.mapNotNull { (p, c) ->
this[p] = c
if (c == '@') p else null
}
.firstOrNull() ?: robot
}

override fun List<String>.parse(): Pair<Pair<Pos, Cave>, List<Direction>> {
override fun List<String>.parse(): Pair<Pair<Array<CharArray>, Array<CharArray>>, Pair<Pos, List<Direction>>> {
val (map, move) = joinToString("\n").split("\n\n")
var start = Pos(0, 0)
val lines = map.lines()
val cave = lines.indices.map { y -> lines.indices.map { x -> lines[y][x].also { if (it == '@') start = Pos(x, y) } }.toCharArray() }.toTypedArray<CharArray>()
val cavePart2 = cave.mapIndexed { _, row ->
row.flatMapIndexed { _, c ->
when (c) {
'O' -> listOf('[', ']')
'@' -> listOf('@', '.')
'#' -> listOf('#', '#')
'.' -> listOf('.', '.')
else -> error("Invalid character")
}
}.toCharArray()
}.toTypedArray<CharArray>()
val directions = move.split("\n").flatMap { s -> s.map { Direction.fromChar(it) } }
return (start to cave) to directions
return (cave to cavePart2) to (start to directions)
}

override val day = "15".toInt()
Expand Down
12 changes: 6 additions & 6 deletions src/test/kotlin/no/rodland/advent_2024/Day15Test.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ internal class Day15Test {
private val data15 = "2024/input_15.txt".readFile()
private val test15 = "2024/input_15_test.txt".readFile()

private val resultTestOne = 10092L
private val resultTestTwo = 2L
private val resultOne = 1552879L
private val resultTwo = 2L
private val resultTestOne = 10092
private val resultTestTwo = 9021
private val resultOne = 1552879
private val resultTwo = 1561175

val test = defaultTestSuiteParseOnInit(
Day15(data15),
Expand All @@ -29,8 +29,8 @@ internal class Day15Test {
resultTwo,
{ Day15(data15) },
{ Day15(test15) },
numTestPart1 = 5,
numTestPart2 = 1
numTestPart1 = 10,
numTestPart2 = 10
)

@Nested
Expand Down

0 comments on commit ec3ca95

Please sign in to comment.