defmodule Day13 do
defmodule Game do
@derive Inspect
defstruct [:a, :b, :prize]
def from_data(data, extra \\ 0) do
Regex.scan(~r/\d+/, data)
|> Enum.map(&String.to_integer(hd(&1)))
|> Enum.chunk_every(2)
|> Enum.map(&List.to_tuple/1)
|> then(fn [a, b, prize] ->
%Game{
a: a,
b: b,
prize: {elem(prize, 0) + extra, elem(prize, 1) + extra},
}
end)
end
def cheapest(game) do
cheapest(game.a, game.b, game.prize)
end
defp cheapest({a1, a2}, {b1, b2}, {s1, s2}) do
c = s2*a1 - a2*s1
d = a1*b2 - a2*b1
if rem(c, d) == 0 do
y = div(c, d)
e = s1 - b1 * y
f = a1
if rem(e, f) == 0 do
x = div(e, f)
x*3 + y
end
end
end
end
def part1(data, extra \\ 0) do
data
|> String.split("\n\n", trim: true)
|> Enum.map(&Game.from_data(&1, extra))
|> Enum.map(&Game.cheapest/1)
|> Enum.reject(& &1 == nil)
|> Enum.sum()
end
def part2(data) do
part1(data, 10000000000000)
end
end
data = IO.read(:stdio, :eof)
{time1 , ans1} = :timer.tc(fn -> Day13.part1(data) end)
IO.puts("Time : #{time1 / 1000000}")
IO.puts("Answer: #{ans1}")
{time2 , ans2} = :timer.tc(fn -> Day13.part2(data) end)
IO.puts("Time : #{time2 / 1000000}")
IO.puts("Answer: #{ans2}")