update to .net 6
continuous-integration/drone/push Build is failing Details

- global usings
- file-scope namespaces
- update drone image tag
This commit is contained in:
Ben Harris 2021-11-09 16:18:13 -05:00
parent f1c329ddaa
commit 811c0f5d74
34 changed files with 1609 additions and 1703 deletions

View File

@ -4,7 +4,7 @@ name: run
steps: steps:
- name: run - name: run
image: mcr.microsoft.com/dotnet/sdk:latest image: mcr.microsoft.com/dotnet/sdk:6.0
commands: commands:
- dotnet test - dotnet test
- dotnet run --project aoc2020/aoc2020.csproj - dotnet run --project aoc2020/aoc2020.csproj

View File

@ -1,4 +1,4 @@
MIT License Copyright (c) <year> <copyright holders> MIT License Copyright (c) 2020 Ben Harris
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,62 +1,60 @@
using System; using System.Diagnostics;
using System.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace aoc2020.test namespace aoc2020.test;
[TestClass]
public class DayTests
{ {
[TestClass] [DataTestMethod]
public class DayTests [DataRow(typeof(Day01), "751776", "42275090")]
[DataRow(typeof(Day02), "556", "605")]
[DataRow(typeof(Day03), "189", "1718180100")]
[DataRow(typeof(Day04), "247", "145")]
[DataRow(typeof(Day05), "878", "504")]
[DataRow(typeof(Day06), "6273", "3254")]
[DataRow(typeof(Day07), "169", "82372")]
[DataRow(typeof(Day08), "1654", "833")]
[DataRow(typeof(Day09), "138879426", "23761694")]
[DataRow(typeof(Day10), "1980", "4628074479616")]
[DataRow(typeof(Day11), "2303", "2057")]
[DataRow(typeof(Day12), "1710", "62045")]
[DataRow(typeof(Day13), "171", "539746751134958")]
[DataRow(typeof(Day14), "17481577045893", "4160009892257")]
[DataRow(typeof(Day15), "257", "8546398")]
[DataRow(typeof(Day16), "19093", "5311123569883")]
// [DataRow(typeof(Day17), "293", "1816")]
[DataRow(typeof(Day18), "12918250417632", "171259538712010")]
[DataRow(typeof(Day19), "160", "357")]
[DataRow(typeof(Day20), "21599955909991", "")]
[DataRow(typeof(Day21), "", "")]
[DataRow(typeof(Day22), "", "")]
[DataRow(typeof(Day23), "", "")]
[DataRow(typeof(Day24), "", "")]
[DataRow(typeof(Day25), "", "")]
public void CheckAllDays(Type dayType, string part1, string part2)
{ {
[DataTestMethod] // create day instance
[DataRow(typeof(Day01), "751776", "42275090")] var s = Stopwatch.StartNew();
[DataRow(typeof(Day02), "556", "605")] var day = Activator.CreateInstance(dayType) as Day;
[DataRow(typeof(Day03), "189", "1718180100")] s.Stop();
[DataRow(typeof(Day04), "247", "145")] Assert.IsNotNull(day, "failed to create day object");
[DataRow(typeof(Day05), "878", "504")] Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in constructor");
[DataRow(typeof(Day06), "6273", "3254")]
[DataRow(typeof(Day07), "169", "82372")]
[DataRow(typeof(Day08), "1654", "833")]
[DataRow(typeof(Day09), "138879426", "23761694")]
[DataRow(typeof(Day10), "1980", "4628074479616")]
[DataRow(typeof(Day11), "2303", "2057")]
[DataRow(typeof(Day12), "1710", "62045")]
[DataRow(typeof(Day13), "171", "539746751134958")]
[DataRow(typeof(Day14), "17481577045893", "4160009892257")]
[DataRow(typeof(Day15), "257", "8546398")]
[DataRow(typeof(Day16), "19093", "5311123569883")]
// [DataRow(typeof(Day17), "293", "1816")]
[DataRow(typeof(Day18), "12918250417632", "171259538712010")]
[DataRow(typeof(Day19), "160", "357")]
[DataRow(typeof(Day20), "21599955909991", "")]
[DataRow(typeof(Day21), "", "")]
[DataRow(typeof(Day22), "", "")]
[DataRow(typeof(Day23), "", "")]
[DataRow(typeof(Day24), "", "")]
[DataRow(typeof(Day25), "", "")]
public void CheckAllDays(Type dayType, string part1, string part2)
{
// create day instance
var s = Stopwatch.StartNew();
var day = (Day) Activator.CreateInstance(dayType);
s.Stop();
Assert.IsNotNull(day, "failed to create day object");
Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in constructor");
// part 1 // part 1
s.Reset(); s.Reset();
s.Start(); s.Start();
var part1Actual = day.Part1(); var part1Actual = day.Part1();
s.Stop(); s.Stop();
Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in part1"); Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in part1");
Assert.AreEqual(part1, part1Actual, $"Incorrect answer for Day {day.DayNumber} Part1"); Assert.AreEqual(part1, part1Actual, $"Incorrect answer for Day {day.DayNumber} Part1");
// part 2 // part 2
s.Reset(); s.Reset();
s.Start(); s.Start();
var part2Actual = day.Part2(); var part2Actual = day.Part2();
s.Stop(); s.Stop();
Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in part2"); Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in part2");
Assert.AreEqual(part2, part2Actual, $"Incorrect answer for Day {day.DayNumber} Part2"); Assert.AreEqual(part2, part2Actual, $"Incorrect answer for Day {day.DayNumber} Part2");
}
} }
} }

View File

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,48 +1,44 @@
using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
namespace aoc2020 namespace aoc2020;
public abstract class Day
{ {
public abstract class Day protected Day(int dayNumber, string puzzleName)
{ {
protected Day(int dayNumber, string puzzleName) DayNumber = dayNumber;
{ PuzzleName = puzzleName;
DayNumber = dayNumber;
PuzzleName = puzzleName;
}
public int DayNumber { get; }
public string PuzzleName { get; }
protected IEnumerable<string> Input =>
File.ReadLines(FileName);
protected string FileName =>
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"input/day{DayNumber,2:00}.in");
public abstract string Part1();
public abstract string Part2();
public void AllParts(bool verbose = true)
{
Console.WriteLine($"Day {DayNumber,2}: {PuzzleName}");
var s = Stopwatch.StartNew();
var part1 = Part1();
s.Stop();
Console.Write($"Part1: {part1,-15} ");
Console.WriteLine(verbose ? $"{s.ScaleMilliseconds()}ms elapsed" : "");
s.Reset();
s.Start();
var part2 = Part2();
s.Stop();
Console.Write($"Part2: {part2,-15} ");
Console.WriteLine(verbose ? $"{s.ScaleMilliseconds()}ms elapsed" : "");
Console.WriteLine();
}
} }
}
public int DayNumber { get; }
public string PuzzleName { get; }
protected IEnumerable<string> Input =>
File.ReadLines(FileName);
protected string FileName =>
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"input/day{DayNumber,2:00}.in");
public abstract string Part1();
public abstract string Part2();
public void AllParts(bool verbose = true)
{
Console.WriteLine($"Day {DayNumber,2}: {PuzzleName}");
var s = Stopwatch.StartNew();
var part1 = Part1();
s.Stop();
Console.Write($"Part1: {part1,-15} ");
Console.WriteLine(verbose ? $"{s.ScaleMilliseconds()}ms elapsed" : "");
s.Reset();
s.Start();
var part2 = Part2();
s.Stop();
Console.Write($"Part2: {part2,-15} ");
Console.WriteLine(verbose ? $"{s.ScaleMilliseconds()}ms elapsed" : "");
Console.WriteLine();
}
}

View File

@ -1,35 +1,31 @@
using System.Collections.Immutable; namespace aoc2020;
using System.Linq;
namespace aoc2020 /// <summary>
/// Day 1: <see href="https://adventofcode.com/2020/day/1" />
/// </summary>
public sealed class Day01 : Day
{ {
/// <summary> private readonly ImmutableHashSet<int> _entries;
/// Day 1: <see href="https://adventofcode.com/2020/day/1" />
/// </summary> public Day01() : base(1, "Report Repair")
public sealed class Day01 : Day
{ {
private readonly ImmutableHashSet<int> _entries; _entries = Input.Select(int.Parse).ToImmutableHashSet();
public Day01() : base(1, "Report Repair")
{
_entries = Input.Select(int.Parse).ToImmutableHashSet();
}
public override string Part1()
{
var entry = _entries.First(e => _entries.Contains(2020 - e));
return $"{entry * (2020 - entry)}";
}
public override string Part2()
{
foreach (var i in _entries)
foreach (var j in _entries)
foreach (var k in _entries)
if (i + j + k == 2020)
return $"{i * j * k}";
return "";
}
} }
}
public override string Part1()
{
var entry = _entries.First(e => _entries.Contains(2020 - e));
return $"{entry * (2020 - entry)}";
}
public override string Part2()
{
foreach (var i in _entries)
foreach (var j in _entries)
foreach (var k in _entries)
if (i + j + k == 2020)
return $"{i * j * k}";
return "";
}
}

View File

@ -1,56 +1,52 @@
using System.Collections.Immutable; namespace aoc2020;
using System.Linq;
namespace aoc2020 /// <summary>
/// Day 2: <see href="https://adventofcode.com/2020/day/1" />
/// </summary>
public sealed class Day02 : Day
{ {
/// <summary> private readonly ImmutableList<Password> _passwords;
/// Day 2: <see href="https://adventofcode.com/2020/day/1" />
/// </summary> public Day02() : base(2, "Password Philosophy")
public sealed class Day02 : Day
{ {
private readonly ImmutableList<Password> _passwords; _passwords = Input.Select(p => new Password(p)).ToImmutableList();
public Day02() : base(2, "Password Philosophy")
{
_passwords = Input.Select(p => new Password(p)).ToImmutableList();
}
public override string Part1()
{
return $"{_passwords.Count(p => p.IsValid)}";
}
public override string Part2()
{
return $"{_passwords.Count(p => p.IsValidByIndex)}";
}
private class Password
{
public Password(string line)
{
var split = line.Split(": ", 2);
var split2 = split[0].Split(' ', 2);
var indices = split2[0].Split('-', 2);
I = int.Parse(indices[0]);
J = int.Parse(indices[1]);
C = char.Parse(split2[1]);
Value = split[1];
}
public bool IsValid =>
Count >= I && Count <= J;
public bool IsValidByIndex =>
(Value[I - 1] == C) ^ (Value[J - 1] == C);
private int Count =>
Value.Count(p => p == C);
private int I { get; }
private int J { get; }
private char C { get; }
private string Value { get; }
}
} }
}
public override string Part1()
{
return $"{_passwords.Count(p => p.IsValid)}";
}
public override string Part2()
{
return $"{_passwords.Count(p => p.IsValidByIndex)}";
}
private class Password
{
public Password(string line)
{
var split = line.Split(": ", 2);
var split2 = split[0].Split(' ', 2);
var indices = split2[0].Split('-', 2);
I = int.Parse(indices[0]);
J = int.Parse(indices[1]);
C = char.Parse(split2[1]);
Value = split[1];
}
public bool IsValid =>
Count >= I && Count <= J;
public bool IsValidByIndex =>
(Value[I - 1] == C) ^ (Value[J - 1] == C);
private int Count =>
Value.Count(p => p == C);
private int I { get; }
private int J { get; }
private char C { get; }
private string Value { get; }
}
}

View File

@ -1,45 +1,42 @@
using System.Linq; namespace aoc2020;
namespace aoc2020 /// <summary>
/// Day 3: <see href="https://adventofcode.com/2020/day/3" />
/// </summary>
public sealed class Day03 : Day
{ {
/// <summary> private readonly string[] _grid;
/// Day 3: <see href="https://adventofcode.com/2020/day/3" /> private readonly int _width;
/// </summary>
public sealed class Day03 : Day public Day03() : base(3, "Toboggan Trajectory")
{ {
private readonly string[] _grid; _grid = Input.ToArray();
private readonly int _width; _width = _grid[0].Length;
public Day03() : base(3, "Toboggan Trajectory")
{
_grid = Input.ToArray();
_width = _grid[0].Length;
}
private long CountSlope(int dx, int dy)
{
long hits = 0;
for (int x = 0, y = 0; y < _grid.Length; y += dy, x = (x + dx) % _width)
if (_grid[y][x] == '#')
hits++;
return hits;
}
public override string Part1()
{
return $"{CountSlope(3, 1)}";
}
public override string Part2()
{
var xSlopes = new[] {1, 3, 5, 7, 1};
var ySlopes = new[] {1, 1, 1, 1, 2};
return xSlopes.Zip(ySlopes)
.Select(s => CountSlope(s.Item1, s.Item2))
.Aggregate((acc, i) => acc * i)
.ToString();
}
} }
}
private long CountSlope(int dx, int dy)
{
long hits = 0;
for (int x = 0, y = 0; y < _grid.Length; y += dy, x = (x + dx) % _width)
if (_grid[y][x] == '#')
hits++;
return hits;
}
public override string Part1()
{
return $"{CountSlope(3, 1)}";
}
public override string Part2()
{
var xSlopes = new[] { 1, 3, 5, 7, 1 };
var ySlopes = new[] { 1, 1, 1, 1, 2 };
return xSlopes.Zip(ySlopes)
.Select(s => CountSlope(s.First, s.Second))
.Aggregate((acc, i) => acc * i)
.ToString();
}
}

View File

@ -1,188 +1,182 @@
using System; namespace aoc2020;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace aoc2020 /// <summary>
/// Day 4: <see href="https://adventofcode.com/2020/day/4" />
/// </summary>
public sealed class Day04 : Day
{ {
/// <summary> private readonly List<Passport> _passports;
/// Day 4: <see href="https://adventofcode.com/2020/day/4" />
/// </summary> public Day04() : base(4, "Passport Processing")
public sealed class Day04 : Day
{ {
private readonly List<Passport> _passports; _passports = new List<Passport>();
public Day04() : base(4, "Passport Processing") var a = new List<string>();
foreach (var line in Input)
{ {
_passports = new List<Passport>(); if (line == "")
var a = new List<string>();
foreach (var line in Input)
{ {
if (line == "") _passports.Add(Passport.Parse(a));
{ a.Clear();
_passports.Add(Passport.Parse(a)); continue;
a.Clear();
continue;
}
a.Add(line);
} }
if (a.Any()) _passports.Add(Passport.Parse(a)); a.Add(line);
} }
public override string Part1() if (a.Any()) _passports.Add(Passport.Parse(a));
}
public override string Part1()
{
return $"{_passports.Count(p => p.IsValid)}";
}
public override string Part2()
{
return $"{_passports.Count(p => p.ExtendedValidation())}";
}
private class Passport
{
private string _byr;
private string _cid;
private string _ecl;
private string _eyr;
private string _hcl;
private string _hgt;
private string _iyr;
private string _pid;
public bool IsValid =>
_byr != null &&
_iyr != null &&
_eyr != null &&
_hgt != null &&
_hcl != null &&
_ecl != null &&
_pid != null;
public bool ExtendedValidation()
{ {
return $"{_passports.Count(p => p.IsValid)}"; if (!IsValid) return false;
}
public override string Part2() // birth year
{ if (int.TryParse(_byr, out var byr))
return $"{_passports.Count(p => p.ExtendedValidation())}";
}
private class Passport
{
private string _byr;
private string _cid;
private string _ecl;
private string _eyr;
private string _hcl;
private string _hgt;
private string _iyr;
private string _pid;
public bool IsValid =>
_byr != null &&
_iyr != null &&
_eyr != null &&
_hgt != null &&
_hcl != null &&
_ecl != null &&
_pid != null;
public bool ExtendedValidation()
{ {
if (!IsValid) return false; if (byr < 1920 || byr > 2002)
// birth year
if (int.TryParse(_byr, out var byr))
{
if (byr < 1920 || byr > 2002)
return false;
}
else
{
return false; return false;
} }
else
// issuance year {
if (int.TryParse(_iyr, out var iyr)) return false;
{
if (iyr < 2010 || iyr > 2020)
return false;
}
else
{
return false;
}
// expiration year
if (int.TryParse(_eyr, out var eyr))
{
if (eyr < 2020 || eyr > 2030)
return false;
}
else
{
return false;
}
// height
if (_hgt.EndsWith("cm"))
{
var h = _hgt.Substring(0, 3);
if (int.TryParse(h, out var hgt))
{
if (hgt < 150 || hgt > 193)
return false;
}
else
{
return false;
}
}
else if (_hgt.EndsWith("in"))
{
var h = _hgt.Substring(0, 2);
if (int.TryParse(h, out var hgt))
{
if (hgt < 59 || hgt > 76)
return false;
}
else
{
return false;
}
}
else
{
return false;
}
// hair color
if (!Regex.IsMatch(_hcl, "#[0-9a-f]{6}"))
return false;
// eye color
if (!new[] {"amb", "blu", "brn", "gry", "grn", "hzl", "oth"}.Contains(_ecl))
return false;
// passport id
if (_pid.Length != 9)
return false;
return true;
} }
public static Passport Parse(IEnumerable<string> list) // issuance year
if (int.TryParse(_iyr, out var iyr))
{ {
var passport = new Passport(); if (iyr < 2010 || iyr > 2020)
foreach (var entry in string.Join(' ', list).Split(' ', StringSplitOptions.TrimEntries)) return false;
{
var spl = entry.Split(':', 2);
switch (spl[0])
{
case "byr":
passport._byr = spl[1];
break;
case "iyr":
passport._iyr = spl[1];
break;
case "eyr":
passport._eyr = spl[1];
break;
case "hgt":
passport._hgt = spl[1];
break;
case "hcl":
passport._hcl = spl[1];
break;
case "ecl":
passport._ecl = spl[1];
break;
case "pid":
passport._pid = spl[1];
break;
case "cid":
passport._cid = spl[1];
break;
}
}
return passport;
} }
else
{
return false;
}
// expiration year
if (int.TryParse(_eyr, out var eyr))
{
if (eyr < 2020 || eyr > 2030)
return false;
}
else
{
return false;
}
// height
if (_hgt.EndsWith("cm"))
{
var h = _hgt[..3];
if (int.TryParse(h, out var hgt))
{
if (hgt < 150 || hgt > 193)
return false;
}
else
{
return false;
}
}
else if (_hgt.EndsWith("in"))
{
var h = _hgt.Substring(0, 2);
if (int.TryParse(h, out var hgt))
{
if (hgt < 59 || hgt > 76)
return false;
}
else
{
return false;
}
}
else
{
return false;
}
// hair color
if (!Regex.IsMatch(_hcl, "#[0-9a-f]{6}"))
return false;
// eye color
if (!new[] { "amb", "blu", "brn", "gry", "grn", "hzl", "oth" }.Contains(_ecl))
return false;
// passport id
if (_pid.Length != 9)
return false;
return true;
}
public static Passport Parse(IEnumerable<string> list)
{
var passport = new Passport();
foreach (var entry in string.Join(' ', list).Split(' ', StringSplitOptions.TrimEntries))
{
var spl = entry.Split(':', 2);
switch (spl[0])
{
case "byr":
passport._byr = spl[1];
break;
case "iyr":
passport._iyr = spl[1];
break;
case "eyr":
passport._eyr = spl[1];
break;
case "hgt":
passport._hgt = spl[1];
break;
case "hcl":
passport._hcl = spl[1];
break;
case "ecl":
passport._ecl = spl[1];
break;
case "pid":
passport._pid = spl[1];
break;
case "cid":
passport._cid = spl[1];
break;
}
}
return passport;
} }
} }
} }

View File

@ -1,34 +1,29 @@
using System; namespace aoc2020;
using System.Collections.Immutable;
using System.Linq;
namespace aoc2020 /// <summary>
/// Day 5: <see href="https://adventofcode.com/2020/day/5" />
/// </summary>
public sealed class Day05 : Day
{ {
/// <summary> private readonly ImmutableHashSet<int> _ids;
/// Day 5: <see href="https://adventofcode.com/2020/day/5" />
/// </summary> public Day05() : base(5, "Binary Boarding")
public sealed class Day05 : Day
{ {
private readonly ImmutableHashSet<int> _ids; _ids = Input
.Select(s =>
public Day05() : base(5, "Binary Boarding") Convert.ToInt32(s.Replace('F', '0').Replace('B', '1').Replace('L', '0').Replace('R', '1'), 2))
{ .OrderBy(i => i)
_ids = Input .ToImmutableHashSet();
.Select(s =>
Convert.ToInt32(s.Replace('F', '0').Replace('B', '1').Replace('L', '0').Replace('R', '1'), 2))
.OrderBy(i => i)
.ToImmutableHashSet();
}
public override string Part1()
{
return $"{_ids.Last()}";
}
public override string Part2()
{
// arithmetic sum of full series
return $"{(_ids.Count + 1) * (_ids.First() + _ids.Last()) / 2 - _ids.Sum()}";
}
} }
}
public override string Part1()
{
return $"{_ids.Last()}";
}
public override string Part2()
{
// arithmetic sum of full series
return $"{(_ids.Count + 1) * (_ids.First() + _ids.Last()) / 2 - _ids.Sum()}";
}
}

View File

@ -1,54 +1,50 @@
using System.Collections.Generic; namespace aoc2020;
using System.Linq;
namespace aoc2020 /// <summary>
/// Day 6: <see href="https://adventofcode.com/2020/day/6" />
/// </summary>
public sealed class Day06 : Day
{ {
/// <summary> private readonly int _countPart1;
/// Day 6: <see href="https://adventofcode.com/2020/day/6" /> private readonly int _countPart2;
/// </summary>
public sealed class Day06 : Day public Day06() : base(6, "Custom Customs")
{ {
private readonly int _countPart1; var alphabet = "abcedfghijklmnopqrstuvwxyz".ToCharArray();
private readonly int _countPart2; _countPart1 = 0;
_countPart2 = 0;
public Day06() : base(6, "Custom Customs") var s = new HashSet<char>();
var lines = new HashSet<string>();
foreach (var line in Input)
{ {
var alphabet = "abcedfghijklmnopqrstuvwxyz".ToCharArray(); if (line == "")
_countPart1 = 0;
_countPart2 = 0;
var s = new HashSet<char>();
var lines = new HashSet<string>();
foreach (var line in Input)
{
if (line == "")
{
_countPart1 += s.Count;
_countPart2 += alphabet.Count(a => lines.All(l => l.Contains(a)));
s.Clear();
lines.Clear();
continue;
}
foreach (var c in line)
s.Add(c);
lines.Add(line);
}
if (s.Any())
{ {
_countPart1 += s.Count; _countPart1 += s.Count;
_countPart2 += alphabet.Count(a => lines.All(l => l.Contains(a))); _countPart2 += alphabet.Count(a => lines.All(l => l.Contains(a)));
s.Clear();
lines.Clear();
continue;
} }
foreach (var c in line)
s.Add(c);
lines.Add(line);
} }
public override string Part1() if (s.Any())
{ {
return $"{_countPart1}"; _countPart1 += s.Count;
} _countPart2 += alphabet.Count(a => lines.All(l => l.Contains(a)));
public override string Part2()
{
return $"{_countPart2}";
} }
} }
}
public override string Part1()
{
return $"{_countPart1}";
}
public override string Part2()
{
return $"{_countPart2}";
}
}

View File

@ -1,61 +1,57 @@
using System.Collections.Generic; namespace aoc2020;
using System.Linq;
namespace aoc2020 /// <summary>
/// Day 7: <see href="https://adventofcode.com/2020/day/7" />
/// </summary>
public sealed class Day07 : Day
{ {
/// <summary> private readonly Dictionary<string, IEnumerable<(int, string)?>> _rules;
/// Day 7: <see href="https://adventofcode.com/2020/day/7" />
/// </summary> public Day07() : base(7, "Handy Haversacks")
public sealed class Day07 : Day
{ {
private readonly Dictionary<string, IEnumerable<(int, string)?>> _rules; _rules = Input.Select(rule =>
public Day07() : base(7, "Handy Haversacks")
{
_rules = Input.Select(rule =>
{
var spl = rule.Split(" bags contain ", 2);
var outer = string.Join(' ', spl[0].Split(' ').Take(2));
var inner = spl[1].Split(", ").Select(ParseQuantity).Where(i => i != null);
return (outer, inner);
})
.ToDictionary(t => t.outer, t => t.inner);
}
private static (int, string)? ParseQuantity(string arg)
{
if (arg == "no other bags.") return null;
var words = arg.Split(' ');
return (int.Parse(words[0]), string.Join(' ', words[1..3]));
}
private int Weight(string node)
{
return 1 + _rules[node].Sum(i => i.Value.Item1 * Weight(i.Value.Item2));
}
public override string Part1()
{
// breadth-first search with Queue
var start = new Queue<string>(new[] {"shiny gold"});
var p = new HashSet<string>();
string node;
while (true)
{ {
node = start.Dequeue(); var spl = rule.Split(" bags contain ", 2);
foreach (var (container, contained) in _rules) var outer = string.Join(' ', spl[0].Split(' ').Take(2));
if (contained.Any(i => i.HasValue && i.Value.Item2 == node) && p.Add(container)) var inner = spl[1].Split(", ").Select(ParseQuantity).Where(i => i != null);
start.Enqueue(container); return (outer, inner);
})
if (!start.Any()) break; .ToDictionary(t => t.outer, t => t.inner);
}
return $"{p.Count}";
}
public override string Part2()
{
return $"{Weight("shiny gold") - 1}";
}
} }
}
private static (int, string)? ParseQuantity(string arg)
{
if (arg == "no other bags.") return null;
var words = arg.Split(' ');
return (int.Parse(words[0]), string.Join(' ', words[1..3]));
}
private int Weight(string node)
{
return 1 + _rules[node].Sum(i => i.Value.Item1 * Weight(i.Value.Item2));
}
public override string Part1()
{
// breadth-first search with Queue
var start = new Queue<string>(new[] { "shiny gold" });
var p = new HashSet<string>();
string node;
while (true)
{
node = start.Dequeue();
foreach (var (container, contained) in _rules)
if (contained.Any(i => i.HasValue && i.Value.Item2 == node) && p.Add(container))
start.Enqueue(container);
if (!start.Any()) break;
}
return $"{p.Count}";
}
public override string Part2()
{
return $"{Weight("shiny gold") - 1}";
}
}

View File

@ -1,77 +1,74 @@
using System.Linq; namespace aoc2020;
namespace aoc2020 /// <summary>
/// Day 8: <see href="https://adventofcode.com/2020/day/8" />
/// </summary>
public sealed class Day08 : Day
{ {
/// <summary> private readonly (string instruction, int value)[] _instructions;
/// Day 8: <see href="https://adventofcode.com/2020/day/8" /> private int _accumulator;
/// </summary> private int _currentInstruction;
public sealed class Day08 : Day
public Day08() : base(8, "Handheld Halting")
{ {
private readonly (string instruction, int value)[] _instructions; _instructions = Input.Select(ParseLine).ToArray();
private int _accumulator; }
private int _currentInstruction;
public Day08() : base(8, "Handheld Halting") private static (string, int) ParseLine(string line)
{
var spl = line.Split(' ', 2);
return (spl[0], int.Parse(spl[1]));
}
private bool Halts()
{
_accumulator = 0;
_currentInstruction = 0;
var visited = new bool[_instructions.Length + 1];
while (!visited[_currentInstruction] && _currentInstruction < _instructions.Length)
{ {
_instructions = Input.Select(ParseLine).ToArray(); visited[_currentInstruction] = true;
}
private static (string, int) ParseLine(string line) switch (_instructions[_currentInstruction].instruction)
{
var spl = line.Split(' ', 2);
return (spl[0], int.Parse(spl[1]));
}
private bool Halts()
{
_accumulator = 0;
_currentInstruction = 0;
var visited = new bool[_instructions.Length + 1];
while (!visited[_currentInstruction] && _currentInstruction < _instructions.Length)
{ {
visited[_currentInstruction] = true; case "acc":
_accumulator += _instructions[_currentInstruction].value;
switch (_instructions[_currentInstruction].instruction) break;
{ case "jmp":
case "acc": _currentInstruction += _instructions[_currentInstruction].value;
_accumulator += _instructions[_currentInstruction].value; continue;
break;
case "jmp":
_currentInstruction += _instructions[_currentInstruction].value;
continue;
}
_currentInstruction++;
} }
return _currentInstruction == _instructions.Length; _currentInstruction++;
} }
public override string Part1() return _currentInstruction == _instructions.Length;
{
Halts();
return $"{_accumulator}";
}
public override string Part2()
{
for (var i = 0; i < _instructions.Length; i++)
// swap each nop and jmp and check if the program halts
if (_instructions[i].instruction == "nop")
{
_instructions[i].instruction = "jmp";
if (Halts()) break;
_instructions[i].instruction = "nop";
}
else if (_instructions[i].instruction == "jmp")
{
_instructions[i].instruction = "nop";
if (Halts()) break;
_instructions[i].instruction = "jmp";
}
return $"{_accumulator}";
}
} }
}
public override string Part1()
{
Halts();
return $"{_accumulator}";
}
public override string Part2()
{
for (var i = 0; i < _instructions.Length; i++)
// swap each nop and jmp and check if the program halts
if (_instructions[i].instruction == "nop")
{
_instructions[i].instruction = "jmp";
if (Halts()) break;
_instructions[i].instruction = "nop";
}
else if (_instructions[i].instruction == "jmp")
{
_instructions[i].instruction = "nop";
if (Halts()) break;
_instructions[i].instruction = "jmp";
}
return $"{_accumulator}";
}
}

View File

@ -1,52 +1,49 @@
using System.Linq; namespace aoc2020;
namespace aoc2020 /// <summary>
/// Day 9: <see href="https://adventofcode.com/2020/day/9" />
/// </summary>
public sealed class Day09 : Day
{ {
/// <summary> private readonly long[] _list;
/// Day 9: <see href="https://adventofcode.com/2020/day/9" /> private long _part1;
/// </summary>
public sealed class Day09 : Day public Day09() : base(9, "Encoding Error")
{ {
private readonly long[] _list; _list = Input.Select(long.Parse).ToArray();
private long _part1;
public Day09() : base(9, "Encoding Error")
{
_list = Input.Select(long.Parse).ToArray();
}
public override string Part1()
{
for (var i = 25; i < _list.Length - 25; i++)
{
var preamble = _list[(i - 25)..i];
if (!preamble.Any(num1 => preamble.Any(num2 => num1 + num2 == _list[i])))
{
_part1 = _list[i];
return $"{_part1}";
}
}
return "";
}
public override string Part2()
{
for (var i = 0; i < _list.Length; i++)
{
long sum = 0;
for (var j = i; j < _list.Length; j++)
{
sum += _list[j];
if (sum > _part1) break;
if (sum != _part1) continue;
var subset = _list[i..(j + 1)].ToArray();
return $"{subset.Min() + subset.Max()}";
}
}
return "";
}
} }
}
public override string Part1()
{
for (var i = 25; i < _list.Length - 25; i++)
{
var preamble = _list[(i - 25)..i];
if (!preamble.Any(num1 => preamble.Any(num2 => num1 + num2 == _list[i])))
{
_part1 = _list[i];
return $"{_part1}";
}
}
return "";
}
public override string Part2()
{
for (var i = 0; i < _list.Length; i++)
{
long sum = 0;
for (var j = i; j < _list.Length; j++)
{
sum += _list[j];
if (sum > _part1) break;
if (sum != _part1) continue;
var subset = _list[i..(j + 1)].ToArray();
return $"{subset.Min() + subset.Max()}";
}
}
return "";
}
}

View File

@ -1,59 +1,55 @@
using System; namespace aoc2020;
using System.Linq;
namespace aoc2020 /// <summary>
/// Day 10: <see href="https://adventofcode.com/2020/day/10" />
/// </summary>
public sealed class Day10 : Day
{ {
/// <summary> private readonly int[] _adapters;
/// Day 10: <see href="https://adventofcode.com/2020/day/10" /> private readonly long[] _memo;
/// </summary>
public sealed class Day10 : Day public Day10() : base(10, "Adapter Array")
{ {
private readonly int[] _adapters; var parsed = Input.Select(int.Parse).ToArray();
private readonly long[] _memo; // add socket and device to the list
_adapters = parsed.Concat(new[] { 0, parsed.Max() + 3 }).OrderBy(i => i).ToArray();
public Day10() : base(10, "Adapter Array") _memo = new long[_adapters.Length];
{
var parsed = Input.Select(int.Parse).ToArray();
// add socket and device to the list
_adapters = parsed.Concat(new[] {0, parsed.Max() + 3}).OrderBy(i => i).ToArray();
_memo = new long[_adapters.Length];
}
private long Connections(int i)
{
if (i == _adapters.Length - 1) _memo[i] = 1;
if (_memo[i] > 0) return _memo[i];
for (var j = i + 1; j <= i + 3 && j < _adapters.Length; j++)
if (_adapters[j] - _adapters[i] <= 3)
_memo[i] += Connections(j);
return _memo[i];
}
public override string Part1()
{
var ones = 0;
var threes = 0;
for (var i = 0; i < _adapters.Length - 1; i++)
switch (_adapters[i + 1] - _adapters[i])
{
case 1:
ones++;
break;
case 3:
threes++;
break;
default: throw new Exception("something went wrong");
}
return $"{ones * threes}";
}
public override string Part2()
{
return $"{Connections(0)}";
}
} }
}
private long Connections(int i)
{
if (i == _adapters.Length - 1) _memo[i] = 1;
if (_memo[i] > 0) return _memo[i];
for (var j = i + 1; j <= i + 3 && j < _adapters.Length; j++)
if (_adapters[j] - _adapters[i] <= 3)
_memo[i] += Connections(j);
return _memo[i];
}
public override string Part1()
{
var ones = 0;
var threes = 0;
for (var i = 0; i < _adapters.Length - 1; i++)
switch (_adapters[i + 1] - _adapters[i])
{
case 1:
ones++;
break;
case 3:
threes++;
break;
default: throw new Exception("something went wrong");
}
return $"{ones * threes}";
}
public override string Part2()
{
return $"{Connections(0)}";
}
}

View File

@ -1,91 +1,87 @@
using System; namespace aoc2020;
using System.Collections.Generic;
using System.Linq;
namespace aoc2020 /// <summary>
/// Day 11: <see href="https://adventofcode.com/2020/day/11" />
/// </summary>
public sealed class Day11 : Day
{ {
/// <summary> public Day11() : base(11, "Seating System")
/// Day 11: <see href="https://adventofcode.com/2020/day/11" />
/// </summary>
public sealed class Day11 : Day
{ {
public Day11() : base(11, "Seating System") }
public override string Part1()
{
var prev = new LifeGame(Input);
while (true)
{
var next = prev.StepPart1();
var same = true;
for (var i = 0; i < next.Grid.Length; i++)
if (!next.Grid[i].SequenceEqual(prev.Grid[i]))
{
same = false;
break;
}
if (same) break;
prev = next;
}
return $"{prev.TotalSeated}";
}
public override string Part2()
{
var prev = new LifeGame(Input);
while (true)
{
var next = prev.StepPart2();
var same = true;
for (var i = 0; i < next.Grid.Length; i++)
if (!next.Grid[i].SequenceEqual(prev.Grid[i]))
{
same = false;
break;
}
if (same) break;
prev = next;
}
return $"{prev.TotalSeated}";
}
private class LifeGame
{
private int _h, _w;
public char[][] Grid;
public LifeGame(IEnumerable<string> input)
{
Grid = input.Select(line => line.ToCharArray()).ToArray();
_h = Grid.Length;
_w = Grid[0].Length;
}
private LifeGame()
{ {
} }
public override string Part1() public int TotalSeated =>
Grid.Sum(l => l.Count(c => c == '#'));
private void PrintBoard()
{ {
var prev = new LifeGame(Input); Console.Clear();
foreach (var line in Grid)
while (true) Console.WriteLine(line);
{
var next = prev.StepPart1();
var same = true;
for (var i = 0; i < next.Grid.Length; i++)
if (!next.Grid[i].SequenceEqual(prev.Grid[i]))
{
same = false;
break;
}
if (same) break;
prev = next;
}
return $"{prev.TotalSeated}";
} }
public override string Part2() public LifeGame StepPart1()
{ {
var prev = new LifeGame(Input); var next = new LifeGame { _h = _h, _w = _w, Grid = Grid.Select(s => s.ToArray()).ToArray() };
while (true) for (var y = 0; y < _h; y++)
{
var next = prev.StepPart2();
var same = true;
for (var i = 0; i < next.Grid.Length; i++)
if (!next.Grid[i].SequenceEqual(prev.Grid[i]))
{
same = false;
break;
}
if (same) break;
prev = next;
}
return $"{prev.TotalSeated}";
}
private class LifeGame
{
private int _h, _w;
public char[][] Grid;
public LifeGame(IEnumerable<string> input)
{
Grid = input.Select(line => line.ToCharArray()).ToArray();
_h = Grid.Length;
_w = Grid[0].Length;
}
private LifeGame()
{
}
public int TotalSeated =>
Grid.Sum(l => l.Count(c => c == '#'));
private void PrintBoard()
{
Console.Clear();
foreach (var line in Grid)
Console.WriteLine(line);
}
public LifeGame StepPart1()
{
var next = new LifeGame {_h = _h, _w = _w, Grid = Grid.Select(s => s.ToArray()).ToArray()};
for (var y = 0; y < _h; y++)
for (var x = 0; x < _w; x++) for (var x = 0; x < _w; x++)
next.Grid[y][x] = Grid[y][x] switch next.Grid[y][x] = Grid[y][x] switch
{ {
@ -94,29 +90,29 @@ namespace aoc2020
_ => Grid[y][x] _ => Grid[y][x]
}; };
// next.PrintBoard(); // next.PrintBoard();
return next; return next;
} }
private char At(int y, int x) private char At(int y, int x)
{ {
return x < 0 || y < 0 || x >= _w || y >= _h ? '.' : Grid[y][x]; return x < 0 || y < 0 || x >= _w || y >= _h ? '.' : Grid[y][x];
} }
private int CountAdjacent(int y, int x) private int CountAdjacent(int y, int x)
{
return new[]
{ {
return new[]
{
At(y - 1, x - 1), At(y - 1, x + 0), At(y - 1, x + 1), At(y - 1, x - 1), At(y - 1, x + 0), At(y - 1, x + 1),
At(y + 0, x - 1), At(y + 0, x + 1), At(y + 0, x - 1), At(y + 0, x + 1),
At(y + 1, x - 1), At(y + 1, x + 0), At(y + 1, x + 1) At(y + 1, x - 1), At(y + 1, x + 0), At(y + 1, x + 1)
}.Count(c => c == '#'); }.Count(c => c == '#');
} }
public LifeGame StepPart2() public LifeGame StepPart2()
{ {
var next = new LifeGame {_h = _h, _w = _w, Grid = Grid.Select(s => s.ToArray()).ToArray()}; var next = new LifeGame { _h = _h, _w = _w, Grid = Grid.Select(s => s.ToArray()).ToArray() };
for (var y = 0; y < _h; y++) for (var y = 0; y < _h; y++)
for (var x = 0; x < _w; x++) for (var x = 0; x < _w; x++)
next.Grid[y][x] = Grid[y][x] switch next.Grid[y][x] = Grid[y][x] switch
{ {
@ -125,33 +121,32 @@ namespace aoc2020
_ => Grid[y][x] _ => Grid[y][x]
}; };
// next.PrintBoard(); // next.PrintBoard();
return next; return next;
} }
private int CanSee(int y, int x) private int CanSee(int y, int x)
{
return new[]
{ {
return new[]
{
TraceRay(y, x, -1, -1), TraceRay(y, x, -1, +0), TraceRay(y, x, -1, +1), TraceRay(y, x, -1, -1), TraceRay(y, x, -1, +0), TraceRay(y, x, -1, +1),
TraceRay(y, x, +0, -1), TraceRay(y, x, +0, +1), TraceRay(y, x, +0, -1), TraceRay(y, x, +0, +1),
TraceRay(y, x, +1, -1), TraceRay(y, x, +1, +0), TraceRay(y, x, +1, +1) TraceRay(y, x, +1, -1), TraceRay(y, x, +1, +0), TraceRay(y, x, +1, +1)
}.Count(c => c == '#'); }.Count(c => c == '#');
} }
private char TraceRay(int y, int x, int dy, int dx) private char TraceRay(int y, int x, int dy, int dx)
{
y += dy;
x += dx;
while (y >= 0 && y < _h && x >= 0 && x < _w)
{ {
if (Grid[y][x] != '.') return Grid[y][x];
y += dy; y += dy;
x += dx; x += dx;
while (y >= 0 && y < _h && x >= 0 && x < _w)
{
if (Grid[y][x] != '.') return Grid[y][x];
y += dy;
x += dx;
}
return '.';
} }
return '.';
} }
} }
} }

View File

@ -1,94 +1,89 @@
using System; namespace aoc2020;
namespace aoc2020 /// <summary>
/// Day 12: <see href="https://adventofcode.com/2020/day/12" />
/// </summary>
public sealed class Day12 : Day
{ {
/// <summary> public Day12() : base(12, "Rain Risk")
/// Day 12: <see href="https://adventofcode.com/2020/day/12" />
/// </summary>
public sealed class Day12 : Day
{ {
public Day12() : base(12, "Rain Risk")
{
}
private static void Swap(ref int x, ref int y)
{
var tmp = x;
x = y;
y = tmp;
}
private (int x, int y, int sx, int sy) ProcessInstructions()
{
// start facing east
int x = 0, y = 0, dx = 1, dy = 0;
int sx = 0, sy = 0, waypointX = 10, waypointY = -1;
foreach (var instruction in Input)
{
var value = int.Parse(instruction[1..]);
switch (instruction[0])
{
case 'N':
y -= value;
waypointY -= value;
break;
case 'S':
y += value;
waypointY += value;
break;
case 'E':
x += value;
waypointX += value;
break;
case 'W':
x -= value;
waypointX -= value;
break;
case 'L':
for (var i = 0; i < value / 90; ++i)
{
Swap(ref dx, ref dy);
Swap(ref waypointX, ref waypointY);
dy *= -1;
waypointY *= -1;
}
break;
case 'R':
for (var i = 0; i < value / 90; ++i)
{
Swap(ref dx, ref dy);
Swap(ref waypointX, ref waypointY);
dx *= -1;
waypointX *= -1;
}
break;
case 'F':
x += dx * value;
y += dy * value;
sx += waypointX * value;
sy += waypointY * value;
break;
default: throw new InvalidOperationException(nameof(instruction));
}
}
return (x, y, sx, sy);
}
public override string Part1()
{
var (x, y, _, _) = ProcessInstructions();
return $"{Math.Abs(x) + Math.Abs(y)}";
}
public override string Part2()
{
var (_, _, sx, sy) = ProcessInstructions();
return $"{Math.Abs(sx) + Math.Abs(sy)}";
}
} }
}
private static void Swap(ref int x, ref int y)
{
(y, x) = (x, y);
}
private (int x, int y, int sx, int sy) ProcessInstructions()
{
// start facing east
int x = 0, y = 0, dx = 1, dy = 0;
int sx = 0, sy = 0, waypointX = 10, waypointY = -1;
foreach (var instruction in Input)
{
var value = int.Parse(instruction[1..]);
switch (instruction[0])
{
case 'N':
y -= value;
waypointY -= value;
break;
case 'S':
y += value;
waypointY += value;
break;
case 'E':
x += value;
waypointX += value;
break;
case 'W':
x -= value;
waypointX -= value;
break;
case 'L':
for (var i = 0; i < value / 90; ++i)
{
Swap(ref dx, ref dy);
Swap(ref waypointX, ref waypointY);
dy *= -1;
waypointY *= -1;
}
break;
case 'R':
for (var i = 0; i < value / 90; ++i)
{
Swap(ref dx, ref dy);
Swap(ref waypointX, ref waypointY);
dx *= -1;
waypointX *= -1;
}
break;
case 'F':
x += dx * value;
y += dy * value;
sx += waypointX * value;
sy += waypointY * value;
break;
default: throw new InvalidOperationException(nameof(instruction));
}
}
return (x, y, sx, sy);
}
public override string Part1()
{
var (x, y, _, _) = ProcessInstructions();
return $"{Math.Abs(x) + Math.Abs(y)}";
}
public override string Part2()
{
var (_, _, sx, sy) = ProcessInstructions();
return $"{Math.Abs(sx) + Math.Abs(sy)}";
}
}

View File

@ -1,54 +1,51 @@
using System.Linq; namespace aoc2020;
namespace aoc2020 /// <summary>
/// Day 13: <see href="https://adventofcode.com/2020/day/13" />
/// </summary>
public sealed class Day13 : Day
{ {
/// <summary> private readonly long[] _buses;
/// Day 13: <see href="https://adventofcode.com/2020/day/13" /> private readonly long _earliest;
/// </summary> private readonly string[] _fullSchedule;
public sealed class Day13 : Day
public Day13() : base(13, "Shuttle Search")
{ {
private readonly long[] _buses; _earliest = long.Parse(Input.First());
private readonly long _earliest; _fullSchedule = Input.Last().Split(',');
private readonly string[] _fullSchedule; _buses = _fullSchedule.Where(c => c != "x").Select(long.Parse).ToArray();
}
public Day13() : base(13, "Shuttle Search") public override string Part1()
{ {
_earliest = long.Parse(Input.First()); for (var i = _earliest; ; i++)
_fullSchedule = Input.Last().Split(','); if (_buses.Any(b => i % b == 0))
_buses = _fullSchedule.Where(c => c != "x").Select(long.Parse).ToArray();
}
public override string Part1()
{
for (var i = _earliest;; i++)
if (_buses.Any(b => i % b == 0))
{
var bus = _buses.First(b => i % b == 0);
return $"{bus * (i - _earliest)}";
}
}
public override string Part2()
{
var i = 0;
long result = 1, multiplier = 1;
foreach (var id in _fullSchedule)
{ {
if (id != "x") var bus = _buses.First(b => i % b == 0);
{ return $"{bus * (i - _earliest)}";
var increment = long.Parse(id); }
while (((result += multiplier) + i) % increment != 0) }
{
}
multiplier *= increment; public override string Part2()
{
var i = 0;
long result = 1, multiplier = 1;
foreach (var id in _fullSchedule)
{
if (id != "x")
{
var increment = long.Parse(id);
while (((result += multiplier) + i) % increment != 0)
{
} }
i++; multiplier *= increment;
} }
return $"{result}"; i++;
} }
return $"{result}";
} }
} }

View File

@ -1,111 +1,106 @@
using System; namespace aoc2020;
using System.Collections.Generic;
using System.Linq;
namespace aoc2020 /// <summary>
/// Day 14: <see href="https://adventofcode.com/2020/day/14" />
/// </summary>
public sealed class Day14 : Day
{ {
/// <summary> public Day14() : base(14, "Docking Data")
/// Day 14: <see href="https://adventofcode.com/2020/day/14" />
/// </summary>
public sealed class Day14 : Day
{ {
public Day14() : base(14, "Docking Data") }
{
}
public override string Part1() public override string Part1()
{ {
var writes = new Dictionary<ulong, ulong>(); var writes = new Dictionary<ulong, ulong>();
ulong mask = 0, bits = 0; ulong mask = 0, bits = 0;
foreach (var line in Input) foreach (var line in Input)
if (line.StartsWith("mask = ")) if (line.StartsWith("mask = "))
{
var str = line.Split("mask = ", 2)[1];
mask = bits = 0;
for (var i = 35; i >= 0; --i)
switch (str[35 - i])
{
case 'X':
mask |= 1UL << i;
break;
case '1':
bits |= 1UL << i;
break;
}
}
else
{
var spl = line.Split(new[] {'[', ']', '='},
StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Skip(1)
.Select(ulong.Parse)
.ToArray();
writes[spl[0]] = (spl[1] & mask) | bits;
}
return $"{writes.Aggregate<KeyValuePair<ulong, ulong>, ulong>(0, (current, w) => current + w.Value)}";
}
public override string Part2()
{
var memory = new Dictionary<ulong, ulong>();
var mask = "";
foreach (var line in Input)
{ {
var spl = line.Split(' ', 3, StringSplitOptions.TrimEntries); var str = line.Split("mask = ", 2)[1];
mask = bits = 0;
if (spl[0] == "mask") for (var i = 35; i >= 0; --i)
{ switch (str[35 - i])
mask = spl[2];
}
else
{
var value = ulong.Parse(spl[2]);
var addr = ulong.Parse(spl[0].Split(new[] {'[', ']'},
StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)[1]);
var floats = new List<int>();
for (var i = 0; i < mask.Length; i++)
switch (mask[i])
{
case 'X':
floats.Add(i);
break;
case '1':
addr |= 1UL << (35 - i);
break;
}
if (floats.Any())
{ {
var combos = new List<ulong> {addr}; case 'X':
mask |= 1UL << i;
foreach (var i in floats) break;
{ case '1':
var newCombos = new List<ulong>(); bits |= 1UL << i;
foreach (var c in combos) break;
{
newCombos.Add(c | (1UL << (35 - i)));
newCombos.Add(c & ~(1UL << (35 - i)));
}
combos = newCombos;
}
foreach (var c in combos)
memory[c] = value;
} }
else }
{ else
memory[addr] = value; {
} var spl = line.Split(new[] { '[', ']', '=' },
} StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Skip(1)
.Select(ulong.Parse)
.ToArray();
writes[spl[0]] = (spl[1] & mask) | bits;
} }
return $"{memory.Aggregate<KeyValuePair<ulong, ulong>, ulong>(0, (current, w) => current + w.Value)}"; return $"{writes.Aggregate<KeyValuePair<ulong, ulong>, ulong>(0, (current, w) => current + w.Value)}";
}
} }
}
public override string Part2()
{
var memory = new Dictionary<ulong, ulong>();
var mask = "";
foreach (var line in Input)
{
var spl = line.Split(' ', 3, StringSplitOptions.TrimEntries);
if (spl[0] == "mask")
{
mask = spl[2];
}
else
{
var value = ulong.Parse(spl[2]);
var addr = ulong.Parse(spl[0].Split(new[] { '[', ']' },
StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)[1]);
var floats = new List<int>();
for (var i = 0; i < mask.Length; i++)
switch (mask[i])
{
case 'X':
floats.Add(i);
break;
case '1':
addr |= 1UL << (35 - i);
break;
}
if (floats.Any())
{
var combos = new List<ulong> { addr };
foreach (var i in floats)
{
var newCombos = new List<ulong>();
foreach (var c in combos)
{
newCombos.Add(c | (1UL << (35 - i)));
newCombos.Add(c & ~(1UL << (35 - i)));
}
combos = newCombos;
}
foreach (var c in combos)
memory[c] = value;
}
else
{
memory[addr] = value;
}
}
}
return $"{memory.Aggregate<KeyValuePair<ulong, ulong>, ulong>(0, (current, w) => current + w.Value)}";
}
}

View File

@ -1,48 +1,45 @@
using System.Linq; namespace aoc2020;
namespace aoc2020 /// <summary>
/// Day 15: <see href="https://adventofcode.com/2020/day/15" />
/// </summary>
public sealed class Day15 : Day
{ {
/// <summary> private readonly int[] _turns;
/// Day 15: <see href="https://adventofcode.com/2020/day/15" /> private int _current;
/// </summary> private int _i;
public sealed class Day15 : Day
public Day15() : base(15, "Rambunctious Recitation")
{ {
private readonly int[] _turns; var initial = Input.First().Split(',').Select(int.Parse).ToArray();
private int _current; _turns = new int[30_000_000];
private int _i;
public Day15() : base(15, "Rambunctious Recitation") // seed array with initial values
{ for (_i = 1; _i < initial.Length + 1; _i++)
var initial = Input.First().Split(',').Select(int.Parse).ToArray(); _turns[initial[_i - 1]] = _i;
_turns = new int[30_000_000];
// seed array with initial values
for (_i = 1; _i < initial.Length + 1; _i++)
_turns[initial[_i - 1]] = _i;
}
public override string Part1()
{
for (; _i != 2020; _i++)
{
var next = _turns[_current] > 0 ? _i - _turns[_current] : 0;
_turns[_current] = _i;
_current = next;
}
return $"{_current}";
}
public override string Part2()
{
for (; _i != 30_000_000; _i++)
{
var next = _turns[_current] > 0 ? _i - _turns[_current] : 0;
_turns[_current] = _i;
_current = next;
}
return $"{_current}";
}
} }
}
public override string Part1()
{
for (; _i != 2020; _i++)
{
var next = _turns[_current] > 0 ? _i - _turns[_current] : 0;
_turns[_current] = _i;
_current = next;
}
return $"{_current}";
}
public override string Part2()
{
for (; _i != 30_000_000; _i++)
{
var next = _turns[_current] > 0 ? _i - _turns[_current] : 0;
_turns[_current] = _i;
_current = next;
}
return $"{_current}";
}
}

View File

@ -1,91 +1,86 @@
using System; namespace aoc2020;
using System.Collections.Generic;
using System.Linq;
namespace aoc2020 /// <summary>
/// Day 16: <see href="https://adventofcode.com/2020/day/16" />
/// </summary>
public sealed class Day16 : Day
{ {
/// <summary> private readonly Dictionary<string, List<Range>> _rules;
/// Day 16: <see href="https://adventofcode.com/2020/day/16" /> private readonly List<List<int>> _tickets;
/// </summary>
public sealed class Day16 : Day public Day16() : base(16, "Ticket Translation")
{ {
private readonly Dictionary<string, List<Range>> _rules; _tickets = new();
private readonly List<List<int>> _tickets; _rules = new();
public Day16() : base(16, "Ticket Translation") foreach (var line in Input)
{ {
_tickets = new List<List<int>>(); var spl = line.Split(": ", 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
_rules = new Dictionary<string, List<Range>>(); if (spl.Length == 2)
foreach (var line in Input)
{ {
var spl = line.Split(": ", 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); var rule = spl[1].Split(" or ").Select(s =>
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]);
var r = s.Split('-').Select(int.Parse).ToList(); }).ToList();
return new Range(r[0], r[1]);
}).ToList();
_rules.Add(spl[0], rule); _rules.Add(spl[0], rule);
} }
else else
{ {
spl = line.Split(','); spl = line.Split(',');
if (spl.Length > 1) if (spl.Length > 1)
_tickets.Add(spl.Select(int.Parse).ToList()); _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])}";
}
} }
}
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])}";
}
}

View File

@ -1,130 +1,126 @@
using System.Collections.Generic; namespace aoc2020;
using System.Linq;
namespace aoc2020 /// <summary>
/// Day 17: <see href="https://adventofcode.com/2020/day/17" />
/// </summary>
public sealed class Day17 : Day
{ {
/// <summary> private readonly Dictionary<(int x, int y, int z), char> _plane;
/// Day 17: <see href="https://adventofcode.com/2020/day/17" /> private readonly Dictionary<(int x, int y, int z, int w), char> _plane4;
/// </summary>
public sealed class Day17 : Day
public Day17() : base(17, "Conway Cubes")
{ {
private readonly Dictionary<(int x, int y, int z), char> _plane; _plane = new Dictionary<(int x, int y, int z), char>();
private readonly Dictionary<(int x, int y, int z, int w), char> _plane4; _plane4 = new Dictionary<(int x, int y, int z, int w), char>();
var input = Input.ToList();
for (var x = 0; x < 32; x++)
public Day17() : base(17, "Conway Cubes")
{
_plane = new Dictionary<(int x, int y, int z), char>();
_plane4 = new Dictionary<(int x, int y, int z, int w), char>();
var input = Input.ToList();
for (var x = 0; x < 32; x++)
for (var y = 0; y < 32; y++) for (var y = 0; y < 32; y++)
for (var z = 0; z < 32; z++) for (var z = 0; z < 32; z++)
_plane[(x, y, z)] = '.'; _plane[(x, y, z)] = '.';
for (var x = 0; x < 32; x++) for (var x = 0; x < 32; x++)
for (var y = 0; y < 32; y++) for (var y = 0; y < 32; y++)
for (var z = 0; z < 32; z++) for (var z = 0; z < 32; z++)
for (var w = 0; w < 32; w++) for (var w = 0; w < 32; w++)
_plane4[(x, y, z, w)] = '.'; _plane4[(x, y, z, w)] = '.';
for (var y = 0; y < input.Count; y++) for (var y = 0; y < input.Count; y++)
for (var x = 0; x < input[y].Length; x++) for (var x = 0; x < input[y].Length; x++)
_plane[(x, y, 0)] = input[y][x]; _plane[(x, y, 0)] = input[y][x];
for (var y = 0; y < input.Count; y++) for (var y = 0; y < input.Count; y++)
for (var x = 0; x < input[y].Length; x++) for (var x = 0; x < input[y].Length; x++)
_plane4[(x, y, 0, 0)] = input[y][x]; _plane4[(x, y, 0, 0)] = input[y][x];
}
private static int Neighbors(IReadOnlyDictionary<(int x, int y, int z), char> plane, int x, int y, int z)
{
var neighbors = 0;
foreach (var i in new[] {-1, 0, 1})
foreach (var j in new[] {-1, 0, 1})
foreach (var k in new[] {-1, 0, 1})
{
if (i == 0 && j == 0 && k == 0) continue;
if (plane[((x + i) & 31, (y + j) & 31, (z + k) & 31)] == '#') neighbors++;
}
return neighbors;
}
private static Dictionary<(int x, int y, int z), char> Iterate(
IReadOnlyDictionary<(int x, int y, int z), char> prev)
{
var next = new Dictionary<(int x, int y, int z), char>();
for (var z = 0; z < 32; z++)
for (var y = 0; y < 32; y++)
for (var x = 0; x < 32; x++)
{
var active = Neighbors(prev, x, y, z);
if (prev[(x, y, z)] == '#')
next[(x, y, z)] = active == 2 || active == 3 ? '#' : '.';
else
next[(x, y, z)] = active == 3 ? '#' : '.';
}
return next;
}
private static int Neighbors4(IReadOnlyDictionary<(int x, int y, int z, int w), char> plane, int x, int y,
int z, int w)
{
var neighbors = 0;
foreach (var i in new[] {-1, 0, 1})
foreach (var j in new[] {-1, 0, 1})
foreach (var k in new[] {-1, 0, 1})
foreach (var l in new[] {-1, 0, 1})
{
if (i == 0 && j == 0 && k == 0 && l == 0) continue;
if (plane[((x + i) & 31, (y + j) & 31, (z + k) & 31, (w + l) & 31)] == '#') neighbors++;
}
return neighbors;
}
private static Dictionary<(int x, int y, int z, int w), char> Iterate4(
IReadOnlyDictionary<(int x, int y, int z, int w), char> prev)
{
var next = new Dictionary<(int x, int y, int z, int w), char>();
for (var z = 0; z < 32; z++)
for (var y = 0; y < 32; y++)
for (var x = 0; x < 32; x++)
for (var w = 0; w < 32; w++)
{
var active = Neighbors4(prev, x, y, z, w);
if (prev[(x, y, z, w)] == '#')
next[(x, y, z, w)] = active == 2 || active == 3 ? '#' : '.';
else
next[(x, y, z, w)] = active == 3 ? '#' : '.';
}
return next;
}
public override string Part1()
{
var plane = _plane;
foreach (var _ in Enumerable.Range(0, 6))
plane = Iterate(plane);
return $"{plane.Values.Count(v => v == '#')}";
}
public override string Part2()
{
var plane = _plane4;
foreach (var _ in Enumerable.Range(0, 6))
plane = Iterate4(plane);
return $"{plane.Values.Count(v => v == '#')}";
}
} }
}
private static int Neighbors(IReadOnlyDictionary<(int x, int y, int z), char> plane, int x, int y, int z)
{
var neighbors = 0;
foreach (var i in new[] { -1, 0, 1 })
foreach (var j in new[] { -1, 0, 1 })
foreach (var k in new[] { -1, 0, 1 })
{
if (i == 0 && j == 0 && k == 0) continue;
if (plane[((x + i) & 31, (y + j) & 31, (z + k) & 31)] == '#') neighbors++;
}
return neighbors;
}
private static Dictionary<(int x, int y, int z), char> Iterate(
IReadOnlyDictionary<(int x, int y, int z), char> prev)
{
var next = new Dictionary<(int x, int y, int z), char>();
for (var z = 0; z < 32; z++)
for (var y = 0; y < 32; y++)
for (var x = 0; x < 32; x++)
{
var active = Neighbors(prev, x, y, z);
if (prev[(x, y, z)] == '#')
next[(x, y, z)] = active == 2 || active == 3 ? '#' : '.';
else
next[(x, y, z)] = active == 3 ? '#' : '.';
}
return next;
}
private static int Neighbors4(IReadOnlyDictionary<(int x, int y, int z, int w), char> plane, int x, int y,
int z, int w)
{
var neighbors = 0;
foreach (var i in new[] { -1, 0, 1 })
foreach (var j in new[] { -1, 0, 1 })
foreach (var k in new[] { -1, 0, 1 })
foreach (var l in new[] { -1, 0, 1 })
{
if (i == 0 && j == 0 && k == 0 && l == 0) continue;
if (plane[((x + i) & 31, (y + j) & 31, (z + k) & 31, (w + l) & 31)] == '#') neighbors++;
}
return neighbors;
}
private static Dictionary<(int x, int y, int z, int w), char> Iterate4(
IReadOnlyDictionary<(int x, int y, int z, int w), char> prev)
{
var next = new Dictionary<(int x, int y, int z, int w), char>();
for (var z = 0; z < 32; z++)
for (var y = 0; y < 32; y++)
for (var x = 0; x < 32; x++)
for (var w = 0; w < 32; w++)
{
var active = Neighbors4(prev, x, y, z, w);
if (prev[(x, y, z, w)] == '#')
next[(x, y, z, w)] = active == 2 || active == 3 ? '#' : '.';
else
next[(x, y, z, w)] = active == 3 ? '#' : '.';
}
return next;
}
public override string Part1()
{
var plane = _plane;
foreach (var _ in Enumerable.Range(0, 6))
plane = Iterate(plane);
return $"{plane.Values.Count(v => v == '#')}";
}
public override string Part2()
{
var plane = _plane4;
foreach (var _ in Enumerable.Range(0, 6))
plane = Iterate4(plane);
return $"{plane.Values.Count(v => v == '#')}";
}
}

View File

@ -1,81 +1,75 @@
using System; namespace aoc2020;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace aoc2020 /// <summary>
/// Day 18: <see href="https://adventofcode.com/2020/day/18" />
/// </summary>
public sealed class Day18 : Day
{ {
/// <summary> private readonly List<string> _expressions;
/// Day 18: <see href="https://adventofcode.com/2020/day/18" />
/// </summary> public Day18() : base(18, "Operation Order")
public sealed class Day18 : Day
{ {
private readonly List<string> _expressions; _expressions = Input.Select(line => line.Replace(" ", "")).ToList();
public Day18() : base(18, "Operation Order")
{
_expressions = Input.Select(line => line.Replace(" ", "")).ToList();
}
private static long Calculate(string expr, Func<char, int> precedence)
{
var postfixNotation = new StringBuilder();
var postfixStack = new Stack<char>();
foreach (var c in expr)
if (char.IsDigit(c))
{
postfixNotation.Append(c);
}
else if (c == '(')
{
postfixStack.Push(c);
}
else if (c == ')')
{
while (postfixStack.Count > 0 && postfixStack.Peek() != '(')
postfixNotation.Append(postfixStack.Pop());
postfixStack.TryPop(out _);
}
else
{
while (postfixStack.Count > 0 && precedence(c) <= precedence(postfixStack.Peek()))
postfixNotation.Append(postfixStack.Pop());
postfixStack.Push(c);
}
while (postfixStack.Count > 0)
postfixNotation.Append(postfixStack.Pop());
var expressionStack = new Stack<long>();
foreach (var c in postfixNotation.ToString())
if (char.IsDigit(c))
{
expressionStack.Push((long) char.GetNumericValue(c));
}
else
{
var a = expressionStack.Pop();
var b = expressionStack.Pop();
if (c == '+') expressionStack.Push(a + b);
if (c == '*') expressionStack.Push(a * b);
}
return expressionStack.Pop();
}
public override string Part1()
{
return $"{_expressions.Sum(expr => Calculate(expr, c => c == '+' || c == '*' ? 1 : 0))}";
}
public override string Part2()
{
return $"{_expressions.Sum(expr => Calculate(expr, c => c switch {'+' => 2, '*' => 1, _ => 0}))}";
}
} }
}
private static long Calculate(string expr, Func<char, int> precedence)
{
var postfixNotation = new StringBuilder();
var postfixStack = new Stack<char>();
foreach (var c in expr)
if (char.IsDigit(c))
{
postfixNotation.Append(c);
}
else if (c == '(')
{
postfixStack.Push(c);
}
else if (c == ')')
{
while (postfixStack.Count > 0 && postfixStack.Peek() != '(')
postfixNotation.Append(postfixStack.Pop());
postfixStack.TryPop(out _);
}
else
{
while (postfixStack.Count > 0 && precedence(c) <= precedence(postfixStack.Peek()))
postfixNotation.Append(postfixStack.Pop());
postfixStack.Push(c);
}
while (postfixStack.Count > 0)
postfixNotation.Append(postfixStack.Pop());
var expressionStack = new Stack<long>();
foreach (var c in postfixNotation.ToString())
if (char.IsDigit(c))
{
expressionStack.Push((long)char.GetNumericValue(c));
}
else
{
var a = expressionStack.Pop();
var b = expressionStack.Pop();
if (c == '+') expressionStack.Push(a + b);
if (c == '*') expressionStack.Push(a * b);
}
return expressionStack.Pop();
}
public override string Part1()
{
return $"{_expressions.Sum(expr => Calculate(expr, c => c == '+' || c == '*' ? 1 : 0))}";
}
public override string Part2()
{
return $"{_expressions.Sum(expr => Calculate(expr, c => c switch { '+' => 2, '*' => 1, _ => 0 }))}";
}
}

View File

@ -1,57 +1,51 @@
using System; namespace aoc2020;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace aoc2020 /// <summary>
/// Day 19: <see href="https://adventofcode.com/2020/day/19" />
/// </summary>
public sealed class Day19 : Day
{ {
/// <summary> private readonly string[] _messages;
/// Day 19: <see href="https://adventofcode.com/2020/day/19" /> private readonly Dictionary<string, string[][]> _rules;
/// </summary> private readonly Stack<string> _stack;
public sealed class Day19 : Day
public Day19() : base(19, "Monster Messages")
{ {
private readonly string[] _messages; _rules = Input.TakeWhile(l => !string.IsNullOrWhiteSpace(l))
private readonly Dictionary<string, string[][]> _rules; .Select(l => l.Split(':'))
private readonly Stack<string> _stack; .Select(a => (key: a[0],
val: a[1].Split('|', StringSplitOptions.RemoveEmptyEntries)
public Day19() : base(19, "Monster Messages") .Select(s => s.Split(' ', StringSplitOptions.RemoveEmptyEntries)).ToArray()))
{ .ToDictionary(a => a.key, a => a.val);
_rules = Input.TakeWhile(l => !string.IsNullOrWhiteSpace(l)) _messages = Input.Skip(_rules.Count + 1).ToArray();
.Select(l => l.Split(':')) _stack = new Stack<string>();
.Select(a => (key: a[0],
val: a[1].Split('|', StringSplitOptions.RemoveEmptyEntries)
.Select(s => s.Split(' ', StringSplitOptions.RemoveEmptyEntries)).ToArray()))
.ToDictionary(a => a.key, a => a.val);
_messages = Input.Skip(_rules.Count + 1).ToArray();
_stack = new Stack<string>();
}
private string MakeRegexExpression(string key)
{
if (_stack.Count(s => s == key) > 10) return "x";
_stack.Push(key);
var sub = string.Join("|", _rules[key].Select(test => test.Length switch
{
1 => test[0][0] == '"' ? test[0].Trim('"') : MakeRegexExpression(test[0]),
_ => string.Join(string.Empty, test.Select(MakeRegexExpression))
}));
_stack.Pop();
return _rules[key].Length > 1 ? $"({sub})" : sub;
}
public override string Part1()
{
var exp = new Regex($"^{MakeRegexExpression("0")}$");
return $"{_messages.Count(m => exp.IsMatch(m))}";
}
public override string Part2()
{
// fix rules 8 and 11
_rules["8"] = new[] {new[] {"42"}, new[] {"42", "8"}};
_rules["11"] = new[] {new[] {"42", "31"}, new[] {"42", "11", "31"}};
var exp = new Regex($"^{MakeRegexExpression("0")}$");
return $"{_messages.Count(m => exp.IsMatch(m))}";
}
} }
}
private string MakeRegexExpression(string key)
{
if (_stack.Count(s => s == key) > 10) return "x";
_stack.Push(key);
var sub = string.Join("|", _rules[key].Select(test => test.Length switch
{
1 => test[0][0] == '"' ? test[0].Trim('"') : MakeRegexExpression(test[0]),
_ => string.Join(string.Empty, test.Select(MakeRegexExpression))
}));
_stack.Pop();
return _rules[key].Length > 1 ? $"({sub})" : sub;
}
public override string Part1()
{
var exp = new Regex($"^{MakeRegexExpression("0")}$");
return $"{_messages.Count(m => exp.IsMatch(m))}";
}
public override string Part2()
{
// fix rules 8 and 11
_rules["8"] = new[] { new[] { "42" }, new[] { "42", "8" } };
_rules["11"] = new[] { new[] { "42", "31" }, new[] { "42", "11", "31" } };
var exp = new Regex($"^{MakeRegexExpression("0")}$");
return $"{_messages.Count(m => exp.IsMatch(m))}";
}
}

View File

@ -1,183 +1,178 @@
using System; namespace aoc2020;
using System.Collections.Generic;
using System.Linq;
namespace aoc2020 /// <summary>
/// Day 20: <see href="https://adventofcode.com/2020/day/20" />
/// </summary>
public sealed class Day20 : Day
{ {
/// <summary> private readonly List<Tile> _allPermutations;
/// Day 20: <see href="https://adventofcode.com/2020/day/20" /> private readonly List<Tile> _topLefts;
/// </summary>
public sealed class Day20 : Day public Day20() : base(20, "Jurassic Jigsaw")
{ {
private readonly List<Tile> _allPermutations; var lines = new List<string>();
private readonly List<Tile> _topLefts; var tiles = new List<Tile>();
var currentTileId = 0;
public Day20() : base(20, "Jurassic Jigsaw") foreach (var line in Input)
{ if (line.StartsWith("Tile "))
var lines = new List<string>();
var tiles = new List<Tile>();
var currentTileId = 0;
foreach (var line in Input)
if (line.StartsWith("Tile "))
{
currentTileId = int.Parse(line.Split(' ', ':')[1]);
}
else if (line == "")
{
tiles.Add(new(currentTileId, lines.Select(l => l.ToCharArray()).ToArray()));
lines.Clear();
}
else
{
lines.Add(line);
}
if (lines.Any()) tiles.Add(new(currentTileId, lines.Select(l => l.ToCharArray()).ToArray()));
_allPermutations = tiles.SelectMany(t => t.AllPermutations()).ToList();
_topLefts = _allPermutations
.Where(t => !_allPermutations.Any(t2 => t.TileId != t2.TileId && t.LeftId == t2.RightId) &&
!_allPermutations.Any(t2 => t.TileId != t2.TileId && t.TopId == t2.BottomId))
.ToList();
}
private int Roughness(Tile arg)
{
var seaMonster = new[]
{ {
currentTileId = int.Parse(line.Split(' ', ':')[1]);
}
else if (line == "")
{
tiles.Add(new(currentTileId, lines.Select(l => l.ToCharArray()).ToArray()));
lines.Clear();
}
else
{
lines.Add(line);
}
if (lines.Any()) tiles.Add(new(currentTileId, lines.Select(l => l.ToCharArray()).ToArray()));
_allPermutations = tiles.SelectMany(t => t.AllPermutations()).ToList();
_topLefts = _allPermutations
.Where(t => !_allPermutations.Any(t2 => t.TileId != t2.TileId && t.LeftId == t2.RightId) &&
!_allPermutations.Any(t2 => t.TileId != t2.TileId && t.TopId == t2.BottomId))
.ToList();
}
private int Roughness(Tile arg)
{
var seaMonster = new[]
{
" # ", " # ",
"# ## ## ###", "# ## ## ###",
" # # # # # # " " # # # # # # "
}.Select(s => s.ToArray()).ToArray(); }.Select(s => s.ToArray()).ToArray();
const int seaMonsterWidth = 20;
const int seaMonsterHeight = 3;
const int seaMonsterTiles = 15;
var placedTiles = new Dictionary<(int x, int y), Tile>(); const int seaMonsterWidth = 20;
bool NotPlaced(Tile tile) => placedTiles!.Values.All(t => t.TileId != tile.TileId); const int seaMonsterHeight = 3;
char Grid(int i, int j) => placedTiles![(i / 8, j / 8)].Pixels[j % 8 + 1][i % 8 + 1]; const int seaMonsterTiles = 15;
bool HasSeaMonster((int x, int y) location) var placedTiles = new Dictionary<(int x, int y), Tile>();
{ bool NotPlaced(Tile tile) => placedTiles!.Values.All(t => t.TileId != tile.TileId);
for (var j = 0; j < seaMonsterHeight; j++) char Grid(int i, int j) => placedTiles![(i / 8, j / 8)].Pixels[j % 8 + 1][i % 8 + 1];
bool HasSeaMonster((int x, int y) location)
{
for (var j = 0; j < seaMonsterHeight; j++)
for (var i = 0; i < seaMonsterWidth; i++) for (var i = 0; i < seaMonsterWidth; i++)
{ {
if (seaMonster![j][i] == ' ') continue; if (seaMonster![j][i] == ' ') continue;
if (Grid(location.x + i, location.y + j) != '#') return false; if (Grid(location.x + i, location.y + j) != '#') return false;
} }
return true; return true;
} }
placedTiles[(0, 0)] = arg; placedTiles[(0, 0)] = arg;
int x = 1, y = 0; int x = 1, y = 0;
while (true) while (true)
{
placedTiles.TryGetValue((x - 1, y), out var left);
placedTiles.TryGetValue((x, y - 1), out var top);
if (left == null && top == null) break;
var firstMatch = _allPermutations
.Where(t => (left is null || t.LeftId == left.RightId) &&
(top is null || t.TopId == top.BottomId))
.Where(NotPlaced)
.FirstOrDefault();
if (firstMatch is not null)
{ {
placedTiles.TryGetValue((x - 1, y), out var left); placedTiles[(x, y)] = firstMatch;
placedTiles.TryGetValue((x, y - 1), out var top); x++;
if (left == null && top == null) break;
var firstMatch = _allPermutations
.Where(t => (left is null || t.LeftId == left.RightId) &&
(top is null || t.TopId == top.BottomId))
.Where(NotPlaced)
.FirstOrDefault();
if (firstMatch is not null)
{
placedTiles[(x, y)] = firstMatch;
x++;
}
else
{
x = 0;
y++;
}
} }
else
{
x = 0;
y++;
}
}
var gridWidth = placedTiles.Keys.Max(t => t.x) + 1; var gridWidth = placedTiles.Keys.Max(t => t.x) + 1;
var gridHeight = placedTiles.Keys.Max(t => t.y) + 1; var gridHeight = placedTiles.Keys.Max(t => t.y) + 1;
var seaMonsterCount = Enumerable.Range(0, gridWidth * 8 - seaMonsterWidth) var seaMonsterCount = Enumerable.Range(0, gridWidth * 8 - seaMonsterWidth)
.SelectMany(_ => Enumerable.Range(0, gridHeight * 8 - seaMonsterHeight), (i, j) => (i, j)) .SelectMany(_ => Enumerable.Range(0, gridHeight * 8 - seaMonsterHeight), (i, j) => (i, j))
.Count(HasSeaMonster); .Count(HasSeaMonster);
if (seaMonsterCount == 0) return 0;
var roughness = 0; if (seaMonsterCount == 0) return 0;
for (var j = 0; j < gridHeight; j++)
var roughness = 0;
for (var j = 0; j < gridHeight; j++)
for (var i = 0; i < gridWidth; i++) for (var i = 0; i < gridWidth; i++)
if (Grid(x, y) == '#') if (Grid(x, y) == '#')
roughness++; roughness++;
return roughness - seaMonsterCount * seaMonsterTiles; return roughness - seaMonsterCount * seaMonsterTiles;
}
public override string Part1()
{
return $"{_topLefts.Select(t => t.TileId).Distinct().Aggregate(1L, (acc, next) => acc * next)}";
}
public override string Part2()
{
return $"{_topLefts.Select(Roughness).First(r => r > 0)}";
}
private record Tile(int TileId, char[][] Pixels)
{
private const int Size = 10;
internal int TopId => GetId(z => (z, 0));
internal int BottomId => GetId(z => (z, Size - 1));
internal int LeftId => GetId(z => (0, z));
internal int RightId => GetId(z => (Size - 1, z));
private int GetId(Func<int, (int x, int y)> selector)
{
return Enumerable.Range(0, Size)
.Select(selector)
.Select((c, i) => (Pixels[c.x][c.y] == '#' ? 1 : 0) << i)
.Aggregate(0, (acc, next) => acc | next);
} }
public override string Part1() private Tile RotateClockwise()
{ {
return $"{_topLefts.Select(t => t.TileId).Distinct().Aggregate(1L, (acc, next) => acc * next)}"; return Transform((x, y, newPixels) => newPixels[x][Size - 1 - y] = Pixels[y][x]);
} }
public override string Part2() private Tile Flip()
{ {
return $"{_topLefts.Select(Roughness).First(r => r > 0)}"; return Transform((x, y, newPixels) => newPixels[y][Size - 1 - x] = Pixels[y][x]);
} }
private record Tile(int TileId, char[][] Pixels) private Tile Transform(Action<int, int, char[][]> transformFunc)
{ {
private const int Size = 10; var newPixels = Enumerable.Repeat(false, Size).Select(_ => new char[Size]).ToArray();
internal int TopId => GetId(z => (z, 0));
internal int BottomId => GetId(z => (z, Size - 1));
internal int LeftId => GetId(z => (0, z));
internal int RightId => GetId(z => (Size - 1, z));
private int GetId(Func<int, (int x, int y)> selector) for (var y = 0; y < Size; y++)
{
return Enumerable.Range(0, Size)
.Select(selector)
.Select((c, i) => (Pixels[c.x][c.y] == '#' ? 1 : 0) << i)
.Aggregate(0, (acc, next) => acc | next);
}
private Tile RotateClockwise()
{
return Transform((x, y, newPixels) => newPixels[x][Size - 1 - y] = Pixels[y][x]);
}
private Tile Flip()
{
return Transform((x, y, newPixels) => newPixels[y][Size - 1 - x] = Pixels[y][x]);
}
private Tile Transform(Action<int, int, char[][]> transformFunc)
{
var newPixels = Enumerable.Repeat(false, Size).Select(_ => new char[Size]).ToArray();
for (var y = 0; y < Size; y++)
for (var x = 0; x < Size; x++) for (var x = 0; x < Size; x++)
transformFunc(x, y, newPixels); transformFunc(x, y, newPixels);
return new(TileId, newPixels); return new(TileId, newPixels);
} }
internal IEnumerable<Tile> AllPermutations() internal IEnumerable<Tile> AllPermutations()
{
var tile = this;
for (var i = 1; i <= 8; i++)
{ {
var tile = this; yield return tile;
for (var i = 1; i <= 8; i++) if (i == 4) tile = Flip();
{ else if (i == 8) yield break;
yield return tile; tile = tile.RotateClockwise();
if (i == 4) tile = Flip();
else if (i == 8) yield break;
tile = tile.RotateClockwise();
}
}
public string Format()
{
return $"Tile {TileId}:\n{string.Join("\n", Pixels.Select(p => new string(p)))}";
} }
} }
public string Format()
{
return $"Tile {TileId}:\n{string.Join("\n", Pixels.Select(p => new string(p)))}";
}
} }
} }

View File

@ -1,22 +1,21 @@
namespace aoc2020 namespace aoc2020;
/// <summary>
/// Day 21: <see href="https://adventofcode.com/2020/day/21" />
/// </summary>
public sealed class Day21 : Day
{ {
/// <summary> public Day21() : base(21, "Allergen Assessment")
/// Day 21: <see href="https://adventofcode.com/2020/day/21" />
/// </summary>
public sealed class Day21 : Day
{ {
public Day21() : base(21, "Allergen Assessment")
{
}
public override string Part1()
{
return "";
}
public override string Part2()
{
return "";
}
} }
}
public override string Part1()
{
return "";
}
public override string Part2()
{
return "";
}
}

View File

@ -1,22 +1,21 @@
namespace aoc2020 namespace aoc2020;
/// <summary>
/// Day 22: <see href="https://adventofcode.com/2020/day/22" />
/// </summary>
public sealed class Day22 : Day
{ {
/// <summary> public Day22() : base(22, "Crab Combat")
/// Day 22: <see href="https://adventofcode.com/2020/day/22" />
/// </summary>
public sealed class Day22 : Day
{ {
public Day22() : base(22, "Crab Combat")
{
}
public override string Part1()
{
return "";
}
public override string Part2()
{
return "";
}
} }
}
public override string Part1()
{
return "";
}
public override string Part2()
{
return "";
}
}

View File

@ -1,22 +1,21 @@
namespace aoc2020 namespace aoc2020;
/// <summary>
/// Day 23: <see href="https://adventofcode.com/2020/day/23" />
/// </summary>
public sealed class Day23 : Day
{ {
/// <summary> public Day23() : base(23, "Crab Cups")
/// Day 23: <see href="https://adventofcode.com/2020/day/23" />
/// </summary>
public sealed class Day23 : Day
{ {
public Day23() : base(23, "Crab Cups")
{
}
public override string Part1()
{
return "";
}
public override string Part2()
{
return "";
}
} }
}
public override string Part1()
{
return "";
}
public override string Part2()
{
return "";
}
}

View File

@ -1,22 +1,21 @@
namespace aoc2020 namespace aoc2020;
/// <summary>
/// Day 24: <see href="https://adventofcode.com/2020/day/24" />
/// </summary>
public sealed class Day24 : Day
{ {
/// <summary> public Day24() : base(24, "Lobby Layout")
/// Day 24: <see href="https://adventofcode.com/2020/day/24" />
/// </summary>
public sealed class Day24 : Day
{ {
public Day24() : base(24, "Lobby Layout")
{
}
public override string Part1()
{
return "";
}
public override string Part2()
{
return "";
}
} }
}
public override string Part1()
{
return "";
}
public override string Part2()
{
return "";
}
}

View File

@ -1,22 +1,21 @@
namespace aoc2020 namespace aoc2020;
/// <summary>
/// Day 25: <see href="https://adventofcode.com/2020/day/25" />
/// </summary>
public sealed class Day25 : Day
{ {
/// <summary> public Day25() : base(25, "Combo Breaker")
/// Day 25: <see href="https://adventofcode.com/2020/day/25" />
/// </summary>
public sealed class Day25 : Day
{ {
public Day25() : base(25, "Combo Breaker")
{
}
public override string Part1()
{
return "";
}
public override string Part2()
{
return "";
}
} }
}
public override string Part1()
{
return "";
}
public override string Part2()
{
return "";
}
}

View File

@ -1,22 +1,21 @@
namespace aoc2020 namespace aoc2020;
/// <summary>
/// Day X: <see href="https://adventofcode.com/2020/day/X" />
/// </summary>
public sealed class DayX : Day
{ {
/// <summary> public DayX() : base(X, "")
/// Day X: <see href="https://adventofcode.com/2020/day/X" />
/// </summary>
public sealed class DayX : Day
{ {
public DayX() : base(X, "")
{
}
public override string Part1()
{
return "";
}
public override string Part2()
{
return "";
}
} }
}
public override string Part1()
{
return "";
}
public override string Part2()
{
return "";
}
}

View File

@ -1,28 +1,26 @@
using System;
using System.Diagnostics; using System.Diagnostics;
namespace aoc2020 namespace aoc2020;
{
public static class Extensions
{
/// <summary>
/// increased accuracy for stopwatch based on frequency.
/// <see
/// href="http://geekswithblogs.net/BlackRabbitCoder/archive/2012/01/12/c.net-little-pitfalls-stopwatch-ticks-are-not-timespan-ticks.aspx">
/// blog
/// details here
/// </see>
/// </summary>
/// <param name="stopwatch"></param>
/// <returns></returns>
public static double ScaleMilliseconds(this Stopwatch stopwatch)
{
return 1_000 * stopwatch.ElapsedTicks / (double) Stopwatch.Frequency;
}
public static bool Contains(this Range range, int i) public static class Extensions
{ {
return i >= range.Start.Value && i <= range.End.Value; /// <summary>
} /// increased accuracy for stopwatch based on frequency.
/// <see
/// href="http://geekswithblogs.net/BlackRabbitCoder/archive/2012/01/12/c.net-little-pitfalls-stopwatch-ticks-are-not-timespan-ticks.aspx">
/// blog
/// details here
/// </see>
/// </summary>
/// <param name="stopwatch"></param>
/// <returns></returns>
public static double ScaleMilliseconds(this Stopwatch stopwatch)
{
return 1_000 * stopwatch.ElapsedTicks / (double)Stopwatch.Frequency;
} }
}
public static bool Contains(this Range range, int i)
{
return i >= range.Start.Value && i <= range.End.Value;
}
}

View File

@ -1,30 +1,27 @@
using System; using System.Reflection;
using System.Linq;
using System.Reflection;
namespace aoc2020 namespace aoc2020;
internal static class Program
{ {
internal static class Program private static void Main(string[] args)
{ {
private static void Main(string[] args) var days = Assembly.GetExecutingAssembly().GetTypes()
{ .Where(t => t.BaseType == typeof(Day))
var days = Assembly.GetExecutingAssembly().GetTypes() .Select(t => Activator.CreateInstance(t) as Day)
.Where(t => t.BaseType == typeof(Day)) .OrderBy(d => d?.DayNumber);
.Select(t => (Day) Activator.CreateInstance(t))
.OrderBy(d => d.DayNumber);
if (args.Length == 1 && int.TryParse(args[0], out var dayNum)) if (args.Length == 1 && int.TryParse(args[0], out var dayNum))
{ {
var day = days.FirstOrDefault(d => d.DayNumber == dayNum); var day = days.FirstOrDefault(d => d?.DayNumber == dayNum);
if (day != null) if (day != null)
day.AllParts(); day.AllParts();
else
Console.WriteLine($"Day {dayNum} invalid or not yet implemented");
}
else else
{ Console.WriteLine($"Day {dayNum} invalid or not yet implemented");
foreach (var d in days) d.AllParts(); }
} else
{
foreach (var d in days) d?.AllParts();
} }
} }
} }

View File

@ -1,8 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -11,4 +13,11 @@
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Using Include="System.Collections.Generic"/>
<Using Include="System.Collections.Immutable"/>
<Using Include="System.Text"/>
<Using Include="System.Text.RegularExpressions"/>
</ItemGroup>
</Project> </Project>