From acbd4a02372bff5ac101d20785c574efc69b4c66 Mon Sep 17 00:00:00 2001 From: Jeremy Kaplan Date: Wed, 16 Dec 2020 00:04:37 -0800 Subject: [PATCH] Day 16 Part 2 --- 2020/day16/day16.ex | 77 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 8 deletions(-) diff --git a/2020/day16/day16.ex b/2020/day16/day16.ex index 51fa87d..0d8e5c8 100644 --- a/2020/day16/day16.ex +++ b/2020/day16/day16.ex @@ -6,18 +6,17 @@ defmodule Day16 do defp test_input do """ - class: 1-3 or 5-7 - row: 6-11 or 33-44 - seat: 13-40 or 45-50 + class: 0-1 or 4-19 + row: 0-5 or 8-19 + seat: 0-13 or 16-19 your ticket: - 7,1,14 + 11,12,13 nearby tickets: - 7,3,47 - 40,4,50 - 55,2,20 - 38,6,12 + 3,9,18 + 15,1,5 + 5,14,9 """ end @@ -80,6 +79,68 @@ defmodule Day16 do Enum.map(nearby, &validate(fields, &1)) |> Enum.sum() end + + def part2 do + {fields, mine, nearby} = read_input() |> parse_input() + + Enum.filter(nearby, &(validate(fields, &1) == 0)) + |> columns(Enum.count(fields)) + |> deduce(fields) + |> departure(mine) + end + + defp departure(mapping, ticket) do + Enum.reduce(mapping, 1, fn {name, idx}, product -> + if String.starts_with?(name, "departure") do + product * Enum.at(ticket, idx) + else + product + end + end) + end + + defp columns(tickets, field_count) do + Enum.reduce(tickets, List.duplicate([], field_count), fn ticket, columns -> + Enum.zip(ticket, columns) + |> Enum.map(fn {value, list} -> [value | list] end) + end) + end + + defp deduce(columns, fields) do + possible = + Enum.map(columns, fn values -> + Enum.filter(fields, fn field -> + Enum.all?(values, &can_match?(field, &1)) + end) + end) + + constrain(%{}, Enum.with_index(possible)) + end + + defp constrain(known, []), do: known + + defp constrain(known, possible) do + {solved, unsolved} = + Enum.split_with(possible, fn {fields, _idx} -> + Enum.count(fields) == 1 + end) + + solved_names = Enum.map(solved, fn {[{name, _r1, _r2}], _idx} -> name end) |> MapSet.new() + + new_possible = + Enum.map(unsolved, fn {fields, idx} -> + new_fields = + Enum.reject(fields, fn {name, _, _} -> + MapSet.member?(solved_names, name) + end) + + {new_fields, idx} + end) + + new_known = Enum.into(solved, known, fn {[{name, _r1, _r2}], idx} -> {name, idx} end) + constrain(new_known, new_possible) + end end Day16.part1() |> IO.inspect() +Day16.part2() |> IO.inspect()