1
0
Fork 0
advent-of-code/2015/lib/2015/13.ex
2022-09-21 09:19:53 -04:00

100 lines
2.1 KiB
Elixir

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