diff --git a/lib/common.ex b/lib/common.ex index 3c6419b..899fbbb 100644 --- a/lib/common.ex +++ b/lib/common.ex @@ -32,4 +32,6 @@ defmodule Aoc2023.Common do end def id(x), do: x + def const(_, x), do: x + def lines(x), do: String.split(x, "\n") end diff --git a/lib/day4.ex b/lib/day4.ex new file mode 100644 index 0000000..16e7160 --- /dev/null +++ b/lib/day4.ex @@ -0,0 +1,39 @@ +defmodule Aoc2023.Day4 do + use Aoc2023 + + defp numbers(values) do + values |> String.split() |> Enum.map(&String.to_integer/1) |> MapSet.new() + end + + def parse(input) do + input + |> lines + |> Enum.map( + &Regex.run(~r/Card\s+(?\d+): (?(\s*\d+)+) \| (?(\s*\d+)+)/, &1, + capture: ["id", "winning", "values"] + ) + ) + |> Enum.map(fn [id, winning, values] -> + {String.to_integer(id), + MapSet.intersection(numbers(winning), numbers(values)) |> MapSet.size()} + end) + end + + def part1(input) do + for {_, count} <- input, + count > 0 do + 2 ** (count - 1) + end + |> Enum.sum() + end + + def part2(input) do + for {id, count} <- input, + id_ <- (id + 1)..(id + count)//1, + reduce: input |> Enum.map(elem(0) &&& const(1)) |> Enum.into(%{}) do + acc -> Map.update!(acc, id_, &(&1 + Map.get(acc, id))) + end + |> Enum.map(pipe(elem(1))) + |> Enum.sum() + end +end diff --git a/lib/mix_tasks.ex b/lib/mix_tasks.ex index 2482d83..59cb84e 100644 --- a/lib/mix_tasks.ex +++ b/lib/mix_tasks.ex @@ -5,6 +5,7 @@ defmodule Mix.Tasks.Aoc do defp module(1), do: Aoc2023.Day1 defp module(2), do: Aoc2023.Day2 defp module(3), do: Aoc2023.Day3 + defp module(4), do: Aoc2023.Day4 # [MODULE INSERTION POINT] defp base_dir(), do: System.get_env("AOC_BASE") @@ -102,7 +103,7 @@ defmodule Mix.Tasks.Aoc do end defp run(day, ["test", "watch"]) do - {:ok, pid} = Mix.Tasks.Aoc.Watcher.start_link({[dirs: ["lib/", "test/day#{day}/"]], self()}) + {:ok, pid} = Mix.Tasks.Aoc.Watcher.start_link({[dirs: ["lib/", "tests/day#{day}/"]], self()}) Process.monitor(pid) loop = fn (loop) -> IO.puts(IO.ANSI.clear() <> IO.ANSI.cursor(0, 0)) @@ -112,7 +113,9 @@ defmodule Mix.Tasks.Aoc do :code.purge(Aoc2023.Common) :code.load_file(module(day)) :code.load_file(Aoc2023.Common) - run(day, ["test"]) + spawn fn -> + run(day, ["test"]) + end receive do :update -> loop.(loop) {:DOWN, _, :process, ^pid, _} -> nil @@ -129,8 +132,6 @@ defmodule Mix.Tasks.Aoc do |> Enum.map(&test(day, &1)) |> Enum.map(fn {test, input, p1e, p2e} -> parsed = mod.parse(input) - p1 = mod.part1(parsed) - p2 = mod.part2(parsed) result = fn (part, got, expected) -> cond do @@ -142,8 +143,8 @@ defmodule Mix.Tasks.Aoc do end end - result.(1, p1, p1e) - result.(2, p2, p2e) + result.(1, mod.part1(parsed), p1e) + result.(2, mod.part2(parsed), p2e) end) end diff --git a/tests/day4/1 b/tests/day4/1 new file mode 100644 index 0000000..9bdb874 --- /dev/null +++ b/tests/day4/1 @@ -0,0 +1,6 @@ +Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 +Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 +Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 +Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 +Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 +Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11 diff --git a/tests/day4/1.1 b/tests/day4/1.1 new file mode 100644 index 0000000..b1bd38b --- /dev/null +++ b/tests/day4/1.1 @@ -0,0 +1 @@ +13 diff --git a/tests/day4/1.2 b/tests/day4/1.2 new file mode 100644 index 0000000..64bb6b7 --- /dev/null +++ b/tests/day4/1.2 @@ -0,0 +1 @@ +30