From c1125d6ede53a691f94f6f7dc8bdb3d03da0f5a9 Mon Sep 17 00:00:00 2001 From: Sloane Perrault Date: Wed, 21 Sep 2022 09:19:53 -0400 Subject: [PATCH] solve 2015 day 13 --- 2015/README.md | 13 +++--- 2015/lib/2015/13.ex | 100 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 2015/lib/2015/13.ex diff --git a/2015/README.md b/2015/README.md index 32fbaa1..c6c37e7 100644 --- a/2015/README.md +++ b/2015/README.md @@ -12,12 +12,12 @@ ``` -| S | M | T | W | T | F | S | -| :-: | :-: | :-: | :-: | :-: | :-: | :-: | -| | | [1] | [2] | [3] | [4] | [5] | -| [6] | [7] | [8] | [9] | [10] | [11] | [12] | -| 13 | 14 | 15 | 16 | 17 | 18 | 19 | -| 20 | 21 | 22 | 23 | 24 | 25 | | +| S | M | T | W | T | F | S | +| :--: | :-: | :-: | :-: | :-: | :-: | :-: | +| | | [1] | [2] | [3] | [4] | [5] | +| [6] | [7] | [8] | [9] | [10] | [11] | [12] | +| [13] | 14 | 15 | 16 | 17 | 18 | 19 | +| 20 | 21 | 22 | 23 | 24 | 25 | | [1]: ./lib/2015/1.ex [2]: ./lib/2015/2.ex @@ -31,3 +31,4 @@ [10]: ./lib/2015/10.ex [11]: ./lib/2015/11.ex [12]: ./lib/2015/12.ex +[13]: ./lib/2015/13.ex diff --git a/2015/lib/2015/13.ex b/2015/lib/2015/13.ex new file mode 100644 index 0000000..1c7d299 --- /dev/null +++ b/2015/lib/2015/13.ex @@ -0,0 +1,100 @@ +import AOC + +aoc 2015, 13 do + import NimbleParsec + + def p1 do + {guests, edges} = parse_input() + + permutations(guests) + |> Enum.map(&happiness(edges, &1)) + |> Enum.max() + end + + def p2 do + {guests, edges} = parse_input() + + guests = guests ++ ["Zach"] + + permutations(guests) + |> Enum.map(&happiness(edges, &1)) + |> Enum.max() + end + + defparsec( + :fact_parsec, + ascii_string([?a..?z, ?A..?Z], min: 1) + |> ignore(string(" would ")) + |> choice([ + string("gain"), + string("lose") + ]) + |> ignore(string(" ")) + |> integer(min: 1) + |> ignore(string(" happiness units by sitting next to ")) + |> ascii_string([?a..?z, ?A..?Z], min: 1) + |> ignore(string(".")) + ) + + def parse_fact(str) do + {:ok, [left, sign, amount, right], _, _, _, _} = fact_parsec(str) + + {{left, right}, edge_value(sign, amount)} + end + + def edge_value("gain", v), do: v + def edge_value("lose", v), do: 0 - v + + def sort({a, b} = p) when a > b, do: swap(p) + def sort(p), do: p + def swap({a, b}), do: {b, a} + + def parse_input() do + edges = + input_stream() + |> Stream.map(&parse_fact/1) + |> Enum.into(%{}) + + guests = + edges + |> Map.keys() + |> Enum.reduce(MapSet.new(), fn {a, b}, acc -> acc |> MapSet.put(a) |> MapSet.put(b) end) + + edges = + for {pair, weight} <- edges, reduce: %{} do + acc -> + sorted = sort(pair) + + if Map.has_key?(acc, sorted) do + acc + else + reverse = swap(pair) + Map.put(acc, sorted, weight + Map.get(edges, reverse)) + end + end + + guests = Enum.to_list(guests) + + {guests, edges} + end + + def permutations([]), do: [[]] + + def permutations(xs) do + for h <- xs, t <- permutations(xs -- [h]), do: [h | t] + end + + def happiness(edges, [a | _] = xs) do + happiness(edges, xs, a, 0) + end + + def happiness(edges, [t], h, acc) do + edge = Map.get(edges, sort({h, t}), 0) + edge + acc + end + + def happiness(edges, [a, b | rest], h, acc) do + edge = Map.get(edges, sort({a, b}), 0) + happiness(edges, [b | rest], h, acc + edge) + end +end