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:
- name: run
image: mcr.microsoft.com/dotnet/sdk:latest
image: mcr.microsoft.com/dotnet/sdk:6.0
commands:
- dotnet test
- 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
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;
namespace aoc2020.test
namespace aoc2020.test;
[TestClass]
public class DayTests
{
[TestClass]
public class DayTests
[DataTestMethod]
[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]
[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)
{
// 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");
// create day instance
var s = Stopwatch.StartNew();
var day = Activator.CreateInstance(dayType) as Day;
s.Stop();
Assert.IsNotNull(day, "failed to create day object");
Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in constructor");
// part 1
s.Reset();
s.Start();
var part1Actual = day.Part1();
s.Stop();
Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in part1");
Assert.AreEqual(part1, part1Actual, $"Incorrect answer for Day {day.DayNumber} Part1");
// part 1
s.Reset();
s.Start();
var part1Actual = day.Part1();
s.Stop();
Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in part1");
Assert.AreEqual(part1, part1Actual, $"Incorrect answer for Day {day.DayNumber} Part1");
// part 2
s.Reset();
s.Start();
var part2Actual = day.Part2();
s.Stop();
Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in part2");
Assert.AreEqual(part2, part2Actual, $"Incorrect answer for Day {day.DayNumber} Part2");
}
// part 2
s.Reset();
s.Start();
var part2Actual = day.Part2();
s.Stop();
Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in 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>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>

View File

@ -1,48 +1,44 @@
using System;
using System.Collections.Generic;
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;
}
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();
}
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();
}
}

View File

@ -1,35 +1,31 @@
using System.Collections.Immutable;
using System.Linq;
namespace aoc2020;
namespace aoc2020
/// <summary>
/// Day 1: <see href="https://adventofcode.com/2020/day/1" />
/// </summary>
public sealed class Day01 : Day
{
/// <summary>
/// Day 1: <see href="https://adventofcode.com/2020/day/1" />
/// </summary>
public sealed class Day01 : Day
private readonly ImmutableHashSet<int> _entries;
public Day01() : base(1, "Report Repair")
{
private readonly ImmutableHashSet<int> _entries;
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 "";
}
_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 "";
}
}

View File

@ -1,56 +1,52 @@
using System.Collections.Immutable;
using System.Linq;
namespace aoc2020;
namespace aoc2020
/// <summary>
/// Day 2: <see href="https://adventofcode.com/2020/day/1" />
/// </summary>
public sealed class Day02 : Day
{
/// <summary>
/// Day 2: <see href="https://adventofcode.com/2020/day/1" />
/// </summary>
public sealed class Day02 : Day
private readonly ImmutableList<Password> _passwords;
public Day02() : base(2, "Password Philosophy")
{
private readonly ImmutableList<Password> _passwords;
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; }
}
_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; }
}
}

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>
/// Day 3: <see href="https://adventofcode.com/2020/day/3" />
/// </summary>
public sealed class Day03 : Day
private readonly string[] _grid;
private readonly int _width;
public Day03() : base(3, "Toboggan Trajectory")
{
private readonly string[] _grid;
private readonly int _width;
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();
}
_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.First, s.Second))
.Aggregate((acc, i) => acc * i)
.ToString();
}
}

View File

@ -1,188 +1,182 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace aoc2020;
namespace aoc2020
/// <summary>
/// Day 4: <see href="https://adventofcode.com/2020/day/4" />
/// </summary>
public sealed class Day04 : Day
{
/// <summary>
/// Day 4: <see href="https://adventofcode.com/2020/day/4" />
/// </summary>
public sealed class Day04 : Day
private readonly List<Passport> _passports;
public Day04() : base(4, "Passport Processing")
{
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>();
var a = new List<string>();
foreach (var line in Input)
if (line == "")
{
if (line == "")
{
_passports.Add(Passport.Parse(a));
a.Clear();
continue;
}
a.Add(line);
_passports.Add(Passport.Parse(a));
a.Clear();
continue;
}
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()
{
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()
// birth year
if (int.TryParse(_byr, out var byr))
{
if (!IsValid) return false;
// birth year
if (int.TryParse(_byr, out var byr))
{
if (byr < 1920 || byr > 2002)
return false;
}
else
{
if (byr < 1920 || byr > 2002)
return false;
}
// issuance year
if (int.TryParse(_iyr, out var iyr))
{
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;
}
else
{
return false;
}
public static Passport Parse(IEnumerable<string> list)
// issuance year
if (int.TryParse(_iyr, out var iyr))
{
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;
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[..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;
using System.Collections.Immutable;
using System.Linq;
namespace aoc2020;
namespace aoc2020
/// <summary>
/// Day 5: <see href="https://adventofcode.com/2020/day/5" />
/// </summary>
public sealed class Day05 : Day
{
/// <summary>
/// Day 5: <see href="https://adventofcode.com/2020/day/5" />
/// </summary>
public sealed class Day05 : Day
private readonly ImmutableHashSet<int> _ids;
public Day05() : base(5, "Binary Boarding")
{
private readonly ImmutableHashSet<int> _ids;
public Day05() : base(5, "Binary Boarding")
{
_ids = Input
.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()}";
}
_ids = Input
.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()}";
}
}

View File

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

View File

@ -1,61 +1,57 @@
using System.Collections.Generic;
using System.Linq;
namespace aoc2020;
namespace aoc2020
/// <summary>
/// Day 7: <see href="https://adventofcode.com/2020/day/7" />
/// </summary>
public sealed class Day07 : Day
{
/// <summary>
/// Day 7: <see href="https://adventofcode.com/2020/day/7" />
/// </summary>
public sealed class Day07 : Day
private readonly Dictionary<string, IEnumerable<(int, string)?>> _rules;
public Day07() : base(7, "Handy Haversacks")
{
private readonly Dictionary<string, IEnumerable<(int, string)?>> _rules;
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)
_rules = Input.Select(rule =>
{
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}";
}
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();
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>
/// Day 8: <see href="https://adventofcode.com/2020/day/8" />
/// </summary>
public sealed class Day08 : Day
private readonly (string instruction, int value)[] _instructions;
private int _accumulator;
private int _currentInstruction;
public Day08() : base(8, "Handheld Halting")
{
private readonly (string instruction, int value)[] _instructions;
private int _accumulator;
private int _currentInstruction;
_instructions = Input.Select(ParseLine).ToArray();
}
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)
{
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)
switch (_instructions[_currentInstruction].instruction)
{
visited[_currentInstruction] = true;
switch (_instructions[_currentInstruction].instruction)
{
case "acc":
_accumulator += _instructions[_currentInstruction].value;
break;
case "jmp":
_currentInstruction += _instructions[_currentInstruction].value;
continue;
}
_currentInstruction++;
case "acc":
_accumulator += _instructions[_currentInstruction].value;
break;
case "jmp":
_currentInstruction += _instructions[_currentInstruction].value;
continue;
}
return _currentInstruction == _instructions.Length;
_currentInstruction++;
}
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}";
}
return _currentInstruction == _instructions.Length;
}
}
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>
/// Day 9: <see href="https://adventofcode.com/2020/day/9" />
/// </summary>
public sealed class Day09 : Day
private readonly long[] _list;
private long _part1;
public Day09() : base(9, "Encoding Error")
{
private readonly long[] _list;
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 "";
}
_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 "";
}
}

View File

@ -1,59 +1,55 @@
using System;
using System.Linq;
namespace aoc2020;
namespace aoc2020
/// <summary>
/// Day 10: <see href="https://adventofcode.com/2020/day/10" />
/// </summary>
public sealed class Day10 : Day
{
/// <summary>
/// Day 10: <see href="https://adventofcode.com/2020/day/10" />
/// </summary>
public sealed class Day10 : Day
private readonly int[] _adapters;
private readonly long[] _memo;
public Day10() : base(10, "Adapter Array")
{
private readonly int[] _adapters;
private readonly long[] _memo;
public Day10() : base(10, "Adapter Array")
{
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)}";
}
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)}";
}
}

View File

@ -1,91 +1,87 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace aoc2020;
namespace aoc2020
/// <summary>
/// Day 11: <see href="https://adventofcode.com/2020/day/11" />
/// </summary>
public sealed class Day11 : Day
{
/// <summary>
/// Day 11: <see href="https://adventofcode.com/2020/day/11" />
/// </summary>
public sealed class Day11 : Day
public Day11() : base(11, "Seating System")
{
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);
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}";
Console.Clear();
foreach (var line in Grid)
Console.WriteLine(line);
}
public override string Part2()
public LifeGame StepPart1()
{
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 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++)
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++)
next.Grid[y][x] = Grid[y][x] switch
{
@ -94,29 +90,29 @@ namespace aoc2020
_ => Grid[y][x]
};
// next.PrintBoard();
return next;
}
// next.PrintBoard();
return next;
}
private char At(int y, int x)
{
return x < 0 || y < 0 || x >= _w || y >= _h ? '.' : Grid[y][x];
}
private char At(int y, int 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 + 0, x - 1), At(y + 0, x + 1),
At(y + 1, x - 1), At(y + 1, x + 0), At(y + 1, x + 1)
}.Count(c => c == '#');
}
}
public LifeGame StepPart2()
{
var next = new LifeGame {_h = _h, _w = _w, Grid = Grid.Select(s => s.ToArray()).ToArray()};
for (var y = 0; y < _h; y++)
public LifeGame StepPart2()
{
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++)
next.Grid[y][x] = Grid[y][x] switch
{
@ -125,33 +121,32 @@ namespace aoc2020
_ => Grid[y][x]
};
// next.PrintBoard();
return next;
}
// next.PrintBoard();
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, +0, -1), TraceRay(y, x, +0, +1),
TraceRay(y, x, +1, -1), TraceRay(y, x, +1, +0), TraceRay(y, x, +1, +1)
}.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;
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>
/// Day 12: <see href="https://adventofcode.com/2020/day/12" />
/// </summary>
public sealed class Day12 : Day
public Day12() : base(12, "Rain Risk")
{
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>
/// Day 13: <see href="https://adventofcode.com/2020/day/13" />
/// </summary>
public sealed class Day13 : Day
private readonly long[] _buses;
private readonly long _earliest;
private readonly string[] _fullSchedule;
public Day13() : base(13, "Shuttle Search")
{
private readonly long[] _buses;
private readonly long _earliest;
private readonly string[] _fullSchedule;
_earliest = long.Parse(Input.First());
_fullSchedule = Input.Last().Split(',');
_buses = _fullSchedule.Where(c => c != "x").Select(long.Parse).ToArray();
}
public Day13() : base(13, "Shuttle Search")
{
_earliest = long.Parse(Input.First());
_fullSchedule = Input.Last().Split(',');
_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)
public override string Part1()
{
for (var i = _earliest; ; i++)
if (_buses.Any(b => i % b == 0))
{
if (id != "x")
{
var increment = long.Parse(id);
while (((result += multiplier) + i) % increment != 0)
{
}
var bus = _buses.First(b => i % b == 0);
return $"{bus * (i - _earliest)}";
}
}
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;
using System.Collections.Generic;
using System.Linq;
namespace aoc2020;
namespace aoc2020
/// <summary>
/// Day 14: <see href="https://adventofcode.com/2020/day/14" />
/// </summary>
public sealed class Day14 : Day
{
/// <summary>
/// Day 14: <see href="https://adventofcode.com/2020/day/14" />
/// </summary>
public sealed class Day14 : Day
public Day14() : base(14, "Docking Data")
{
public Day14() : base(14, "Docking Data")
{
}
}
public override string Part1()
{
var writes = new Dictionary<ulong, ulong>();
ulong mask = 0, bits = 0;
public override string Part1()
{
var writes = new Dictionary<ulong, ulong>();
ulong mask = 0, bits = 0;
foreach (var line in Input)
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)
foreach (var line in Input)
if (line.StartsWith("mask = "))
{
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 str = line.Split("mask = ", 2)[1];
mask = bits = 0;
for (var i = 35; i >= 0; --i)
switch (str[35 - i])
{
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;
case 'X':
mask |= 1UL << i;
break;
case '1':
bits |= 1UL << i;
break;
}
else
{
memory[addr] = value;
}
}
}
else
{
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>
/// Day 15: <see href="https://adventofcode.com/2020/day/15" />
/// </summary>
public sealed class Day15 : Day
private readonly int[] _turns;
private int _current;
private int _i;
public Day15() : base(15, "Rambunctious Recitation")
{
private readonly int[] _turns;
private int _current;
private int _i;
var initial = Input.First().Split(',').Select(int.Parse).ToArray();
_turns = new int[30_000_000];
public Day15() : base(15, "Rambunctious Recitation")
{
var initial = Input.First().Split(',').Select(int.Parse).ToArray();
_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}";
}
// 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}";
}
}

View File

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

View File

@ -1,57 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace aoc2020;
namespace aoc2020
/// <summary>
/// Day 19: <see href="https://adventofcode.com/2020/day/19" />
/// </summary>
public sealed class Day19 : Day
{
/// <summary>
/// Day 19: <see href="https://adventofcode.com/2020/day/19" />
/// </summary>
public sealed class Day19 : Day
private readonly string[] _messages;
private readonly Dictionary<string, string[][]> _rules;
private readonly Stack<string> _stack;
public Day19() : base(19, "Monster Messages")
{
private readonly string[] _messages;
private readonly Dictionary<string, string[][]> _rules;
private readonly Stack<string> _stack;
public Day19() : base(19, "Monster Messages")
{
_rules = Input.TakeWhile(l => !string.IsNullOrWhiteSpace(l))
.Select(l => l.Split(':'))
.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))}";
}
_rules = Input.TakeWhile(l => !string.IsNullOrWhiteSpace(l))
.Select(l => l.Split(':'))
.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))}";
}
}

View File

@ -1,183 +1,178 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace aoc2020;
namespace aoc2020
/// <summary>
/// Day 20: <see href="https://adventofcode.com/2020/day/20" />
/// </summary>
public sealed class Day20 : Day
{
/// <summary>
/// Day 20: <see href="https://adventofcode.com/2020/day/20" />
/// </summary>
public sealed class Day20 : Day
private readonly List<Tile> _allPermutations;
private readonly List<Tile> _topLefts;
public Day20() : base(20, "Jurassic Jigsaw")
{
private readonly List<Tile> _allPermutations;
private readonly List<Tile> _topLefts;
var lines = new List<string>();
var tiles = new List<Tile>();
var currentTileId = 0;
public Day20() : base(20, "Jurassic Jigsaw")
{
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[]
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[]
{
" # ",
"# ## ## ###",
" # # # # # # "
}.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>();
bool NotPlaced(Tile tile) => placedTiles!.Values.All(t => t.TileId != tile.TileId);
char Grid(int i, int j) => placedTiles![(i / 8, j / 8)].Pixels[j % 8 + 1][i % 8 + 1];
const int seaMonsterWidth = 20;
const int seaMonsterHeight = 3;
const int seaMonsterTiles = 15;
bool HasSeaMonster((int x, int y) location)
{
for (var j = 0; j < seaMonsterHeight; j++)
var placedTiles = new Dictionary<(int x, int y), Tile>();
bool NotPlaced(Tile tile) => placedTiles!.Values.All(t => t.TileId != tile.TileId);
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++)
{
if (seaMonster![j][i] == ' ') continue;
if (Grid(location.x + i, location.y + j) != '#') return false;
}
return true;
}
return true;
}
placedTiles[(0, 0)] = arg;
int x = 1, y = 0;
while (true)
placedTiles[(0, 0)] = arg;
int x = 1, y = 0;
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.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[(x, y)] = firstMatch;
x++;
}
else
{
x = 0;
y++;
}
placedTiles[(x, y)] = firstMatch;
x++;
}
else
{
x = 0;
y++;
}
}
var gridWidth = placedTiles.Keys.Max(t => t.x) + 1;
var gridHeight = placedTiles.Keys.Max(t => t.y) + 1;
var gridWidth = placedTiles.Keys.Max(t => t.x) + 1;
var gridHeight = placedTiles.Keys.Max(t => t.y) + 1;
var seaMonsterCount = Enumerable.Range(0, gridWidth * 8 - seaMonsterWidth)
.SelectMany(_ => Enumerable.Range(0, gridHeight * 8 - seaMonsterHeight), (i, j) => (i, j))
.Count(HasSeaMonster);
if (seaMonsterCount == 0) return 0;
var seaMonsterCount = Enumerable.Range(0, gridWidth * 8 - seaMonsterWidth)
.SelectMany(_ => Enumerable.Range(0, gridHeight * 8 - seaMonsterHeight), (i, j) => (i, j))
.Count(HasSeaMonster);
var roughness = 0;
for (var j = 0; j < gridHeight; j++)
if (seaMonsterCount == 0) return 0;
var roughness = 0;
for (var j = 0; j < gridHeight; j++)
for (var i = 0; i < gridWidth; i++)
if (Grid(x, y) == '#')
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;
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));
var newPixels = Enumerable.Repeat(false, Size).Select(_ => new char[Size]).ToArray();
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);
}
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 y = 0; y < Size; y++)
for (var x = 0; x < Size; x++)
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;
for (var i = 1; i <= 8; i++)
{
yield return tile;
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)))}";
yield return tile;
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)))}";
}
}
}
}

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>
/// Day 21: <see href="https://adventofcode.com/2020/day/21" />
/// </summary>
public sealed class Day21 : Day
public Day21() : base(21, "Allergen Assessment")
{
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>
/// Day 22: <see href="https://adventofcode.com/2020/day/22" />
/// </summary>
public sealed class Day22 : Day
public Day22() : base(22, "Crab Combat")
{
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>
/// Day 23: <see href="https://adventofcode.com/2020/day/23" />
/// </summary>
public sealed class Day23 : Day
public Day23() : base(23, "Crab Cups")
{
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>
/// Day 24: <see href="https://adventofcode.com/2020/day/24" />
/// </summary>
public sealed class Day24 : Day
public Day24() : base(24, "Lobby Layout")
{
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>
/// Day 25: <see href="https://adventofcode.com/2020/day/25" />
/// </summary>
public sealed class Day25 : Day
public Day25() : base(25, "Combo Breaker")
{
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>
/// Day X: <see href="https://adventofcode.com/2020/day/X" />
/// </summary>
public sealed class DayX : Day
public DayX() : base(X, "")
{
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;
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;
}
namespace aoc2020;
public static bool Contains(this Range range, int i)
{
return i >= range.Start.Value && i <= range.End.Value;
}
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)
{
return i >= range.Start.Value && i <= range.End.Value;
}
}

View File

@ -1,30 +1,27 @@
using System;
using System.Linq;
using System.Reflection;
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))
.Select(t => (Day) Activator.CreateInstance(t))
.OrderBy(d => d.DayNumber);
var days = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.BaseType == typeof(Day))
.Select(t => Activator.CreateInstance(t) as Day)
.OrderBy(d => d?.DayNumber);
if (args.Length == 1 && int.TryParse(args[0], out var dayNum))
{
var day = days.FirstOrDefault(d => d.DayNumber == dayNum);
if (day != null)
day.AllParts();
else
Console.WriteLine($"Day {dayNum} invalid or not yet implemented");
}
if (args.Length == 1 && int.TryParse(args[0], out var dayNum))
{
var day = days.FirstOrDefault(d => d?.DayNumber == dayNum);
if (day != null)
day.AllParts();
else
{
foreach (var d in days) d.AllParts();
}
Console.WriteLine($"Day {dayNum} invalid or not yet implemented");
}
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>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
@ -11,4 +13,11 @@
</None>
</ItemGroup>
<ItemGroup>
<Using Include="System.Collections.Generic"/>
<Using Include="System.Collections.Immutable"/>
<Using Include="System.Text"/>
<Using Include="System.Text.RegularExpressions"/>
</ItemGroup>
</Project>