Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
4 changed files
with
255 additions
and
0 deletions.
There are no files selected for viewing
153 changes: 153 additions & 0 deletions
153
advent-of-code/src/main/kotlin/com/akikanellis/adventofcode/year2022/Day16.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
package com.akikanellis.adventofcode.year2022 | ||
|
||
object Day16 { | ||
private val VALVES_REGEX = | ||
"Valve (.+) has flow rate=(.+); tunnels? leads? to valves? (.+)".toRegex() | ||
|
||
fun highestPressureThanCanBeReleased(input: String, elephantWillHelp: Boolean) = | ||
valves(input, elephantWillHelp) | ||
.highestPressureThanCanBeReleased() | ||
|
||
private fun valves(input: String, elephantWillHelp: Boolean): Valves { | ||
val valvesToNeighbourNames = valvesToNeighbourNames(input) | ||
val valves = valvesToNeighbourNames.map { (valve, _) -> valve } | ||
|
||
valvesToNeighbourNames.forEach { (valve, neighbourNames) -> | ||
valve.neighbours = valves.filter { it.name in neighbourNames } | ||
} | ||
valves.forEach { valve -> initialiseDistancesToOtherValves(valve) } | ||
|
||
return Valves( | ||
valves = valves, | ||
elephantWillHelp = elephantWillHelp | ||
) | ||
} | ||
|
||
private fun valvesToNeighbourNames(input: String) = input.lines() | ||
.filter { it.isNotBlank() } | ||
.map { line -> | ||
val groupValues = VALVES_REGEX.matchEntire(line)!!.groupValues | ||
Pair( | ||
Valve( | ||
name = groupValues[1], | ||
flowRate = groupValues[2].toInt() | ||
), | ||
groupValues[3].split(", ") | ||
) | ||
} | ||
|
||
private fun initialiseDistancesToOtherValves(valve: Valve) { | ||
val valveNameToShortestDistance = mutableMapOf<String, Int>() | ||
.apply { put(valve.name, 0) } | ||
|
||
val remainingValves = mutableListOf(valve) | ||
while (remainingValves.isNotEmpty()) { | ||
val currentValve = remainingValves.removeFirst() | ||
val updatedDistanceToCurrentValveNeighbours = | ||
valveNameToShortestDistance[currentValve.name]!! + 1 | ||
|
||
currentValve.neighbours.forEach { currentValveNeighbour -> | ||
val precomputedDistanceToCurrentValveNeighbour = | ||
valveNameToShortestDistance.getOrDefault( | ||
currentValveNeighbour.name, | ||
Int.MAX_VALUE | ||
) | ||
|
||
if ( | ||
updatedDistanceToCurrentValveNeighbours < | ||
precomputedDistanceToCurrentValveNeighbour | ||
) { | ||
valveNameToShortestDistance[currentValveNeighbour.name] = | ||
updatedDistanceToCurrentValveNeighbours | ||
remainingValves += currentValveNeighbour | ||
} | ||
} | ||
} | ||
|
||
valve.valveNameToShortestDistance = valveNameToShortestDistance | ||
} | ||
|
||
private class Valves( | ||
val startValve: Valve, | ||
val openableValves: Set<Valve>, | ||
val elephantWillHelp: Boolean, | ||
val elephantIsHelping: Boolean | ||
) { | ||
constructor( | ||
valves: List<Valve>, | ||
elephantWillHelp: Boolean | ||
) : this( | ||
startValve = valves.single { it.name == "AA" }, | ||
openableValves = valves.filter { it.flowRate > 0 }.toSet(), | ||
elephantWillHelp = elephantWillHelp, | ||
elephantIsHelping = false | ||
) | ||
|
||
val totalMinutes = if (elephantWillHelp || elephantIsHelping) 26 else 30 | ||
val precomputedSystemStateToMaxPressure = mutableMapOf<SystemState, Int>() | ||
|
||
fun highestPressureThanCanBeReleased() = highestPressureThanCanBeReleased( | ||
remainingMinutes = totalMinutes, | ||
currentValve = startValve, | ||
remainingValves = openableValves | ||
) | ||
|
||
private fun highestPressureThanCanBeReleased( | ||
remainingMinutes: Int, | ||
currentValve: Valve, | ||
remainingValves: Set<Valve> | ||
): Int { | ||
val currentValvePressure = remainingMinutes * currentValve.flowRate | ||
val currentSystemState = SystemState( | ||
currentValveName = currentValve.name, | ||
remainingMinutes = remainingMinutes, | ||
remainingValves = remainingValves | ||
) | ||
|
||
return currentValvePressure + precomputedSystemStateToMaxPressure | ||
.getOrPut(currentSystemState) { | ||
val remainingValvesMaxPressure = remainingValves | ||
.filter { nextValve -> | ||
currentValve.distanceTo(nextValve) < remainingMinutes | ||
} | ||
.maxOfOrNull { nextValve -> | ||
val remainingMinutesForNextValve = | ||
remainingMinutes - currentValve.distanceTo(nextValve) - 1 | ||
|
||
highestPressureThanCanBeReleased( | ||
remainingMinutes = remainingMinutesForNextValve, | ||
currentValve = nextValve, | ||
remainingValves = remainingValves - nextValve | ||
) | ||
} ?: 0 | ||
|
||
if (elephantWillHelp && !elephantIsHelping) { | ||
maxOf( | ||
remainingValvesMaxPressure, | ||
Valves( | ||
startValve = startValve, | ||
openableValves = remainingValves, | ||
elephantWillHelp = false, | ||
elephantIsHelping = true | ||
).highestPressureThanCanBeReleased() | ||
) | ||
} else { | ||
remainingValvesMaxPressure | ||
} | ||
} | ||
} | ||
} | ||
|
||
private data class Valve(val name: String, val flowRate: Int) { | ||
lateinit var neighbours: List<Valve> | ||
lateinit var valveNameToShortestDistance: Map<String, Int> | ||
|
||
fun distanceTo(other: Valve) = valveNameToShortestDistance[other.name]!! | ||
} | ||
|
||
private data class SystemState( | ||
val currentValveName: String, | ||
val remainingMinutes: Int, | ||
val remainingValves: Set<Valve> | ||
) | ||
} |
28 changes: 28 additions & 0 deletions
28
advent-of-code/src/test/kotlin/com/akikanellis/adventofcode/year2022/Day16Test.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.akikanellis.adventofcode.year2022 | ||
|
||
import com.akikanellis.adventofcode.testutils.resourceText | ||
import org.junit.jupiter.params.ParameterizedTest | ||
import org.junit.jupiter.params.provider.CsvSource | ||
import kotlin.test.assertEquals | ||
|
||
class Day16Test { | ||
@ParameterizedTest | ||
@CsvSource( | ||
"/day-16-input-example.txt, false, 1_651", | ||
"/day-16-input-puzzle.txt, false, 1_653", | ||
"/day-16-input-example.txt, true, 1_707", | ||
"/day-16-input-puzzle.txt, true, 2_223" | ||
) | ||
fun `finds highest pressure that can be released`( | ||
inputFile: String, | ||
elephantWillHelp: Boolean, | ||
expectedPressure: Int | ||
) { | ||
val input = resourceText(inputFile) | ||
|
||
val highestPressureThanCanBeReleased = | ||
Day16.highestPressureThanCanBeReleased(input, elephantWillHelp) | ||
|
||
assertEquals(expectedPressure, highestPressureThanCanBeReleased) | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
advent-of-code/src/test/resources/day-16-input-example.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB | ||
Valve BB has flow rate=13; tunnels lead to valves CC, AA | ||
Valve CC has flow rate=2; tunnels lead to valves DD, BB | ||
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE | ||
Valve EE has flow rate=3; tunnels lead to valves FF, DD | ||
Valve FF has flow rate=0; tunnels lead to valves EE, GG | ||
Valve GG has flow rate=0; tunnels lead to valves FF, HH | ||
Valve HH has flow rate=22; tunnel leads to valve GG | ||
Valve II has flow rate=0; tunnels lead to valves AA, JJ | ||
Valve JJ has flow rate=21; tunnel leads to valve II |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
Valve MU has flow rate=0; tunnels lead to valves VT, LA | ||
Valve TQ has flow rate=0; tunnels lead to valves HU, SU | ||
Valve YH has flow rate=0; tunnels lead to valves CN, BN | ||
Valve EO has flow rate=0; tunnels lead to valves IK, CN | ||
Valve MH has flow rate=0; tunnels lead to valves GG, HG | ||
Valve RJ has flow rate=0; tunnels lead to valves AA, RI | ||
Valve XZ has flow rate=0; tunnels lead to valves PX, VT | ||
Valve UU has flow rate=0; tunnels lead to valves DT, XG | ||
Valve KV has flow rate=13; tunnels lead to valves HN, CV, PE, XD, TA | ||
Valve SU has flow rate=19; tunnels lead to valves TQ, HF, OL, SF | ||
Valve BB has flow rate=0; tunnels lead to valves NS, HR | ||
Valve RI has flow rate=4; tunnels lead to valves ML, EE, TZ, RJ, PE | ||
Valve TZ has flow rate=0; tunnels lead to valves VT, RI | ||
Valve LY has flow rate=0; tunnels lead to valves EE, RP | ||
Valve PX has flow rate=0; tunnels lead to valves XZ, JQ | ||
Valve VH has flow rate=0; tunnels lead to valves DT, TA | ||
Valve HN has flow rate=0; tunnels lead to valves KV, LR | ||
Valve LR has flow rate=0; tunnels lead to valves HR, HN | ||
Valve NJ has flow rate=0; tunnels lead to valves QF, JC | ||
Valve AM has flow rate=0; tunnels lead to valves OJ, AA | ||
Valve FM has flow rate=0; tunnels lead to valves VT, RP | ||
Valve VT has flow rate=5; tunnels lead to valves IP, XZ, TZ, FM, MU | ||
Valve HF has flow rate=0; tunnels lead to valves NR, SU | ||
Valve HR has flow rate=11; tunnels lead to valves BB, KO, LR | ||
Valve WX has flow rate=0; tunnels lead to valves CN, IP | ||
Valve PE has flow rate=0; tunnels lead to valves KV, RI | ||
Valve QF has flow rate=17; tunnels lead to valves YI, NJ | ||
Valve EE has flow rate=0; tunnels lead to valves LY, RI | ||
Valve UH has flow rate=25; tunnel leads to valve YI | ||
Valve CV has flow rate=0; tunnels lead to valves KV, NS | ||
Valve SF has flow rate=0; tunnels lead to valves YN, SU | ||
Valve RP has flow rate=3; tunnels lead to valves HG, FM, OJ, IK, LY | ||
Valve XD has flow rate=0; tunnels lead to valves IL, KV | ||
Valve GG has flow rate=12; tunnels lead to valves ML, IL, MH, OL, KA | ||
Valve XG has flow rate=0; tunnels lead to valves LI, UU | ||
Valve YA has flow rate=21; tunnels lead to valves UJ, GQ | ||
Valve OL has flow rate=0; tunnels lead to valves GG, SU | ||
Valve AN has flow rate=0; tunnels lead to valves AA, IX | ||
Valve LI has flow rate=15; tunnel leads to valve XG | ||
Valve GQ has flow rate=0; tunnels lead to valves YA, KO | ||
Valve HU has flow rate=0; tunnels lead to valves TQ, DT | ||
Valve OJ has flow rate=0; tunnels lead to valves RP, AM | ||
Valve YN has flow rate=0; tunnels lead to valves SF, JQ | ||
Valve ML has flow rate=0; tunnels lead to valves RI, GG | ||
Valve UJ has flow rate=0; tunnels lead to valves YA, NS | ||
Valve IX has flow rate=0; tunnels lead to valves AN, JQ | ||
Valve JC has flow rate=0; tunnels lead to valves JQ, NJ | ||
Valve TA has flow rate=0; tunnels lead to valves KV, VH | ||
Valve DT has flow rate=16; tunnels lead to valves UU, HU, KA, VH | ||
Valve NR has flow rate=0; tunnels lead to valves HF, CN | ||
Valve YI has flow rate=0; tunnels lead to valves QF, UH | ||
Valve AA has flow rate=0; tunnels lead to valves AM, AN, BN, LA, RJ | ||
Valve BN has flow rate=0; tunnels lead to valves AA, YH | ||
Valve KA has flow rate=0; tunnels lead to valves GG, DT | ||
Valve IL has flow rate=0; tunnels lead to valves GG, XD | ||
Valve CN has flow rate=7; tunnels lead to valves YH, EO, WX, NR, OM | ||
Valve IP has flow rate=0; tunnels lead to valves WX, VT | ||
Valve OM has flow rate=0; tunnels lead to valves CN, JQ | ||
Valve KO has flow rate=0; tunnels lead to valves GQ, HR | ||
Valve LA has flow rate=0; tunnels lead to valves AA, MU | ||
Valve JQ has flow rate=6; tunnels lead to valves IX, JC, PX, YN, OM | ||
Valve IK has flow rate=0; tunnels lead to valves EO, RP | ||
Valve HG has flow rate=0; tunnels lead to valves MH, RP | ||
Valve NS has flow rate=23; tunnels lead to valves CV, BB, UJ |