diff --git a/days/src/main/kotlin/Day17.kt b/days/src/main/kotlin/Day17.kt new file mode 100644 index 0000000..e14c573 --- /dev/null +++ b/days/src/main/kotlin/Day17.kt @@ -0,0 +1,127 @@ +package be.vandewalleh.aoc.days + +import be.vandewalleh.aoc.utils.input.Day +import be.vandewalleh.aoc.utils.input.Input +import be.vandewalleh.aoc.utils.input.Lines +import be.vandewalleh.aoc.utils.input.createDay + +data class Point(val x: Int, val y: Int, val z: Int) + +data class Point4(val x: Int, val y: Int, val z: Int, val blah: Int) + +enum class State { Active, Inactive } + +@Day(17) +class Day17(@Lines val input: Input>) { + + private fun neighbours3(point: Point): List { + val points = mutableListOf() + for (x in point.x - 1..point.x + 1) { + for (y in point.y - 1..point.y + 1) { + for (z in point.z - 1..point.z + 1) { + val generatedPoint = Point(x, y, z) + if (generatedPoint != point) + points.add(generatedPoint) + } + } + } + check(points.size == 26) { "Points size was ${points.size}" } + return points + } + + private fun neighbours4(point: Point4): List { + val points = mutableListOf() + for (x in point.x - 1..point.x + 1) { + for (y in point.y - 1..point.y + 1) { + for (z in point.z - 1..point.z + 1) { + for (blah in point.blah - 1..point.blah + 1) { + val generatedPoint = Point4(x, y, z, blah) + if (generatedPoint != point) + points.add(generatedPoint) + } + } + } + } + check(points.size == 80) { "Points size was ${points.size}" } + return points + } + + fun part1(): Int { + val grid = parseGrid3() + repeat(6) { step3(grid) } + return grid.values.count { it == State.Active } + } + + private fun parseGrid3(): MutableMap { + val grid = mutableMapOf() + input.value.forEachIndexed { index, row -> + row.forEachIndexed { col, char -> + val state = if (char == '#') State.Active else State.Inactive + grid[Point(index, col, 0)] = state + } + } + return grid + } + + private fun parseGrid4(): MutableMap { + val grid = mutableMapOf() + input.value.forEachIndexed { index, row -> + row.forEachIndexed { col, char -> + val state = if (char == '#') State.Active else State.Inactive + grid[Point4(index, col, 0, 0)] = state + } + } + return grid + } + + private fun step3(grid: MutableMap) { + val pointsToConsider = grid.keys.flatMap { neighbours3(it) }.toSet() + + val modifications = mutableMapOf() + for (point in pointsToConsider) { + val neighbours = neighbours3(point) + val activeNeighboursCount = neighbours.count { grid[it] ?: State.Inactive == State.Active } + val state = grid[point] ?: State.Inactive + if (state == State.Active && activeNeighboursCount !in 2..3) { + modifications[point] = State.Inactive + } else if (activeNeighboursCount == 3) { + modifications[point] = State.Active + } + } + for ((point, state) in modifications) { + grid[point] = state + } + } + + private fun step4(grid: MutableMap) { + val pointsToConsider = grid.keys.flatMap { neighbours4(it) }.toSet() + + val modifications = mutableMapOf() + for (point in pointsToConsider) { + val neighbours = neighbours4(point) + val activeNeighboursCount = neighbours.count { grid[it] ?: State.Inactive == State.Active } + val state = grid[point] ?: State.Inactive + if (state == State.Active && activeNeighboursCount !in 2..3) { + modifications[point] = State.Inactive + } else if (activeNeighboursCount == 3) { + modifications[point] = State.Active + } + } + for ((point, state) in modifications) { + grid[point] = state + } + } + + fun part2(): Int { + val grid = parseGrid4() + repeat(6) { step4(grid) } + return grid.values.count { it == State.Active } + } + +} + +fun main() = with(createDay( +)) { + println(part1()) + println(part2()) +} diff --git a/days/src/main/resources/day17.txt b/days/src/main/resources/day17.txt new file mode 100644 index 0000000..a1ba28d --- /dev/null +++ b/days/src/main/resources/day17.txt @@ -0,0 +1,8 @@ +##..#.#. +#####.## +#######. +#..#..#. +#.#...## +..#....# +....#..# +..##.#..