# Day 21 ## Section ```elixir input = File.read!("day21.txt") [[_, p1], [_, p2]] = Regex.scan(~r/: (\d)/, input) p1 = String.to_integer(p1) p2 = String.to_integer(p2) {p1, p2} ``` ``` {3, 5} ``` ```elixir round = Stream.unfold(0, &{&1, &1 + 1}) |> Stream.scan({{0, p1}, {0, p2}}, fn n, {{s, p}, other} -> p = rem(p - 1 + 6 + n * 9, 10) + 1 {other, {s + p, p}} end) |> Enum.take_while(fn {{s, _}, {_, _}} -> s < 1000 end) {rounds, {{loser, _}, _}} = {length(round), List.last(round)} rounds * 3 * loser ``` ``` 720750 ``` ```elixir defmodule Day21.Task2 do def play(p1, p2) do tid = :ets.new(__MODULE__, []) {a, b} = cached_round({p1 - 1, 0}, {p2 - 1, 0}, tid) :ets.delete(tid) max(a, b) end defp cached_round(a, b, tid) do case :ets.lookup(tid, {a, b}) do [{_, v}] -> v [] -> value = round(a, b, tid) :ets.insert(tid, {{a, b}, value}) value end end defp round({_, s}, _, _) when s >= 21, do: {1, 0} defp round(_, {_, s}, _) when s >= 21, do: {0, 1} defp round({pos, score}, p2, tid) do for a <- 1..3, b <- 1..3, c <- 1..3, reduce: {0, 0} do {wins1, wins2} -> next = rem(pos + a + b + c, 10) {nscore2, nscore1} = cached_round( p2, {next, score + next + 1}, tid ) {wins1 + nscore1, wins2 + nscore2} end end end ``` ``` {:module, Day21.Task2, <<70, 79, 82, 49, 0, 0, 12, ...>>, {:round, 3}} ``` ```elixir Day21.Task2.play(p1, p2) ``` ``` 275067741811212 ```