diff --git a/README.md b/README.md index ecd9c57..c98ada1 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,8 @@ Advent of Code is an Advent calendar of small programming puzzles by [Eric Wastl - Day 4: [Ceres Search](https://adventofcode.com/2024/day/4) -- [Day4.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day4.kt) - Day 5: [Print Queue](https://adventofcode.com/2024/day/5) -- [Day5.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day5.kt) - Day 7: [Bridge Repair](https://adventofcode.com/2024/day/7) -- [Day7.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day7.kt) -- Day 8: [Resonant Collinearity](https://adventofcode.com/2024/day/8) -- [Day7.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day8.kt) +- Day 8: [Resonant Collinearity](https://adventofcode.com/2024/day/8) -- [Day8.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day8.kt) +- Day 14: [Restroom Redoubt](https://adventofcode.com/2024/day/14) -- [Day14.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day14.kt) ### Features diff --git a/src/main/kotlin/days/Day14.kt b/src/main/kotlin/days/Day14.kt new file mode 100644 index 0000000..021c23f --- /dev/null +++ b/src/main/kotlin/days/Day14.kt @@ -0,0 +1,69 @@ +package days + +@AdventOfCodePuzzle( + name = "Restroom Redoubt", + url = "https://adventofcode.com/2024/day/14", + date = Date(day = 14, year = 2024) +) +class Day14(val input: List) : Puzzle { + + val robots: List = input.map { line -> Robot.from(line) } + + val bounds = if (input.size < 100) Point(11, 7) else Point(101, 103) + + override fun partOne() = robots + .map { it.move(100).bounds(bounds) } + .groupingBy() { quadrant(it.position) }.eachCount() + .filter { it.key != 0 } + .values + .fold(1L) { a, b -> a * b } + + override fun partTwo(): Int = + generateSequence(0) { it + 1 } + .firstNotNullOfOrNull { seconds -> + val count = robots + .map { it.move(seconds).bounds(bounds).position } + .toSet().count() + if (count == input.size) seconds else null + } ?: error("No solution found") + + fun draw(robots: List) { + (0..bounds.y).forEach { y -> + (0..bounds.x).map { x -> + if (robots.any { it.position == Point(x, y) }) "#" else "." + }.joinToString("").also { println(it) } + } + } + + private fun quadrant(p: Point): Int = + when { // top left, top right, bottom left, bottom right + p.x in 0..<(bounds.x / 2) && p.y in 0..<(bounds.y / 2) -> 1 // top left + p.x in (bounds.x / 2 + 1)..bounds.x && p.y in 0..<(bounds.y / 2) -> 2 // top right + p.x in 0..<(bounds.x / 2) && p.y in (bounds.y / 2 + 1)..bounds.y -> 3 // bottom left + p.x in (bounds.x / 2 + 1)..bounds.x && p.y in (bounds.y / 2 + 1)..bounds.y -> 4 // bottom right + else -> 0 + } + + data class Robot(val position: Point, val velocity: Point) { + fun move(times: Int) = Robot(position + (velocity * times), velocity) + fun bounds(bounds: Point) = Robot(position.moveToBounds(bounds), velocity) + + companion object { + fun from(line: String): Robot { + val (p, v) = line.split(" ") + val position = p.removePrefix("p=").split(",").map { it.toInt() } + val velocity = v.removePrefix("v=").split(",").map { it.toInt() } + return Robot(Point(position[0], position[1]), Point(velocity[0], velocity[1])) + } + } + } + + data class Point(val x: Int, val y: Int) { + operator fun plus(other: Point) = Point(x + other.x, y + other.y) + operator fun minus(other: Point) = Point(x - other.x, y - other.y) + operator fun times(o: Int) = Point(x * o, y * o) + + fun moveToBounds(bounds: Point) = Point(x.mod(bounds.x), y.mod(bounds.y)) + } + +} \ No newline at end of file diff --git a/src/main/resources/input_day_14.txt b/src/main/resources/input_day_14.txt new file mode 100644 index 0000000..ffdfcad --- /dev/null +++ b/src/main/resources/input_day_14.txt @@ -0,0 +1,500 @@ +p=54,45 v=-37,75 +p=39,0 v=-91,50 +p=55,25 v=64,18 +p=75,15 v=70,-15 +p=38,8 v=66,-55 +p=86,42 v=7,73 +p=26,0 v=-72,-1 +p=15,20 v=77,-77 +p=77,45 v=44,-98 +p=2,16 v=-98,-99 +p=73,62 v=93,-79 +p=26,65 v=12,57 +p=93,84 v=32,-2 +p=37,57 v=-28,57 +p=29,65 v=22,71 +p=83,92 v=-82,-81 +p=59,75 v=82,-59 +p=32,51 v=-35,8 +p=30,14 v=-28,-77 +p=89,83 v=-67,-62 +p=12,52 v=-90,84 +p=81,12 v=-10,91 +p=52,86 v=-92,44 +p=4,38 v=-43,10 +p=21,57 v=-16,38 +p=82,49 v=52,3 +p=49,93 v=-1,74 +p=62,59 v=-67,16 +p=65,43 v=-3,-44 +p=30,23 v=9,7 +p=74,31 v=98,83 +p=0,56 v=-94,59 +p=33,50 v=-18,-22 +p=95,33 v=24,20 +p=49,82 v=-29,-81 +p=43,79 v=71,69 +p=92,94 v=83,83 +p=7,82 v=44,-28 +p=65,26 v=63,29 +p=63,48 v=34,-16 +p=98,85 v=-87,-56 +p=24,35 v=-19,25 +p=16,26 v=56,-52 +p=49,87 v=37,9 +p=7,21 v=-37,4 +p=60,77 v=-46,20 +p=31,81 v=75,-86 +p=92,10 v=-59,61 +p=12,61 v=11,-35 +p=93,60 v=-79,-76 +p=73,84 v=-57,-2 +p=89,64 v=-4,92 +p=22,46 v=2,-68 +p=52,15 v=-46,-39 +p=85,43 v=-22,-49 +p=40,43 v=-82,27 +p=47,1 v=-53,-57 +p=73,77 v=-58,52 +p=77,15 v=-12,-9 +p=56,51 v=50,27 +p=8,29 v=68,-55 +p=78,19 v=-79,7 +p=59,26 v=84,-72 +p=87,14 v=15,10 +p=4,98 v=-61,77 +p=72,13 v=-48,-69 +p=7,19 v=4,51 +p=75,82 v=-24,88 +p=55,2 v=-82,7 +p=74,73 v=-85,41 +p=37,66 v=-36,-5 +p=22,10 v=-79,88 +p=63,25 v=60,49 +p=9,31 v=-42,13 +p=64,74 v=-56,33 +p=49,50 v=25,-82 +p=15,38 v=13,-93 +p=84,23 v=-10,-53 +p=50,48 v=-54,35 +p=43,100 v=95,46 +p=76,2 v=-3,-61 +p=69,11 v=-75,-23 +p=76,38 v=3,94 +p=9,4 v=-24,-18 +p=72,7 v=87,28 +p=55,1 v=64,88 +p=0,33 v=50,-42 +p=26,55 v=29,-31 +p=39,87 v=-99,4 +p=92,86 v=-51,-47 +p=98,98 v=-50,50 +p=62,65 v=90,87 +p=47,3 v=85,-79 +p=61,50 v=27,16 +p=49,100 v=-75,55 +p=49,85 v=-83,36 +p=83,18 v=34,-77 +p=64,46 v=43,-79 +p=52,74 v=56,-86 +p=92,53 v=8,69 +p=36,25 v=7,-47 +p=82,101 v=-22,96 +p=0,36 v=-51,44 +p=0,18 v=50,45 +p=7,30 v=-66,-96 +p=40,28 v=27,-87 +p=75,79 v=-39,90 +p=58,85 v=-95,-20 +p=44,84 v=-60,-7 +p=63,14 v=61,10 +p=40,69 v=-36,60 +p=20,95 v=58,85 +p=26,80 v=-59,-18 +p=67,73 v=-27,-27 +p=88,79 v=32,58 +p=72,2 v=-14,48 +p=99,42 v=72,-1 +p=1,20 v=-51,72 +p=39,86 v=-27,20 +p=91,61 v=-78,-19 +p=78,22 v=-29,-20 +p=26,81 v=-99,52 +p=60,32 v=-98,-81 +p=19,65 v=-80,-73 +p=70,82 v=62,44 +p=10,20 v=77,21 +p=98,49 v=-5,35 +p=22,58 v=-7,68 +p=64,35 v=-66,40 +p=44,79 v=9,-32 +p=33,42 v=33,-44 +p=93,94 v=-74,47 +p=27,42 v=84,-60 +p=55,47 v=-31,82 +p=23,37 v=-7,-79 +p=28,95 v=-71,53 +p=47,32 v=-17,-98 +p=28,72 v=57,44 +p=75,81 v=-75,3 +p=47,27 v=10,-3 +p=39,27 v=2,85 +p=56,38 v=-10,-71 +p=50,34 v=-46,-96 +p=11,49 v=23,3 +p=8,3 v=-61,99 +p=20,91 v=51,-26 +p=14,19 v=40,-9 +p=69,49 v=49,74 +p=4,62 v=69,45 +p=60,81 v=81,-51 +p=12,79 v=-61,28 +p=38,2 v=19,-42 +p=74,42 v=-13,-49 +p=4,94 v=22,58 +p=42,20 v=-90,48 +p=32,68 v=-35,-70 +p=92,34 v=68,78 +p=48,24 v=78,-15 +p=51,92 v=9,47 +p=93,1 v=51,-42 +p=89,32 v=71,-3 +p=46,17 v=-46,-74 +p=37,44 v=-62,-46 +p=95,41 v=-3,92 +p=0,45 v=87,46 +p=60,6 v=-93,12 +p=44,98 v=92,-56 +p=78,76 v=74,63 +p=20,11 v=-76,-95 +p=23,99 v=-25,-34 +p=2,12 v=-51,15 +p=9,11 v=-40,46 +p=31,51 v=48,51 +p=70,87 v=-31,-10 +p=27,32 v=95,81 +p=81,41 v=-40,43 +p=69,62 v=44,3 +p=28,33 v=-81,-10 +p=74,87 v=37,-81 +p=50,46 v=-54,59 +p=75,102 v=89,61 +p=26,59 v=48,-57 +p=60,3 v=92,77 +p=55,23 v=-65,-69 +p=65,82 v=-16,64 +p=43,9 v=-88,-46 +p=33,24 v=-60,-94 +p=76,61 v=-48,95 +p=98,4 v=-42,-34 +p=87,42 v=15,-33 +p=54,27 v=91,-28 +p=65,17 v=-59,55 +p=70,8 v=-30,15 +p=18,12 v=39,56 +p=76,63 v=-67,-22 +p=61,53 v=-4,17 +p=74,34 v=16,29 +p=2,28 v=-92,-85 +p=51,97 v=-62,-68 +p=77,14 v=98,-12 +p=11,53 v=-43,51 +p=83,80 v=-49,6 +p=38,84 v=64,-60 +p=83,75 v=33,-70 +p=68,42 v=-57,-6 +p=99,41 v=34,-34 +p=86,89 v=16,52 +p=85,2 v=-86,-91 +p=12,59 v=37,97 +p=77,9 v=-67,72 +p=84,66 v=-4,30 +p=99,89 v=76,-37 +p=76,59 v=-57,38 +p=31,77 v=56,90 +p=22,15 v=-25,-15 +p=30,59 v=-39,85 +p=6,68 v=87,-35 +p=19,99 v=-25,26 +p=54,43 v=99,95 +p=88,64 v=98,38 +p=32,11 v=47,80 +p=29,42 v=-5,-79 +p=24,4 v=75,61 +p=16,69 v=-5,36 +p=11,63 v=86,68 +p=80,34 v=-3,-52 +p=77,25 v=-50,45 +p=66,16 v=63,-96 +p=55,39 v=-47,32 +p=46,31 v=-82,-44 +p=65,0 v=15,-79 +p=59,58 v=-21,-61 +p=50,95 v=65,-50 +p=94,94 v=97,-45 +p=28,13 v=29,53 +p=97,35 v=96,89 +p=15,20 v=32,-62 +p=64,39 v=-92,-57 +p=33,20 v=38,-74 +p=5,14 v=-4,64 +p=2,73 v=43,-45 +p=91,20 v=24,-39 +p=31,48 v=29,-27 +p=5,39 v=13,-66 +p=79,14 v=-95,-9 +p=13,5 v=-91,78 +p=8,7 v=-7,-66 +p=88,72 v=-4,79 +p=72,11 v=80,53 +p=9,93 v=-43,9 +p=51,2 v=37,12 +p=3,87 v=-88,-40 +p=67,93 v=-3,70 +p=62,102 v=-67,-23 +p=68,23 v=83,79 +p=11,6 v=-51,-34 +p=49,29 v=92,70 +p=62,54 v=-93,-8 +p=64,15 v=63,37 +p=28,91 v=-45,-13 +p=85,80 v=70,-89 +p=75,72 v=-76,-21 +p=12,55 v=57,-4 +p=13,94 v=-40,-67 +p=36,25 v=-2,-59 +p=7,6 v=51,-59 +p=64,91 v=-75,-26 +p=35,83 v=1,63 +p=87,62 v=-31,-37 +p=44,86 v=-49,-10 +p=49,98 v=-37,69 +p=78,85 v=-49,-83 +p=11,34 v=-78,56 +p=33,59 v=-56,30 +p=47,85 v=-55,1 +p=72,35 v=-11,56 +p=79,38 v=34,5 +p=6,48 v=31,98 +p=64,62 v=-84,-16 +p=27,6 v=-35,80 +p=53,19 v=46,-1 +p=74,7 v=-21,34 +p=97,61 v=31,35 +p=24,47 v=20,-30 +p=44,48 v=-91,97 +p=94,41 v=-13,-60 +p=9,28 v=-61,59 +p=56,64 v=-66,82 +p=42,94 v=-57,-65 +p=57,28 v=76,1 +p=3,74 v=21,-35 +p=74,9 v=1,71 +p=47,55 v=-19,-38 +p=95,40 v=60,92 +p=68,52 v=-94,-49 +p=92,9 v=42,-58 +p=32,48 v=-54,43 +p=58,98 v=92,-96 +p=80,75 v=14,-59 +p=71,18 v=98,7 +p=96,32 v=-22,-1 +p=70,60 v=26,-65 +p=40,54 v=-27,29 +p=25,96 v=86,1 +p=2,96 v=-97,-37 +p=63,84 v=63,85 +p=65,84 v=-48,-78 +p=55,69 v=17,-73 +p=87,34 v=-95,27 +p=7,47 v=76,17 +p=12,55 v=68,-47 +p=15,26 v=-56,-92 +p=72,67 v=57,56 +p=67,84 v=73,93 +p=30,59 v=1,-38 +p=89,20 v=-43,-25 +p=74,40 v=75,-9 +p=77,60 v=19,-76 +p=62,97 v=-20,-12 +p=28,42 v=66,84 +p=18,28 v=30,16 +p=62,75 v=34,-37 +p=95,18 v=78,94 +p=39,42 v=-27,-30 +p=90,39 v=79,-33 +p=21,98 v=11,-96 +p=21,55 v=-83,-91 +p=50,21 v=-92,86 +p=19,58 v=-25,-54 +p=59,8 v=-56,-85 +p=99,99 v=-87,36 +p=46,29 v=57,-14 +p=50,59 v=-65,-54 +p=42,87 v=1,17 +p=40,84 v=74,36 +p=58,87 v=44,11 +p=95,80 v=98,-62 +p=51,20 v=-28,-93 +p=11,80 v=-79,-13 +p=33,28 v=6,81 +p=81,77 v=-49,-32 +p=94,70 v=-5,-62 +p=36,77 v=-45,-73 +p=54,82 v=40,-33 +p=97,98 v=-69,70 +p=30,14 v=92,53 +p=95,44 v=52,21 +p=36,51 v=38,46 +p=7,102 v=44,-63 +p=73,51 v=65,-96 +p=34,46 v=-63,27 +p=24,84 v=84,-78 +p=14,46 v=-17,62 +p=55,29 v=-29,-74 +p=40,73 v=42,-94 +p=35,55 v=-71,73 +p=13,17 v=58,64 +p=22,54 v=-44,-46 +p=21,77 v=-90,33 +p=85,11 v=53,50 +p=53,95 v=44,-61 +p=18,29 v=-97,-6 +p=1,11 v=-69,80 +p=6,55 v=49,92 +p=33,11 v=38,-28 +p=69,6 v=82,-7 +p=74,81 v=43,3 +p=28,52 v=-81,-87 +p=61,93 v=85,-53 +p=20,45 v=-81,30 +p=47,21 v=-64,75 +p=98,57 v=51,-51 +p=49,40 v=-92,51 +p=4,5 v=11,66 +p=100,21 v=-16,90 +p=15,18 v=72,64 +p=26,85 v=-25,-19 +p=63,76 v=90,-24 +p=86,20 v=-3,-77 +p=14,36 v=-52,54 +p=68,18 v=-2,10 +p=95,20 v=-68,-39 +p=26,82 v=11,-13 +p=0,71 v=-79,9 +p=77,101 v=-26,5 +p=61,7 v=48,98 +p=36,6 v=-17,-15 +p=12,98 v=-13,59 +p=19,72 v=11,-65 +p=30,45 v=66,54 +p=62,99 v=-20,23 +p=64,73 v=-86,30 +p=3,71 v=-14,-62 +p=92,66 v=-33,-51 +p=89,24 v=-77,-93 +p=2,101 v=50,39 +p=42,18 v=46,-28 +p=97,69 v=87,96 +p=51,79 v=36,14 +p=46,4 v=63,-83 +p=83,2 v=24,38 +p=71,3 v=-77,72 +p=47,94 v=17,47 +p=56,95 v=5,-15 +p=98,76 v=78,-32 +p=34,45 v=-24,-28 +p=72,98 v=-57,-34 +p=14,69 v=21,-19 +p=3,57 v=59,65 +p=54,26 v=-84,37 +p=71,29 v=96,-60 +p=18,10 v=-25,-99 +p=66,34 v=-85,-66 +p=30,0 v=-63,9 +p=46,40 v=-72,32 +p=54,97 v=29,88 +p=95,40 v=98,5 +p=79,26 v=14,-53 +p=86,19 v=-65,-70 +p=19,98 v=-50,56 +p=63,51 v=26,-27 +p=54,9 v=36,-85 +p=25,25 v=41,31 +p=52,82 v=43,96 +p=29,82 v=-81,-75 +p=46,4 v=-97,-86 +p=12,30 v=13,54 +p=13,27 v=40,7 +p=77,32 v=16,-55 +p=17,100 v=-99,-36 +p=6,18 v=82,-99 +p=53,52 v=-9,-68 +p=53,43 v=-37,-98 +p=7,102 v=13,-61 +p=46,36 v=55,35 +p=20,47 v=13,49 +p=96,10 v=-96,-85 +p=77,42 v=-94,24 +p=0,61 v=-42,-92 +p=84,29 v=-13,31 +p=77,26 v=71,81 +p=22,20 v=-45,37 +p=3,61 v=-79,-54 +p=2,48 v=4,87 +p=53,71 v=18,98 +p=20,85 v=-25,54 +p=83,51 v=-71,-19 +p=46,79 v=-64,13 +p=16,99 v=-10,1 +p=64,20 v=62,70 +p=39,88 v=-91,-67 +p=14,79 v=87,98 +p=7,65 v=39,-78 +p=91,96 v=23,12 +p=39,74 v=82,36 +p=17,74 v=-80,71 +p=63,31 v=-75,-60 +p=51,95 v=64,93 +p=95,63 v=-89,69 +p=86,83 v=-60,85 +p=45,9 v=25,43 +p=44,101 v=-73,31 +p=64,22 v=-92,-74 +p=26,30 v=5,-14 +p=64,95 v=8,47 +p=94,61 v=13,25 +p=40,97 v=-27,80 +p=99,48 v=2,-72 +p=75,84 v=-94,-29 +p=19,38 v=-43,5 +p=97,75 v=69,3 +p=19,57 v=39,57 +p=54,11 v=-91,9 +p=88,40 v=-96,-71 +p=63,10 v=-75,7 +p=90,36 v=-76,51 +p=34,7 v=38,-4 +p=5,86 v=22,-64 +p=0,2 v=-42,-88 +p=24,94 v=66,-75 +p=4,84 v=22,17 +p=73,98 v=33,47 +p=0,68 v=-23,-51 +p=28,13 v=-81,-12 +p=62,13 v=-67,2 +p=75,67 v=21,-76 +p=46,89 v=17,-44 +p=29,8 v=-64,80 +p=64,35 v=-93,34 +p=77,66 v=-77,80 +p=23,55 v=-73,-80 +p=69,1 v=16,-85 +p=36,88 v=-8,-80 +p=46,5 v=63,-53 +p=53,91 v=-9,90 +p=79,87 v=-58,-40 +p=59,19 v=-64,-39 +p=65,70 v=47,-3 +p=96,43 v=42,-33 +p=91,17 v=13,59 \ No newline at end of file diff --git a/src/test/kotlin/SolutionsTest.kt b/src/test/kotlin/SolutionsTest.kt index 14356fd..f68c7e3 100644 --- a/src/test/kotlin/SolutionsTest.kt +++ b/src/test/kotlin/SolutionsTest.kt @@ -16,6 +16,7 @@ class SolutionsTest { Day5(InputReader.getInputAsList(5)) to Pair(6041, 4884), Day7(InputReader.getInputAsList(7)) to Pair(267566105056L, 116094961956019L), Day8(InputReader.getInputAsList(8)) to Pair(371, 1229), + Day14(InputReader.getInputAsList(14)) to Pair(214109808L, 7687), ) .map { (day, answers) -> DynamicTest.dynamicTest("${day.javaClass.simpleName} -> ${answers.first} / ${answers.second}") { diff --git a/src/test/kotlin/days/Day14Test.kt b/src/test/kotlin/days/Day14Test.kt new file mode 100644 index 0000000..9a75bfa --- /dev/null +++ b/src/test/kotlin/days/Day14Test.kt @@ -0,0 +1,34 @@ +package days + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test + +@DisplayName("Day 14") +class Day14Test { + val robots = """ + p=0,4 v=3,-3 + p=6,3 v=-1,-3 + p=10,3 v=-1,2 + p=2,0 v=2,-1 + p=0,0 v=1,3 + p=3,0 v=-2,-2 + p=7,6 v=-1,-3 + p=3,0 v=-1,-2 + p=9,3 v=2,3 + p=7,3 v=-1,2 + p=2,4 v=2,-3 + p=9,5 v=-3,-3""".trimIndent().lines() + + @Nested + @DisplayName("Part 1") + inner class Part1 { + + @Test + fun `Multiplying these together gives a total safety factor of 12`() { + assertThat(Day14(robots).partOne()).isEqualTo(12) + } + } + +} \ No newline at end of file