namespace AOC2020; /// /// Day 16: /// public sealed class Day16() : Day(2020, 16, "Ticket Translation") { private Dictionary>? _rules; private List>? _tickets; public override void ProcessInput() { _tickets = []; _rules = []; foreach (var line in Input) { var spl = line.Split(": ", 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); if (spl.Length == 2) { var rule = spl[1].Split(" or ").Select(s => { var r = s.Split('-').Select(int.Parse).ToList(); return new Range(r[0], r[1]); }).ToList(); _rules.Add(spl[0], rule); } else { spl = line.Split(','); if (spl.Length > 1) _tickets.Add(spl.Select(int.Parse).ToList()); } } } public override object Part1() { var allValues = _tickets!.Skip(1).SelectMany(t => t); var allRules = _rules!.Values.SelectMany(r => r); return allValues.Where(t => !allRules.Any(r => r.Contains(t))).Sum(); } public override object Part2() { var ticketFields = _tickets! // valid tickets .Where(ticket => ticket .All(t => _rules!.Values .SelectMany(r => r) .Any(r => r.Contains(t)))) // group by index .SelectMany(inner => inner.Select((item, index) => new { item, index })) .GroupBy(i => i.index, i => i.item) .Select(g => g.ToList()) .Select((val, i) => new { Value = val, Index = i }) .ToList(); var matchedRules = _rules! // find matching rules and indices .SelectMany(x => ticketFields .Where(y => y.Value.All(z => x.Value.Any(r => r.Contains(z)))) .Select(y => (x.Key, y.Index)) .ToList()) .ToList(); matchedRules.Sort((a, b) => matchedRules.Count(x => x.Key == a.Key) - matchedRules.Count(x => x.Key == b.Key)); while (matchedRules.Any(x => matchedRules.Count(y => y.Key == x.Key) > 1)) foreach (var (key, index) in matchedRules.Where(y => matchedRules.Count(z => z.Key == y.Key) == 1 && matchedRules.Count(z => z.Index == y.Index) > 1)) // filter matches by index matchedRules = matchedRules .Where(x => x.Index != index || x.Key == key) .ToList(); var departureFields = matchedRules.Where(r => r.Key.StartsWith("departure")); return departureFields.Aggregate(1L, (l, match) => l * _tickets!.First()[match.Index]); } }