[enemyHp, enemyDamage, enemyArmor] = File.stream!("inputs/day21.txt") |> Stream.map(fn line -> [num] = Regex.run(~r/\d+/, line) {num, ""} = Integer.parse(num) num end) |> Enum.take(3) playerHp = 100 # {cost, damage, armor} # pick exactly one weapons = [ {8, 4, 0}, {10, 5, 0}, {25, 6, 0}, {40, 7, 0}, {74, 8, 0} ] # pick 0-1 armors = [ nil, {13, 0, 1}, {31, 0, 2}, {53, 0, 3}, {75, 0, 4}, {102, 0, 5} ] # pick 0-2 rings = [ nil, {25, 1, 0}, {50, 2, 0}, {100, 3, 0}, {20, 0, 1}, {40, 0, 2}, {80, 0, 3} ] simulateBattle = fn playerDamage, playerArmor -> playerDamagePerHit = max(1, playerDamage - enemyArmor) enemyDamagePerHit = max(1, enemyDamage - playerArmor) playerHitsToVictory = ceil(enemyHp / playerDamagePerHit) enemyHitsToVictory = ceil(playerHp / enemyDamagePerHit) playerHitsToVictory <= enemyHitsToVictory end allCombinations = for weapon <- weapons, armor <- armors, ring1 <- rings, ring2 <- rings, is_nil(ring1) || ring1 != ring2 do Enum.filter([weapon, armor, ring1, ring2], &(!is_nil(&1))) |> Enum.reduce({0, 0, 0}, fn {c1, d1, a1}, {c2, d2, a2} -> {c1 + c2, d1 + d2, a1 + a2} end) end winningCost = Enum.filter(allCombinations, fn {_, damage, armor} -> simulateBattle.(damage, armor) end) |> Enum.map(fn {cost, _, _} -> cost end) |> Enum.min() IO.puts("Minimum winning cost: #{winningCost}") losingCost = Enum.filter(allCombinations, fn {_, damage, armor} -> !simulateBattle.(damage, armor) end) |> Enum.map(fn {cost, _, _} -> cost end) |> Enum.max() IO.puts("Maximum losing cost: #{losingCost}")