Advent of Code 2015 Day 21 Part 2
Mix.install([
{:kino_aoc, "~> 0.1"}
])
Get Inputs
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2015", "21", System.fetch_env!("LB_SESSION"))
My answer
load_shop_menu = fn menu ->
menu
|> String.trim()
|> String.split("\n")
|> Enum.map(fn row ->
row
|> String.split(" ", trim: true)
|> then(fn [name, cost, damage, armor] ->
%{
name: name,
cost: cost |> String.trim() |> String.to_integer(),
damage: damage |> String.trim() |> String.to_integer(),
armor: armor |> String.trim() |> String.to_integer(),
}
end)
end)
end
weapons =
"""
Dagger 8 4 0
Shortsword 10 5 0
Warhammer 25 6 0
Longsword 40 7 0
Greataxe 74 8 0
"""
|> load_shop_menu.()
armors =
"""
Leather 13 0 1
Chainmail 31 0 2
Splintmail 53 0 3
Bandedmail 75 0 4
Platemail 102 0 5
"""
|> load_shop_menu.()
rings =
"""
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
"""
|> load_shop_menu.()
{weapons, armors, rings}
defmodule Game do
def battle(player, boss) do
boss_hp = boss.hp - max(1, player.damage - boss.armor)
if boss_hp < 1 do
:win
else
player_hp = player.hp - max(1, boss.damage - player.armor)
if player_hp < 1 do
:lose
else
battle(
Map.put(player, :hp, player_hp),
Map.put(boss, :hp, boss_hp)
)
end
end
end
end
player = %{
hp: 8,
damage: 5,
armor: 5
}
boss = %{
hp: 12,
damage: 7,
armor: 2
}
{player, boss}
Game.battle(player, boss)
defmodule Combinations do
def all(_, 0), do: [[]]
def all([], _), do: []
def all(list, n) when length(list) == n, do: [list]
def all([head | tail], n) do
with_head = for combo <- all(tail, n - 1), do: [head | combo]
without_head = all(tail, n)
with_head ++ without_head
end
end
weapon_combinations = Combinations.all(weapons, 1)
armor_combinations = Combinations.all(armors, 0) ++ Combinations.all(armors, 1)
ring_combinations =
Combinations.all(rings, 0) ++ Combinations.all(rings, 1) ++ Combinations.all(rings, 2)
equipment_combinations =
for weapon <- weapon_combinations,
armor <- armor_combinations,
ring <- ring_combinations do
(weapon ++ armor ++ ring)
|> Enum.reduce(%{cost: 0, damage: 0, armor: 0}, fn equipment, acc_equipments ->
acc_equipments
|> Map.put(:cost, acc_equipments.cost + equipment.cost)
|> Map.put(:damage, acc_equipments.damage + equipment.damage)
|> Map.put(:armor, acc_equipments.armor + equipment.armor)
end)
end
boss =
puzzle_input
|> String.split("\n")
|> Enum.map(fn row ->
row
|> String.split(": ")
|> Enum.at(1)
|> String.to_integer()
end)
|> then(fn [hp, damage, armor] ->
%{hp: hp, damage: damage, armor: armor}
end)
equipment_combinations
|> Enum.sort_by(&(&1.cost), :desc)
|> Enum.find(fn equipments ->
Game.battle(Map.put(equipments, :hp, 100), boss) == :lose
end)