aoc2020/aoc2020/Day16.cs

87 lines
2.9 KiB
C#

namespace aoc2020;
/// <summary>
/// Day 16: <see href="https://adventofcode.com/2020/day/16" />
/// </summary>
public sealed class Day16 : Day
{
private readonly Dictionary<string, List<Range>> _rules;
private readonly List<List<int>> _tickets;
public Day16() : base(16, "Ticket Translation")
{
_tickets = new();
_rules = new();
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 string 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 string 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])}";
}
}