summaryrefslogtreecommitdiff
path: root/2015/day22.exs
diff options
context:
space:
mode:
authorJustin Wernick <justin@worthe-it.co.za>2024-10-18 10:27:31 +0200
committerJustin Wernick <justin@worthe-it.co.za>2024-10-18 10:27:31 +0200
commitb97d59a40674787776947ad6485e22c5ef5862b9 (patch)
treeffe7408d320b4ca0bfe6e0884abdee89e4c306b3 /2015/day22.exs
parent4275d5887f99b6a660745bd45d1c0497c8233359 (diff)
Day 22
Diffstat (limited to '2015/day22.exs')
-rw-r--r--2015/day22.exs177
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}")