Skip to content

Commit db61e75

Browse files
committed
day 11, part 1 solution
1 parent 742ee10 commit db61e75

File tree

6 files changed

+204
-0
lines changed

6 files changed

+204
-0
lines changed

.idea/gradle.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

day11/build.gradle.kts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
plugins {
2+
id("org.adventofcode.kotlin-application-conventions")
3+
}
4+
5+
dependencies {
6+
7+
}
8+
9+
application {
10+
mainClass.set("org.adventofcode.AppKt")
11+
}
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package org.adventofcode
2+
3+
import java.io.File
4+
5+
typealias EnergyLevel = Int;
6+
typealias EnergyGrid = List<List<EnergyLevel>>;
7+
typealias EnergyGridMap = Map<Point, EnergyLevel>
8+
data class Point(val row: Int = 0, val col: Int = 0)
9+
data class Simulation(val grid: EnergyGrid)
10+
data class FlashResult(val energyGridMap: EnergyGridMap, val flashedPoints: Set<Point>)
11+
data class SimulationStepResult(val simulation: Simulation, val flashedPoints: Set<Point>) {
12+
val grid = simulation.grid
13+
}
14+
15+
fun EnergyLevel.step(): EnergyLevel {
16+
return when (this) {
17+
9 -> 0
18+
else -> this + 1
19+
}
20+
}
21+
22+
fun Point.toMinimalString(): String {
23+
return "($row, $col)"
24+
}
25+
26+
operator fun EnergyGrid.contains(p: Point): Boolean {
27+
if (p.row < 0 || p.row >= this.size) return false
28+
val rowData = this[p.row]
29+
if (p.col < 0 || p.col >= rowData.size) return false
30+
return true
31+
}
32+
33+
fun EnergyGrid.findAllPointsNeighboring(p: Point): List<Point> {
34+
return (-1..1).map { rowOffset ->
35+
(-1..1).map { colOffset ->
36+
val neighboringPoint = Point(p.row + rowOffset, p.col + colOffset)
37+
if (neighboringPoint in this && neighboringPoint != p) {
38+
neighboringPoint
39+
} else null
40+
}
41+
}.flatten().filterNotNull()
42+
}
43+
44+
fun EnergyGrid.map(fn: ((Point, EnergyLevel) -> EnergyLevel)? = null): EnergyGrid {
45+
return this.mapIndexed { rowIdx, rowData ->
46+
rowData.mapIndexed { colIdx, energyLevel ->
47+
val point = Point(rowIdx, colIdx)
48+
fn?.let { fn(point, energyLevel) } ?: energyLevel
49+
}
50+
}
51+
}
52+
53+
fun EnergyGrid.toMap(
54+
fn: ((Point, EnergyLevel) -> EnergyLevel)? = null,
55+
): Map<Point, EnergyLevel> {
56+
return this.mapIndexed { rowIdx, rowData ->
57+
rowData.mapIndexed { colIdx, energyLevel ->
58+
val point = Point(rowIdx, colIdx)
59+
val nextEnergyLevel = fn?.let { fn(point, energyLevel) } ?: energyLevel
60+
point to nextEnergyLevel
61+
}
62+
}.flatten().toMap()
63+
}
64+
65+
fun EnergyGrid.prettyPrint() {
66+
this.map { rowData ->
67+
println(rowData.joinToString(" "))
68+
}
69+
}
70+
71+
fun EnergyGridMap.applyTo(energyGrid: EnergyGrid): EnergyGrid {
72+
return energyGrid.map { point, energy -> this[point].let { it } ?: energy }
73+
}
74+
75+
fun Simulation.flashAt(
76+
focusPoint: Point,
77+
energyGridMap: EnergyGridMap,
78+
flashedPoints: Set<Point> = setOf(),
79+
): FlashResult {
80+
val focusEnergyLevel = energyGridMap[focusPoint]
81+
82+
if (focusEnergyLevel != 0 || focusPoint in flashedPoints) {
83+
return FlashResult(energyGridMap, flashedPoints)
84+
}
85+
86+
val neighboringPoints = grid.findAllPointsNeighboring(focusPoint)
87+
val updatedEnergyLevels = neighboringPoints.mapNotNull { point ->
88+
energyGridMap[point]?.let { energyLevel ->
89+
if (energyLevel > 0 && point !in flashedPoints) {
90+
point to energyLevel.step()
91+
} else null
92+
}
93+
}
94+
95+
val nextFlashedPoints = focusEnergyLevel?.let { if (it == 0) {
96+
flashedPoints + focusPoint
97+
} else flashedPoints } ?: flashedPoints
98+
val nextEnergyGridMap = energyGridMap + updatedEnergyLevels
99+
100+
if (updatedEnergyLevels.isEmpty()) {
101+
return FlashResult(nextEnergyGridMap, nextFlashedPoints)
102+
}
103+
104+
val result = updatedEnergyLevels
105+
.map { (p) -> p }
106+
.fold(nextEnergyGridMap to nextFlashedPoints) { acc, point ->
107+
val result = flashAt(point, acc.first, acc.second)
108+
acc.first + result.energyGridMap to acc.second + result.flashedPoints
109+
}
110+
111+
return FlashResult(result.first, result.second)
112+
}
113+
114+
fun Simulation.flashAt(
115+
row: Int,
116+
col: Int,
117+
energyGridMap: EnergyGridMap,
118+
flashedPoints: Set<Point> = setOf(),
119+
): FlashResult {
120+
return flashAt(Point(row, col), energyGridMap, flashedPoints)
121+
}
122+
123+
fun Simulation.flashAll(energyGridMap: EnergyGridMap): FlashResult {
124+
val startingPoints = energyGridMap
125+
.toList()
126+
.filter { (_, energyLevel) -> energyLevel == 0 }
127+
.map { (p) -> p }
128+
val initFlashedPoint = setOf<Point>()
129+
val result = startingPoints
130+
.fold(energyGridMap to initFlashedPoint) { acc, point ->
131+
val result = flashAt(point, acc.first, acc.second)
132+
acc.first + result.energyGridMap to acc.second + result.flashedPoints
133+
}
134+
return FlashResult(result.first, result.second)
135+
}
136+
137+
fun Simulation.step(): SimulationStepResult {
138+
val energyGridMap = this.grid.toMap { _, energyLevel -> energyLevel.step() }
139+
val flashResult = flashAll(energyGridMap)
140+
val nextGrid = flashResult.energyGridMap.applyTo(this.grid)
141+
return SimulationStepResult(Simulation(nextGrid), flashResult.flashedPoints)
142+
}
143+
144+
fun runSoluationPart1(energyGrid: EnergyGrid, stepCount: Int = 10) {
145+
println("Day 11 Solution: Part1\n")
146+
147+
var initSimulation = Simulation(energyGrid)
148+
val initStep = Triple(0, initSimulation, 0)
149+
var steps = (1..stepCount).fold(listOf(initStep)) { steps, stepCounter ->
150+
val (_, simulation, flashCount) = steps.last()
151+
val stepResult = simulation.step()
152+
steps + Triple(stepCounter, stepResult.simulation, stepResult.flashedPoints.size)
153+
}
154+
155+
steps.forEach { (step, simulation, flashCount) ->
156+
println("After step $step")
157+
simulation.grid.prettyPrint()
158+
println()
159+
}
160+
161+
val totalFlashes = steps.sumOf { (_, _, flashCount) -> flashCount }
162+
println("Total flashes: $totalFlashes")
163+
}
164+
165+
fun main() {
166+
val energyGrid = File("day11/src/main/resources/puzzleInput.txt")
167+
.readLines()
168+
.map { it.toList().map { c -> c.digitToInt() } }
169+
170+
runSoluationPart1(energyGrid, 100)
171+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
5212166716
2+
1567322581
3+
2268461548
4+
3481561744
5+
6248342248
6+
6526667368
7+
5627335775
8+
8124511754
9+
4614137683
10+
4724561156
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
5483143223
2+
2745854711
3+
5264556173
4+
6141336146
5+
6357385478
6+
4167524645
7+
2176841721
8+
6882881134
9+
4846848554
10+
5283751526

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ include(
1919
"day08",
2020
"day09",
2121
"day10",
22+
"day11",
2223
)

0 commit comments

Comments
 (0)