From c98303d0c1e62fbbc3a62fca43d1e434a869759f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Ytterstr=C3=B6m?= Date: Mon, 5 Dec 2022 23:17:30 +0100 Subject: [PATCH] Add solutions for 2022:4-5 --- 2022-elixir/lib/solutions/day_04.ex | 57 ++++++++++ 2022-elixir/lib/solutions/day_05.ex | 122 +++++++++++++++++++++ 2022-elixir/test/solutions/day_04_test.exs | 30 +++++ 2022-elixir/test/solutions/day_05_test.exs | 33 ++++++ 4 files changed, 242 insertions(+) create mode 100644 2022-elixir/lib/solutions/day_04.ex create mode 100644 2022-elixir/lib/solutions/day_05.ex create mode 100644 2022-elixir/test/solutions/day_04_test.exs create mode 100644 2022-elixir/test/solutions/day_05_test.exs diff --git a/2022-elixir/lib/solutions/day_04.ex b/2022-elixir/lib/solutions/day_04.ex new file mode 100644 index 0000000..df6c641 --- /dev/null +++ b/2022-elixir/lib/solutions/day_04.ex @@ -0,0 +1,57 @@ +defmodule Aoc.Solution.Day04 do + import Aoc.Utils + + @name "Day 4: Camp Cleanup" + @behaviour Solution + + @impl Solution + def get_name, do: @name + + @impl Solution + def present(solution), do: "#{solution} assignment pairs overlap" + + @impl Solution + def present_again(solution), do: "Solution is #{solution}" + + @impl Solution + def parse!(raw) do + raw + |> split_lines() + |> Enum.map(fn l -> parse_values(l, ",") end) + end + + @impl Solution + def solve(pairs) do + pairs + |> ranges() + |> overlaps() + |> Enum.count() + end + + @impl Solution + def solve_again(pairs) do + pairs + |> ranges() + |> strict_overlaps() + |> Enum.count() + end + + def ranges(rows) when length(rows) > 2 do + Enum.map(rows, &ranges/1) + end + + def ranges(pairs) do + Enum.map(pairs, fn p -> + [start, stop] = parse_values(p, "-") |> Enum.map(&String.to_integer/1) + MapSet.new(start..stop) + end) + end + + def overlaps(ranges), do: Enum.filter(ranges, &overlap?/1) + + def overlap?([a, b]), do: MapSet.subset?(a, b) or MapSet.subset?(b, a) + + def strict_overlaps(ranges), do: Enum.filter(ranges, &strict_overlap?/1) + + def strict_overlap?([a, b]), do: MapSet.intersection(a, b) |> Enum.count() > 0 +end diff --git a/2022-elixir/lib/solutions/day_05.ex b/2022-elixir/lib/solutions/day_05.ex new file mode 100644 index 0000000..b244f19 --- /dev/null +++ b/2022-elixir/lib/solutions/day_05.ex @@ -0,0 +1,122 @@ +defmodule Aoc.Solution.Day05 do + import Aoc.Utils + + @name "Day 5: Supply Stacks" + @behaviour Solution + + @impl Solution + def get_name, do: @name + + @impl Solution + def present(solution), do: "On 9000, top crate on each stack is #{solution}" + + @impl Solution + def present_again(solution), do: "On 9001, top crate on each stack is #{solution}" + + @impl Solution + def parse!(raw) do + [initial_state, instructions] = raw |> String.split("\n\n") + + { + initial_state |> String.split("\n") |> Enum.drop(-1) |> parse_state(), + instructions |> String.trim() |> split_lines() |> parse_instructions() + } + end + + @impl Solution + def solve({state, instructions}) do + state + |> move(instructions, 9000) + |> topmost() + end + + @impl Solution + def solve_again({state, instructions}) do + state + |> move(instructions, 9001) + |> topmost() + end + + def parse_state(state) do + blank = "[-]" + len = Enum.map(state, &String.length/1) |> Enum.max() + + Enum.map(state, fn line -> + line + |> String.pad_trailing(len) + |> String.pad_leading(len + 1) + |> String.replace(" ", " #{blank}") + end) + |> Enum.map(fn l -> + l + |> String.trim() + |> String.split() + end) + |> Enum.zip() + |> Enum.map(fn t -> + t + |> Tuple.to_list() + |> Enum.reject(fn v -> v == blank end) + |> Enum.map(fn v -> + v + |> String.slice(1..-2) + end) + end) + end + + def parse_instructions(lines) do + Enum.map(lines, fn "move " <> line -> + [steps, _f, from, _t, to] = String.split(line) + Enum.map([steps, from, to], &String.to_integer/1) + end) + end + + def move(state, [], _), do: state + + def move(state, [[n, from, to] | remaining], model) do + move( + case model do + 9000 -> _move_9000(state, from - 1, to - 1, n) + 9001 -> _move_9001(state, from - 1, to - 1, n) + end, + remaining, + model + ) + end + + def _move_9001(state, from, to, n) do + {pre, rem} = state |> Enum.at(from) |> Enum.split(n) + + state + |> List.update_at(from, fn _ -> rem end) + |> List.update_at(to, fn l -> pre ++ l end) + end + + def _move_9000(state, _from, _to, 0) do + state + end + + def _move_9000(state, from, to, n) do + case Enum.at(state, from) do + [a | rem] -> + _move_9000( + state + |> List.update_at(from, fn _ -> rem end) + |> List.update_at(to, fn l -> [a | l] end), + from, + to, + n - 1 + ) + + [] -> + state + + nil -> + state + end + end + + def topmost(state) do + state |> Enum.map(&List.first/1) |> Enum.join("") + end +end diff --git a/2022-elixir/test/solutions/day_04_test.exs b/2022-elixir/test/solutions/day_04_test.exs new file mode 100644 index 0000000..2ff7be3 --- /dev/null +++ b/2022-elixir/test/solutions/day_04_test.exs @@ -0,0 +1,30 @@ +defmodule Day04Test do + use ExUnit.Case + doctest Aoc.Solution.Day04 + import Aoc.Solution.Day04 + + @input ~s( + 2-4,6-8 + 2-3,4-5 + 5-7,7-9 + 2-8,3-7 + 6-6,4-6 + 2-6,4-8 + ) + + test "04: Camp Cleanup, part 1" do + expected = 2 + + result = @input |> parse!() |> solve() + + assert result == expected + end + + test "04: Camp Cleanup, part 2" do + expected = 4 + + result = @input |> parse!() |> solve_again() + + assert result == expected + end +end diff --git a/2022-elixir/test/solutions/day_05_test.exs b/2022-elixir/test/solutions/day_05_test.exs new file mode 100644 index 0000000..12c6f79 --- /dev/null +++ b/2022-elixir/test/solutions/day_05_test.exs @@ -0,0 +1,33 @@ +defmodule Day05Test do + use ExUnit.Case + doctest Aoc.Solution.Day05 + import Aoc.Solution.Day05 + + @input ~s( + [D] +[N] [C] +[Z] [M] [P] + 1 2 3 + +move 1 from 2 to 1 +move 3 from 1 to 3 +move 2 from 2 to 1 +move 1 from 1 to 2 +) + + test "05: Supply Stacks, part 1" do + expected = "CMZ" + + result = @input |> parse!() |> solve() + + assert result == expected + end + + test "05: Supply Stacks, part 2" do + expected = "MCD" + + result = @input |> parse!() |> solve_again() + + assert result == expected + end +end