diff --git a/src/aoc2024/Day14.kt b/src/aoc2024/Day14.kt index 9958ecc..2380586 100644 --- a/src/aoc2024/Day14.kt +++ b/src/aoc2024/Day14.kt @@ -51,7 +51,7 @@ p=9,5 v=-3,-3 2) px == w/2, py > w/2 % h */ val z = Array(robots.size) { IntArray(4) } - for (t in 1..1000000000L) { + for (t in 1..w * h) { /*val good = robots.all { val x = ((it[0] + t * (it[2] + w)) % w).toInt() val y = ((it[1] + t * (it[3] + h)) % h).toInt() @@ -68,7 +68,7 @@ p=9,5 v=-3,-3 z.forEach { grid[it[0], it[1]] = '*' } grid.debug() println() - break + return t } return 0 } diff --git a/src/aoc2024/Day15.kt b/src/aoc2024/Day15.kt new file mode 100644 index 0000000..bee6fe7 --- /dev/null +++ b/src/aoc2024/Day15.kt @@ -0,0 +1,230 @@ +package aoc2024 + +import CharGrid +import println +import readInput + +/* +--- Day 15: Warehouse Woes --- +https://adventofcode.com/2024/day/15 +*/ +fun main() { + + val inlineTestInput2 = """ +########## +#..O..O.O# +#......O.# +#.OO..O.O# +#..O@..O.# +#O#..O...# +#O..O..O.# +#.OO.O.OO# +#....O...# +########## + +^v>^vv^v>v<>v^v<<><>>v^v^>^<<<><^ +vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<^<^^>>>^<>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^v^^<^^vv< +<>^^^^>>>v^<>vvv^>^^^vv^^>v<^^^^v<>^>vvvv><>>v^<<^^^^^ +^><^><>>><>^^<<^^v>>><^^>v>>>^v><>^v><<<>vvvv>^<><<>^>< +^>><>^v<><^vvv<^^<><^v<<<><<<^^<^>>^<<<^>>^v^>>^v>vv>^<<^v<>><<><<>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^ +<><^^>^^^<>^vv<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<> +^^>vv<^v^v^<>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<>< +v^^>>><<^^<>>^v^v^<<>^<^v^v><^<<<><<^vv>>v>v^<<^ +""" + + val inlineTestInput = """ +######## +#..O.O.# +##@.O..# +#...O..# +#.#.O..# +#...O..# +#......# +######## + +<^^>>>vv>v<< +""" + + val inlineTestInput3 = """ +####### +#...#.# +#.....# +#..OO@# +#..O..# +#.....# +####### + +): Int { + val splitp = input.withIndex().find { it.value.isEmpty() }!!.index + val grid = CharGrid(input.take(splitp)) + val inst = input.drop(splitp).joinToString("") + var (rc, rd) = grid.findMatches { it == '@' }[0] + for (m in inst) { + grid[rc, rd] = '.' + var dc = 0 + var dr = 0 + when (m) { + '<' -> dc = -1 + '>' -> dc = 1 + '^' -> dr = -1 + 'v' -> dr = 1 + } + var s = 1 + while (grid[rc + dc * s, rd + dr * s] != '.') { + if (grid[rc + dc * s, rd + dr * s] == '#') { + s = 0 + break + } + s++ + } + if (s > 0) { + if (s > 1) { + grid[rc + dc * s, rd + dr * s] = 'O' + } + rc += dc + rd += dr + } + grid[rc, rd] = '@' + } + return grid.generateGridPos().filter { grid[it] == 'O' }.sumOf { it.dc + it.dr * 100 } + } + + fun canMove(grid: CharGrid, bc: Int, rd: Int, dr: Int): Boolean { + if ((grid[bc, rd] == '[')) { + val c1 = grid[bc, rd + dr] + val c2 = grid[bc + 1, rd + dr] + if ((c1 == '.') && (c2 == '.')) return true + if ((c1 == '#') || (c2 == '#')) return false + if ((c1 == '[')) return canMove(grid, bc, rd + dr, dr) + return (if (c1 == ']') canMove(grid, bc - 1, rd + dr, dr) else true) + && (if (c2 == '[') canMove(grid, bc + 1, rd + dr, dr) else true) + } else if ((grid[bc, rd] == ']')) { + return canMove(grid, bc - 1, rd, dr) + } else { + throw IllegalStateException() + } + } + + fun doMove(grid: CharGrid, bc: Int, rd: Int, dr: Int) { + if ((grid[bc, rd] == '[')) { + val c1 = grid[bc, rd + dr] + val c2 = grid[bc + 1, rd + dr] + if ((c1 == '[')) { + doMove(grid, bc, rd + dr, dr) + } else { + if (c1 == ']') doMove(grid, bc - 1, rd + dr, dr) + if (c2 == '[') doMove(grid, bc + 1, rd + dr, dr) + } + if ((grid[bc, rd + dr] == '.') && (grid[bc + 1, rd + dr] == '.')) { + grid[bc, rd + dr] = '[' + grid[bc + 1, rd + dr] = ']' + grid[bc, rd] = '.' + grid[bc + 1, rd] = '.' + } else { + throw IllegalStateException() + } + } else if ((grid[bc, rd] == ']')) { + doMove(grid, bc - 1, rd, dr) + } + } + + fun part2(input: List): Int { + val splitp = input.withIndex().find { it.value.isEmpty() }!!.index + val sgrid = CharGrid(input.take(splitp)) + val grid = CharGrid(sgrid.width * 2, sgrid.height) + sgrid.generateGridPos().forEach { + when (val cc = sgrid[it]) { + '@' -> { + grid[it.dc * 2, it.dr] = cc + grid[it.dc * 2 + 1, it.dr] = '.' + } + + 'O' -> { + grid[it.dc * 2, it.dr] = '[' + grid[it.dc * 2 + 1, it.dr] = ']' + } + + else -> { + grid[it.dc * 2, it.dr] = cc + grid[it.dc * 2 + 1, it.dr] = cc + } + } + } + val inst = input.drop(splitp).joinToString("") + var (rc, rd) = grid.findMatches { it == '@' }[0] + for (m in inst) { + grid[rc, rd] = '.' + var dc = 0 + var dr = 0 + when (m) { + '<' -> dc = -1 + '>' -> dc = 1 + '^' -> dr = -1 + 'v' -> dr = 1 + } + if (dc != 0) { + var s = 1 + var bc: Char? = null + while (grid[rc + dc * s, rd] != '.') { + val cc = grid[rc + dc * s, rd] + if (cc == '#') { + s = 0 + break + } else { + if (bc != null && cc == bc) { + s = 0 + break + } + bc = cc + } + s++ + } + if (s > 0) { + if (s > 1) { + for (p in s downTo 1) { + grid[rc + dc * p, rd] = grid[rc + dc * (p - 1), rd] + } + } + rc += dc + rd += dr + } + } else { + if (grid[rc, rd + dr] != '.') { + if (grid[rc, rd + dr] != '#') { + if (canMove(grid, rc, rd + dr, dr)) { + doMove(grid, rc, rd + dr, dr) + rc += dc + rd += dr + } + } + } else { + rc += dc + rd += dr + } + } + grid[rc, rd] = '@' + } + return grid.generateGridPos().filter { grid[it] == '[' }.sumOf { it.dc + it.dr * 100 } + } + + // test if implementation meets criteria from the description, like: + val testInput = inlineTestInput.trim().reader().readLines() + val testInput2 = inlineTestInput2.trim().reader().readLines() + val testInput3 = inlineTestInput3.trim().reader().readLines() + //val testInput = readInput("aoc2024/Day15_test") + val testInputPart1Result = part1(testInput) + println("Part 1 Test: $testInputPart1Result") + val testInputPart2Result = part2(testInput2) + println("Part 2 Test: $testInputPart2Result") + check(testInputPart1Result == 2028) + check(testInputPart2Result == 9021) + + val input = readInput("aoc2024/Day15") + part1(input).println() + part2(input).println() +}