Day 19
Mix.install([
{:kino_aoc, git: "https://github.com/ljgago/kino_aoc"}
])
:ok
Section
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2022", "19", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
{:ok,
"Blueprint 1: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 15 clay. Each geode robot costs 2 ore and 8 obsidian.\nBlueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 17 clay. Each geode robot costs 3 ore and 10 obsidian.\nBlueprint 3: Each ore robot costs 2 ore. Each clay robot costs 2 ore. Each obsidian robot costs 2 ore and 20 clay. Each geode robot costs 2 ore and 14 obsidian.\nBlueprint 4: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 4 ore and 15 obsidian.\nBlueprint 5: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 13 clay. Each geode robot costs 3 ore and 15 obsidian.\nBlueprint 6: Each ore robot costs 2 ore. Each clay robot costs 2 ore. Each obsidian robot costs 2 ore and 15 clay. Each geode robot costs 2 ore and 7 obsidian.\nBlueprint 7: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 9 clay. Each geode robot costs 3 ore and 7 obsidian.\nBlueprint 8: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 2 ore and 8 obsidian.\nBlueprint 9: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 4 ore and 18 obsidian.\nBlueprint 10: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 11 clay. Each geode robot costs 2 ore and 19 obsidian.\nBlueprint 11: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 7 clay. Each geode robot costs 3 ore and 10 obsidian.\nBlueprint 12: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 11 clay. Each geode robot costs 2 ore and 16 obsidian.\nBlueprint 13: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 16 clay. Each geode robot costs 3 ore and 15 obsidian.\nBlueprint 14: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 3 ore and 13 obsidian.\nBlueprint 15: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 13 clay. Each geode robot costs 2 ore and 20 obsidian.\nBlueprint 16: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 14 clay. Each geode robot costs 4 ore and 10 obsidian.\nBlueprint 17: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 17 clay. Each geode robot costs 3 ore and 16 obsidian.\nBlueprint 18: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 20 clay. Each geode robot costs 2 ore and 17 obsidian.\nBlueprint 19: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 4 ore and 12 obsidian.\nBlueprint 20: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 16 clay. Each geode robot costs 3 ore and 20 obsidian.\nBlueprint 21: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 4 ore and 12 obsidian.\nBlueprint 22: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 13 clay. Each geode robot costs 3 ore and 19 obsidian.\nBlueprint 23: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 3 ore and 8 obsidian.\nBlueprint 24: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 13 clay. Each geode robot costs 2 ore and 9 obsidian.\nBlueprint 25: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 5 clay. Each geode robot costs 3 ore and 15 obsidian.\nBlueprint 26: Each ore robot costs 4 ore. Each clay robot costs " <> ...}
puzzle_input = """
Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian.
Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian.
"""
"Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian.\nBlueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian.\n"
regex =
~r/ore robot.*(?\d+) ore.*clay robot.*(?\d+) ore.*obsidian robot.*(?\d+) ore and (?\d+) clay.*geode robot.*(?\d+) ore and (?\d+) obsidian/
plans =
puzzle_input
|> String.split("\n", trim: true)
|> Kino.render()
|> Enum.map(fn line ->
blueprint =
Regex.named_captures(regex, line)
|> Map.new(fn {k, v} ->
{String.to_atom(k), String.to_integer(v)}
end)
%{
ore: %{ore: blueprint.ore_ore},
clay: %{ore: blueprint.clay_ore},
obsidian: %{ore: blueprint.obsidian_ore, clay: blueprint.obsidian_clay},
geode: %{ore: blueprint.geode_ore, obsidian: blueprint.geode_obsidian},
max: %{
ore:
Enum.max([
blueprint.ore_ore,
blueprint.clay_ore,
blueprint.obsidian_ore,
blueprint.geode_ore
]),
clay: blueprint.obsidian_clay,
obsidian: blueprint.geode_obsidian
}
}
end)
["Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian.",
"Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian."]
[
%{
clay: %{ore: 2},
geode: %{obsidian: 7, ore: 2},
max: %{clay: 14, obsidian: 7, ore: 4},
obsidian: %{clay: 14, ore: 3},
ore: %{ore: 4}
},
%{
clay: %{ore: 3},
geode: %{obsidian: 12, ore: 3},
max: %{clay: 8, obsidian: 12, ore: 3},
obsidian: %{clay: 8, ore: 3},
ore: %{ore: 2}
}
]
defmodule Blueprint do
def produce(plan, time, machines) do
produce(plan, time, machines, %{ore: 0, clay: 0, obsidian: 0, geode: 0})
end
def produce(_plan, 0, machines, stash) do
%{machines: machines, stash: stash}
end
def produce(plan, time_left, machines, stash) do
do_shopping(plan, stash)
|> Enum.filter(fn {k, _} -> (machines[k] || 0) < plan.max[k] end)
|> Enum.flat_map(fn {machine, new_stash} ->
# if machine in [:obsidian, :geode], do: IO.inspect(new_stash)
[
produce(
plan,
time_left - 1,
add_machine(machine, machines),
update_stash(machines, new_stash)
)
]
end)
# |> tap(fn list ->
# Enum.filter(list, & &1.obsidian > 0)
# |> Enum.map(&IO.inspect/1)
# end)
|> Enum.max_by(& &1.stash.geode)
end
defp add_machine(nil, machines), do: machines
defp add_machine(name, machines), do: Map.update(machines, name, 1, &(&1 + 1))
defp update_stash(machines, stash) do
Enum.reduce(machines, stash, fn {k, v}, acc ->
Map.update(acc, k, v, &(&1 + v))
end)
end
def do_shopping(plan, stash)
when stash.ore >= plan.geode.ore and stash.obsidian >= plan.geode.obsidian,
do: [{:geode, buy(plan.geode, stash)}]
def do_shopping(plan, stash)
when stash.ore >= plan.obsidian.ore and stash.clay >= plan.obsidian.clay,
do: [{:obsidian, buy(plan.obsidian, stash)}, {nil, stash}]
def do_shopping(plan, stash) do
[
{nil, stash}
| Enum.flat_map([:ore, :clay], fn k ->
if stash.ore >= plan[k].ore do
[{k, %{stash | ore: stash.ore - plan[k].ore}}]
else
[]
end
end)
]
end
defp buy(price, stash) do
Map.merge(stash, price, fn _k, v1, v2 -> v1 - v2 end)
end
end
{:module, Blueprint, <<70, 79, 82, 49, 0, 0, 22, ...>>, {:buy, 2}}
plan = hd(plans) |> Kino.inspect()
stash = %{clay: 35, geode: 0, obsidian: 0, ore: 4}
Blueprint.do_shopping(plan, stash)
%{
clay: %{ore: 2},
geode: %{obsidian: 7, ore: 2},
max: %{clay: 14, obsidian: 7, ore: 4},
obsidian: %{clay: 14, ore: 3},
ore: %{ore: 4}
}
[
obsidian: %{clay: 21, geode: 0, obsidian: 0, ore: 1},
nil: %{clay: 35, geode: 0, obsidian: 0, ore: 4}
]
plans
# |> Enum.drop(1)
|> Enum.take(1)
|> Kino.inspect()
|> Enum.map(fn plan -> Blueprint.produce(plan, 24, %{ore: 1}) end)
[
%{
clay: %{ore: 2},
geode: %{obsidian: 7, ore: 2},
max: %{clay: 14, obsidian: 7, ore: 4},
obsidian: %{clay: 14, ore: 3},
ore: %{ore: 4}
}
]