Skip to content

Commit

Permalink
day 16 part one OK, part two WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
kgeri committed Dec 17, 2022
1 parent 57f68b2 commit 71fd827
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 0 deletions.
121 changes: 121 additions & 0 deletions src/main/kotlin/me/gergo/Aoc16.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package me.gergo

import java.io.File
import kotlin.math.max

fun main() {
val valves = File("src/main/resources/input16.txt").readLines()
.mapIndexed(::parseValves)
val valvesByName = valves.associateBy(Valve::name)
val neighbors = valves.associateWith { v -> v.tunnelsTo.map { valvesByName[it]!! } }

// Part One - dynamic programming, memoization
data class MemoKey(val valve: Valve, val opened: Set<Valve>, val minute: Int)

val memo = mutableMapOf<MemoKey, Int>()

fun findMaxPressure(current: Valve, opened: Set<Valve>, minute: Int): Int {
val key = MemoKey(current, opened, minute)
var max = memo[key]
if (max == null) {
val pressureReleased = opened.sumOf(Valve::rate)
max = pressureReleased + if (minute == 30) 0
else {
max(
if (current.rate > 0 && !opened.contains(current)) // Stay here and open current valve (if the valve is not damaged)
findMaxPressure(current, opened.plus(current), minute + 1) else 0,
neighbors[current]!!.maxOf { // ...or don't open the valve and move to a neighbor
findMaxPressure(it, opened, minute + 1)
}
)
}
memo[key] = max
}
return max
}

// FUK. I spent HOURS wondering why the sample data passes and my puzzle input does not... "You start at valve AA", NOT the first valve :|
val aa = valves.first { it.name == "AA" }

val result1 = findMaxPressure(aa, emptySet(), 1)
println("Max pressure released : $result1")

// Part Two
data class MemoKey2(
val me: Valve,
val eli: Valve,
val opened: Long,
val openedRate: Int,
val meVisited: Long,
val eliVisited: Long,
val minute: Int
) {
fun meCanOpen() = me.rate > 0 && !opened.isBitSet(me.index)
fun eliCanOpen() = eli.rate > 0 && !opened.isBitSet(eli.index)

fun meNeighbors() = neighbors[me]!!
fun eliNeighbors() = neighbors[eli]!!

fun meMovesEliOpens(neighbor: Valve) =
MemoKey2(neighbor, eli, opened.setBit(eli.index), openedRate + eli.rate, meVisited.setBit(me.index), eliVisited, minute + 1)

fun eliMovesMeOpens(neighbor: Valve) =
MemoKey2(me, neighbor, opened.setBit(me.index), openedRate + me.rate, meVisited, eliVisited.setBit(eli.index), minute + 1)

fun weBothOpen() =
MemoKey2(me, eli, opened.setBit(me.index).setBit(eli.index), openedRate + me.rate + eli.rate, meVisited, eliVisited, minute + 1)

fun weBothMove(n1: Valve, n2: Valve) =
MemoKey2(n1, n2, opened, openedRate, meVisited.setBit(me.index), eliVisited.setBit(eli.index), minute + 1)
}

val memo2 = mutableMapOf<MemoKey2, Int>()

fun permutations(k: MemoKey2) = sequence {
if (k.meCanOpen() && k.eliCanOpen() && k.me != k.eli) yield(k.weBothOpen()) // Both valves can be opened
if (k.meCanOpen())
for (n in k.eliNeighbors()) { // My valve can be opened, Eli can move
if (k.meVisited.isBitSet(n.index)) continue // Eli shouldn't go where I went
yield(k.eliMovesMeOpens(n))
}
if (k.eliCanOpen())
for (n in k.meNeighbors()) { // Eli's valve can be opened, I can move
if (k.eliVisited.isBitSet(n.index)) continue // I shouldn't go where Eli went
yield(k.meMovesEliOpens(n))
}
for (mn in k.meNeighbors()) { // We both move
if (k.eliVisited.isBitSet(mn.index)) continue // I shouldn't go where Eli went
for (en in k.eliNeighbors()) {
if (k.meVisited.isBitSet(en.index)) continue // Eli shouldn't go where I went
yield(k.weBothMove(mn, en))
}
}
}

fun findMaxPressureWithElephant(key: MemoKey2): Int {
if (key.minute == 26) return key.openedRate // We're done!

val cachedMax = memo2[key]
if (cachedMax != null) return cachedMax

val max = key.openedRate + (permutations(key).map(::findMaxPressureWithElephant).maxOrNull() ?: 0)
memo2[key] = max

if (memo2.size % 1000000 == 0) println("Memo entries: ${memo2.size}")
return max
}

val result2 = findMaxPressureWithElephant(MemoKey2(aa, aa, 0L, 0, 0L, 0L, 1))
println("Max pressure released with Eli: $result2")
}

private fun Long.isBitSet(index: Int): Boolean = this and (1L shl index) != 0L
private fun Long.setBit(index: Int): Long = this or (1L shl index)

private data class Valve(val index: Int, val name: String, val rate: Int, val tunnelsTo: List<String>)

private val ValveTunnelFormat = Regex("Valve (\\w+) has flow rate=(\\d+); tunnels? leads? to valves? (.*)")
private fun parseValves(i: Int, line: String): Valve {
val (_, name, rate, tunnels) = ValveTunnelFormat.matchEntire(line)!!.groupValues
return Valve(i, name, rate.toInt(), tunnels.split(", "))
}
63 changes: 63 additions & 0 deletions src/main/resources/input16.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
Valve OQ has flow rate=17; tunnels lead to valves NB, AK, KL
Valve HP has flow rate=0; tunnels lead to valves ZX, KQ
Valve GO has flow rate=0; tunnels lead to valves HR, GW
Valve PD has flow rate=9; tunnels lead to valves XN, EV, QE, MW
Valve NQ has flow rate=0; tunnels lead to valves HX, ZX
Valve DW has flow rate=0; tunnels lead to valves IR, WE
Valve TN has flow rate=24; tunnels lead to valves KL, EI
Valve JJ has flow rate=0; tunnels lead to valves EV, HR
Valve KH has flow rate=0; tunnels lead to valves ZQ, AA
Valve PH has flow rate=0; tunnels lead to valves FN, QE
Valve FD has flow rate=0; tunnels lead to valves SM, HX
Valve SM has flow rate=7; tunnels lead to valves WW, RZ, FD, HO, KQ
Valve PU has flow rate=0; tunnels lead to valves VL, IR
Valve OM has flow rate=0; tunnels lead to valves CM, AA
Valve KX has flow rate=20; tunnel leads to valve PC
Valve IR has flow rate=3; tunnels lead to valves PU, CM, WW, DW, AF
Valve XG has flow rate=0; tunnels lead to valves RX, OF
Valve QE has flow rate=0; tunnels lead to valves PH, PD
Valve GW has flow rate=0; tunnels lead to valves JQ, GO
Valve HO has flow rate=0; tunnels lead to valves SM, TY
Valve WU has flow rate=0; tunnels lead to valves SG, RZ
Valve MS has flow rate=0; tunnels lead to valves UE, OF
Valve JS has flow rate=0; tunnels lead to valves DO, ZX
Valve YQ has flow rate=0; tunnels lead to valves BC, SG
Valve EJ has flow rate=0; tunnels lead to valves AA, LR
Valve EI has flow rate=0; tunnels lead to valves BV, TN
Valve NC has flow rate=0; tunnels lead to valves TS, BC
Valve AF has flow rate=0; tunnels lead to valves IR, HX
Valve OX has flow rate=0; tunnels lead to valves HR, BV
Valve BF has flow rate=0; tunnels lead to valves JQ, SY
Valve CA has flow rate=0; tunnels lead to valves YD, HX
Valve KQ has flow rate=0; tunnels lead to valves HP, SM
Valve NB has flow rate=0; tunnels lead to valves OQ, OF
Valve SY has flow rate=0; tunnels lead to valves BF, BV
Valve AA has flow rate=0; tunnels lead to valves KH, EJ, OM, TY, DO
Valve BC has flow rate=11; tunnels lead to valves WE, RX, YQ, LR, NC
Valve HR has flow rate=14; tunnels lead to valves OX, GO, JJ
Valve WE has flow rate=0; tunnels lead to valves DW, BC
Valve MW has flow rate=0; tunnels lead to valves JQ, PD
Valve DO has flow rate=0; tunnels lead to valves JS, AA
Valve PC has flow rate=0; tunnels lead to valves AK, KX
Valve YD has flow rate=0; tunnels lead to valves CA, OF
Valve RX has flow rate=0; tunnels lead to valves XG, BC
Valve CM has flow rate=0; tunnels lead to valves IR, OM
Valve HX has flow rate=6; tunnels lead to valves ZQ, NQ, AF, FD, CA
Valve ZQ has flow rate=0; tunnels lead to valves KH, HX
Valve BV has flow rate=21; tunnels lead to valves SY, OX, EI
Valve AK has flow rate=0; tunnels lead to valves PC, OQ
Valve UE has flow rate=0; tunnels lead to valves MS, JQ
Valve LR has flow rate=0; tunnels lead to valves BC, EJ
Valve JQ has flow rate=8; tunnels lead to valves MW, UE, BF, GW
Valve VL has flow rate=0; tunnels lead to valves PU, ZX
Valve EV has flow rate=0; tunnels lead to valves JJ, PD
Valve TS has flow rate=0; tunnels lead to valves NC, ZX
Valve RZ has flow rate=0; tunnels lead to valves SM, WU
Valve OF has flow rate=13; tunnels lead to valves XG, YD, NB, MS, XN
Valve WW has flow rate=0; tunnels lead to valves SM, IR
Valve TY has flow rate=0; tunnels lead to valves HO, AA
Valve XN has flow rate=0; tunnels lead to valves OF, PD
Valve SG has flow rate=15; tunnels lead to valves WU, YQ
Valve FN has flow rate=25; tunnel leads to valve PH
Valve KL has flow rate=0; tunnels lead to valves TN, OQ
Valve ZX has flow rate=5; tunnels lead to valves JS, HP, VL, NQ, TS

0 comments on commit 71fd827

Please sign in to comment.