Skip to content

Commit

Permalink
a little 2015
Browse files Browse the repository at this point in the history
  • Loading branch information
elwaxoro committed Dec 27, 2024
1 parent 1248f8c commit 201e2a1
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 0 deletions.
66 changes: 66 additions & 0 deletions advent/src/test/kotlin/org/elwaxoro/advent/y2015/Dec19.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.elwaxoro.advent.y2015

import org.elwaxoro.advent.PuzzleDayTester
import org.elwaxoro.advent.takeSplit

/**
* Day 19: Medicine for Rudolph
*/
class Dec19 : PuzzleDayTester(19, 2015) {

override fun part1(): Any = loader().let { (choices, input) ->
choices.flatMap { (a, b) ->
input.mapIndexedNotNull { i, _ ->
if (input.substring(i).startsWith(a)) {
input.replacer(a, b, i)
} else {
null
}
}
}.distinct().size
}

/**
* There's a reduction that always gets stuck:
* CRnSiRnFYCaRnFArArFArAl
* Just keep trying random replacements until it succeeds!
*/
override fun part2(): Any = loader().let { (choices, input) ->
var replacements: Int
do {
replacements = randomReplacer(choices, input)
} while (replacements < 0)
replacements
}

private fun String.replacer(a: String, b: String, i: Int): String =
if (i < 0) {
this
} else {
val (x, y) = takeSplit(i)
x + y.replaceFirst(a, b)
}

private fun randomReplacer(choices: List<List<String>>, input: String): Int {
var working = input
var replacements = 0
while (working != "e") {
val last = replacements
choices.shuffled().forEach { (a, b) ->
if (working.contains(b)) {
replacements++
working = working.replacer(b, a, working.lastIndexOf(b))
}
}
if (last == replacements) {
println("Got stuck: $working")
return -1
}
}
return replacements
}

private fun loader() = load(delimiter = "\n\n").let { (r, i) ->
r.split("\n").map { it.split(" => ") } to i
}
}
14 changes: 14 additions & 0 deletions advent/src/test/kotlin/org/elwaxoro/advent/y2015/Dec20.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.elwaxoro.advent.y2015

import org.elwaxoro.advent.PuzzleDayTester

/**
* Day 20: Infinite Elves and Infinite Houses
*/
class Dec20: PuzzleDayTester(20, 2015) {
val input = 33100000

override fun part1(): Any = "TODO"

override fun part2(): Any = "TODO"
}
108 changes: 108 additions & 0 deletions advent/src/test/kotlin/org/elwaxoro/advent/y2015/Dec21.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package org.elwaxoro.advent.y2015

import org.elwaxoro.advent.PuzzleDayTester
import org.elwaxoro.advent.combinations
import kotlin.math.max

/**
* Item shop:
* Weapons: Cost Damage Armor
* Dagger 8 4 0
* Shortsword 10 5 0
* Warhammer 25 6 0
* Longsword 40 7 0
* Greataxe 74 8 0
*
* Armor: Cost Damage Armor
* Leather 13 0 1
* Chainmail 31 0 2
* Splintmail 53 0 3
* Bandedmail 75 0 4
* Platemail 102 0 5
*
* Rings: Cost Damage Armor
* Damage +1 25 1 0
* Damage +2 50 2 0
* Damage +3 100 3 0
* Defense +1 20 0 1
* Defense +2 40 0 2
* Defense +3 80 0 3
*
* Player HP:
* 100
*
* Boss:
* Hit Points: 100
* Damage: 8
* Armor: 2
*/
class Dec21 : PuzzleDayTester(21, 2015) {

override fun part1(): Any = tryAllTheCombos { it }.min()

override fun part2(): Any = tryAllTheCombos { !it }.max()

private fun tryAllTheCombos(selector: (result: Boolean) -> Boolean) =
weapons.flatMap { w ->
armor.flatMap { a ->
rings.combinations(2).mapNotNull { r ->
val gear = listOf(w, a) + r
val outcome = battle(
Fighter(100, gear.sumOf { it.atk }, gear.sumOf { it.def }),
Fighter(100, 8, 2)
)
gear.sumOf { it.cost }.takeIf { selector.invoke(outcome) }
}
}
}

private fun battle(player: Fighter, boss: Fighter): Boolean {
while (player.hp > 0 && boss.hp > 0) {
boss.hp -= max(player.atk - boss.def, 1)
if (boss.hp > 0) {
player.hp -= max(boss.atk - player.def, 1)
}
}
return player.hp > 0
}

private val weapons = listOf(
Item(8, 4), // dagger
Item(10, 5), // shortsword
Item(25, 6), // warhammer
Item(40, 7), // longsword
Item(74, 8), // greataxe
)

private val armor = listOf(
Item(0, 0, 0), // nakers
Item(13, 0, 1), // leather
Item(31, 0, 2), // chainmail
Item(53, 0, 3), // splintmail
Item(75, 0, 4), // bandedmail
Item(102, 0, 5), // platemail
)

private val rings = listOf(
Item(0, 0, 0), // empty finger
Item(0, 0, 0), // empty finger
Item(25, 1), // +1 atk
Item(50, 2), // +2 atk
Item(100, 3), // +3 atk
Item(20, 0, 1), // +1 def
Item(40, 0, 2), // +2 def
Item(80, 0, 3), // +3 def
)

private data class Item(
val cost: Int,
val atk: Int = 0,
val def: Int = 0
)

private data class Fighter(
var hp: Int,
var atk: Int,
var def: Int,
)
}
45 changes: 45 additions & 0 deletions advent/src/test/resources/2015/Dec19.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
Al => ThF
Al => ThRnFAr
B => BCa
B => TiB
B => TiRnFAr
Ca => CaCa
Ca => PB
Ca => PRnFAr
Ca => SiRnFYFAr
Ca => SiRnMgAr
Ca => SiTh
F => CaF
F => PMg
F => SiAl
H => CRnAlAr
H => CRnFYFYFAr
H => CRnFYMgAr
H => CRnMgYFAr
H => HCa
H => NRnFYFAr
H => NRnMgAr
H => NTh
H => OB
H => ORnFAr
Mg => BF
Mg => TiMg
N => CRnFAr
N => HSi
O => CRnFYFAr
O => CRnMgAr
O => HP
O => NRnFAr
O => OTi
P => CaP
P => PTi
P => SiRnFAr
Si => CaSi
Th => ThCa
Ti => BP
Ti => TiTi
e => HF
e => NAl
e => OMg

CRnCaSiRnBSiRnFArTiBPTiTiBFArPBCaSiThSiRnTiBPBPMgArCaSiRnTiMgArCaSiThCaSiRnFArRnSiRnFArTiTiBFArCaCaSiRnSiThCaCaSiRnMgArFYSiRnFYCaFArSiThCaSiThPBPTiMgArCaPRnSiAlArPBCaCaSiRnFYSiThCaRnFArArCaCaSiRnPBSiRnFArMgYCaCaCaCaSiThCaCaSiAlArCaCaSiRnPBSiAlArBCaCaCaCaSiThCaPBSiThPBPBCaSiRnFYFArSiThCaSiRnFArBCaCaSiRnFYFArSiThCaPBSiThCaSiRnPMgArRnFArPTiBCaPRnFArCaCaCaCaSiRnCaCaSiRnFYFArFArBCaSiThFArThSiThSiRnTiRnPMgArFArCaSiThCaPBCaSiRnBFArCaCaPRnCaCaPMgArSiRnFYFArCaSiThRnPBPMgAr

0 comments on commit 201e2a1

Please sign in to comment.