Skip to content

Commit cd6ff5d

Browse files
committed
Year 2015 Day 22
1 parent 76ff4b6 commit cd6ff5d

File tree

4 files changed

+69
-0
lines changed

4 files changed

+69
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,4 @@ The minimal SBT project provides:
231231
| 19 | [Medicine for Rudolph](https://adventofcode.com/2015/day/19) | [Source](src/main/scala/AdventOfCode2015/Day19.scala) |
232232
| 20 | [Infinite Elves and Infinite Houses](https://adventofcode.com/2015/day/20) | [Source](src/main/scala/AdventOfCode2015/Day20.scala) |
233233
| 21 | [RPG Simulator 20XX](https://adventofcode.com/2015/day/21) | [Source](src/main/scala/AdventOfCode2015/Day21.scala) |
234+
| 22 | [Wizard Simulator 20XX](https://adventofcode.com/2015/day/22) | [Source](src/main/scala/AdventOfCode2015/Day22.scala) |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Hit Points: 55
2+
Damage: 8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package AdventOfCode2015
2+
3+
object Day22:
4+
val MagicMissile = Spell(53, 1)
5+
val Drain = Spell(73, 1)
6+
val Shield = Spell(113, 6)
7+
val Poison = Spell(173, 6)
8+
val Recharge = Spell(229, 5)
9+
val spells = Set(MagicMissile, Drain, Shield, Poison, Recharge)
10+
11+
case class Spell(cost: Int, duration: Int)
12+
13+
case class State(hero: Int, mana: Int, spent: Int, armor: Int, boss: Int, damage: Int, active: Map[Spell, Int]):
14+
def applyEffects: State = active.foldLeft(copy(armor = 0)) { case (state, (spell, duration)) =>
15+
val next = state.effect(spell)
16+
if duration == 1 then next.copy(active = state.active.removed(spell))
17+
else next.copy(active = state.active.updated(spell, duration - 1))
18+
}
19+
def effect(spell: Spell): State = spell match
20+
case MagicMissile => copy(boss = boss - 4)
21+
case Drain => copy(hero = hero + 2, boss = boss - 2)
22+
case Shield => copy(armor = 7)
23+
case Poison => copy(boss = boss - 3)
24+
case Recharge => copy(mana = mana + 101)
25+
def heroTurn(spell: Spell): State = copy(mana = mana - spell.cost, spent = spent + spell.cost, active = active + (spell -> spell.duration))
26+
def bossTurn: State = copy(hero = hero - (damage - armor).max(1))
27+
def hardMode: State = copy(hero = hero - 1)
28+
29+
def parse(input: Seq[String]): State =
30+
val Seq(health, damage) = input.map(_.filter(_.isDigit).toInt)
31+
State(50, 500, 0, 0, health, damage, Map())
32+
33+
def fight(start: State, hard: Boolean): Int =
34+
var result = Int.MaxValue
35+
36+
def helper(state: State, playerTurn: Boolean): Unit =
37+
val first = if hard && playerTurn then state.hardMode else state
38+
val second = first.applyEffects
39+
40+
if first.spent >= result || first.hero <= 0 then ()
41+
else if second.boss <= 0 then result = result.min(second.spent)
42+
else if !playerTurn then helper(second.bossTurn, !playerTurn)
43+
else spells
44+
.diff(second.active.keySet)
45+
.filter(_.cost <= second.mana)
46+
.foreach(spell => helper(second.heroTurn(spell), !playerTurn))
47+
end helper
48+
49+
helper(start, true)
50+
result
51+
end fight
52+
53+
def part1(input: Seq[String]): Int = fight(parse(input), false)
54+
55+
def part2(input: Seq[String]): Int = fight(parse(input), true)
56+
57+
def main(args: Array[String]): Unit =
58+
val data = io.Source.fromResource("AdventOfCode2015/Day22.txt").getLines().toSeq
59+
println(part1(data))
60+
println(part2(data))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package AdventOfCode2015
2+
3+
import org.scalatest.funsuite.AnyFunSuite
4+
5+
class Day22Suite extends AnyFunSuite
6+
// No unit tests possible

0 commit comments

Comments
 (0)