diff options
author | Justin Wernick <justin@worthe-it.co.za> | 2024-10-18 10:27:31 +0200 |
---|---|---|
committer | Justin Wernick <justin@worthe-it.co.za> | 2024-10-18 10:27:31 +0200 |
commit | b97d59a40674787776947ad6485e22c5ef5862b9 (patch) | |
tree | ffe7408d320b4ca0bfe6e0884abdee89e4c306b3 /2015/day22.exs | |
parent | 4275d5887f99b6a660745bd45d1c0497c8233359 (diff) |
Day 22
Diffstat (limited to '2015/day22.exs')
-rw-r--r-- | 2015/day22.exs | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/2015/day22.exs b/2015/day22.exs new file mode 100644 index 0000000..6b7f2f7 --- /dev/null +++ b/2015/day22.exs @@ -0,0 +1,177 @@ +[enemyHp, enemyDamage] = + File.stream!("inputs/day22.txt") + |> Stream.map(fn line -> + [num] = Regex.run(~r/\d+/, line) + {num, ""} = Integer.parse(num) + num + end) + |> Enum.take(2) + +defmodule BattleSimulator do + def magicMissile({playerMana, {playerHp, enemyHp, enemyDamage, hardMode}, effects}) do + {53, {playerMana, {playerHp, enemyHp - 4, enemyDamage, hardMode}, effects}} + end + + def drain({playerMana, {playerHp, enemyHp, enemyDamage, hardMode}, effects}) do + {73, {playerMana, {playerHp + 2, enemyHp - 2, enemyDamage, hardMode}, effects}} + end + + def shield({playerMana, health, {shield, poison, recharge}}) when shield == 0 do + {113, {playerMana, health, {shield + 6, poison, recharge}}} + end + + def shield(_) do + nil + end + + def poison({playerMana, health, {shield, poison, recharge}}) when poison == 0 do + {173, {playerMana, health, {shield, poison + 6, recharge}}} + end + + def poison(_) do + nil + end + + def recharge({playerMana, health, {shield, poison, recharge}}) when recharge == 0 do + {229, {playerMana, health, {shield, poison, recharge + 5}}} + end + + def recharge(_) do + nil + end + + def payManaCost({manaCost, {playerMana, health, effects}}) do + {manaCost, {playerMana - manaCost, health, effects}} + end + + def shieldEffect({manaCost, {playerMana, health, {shield, poison, recharge}}}) + when shield > 0 do + {manaCost, {playerMana, health, {shield - 1, poison, recharge}}} + end + + def shieldEffect(state) do + state + end + + def difficultyCheck( + {manaCost, {playerMana, {playerHp, enemyHp, enemyDamage, hardMode}, status}} + ) + when hardMode == true do + {manaCost, {playerMana, {playerHp - 1, enemyHp, enemyDamage, hardMode}, status}} + end + + def difficultyCheck(state) do + state + end + + def poisonEffect( + {manaCost, + {playerMana, {playerHp, enemyHp, enemyDamage, hardMode}, {shield, poison, recharge}}} + ) + when poison > 0 do + {manaCost, + {playerMana, {playerHp, enemyHp - 3, enemyDamage, hardMode}, {shield, poison - 1, recharge}}} + end + + def poisonEffect(state) do + state + end + + def rechargeEffect({manaCost, {playerMana, health, {shield, poison, recharge}}}) + when recharge > 0 do + {manaCost, {playerMana + 101, health, {shield, poison, recharge - 1}}} + end + + def rechargeEffect(state) do + state + end + + def outcomeCheck({manaCost, {_, {_, enemyHp, _, _}, _}}) when enemyHp <= 0 do + {manaCost, :victory} + end + + def outcomeCheck({manaCost, {_, {playerHp, _, _, _}, _}}) when playerHp <= 0 do + {manaCost, :defeat} + end + + def outcomeCheck(state) do + state + end + + def enemyAttack( + {manaCost, + {playerMana, {playerHp, enemyHp, enemyDamage, hardMode}, {shield, poison, recharge}}} + ) do + armor = + if shield > 0 do + 7 + else + 0 + end + + {manaCost, + {playerMana, {playerHp - max(1, enemyDamage - armor), enemyHp, enemyDamage, hardMode}, + {shield, poison, recharge}}} + end + + def enemyAttack(state) do + state + end + + def nextRound(state) do + playerImmediateEffects = [ + magicMissile(state), + drain(state), + shield(state), + poison(state), + recharge(state) + ] + + Enum.filter(playerImmediateEffects, &(!is_nil(&1))) + |> Enum.filter(fn {manaCost, {playerMana, _, _}} -> manaCost <= playerMana end) + |> Enum.map(&payManaCost/1) + |> Enum.map(&shieldEffect/1) + |> Enum.map(&poisonEffect/1) + |> Enum.map(&rechargeEffect/1) + |> Enum.map(&outcomeCheck/1) + |> Enum.map(&enemyAttack/1) + |> Enum.map(&outcomeCheck/1) + |> Enum.map(&difficultyCheck/1) + |> Enum.map(&shieldEffect/1) + |> Enum.map(&poisonEffect/1) + |> Enum.map(&rechargeEffect/1) + |> Enum.map(&outcomeCheck/1) + end + + def findMinManaCostVictory(:victory) do + 0 + end + + def findMinManaCostVictory(state) do + Enum.filter(nextRound(state), fn + {_, :defeat} -> false + _ -> true + end) + |> Enum.map(fn {manaCost, nextState} -> + remainingManaCost = findMinManaCostVictory(nextState) + + if remainingManaCost == nil do + nil + else + manaCost + remainingManaCost + end + end) + |> Enum.filter(&(!is_nil(&1))) + |> Enum.min(fn -> nil end) + end +end + +manaCost = + BattleSimulator.findMinManaCostVictory({500, {50, enemyHp, enemyDamage, false}, {0, 0, 0}}) + +IO.puts("Minimum mana cost to Victory: #{manaCost}") + +manaCostHardMode = + BattleSimulator.findMinManaCostVictory({500, {50, enemyHp, enemyDamage, true}, {0, 0, 0}}) + +IO.puts("Minimum mana cost to Victory (Hard Mode): #{manaCostHardMode}") |