├── .editorconfig ├── .gitattributes ├── .gitignore ├── AdventOfCode.Common ├── AdventOfCode.Common.csproj ├── Attributes │ └── PuzzleAttribute.cs ├── Extensions │ ├── DictionaryExtensions.cs │ ├── MapExtensions.cs │ ├── NumberExtensions.cs │ └── SpanExtensions.cs ├── Interfaces │ └── IPuzzle.cs ├── Models │ ├── PuzzleInput.cs │ └── PuzzleModel.cs ├── ProjectionEqualityComparer.cs └── ValueArray.cs ├── AdventOfCode.Puzzles ├── 2015 │ ├── AdventOfCode.Puzzles.2015.csproj │ ├── day01.fastest.cs │ ├── day01.original.cs │ ├── day02.original.cs │ ├── day03.original.cs │ ├── day04.original.cs │ ├── day05.original.cs │ ├── day06.original.cs │ ├── day07.original.cs │ ├── day08.original.cs │ ├── day09.original.cs │ ├── day10.original.cs │ ├── day11.original.cs │ ├── day12.original.cs │ ├── day13.original.cs │ ├── day14.original.cs │ ├── day15.original.cs │ ├── day16.original.cs │ ├── day17.original.cs │ ├── day18.original.cs │ ├── day19.original.cs │ ├── day20.original.cs │ ├── day21.original.cs │ ├── day22.original.cs │ ├── day23.original.cs │ ├── day24.original.cs │ └── day25.original.cs ├── 2016 │ ├── AdventOfCode.Puzzles.2016.csproj │ ├── day01.original.cs │ ├── day02.original.cs │ ├── day03.original.cs │ ├── day04.original.cs │ ├── day05.original.cs │ ├── day06.original.cs │ ├── day07.original.cs │ ├── day08.original.cs │ ├── day09.original.cs │ ├── day10.original.cs │ ├── day11.original.cs │ ├── day12.original.cs │ ├── day13.original.cs │ ├── day14.original.cs │ ├── day15.original.cs │ ├── day16.original.cs │ ├── day17.original.cs │ ├── day18.original.cs │ ├── day19.original.cs │ ├── day20.original.cs │ ├── day21.original.cs │ ├── day22.original.cs │ ├── day23.original.cs │ ├── day24.original.cs │ └── day25.original.cs ├── 2017 │ ├── AdventOfCode.Puzzles.2017.csproj │ ├── day01.fastest.cs │ ├── day01.original.cs │ ├── day02.fastest.cs │ ├── day02.original.cs │ ├── day03.fastest.cs │ ├── day03.original.cs │ ├── day04.fastest.cs │ ├── day04.original.cs │ ├── day05.fastest.cs │ ├── day05.original.cs │ ├── day06.fastest.cs │ ├── day06.original.cs │ ├── day07.fastest.cs │ ├── day07.original.cs │ ├── day08.fastest.cs │ ├── day08.original.cs │ ├── day09.fastest.cs │ ├── day09.original.cs │ ├── day10.fastest.cs │ ├── day10.original.cs │ ├── day11.fastest.cs │ ├── day11.original.cs │ ├── day12.fastest.cs │ ├── day12.original.cs │ ├── day13.fastest.cs │ ├── day13.original.cs │ ├── day14.original.cs │ ├── day15.fastest.cs │ ├── day15.original.cs │ ├── day16.fastest.cs │ ├── day16.original.cs │ ├── day17.fastest.cs │ ├── day17.original.cs │ ├── day18.fastest.cs │ ├── day18.original.cs │ ├── day19.original.cs │ ├── day20.original.cs │ ├── day21.original.cs │ ├── day22.original.cs │ ├── day23.original.cs │ ├── day24.fastest.cs │ ├── day24.original.cs │ └── day25.original.cs ├── 2018 │ ├── AdventOfCode.Puzzles.2018.csproj │ ├── day01.original.cs │ ├── day02.original.cs │ ├── day03.original.cs │ ├── day04.original.cs │ ├── day05.original.cs │ ├── day06.original.cs │ ├── day07.original.cs │ ├── day08.original.cs │ ├── day09.original.cs │ ├── day10.original.cs │ ├── day11.original.cs │ ├── day12.original.cs │ ├── day13.original.cs │ ├── day14.original.cs │ ├── day15.original.cs │ ├── day16.original.cs │ ├── day17.original.cs │ ├── day18.original.cs │ ├── day19.original.cs │ ├── day20.original.cs │ ├── day21.original.cs │ ├── day22.original.cs │ ├── day23.original.cs │ ├── day24.original.cs │ └── day25.original.cs ├── 2019 │ ├── AdventOfCode.Puzzles.2019.csproj │ ├── IntCodeComputer.cs │ ├── day01.fastest.cs │ ├── day01.original.cs │ ├── day02.fastest.cs │ ├── day02.original.cs │ ├── day03.original.cs │ ├── day04.original.cs │ ├── day05.fastest.cs │ ├── day05.original.cs │ ├── day06.original.cs │ ├── day07.original.cs │ ├── day08.original.cs │ ├── day09.original.cs │ ├── day10.original.cs │ ├── day11.original.cs │ ├── day12.original.cs │ ├── day13.original.cs │ ├── day14.original.cs │ ├── day15.original.cs │ ├── day16.original.cs │ ├── day17.original.cs │ ├── day18.original.cs │ ├── day19.original.cs │ ├── day20.original.cs │ ├── day21.original.cs │ ├── day22.original.cs │ ├── day23.original.cs │ ├── day24.original.cs │ ├── day25.original.cs │ └── intcode_disassem.linq ├── 2020 │ ├── AdventOfCode.Puzzles.2020.csproj │ ├── day01.original.cs │ ├── day02.fastest.cs │ ├── day02.original.cs │ ├── day03.fastest.cs │ ├── day03.original.cs │ ├── day04.original.cs │ ├── day05.original.cs │ ├── day06.original.cs │ ├── day07.original.cs │ ├── day08.original.cs │ ├── day09.fastest.cs │ ├── day09.original.cs │ ├── day10.original.cs │ ├── day11.fastest.cs │ ├── day11.original.cs │ ├── day12.original.cs │ ├── day13.fastest.cs │ ├── day13.original.cs │ ├── day14.original.cs │ ├── day15.original.cs │ ├── day16.original.cs │ ├── day17.original.cs │ ├── day18.original.cs │ ├── day19.original.cs │ ├── day20.original.cs │ ├── day21.original.cs │ ├── day22.original.cs │ ├── day23.original.cs │ ├── day24.original.cs │ └── day25.original.cs ├── 2021 │ ├── AdventOfCode.Puzzles.2021.csproj │ ├── day01.fastest.cs │ ├── day01.original.cs │ ├── day02.original.cs │ ├── day03.original.cs │ ├── day04.original.cs │ ├── day05.original.cs │ ├── day06.fastest.cs │ ├── day06.original.cs │ ├── day07.fastest.cs │ ├── day07.original.cs │ ├── day08.original.cs │ ├── day09.original.cs │ ├── day10.original.cs │ ├── day11.original.cs │ ├── day12.original.cs │ ├── day13.original.cs │ ├── day14.original.cs │ ├── day15.original.cs │ ├── day16.original.cs │ ├── day17.original.cs │ ├── day18.original.cs │ ├── day19.original.cs │ ├── day20.original.cs │ ├── day21.original.cs │ ├── day22.original.cs │ ├── day23.original.cs │ ├── day24.original.cs │ └── day25.original.cs ├── 2022 │ ├── AdventOfCode.Puzzles.2022.csproj │ ├── day01.fastest.cs │ ├── day01.original.cs │ ├── day02.original.cs │ ├── day03.fastest.cs │ ├── day03.original.cs │ ├── day04.fastest.cs │ ├── day04.original.cs │ ├── day05.fastest.cs │ ├── day05.original.cs │ ├── day06.fastest.cs │ ├── day06.original.cs │ ├── day07.fastest.cs │ ├── day07.original.cs │ ├── day08.fastest.cs │ ├── day08.original.cs │ ├── day09.fastest.cs │ ├── day09.original.cs │ ├── day10.fastest.cs │ ├── day10.original.cs │ ├── day11.original.cs │ ├── day12.original.cs │ ├── day13.original.cs │ ├── day14.fastest.cs │ ├── day14.original.cs │ ├── day15.original.cs │ ├── day16.original.cs │ ├── day17.original.cs │ ├── day18.original.cs │ ├── day19.original.cs │ ├── day20.original.cs │ ├── day21.original.cs │ ├── day22.original.cs │ ├── day23.original.cs │ ├── day24.original.cs │ └── day25.original.cs ├── 2023 │ ├── AdventOfCode.Puzzles.2023.csproj │ ├── day01.fastest.cs │ ├── day01.original.cs │ ├── day02.fastest.cs │ ├── day02.original.cs │ ├── day03.fastest.cs │ ├── day03.original.cs │ ├── day04.fastest.cs │ ├── day04.original.cs │ ├── day05.fastest.cs │ ├── day05.original.cs │ ├── day06.fastest.cs │ ├── day06.original.cs │ ├── day07.fastest.cs │ ├── day07.original.cs │ ├── day08.fastest.cs │ ├── day08.original.cs │ ├── day09.fastest.cs │ ├── day09.original.cs │ ├── day10.fastest.cs │ ├── day10.original.cs │ ├── day11.fastest.cs │ ├── day11.original.cs │ ├── day12.fastest.cs │ ├── day12.original.cs │ ├── day13.fastest.cs │ ├── day13.original.cs │ ├── day14.fastest.cs │ ├── day14.original.cs │ ├── day15.fastest.cs │ ├── day15.original.cs │ ├── day16.original.cs │ ├── day17.original.cs │ ├── day18.fastest.cs │ ├── day18.original.cs │ ├── day19.original.cs │ ├── day20.original.cs │ ├── day21.original.cs │ ├── day22.original.cs │ ├── day23.original.cs │ ├── day24.original.cs │ └── day25.original.cs └── 2024 │ ├── AdventOfCode.Puzzles.2024.csproj │ ├── day01.fastest.cs │ ├── day01.original.cs │ ├── day02.fastest.cs │ ├── day02.original.cs │ ├── day03.fastest.cs │ ├── day03.original.cs │ ├── day04.fastest.cs │ ├── day04.original.cs │ ├── day05.fastest.cs │ ├── day05.original.cs │ ├── day06.original.cs │ ├── day07.original.cs │ ├── day08.original.cs │ ├── day09.original.cs │ ├── day10.original.cs │ ├── day11.original.cs │ ├── day12.original.cs │ ├── day13.original.cs │ ├── day14.original.cs │ ├── day15.original.cs │ ├── day16.original.cs │ ├── day17.original.cs │ ├── day18.original.cs │ ├── day19.original.cs │ ├── day20.original.cs │ ├── day21.original.cs │ ├── day22.original.cs │ ├── day23.original.cs │ ├── day24.original.cs │ └── day25.original.cs ├── AdventOfCode.Runner ├── AdventOfCode.Runner.csproj ├── BenchmarkInputProvider.cs ├── Program.cs ├── Program.docopt.txt ├── Properties │ └── launchSettings.json ├── PuzzleBenchmarkRunner.cs ├── PuzzleInputProvider.cs ├── PuzzleResult.cs └── PuzzleRunner.cs ├── AdventOfCode.sln ├── Directory.Build.props ├── Directory.Packages.props └── license.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific files 2 | *.suo 3 | *.user 4 | *.userosscache 5 | *.sln.docstates 6 | *.vcxproj.filters 7 | 8 | # C# Build objects 9 | [Bb]in/ 10 | [Oo]bj/ 11 | 12 | # Visual Studio User Prefs 13 | .vs/ 14 | 15 | # Ignore app settings file, session id is secret and goes there 16 | appsettings.json 17 | 18 | # Ignore input files, they will be re-downloaded 19 | *.input.txt 20 | 21 | # BDN Artifacts 22 | BenchmarkDotNet.Artifacts/ 23 | -------------------------------------------------------------------------------- /AdventOfCode.Common/AdventOfCode.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AdventOfCode.Common/Attributes/PuzzleAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Common.Attributes; 2 | 3 | public enum CodeType 4 | { 5 | Original, 6 | Fastest, 7 | } 8 | 9 | [AttributeUsage(AttributeTargets.Class)] 10 | public sealed class PuzzleAttribute(int year, int day, CodeType codeType, string? name = null) : Attribute 11 | { 12 | public string? Name { get; } = name; 13 | public int Year { get; } = year; 14 | public int Day { get; } = day; 15 | public CodeType CodeType { get; } = codeType; 16 | } 17 | -------------------------------------------------------------------------------- /AdventOfCode.Common/Extensions/DictionaryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace AdventOfCode.Common.Extensions; 4 | 5 | public static class DictionaryExtensions 6 | { 7 | public static TValue GetOrAdd(this Dictionary dict, TKey key, Func func) 8 | where TKey : notnull 9 | { 10 | ref var value = ref CollectionsMarshal.GetValueRefOrAddDefault(dict, key, out var exists); 11 | if (!exists) value = func(key); 12 | return value!; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AdventOfCode.Common/Interfaces/IPuzzle.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Common.Interfaces; 2 | 3 | public interface IPuzzle 4 | { 5 | (string part1, string part2) Solve(PuzzleInput input); 6 | } 7 | -------------------------------------------------------------------------------- /AdventOfCode.Common/Models/PuzzleInput.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Common.Models; 2 | 3 | public record PuzzleInput(byte[] Bytes, string Text, string[] Lines) 4 | { 5 | public ReadOnlySpan Span => Bytes; 6 | } 7 | -------------------------------------------------------------------------------- /AdventOfCode.Common/Models/PuzzleModel.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Common.Models; 2 | 3 | public readonly record struct PuzzleModel( 4 | string? Name, 5 | int Year, 6 | int Day, 7 | CodeType CodeType, 8 | Type PuzzleType 9 | ); 10 | -------------------------------------------------------------------------------- /AdventOfCode.Common/ProjectionEqualityComparer.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Common; 2 | 3 | public static class ProjectionEqualityComparer 4 | { 5 | /// 6 | /// Creates an equality comparer using the provided function 7 | /// 8 | /// The equality function 9 | /// The new comparer 10 | /// 11 | /// The returned comparer may or may not be valid in a hashset or dictionary, 12 | /// depending on how the relates to the 13 | /// default hashcode for . 14 | /// 15 | public static IEqualityComparer Create(Func equalityFunction) => 16 | new ProjectionEqualityComparerImpl(equalityFunction, EqualityComparer.Default.GetHashCode!); 17 | 18 | /// 19 | /// Creates an equality comparer using the provided functions 20 | /// 21 | /// The equality function 22 | /// The hash function 23 | /// The new comparer 24 | public static IEqualityComparer Create(Func equalityFunction, Func hashFunction) => 25 | new ProjectionEqualityComparerImpl(equalityFunction, hashFunction); 26 | 27 | /// 28 | /// Creates a new instance of an equality comparer using the provided functions 29 | /// 30 | /// The equality function 31 | /// The hash function 32 | private sealed class ProjectionEqualityComparerImpl( 33 | Func equalityFunction, 34 | Func hashFunction 35 | ) : EqualityComparer 36 | { 37 | /// 38 | public override bool Equals(T? x, T? y) => equalityFunction(x, y); 39 | 40 | /// 41 | public override int GetHashCode(T obj) => hashFunction(obj); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/AdventOfCode.Puzzles.2015.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | AdventOfCode.Puzzles._2015 4 | disable 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day01.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2015; 2 | 3 | [Puzzle(2015, 01, CodeType.Fastest)] 4 | public class Day_01_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var level = 0; 9 | foreach (var c in input.Bytes) 10 | level += (('(' - c) * 2) + 1; 11 | var partA = level; 12 | 13 | level = 0; 14 | var cnt = 0; 15 | foreach (var c in input.Bytes) 16 | { 17 | cnt++; 18 | level += (('(' - c) * 2) + 1; 19 | if (level < 0) 20 | break; 21 | } 22 | 23 | return (partA.ToString(), cnt.ToString()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day01.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2015; 2 | 3 | [Puzzle(2015, 01, CodeType.Original)] 4 | public class Day_01_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var level = 0; 9 | var basement = 0; 10 | foreach ((var i, var c) in input.Bytes.Index(1)) 11 | { 12 | level += (('(' - c) * 2) + 1; 13 | if (basement == 0 && level == -1) 14 | basement = i; 15 | } 16 | 17 | return (level.ToString(), basement.ToString()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day02.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2015; 2 | 3 | [Puzzle(2015, 02, CodeType.Original)] 4 | public partial class Day_02_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var boxes = input.Lines 9 | .Select(l => BoxRegex().Match(l)) 10 | .Select(m => 11 | new[] 12 | { 13 | Convert.ToInt32(m.Groups["l"].Value), 14 | Convert.ToInt32(m.Groups["w"].Value), 15 | Convert.ToInt32(m.Groups["h"].Value), 16 | } 17 | .OrderBy(l => l) 18 | .ToList()) 19 | .ToList(); 20 | 21 | var totalWrappingPaper = 22 | boxes 23 | .Select(b => new[] { b[0] * b[1], b[0] * b[2], b[1] * b[2], }.OrderBy(a => a).ToArray()) 24 | .Select(a => (3 * a[0]) + (2 * a[1]) + (2 * a[2])) 25 | .Sum(); 26 | 27 | var totalRibbonLength = 28 | boxes 29 | .Select(b => (b[0] * b[1] * b[2]) + (2 * b[0]) + (2 * b[1])) 30 | .Sum(); 31 | 32 | return ( 33 | totalWrappingPaper.ToString(), 34 | totalRibbonLength.ToString()); 35 | } 36 | 37 | [GeneratedRegex("(?\\d+)x(?\\d+)x(?\\d+)", RegexOptions.ExplicitCapture)] 38 | private static partial Regex BoxRegex(); 39 | } 40 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day03.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2015; 2 | 3 | [Puzzle(2015, 03, CodeType.Original)] 4 | public class Day_03_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var current = (x: 0, y: 0); 9 | var santaHouses = input.Bytes 10 | .Select(c => 11 | { 12 | if (c == '>') current = (current.x + 1, current.y); 13 | if (c == '<') current = (current.x - 1, current.y); 14 | if (c == '^') current = (current.x, current.y + 1); 15 | if (c == 'v') current = (current.x, current.y - 1); 16 | return current; 17 | }) 18 | .Concat([(0, 0)]) 19 | .Distinct() 20 | .Count(); 21 | 22 | current = (x: 0, y: 0); 23 | var other = current; 24 | var bothHouses = input.Bytes 25 | .Select(c => 26 | { 27 | var t = other; 28 | if (c == '>') other = (current.x + 1, current.y); 29 | if (c == '<') other = (current.x - 1, current.y); 30 | if (c == '^') other = (current.x, current.y + 1); 31 | if (c == 'v') other = (current.x, current.y - 1); 32 | current = t; 33 | return other; 34 | }) 35 | .Concat([(0, 0)]) 36 | .Distinct() 37 | .Count(); 38 | 39 | return ( 40 | santaHouses.ToString(), 41 | bothHouses.ToString()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day04.original.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography; 2 | using System.Text; 3 | 4 | namespace AdventOfCode.Puzzles._2015; 5 | 6 | [Puzzle(2015, 04, CodeType.Original)] 7 | public class Day_04_Original : IPuzzle 8 | { 9 | private static bool HasLeadingZeros(int numZeros, byte[] bytes) 10 | { 11 | for (var i = 0; i < numZeros; i++) 12 | { 13 | var mask = (i % 2 == 0) ? (byte)0xf0 : (byte)0x0f; 14 | if ((bytes[i / 2] & mask) != 0x00) 15 | return false; 16 | } 17 | 18 | return true; 19 | } 20 | 21 | #pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms 22 | #pragma warning disable CA1850 // Prefer static 'HashData' method over 'ComputeHash' 23 | private static int GetPassword(string input, int numZeros) 24 | { 25 | using var md5 = MD5.Create(); 26 | for (var i = 0; ; i++) 27 | { 28 | var hashSrc = input + i.ToString(); 29 | var hashSrcBytes = Encoding.ASCII.GetBytes(hashSrc); 30 | var hash = md5.ComputeHash(hashSrcBytes); 31 | if (HasLeadingZeros(numZeros, hash)) 32 | return i; 33 | } 34 | } 35 | #pragma warning restore CA1850 // Prefer static 'HashData' method over 'ComputeHash' 36 | #pragma warning restore CA5351 // Do Not Use Broken Cryptographic Algorithms 37 | 38 | public (string, string) Solve(PuzzleInput input) 39 | { 40 | var inp = input.Lines[0]; 41 | return ( 42 | GetPassword(inp, 5).ToString(), 43 | GetPassword(inp, 6).ToString()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day05.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2015; 2 | 3 | [Puzzle(2015, 05, CodeType.Original)] 4 | public class Day_05_Original : IPuzzle 5 | { 6 | private static bool HasThreeVowels(string str) => str 7 | .Where(c => c is 'a' or 'e' or 'i' or 'o' or 'u') 8 | .Take(3) 9 | .Count() == 3; 10 | 11 | private static bool HasPair(string str) => 12 | str.Lead(1, (f, s) => f == s).Any(b => b); 13 | 14 | private static readonly string[] s_evilStrings = ["ab", "cd", "pq", "xy",]; 15 | private static bool HasEvilStrings(string str) => 16 | s_evilStrings.Any(str.Contains); 17 | 18 | private static bool IsNicePartA(string str) => 19 | !HasEvilStrings(str) 20 | && HasPair(str) 21 | && HasThreeVowels(str); 22 | 23 | private static bool HasRepeatLetter(string str) => 24 | str.Lead(2, (f, s) => f == s).Any(b => b); 25 | 26 | private static bool HasDuplicatePair(string str) => 27 | Enumerable.Range(0, str.Length - 1) 28 | .Select(i => new { index = i, pair = str.Substring(i, 2) }) 29 | .GroupBy(_ => _.pair) 30 | .Where(g => g.Count() > 1) 31 | .Any(g => g.Last().index - g.First().index > 1); 32 | 33 | private static bool IsNicePartB(string str) => 34 | HasDuplicatePair(str) 35 | && HasRepeatLetter(str); 36 | 37 | public (string, string) Solve(PuzzleInput input) 38 | { 39 | var lines = input.Lines; 40 | 41 | return ( 42 | lines.Count(IsNicePartA).ToString(), 43 | lines.Count(IsNicePartB).ToString()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day08.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2015; 2 | 3 | [Puzzle(2015, 08, CodeType.Original)] 4 | public partial class Day_08_Original : IPuzzle 5 | { 6 | private static int GetDecodedLength(string str) => 7 | DecodeRegex() 8 | .Match(str) 9 | .Groups["char"] 10 | .Captures 11 | .Count; 12 | 13 | public (string, string) Solve(PuzzleInput input) 14 | { 15 | var lines = input.Lines; 16 | var inputLength = lines.Select(s => s.Length).Sum(); 17 | 18 | var decodedLength = lines.Select(GetDecodedLength).Sum(); 19 | var partA = inputLength - decodedLength; 20 | 21 | var encodedVariance = lines 22 | .Select(s => s.Count(c => c is '\\' or '\"') + 2) 23 | .Sum(); 24 | var partB = encodedVariance; 25 | 26 | return (partA.ToString(), partB.ToString()); 27 | } 28 | 29 | [GeneratedRegex(@"""(?\\x.{2}|\\\\|\\\""|\w)*""", RegexOptions.ExplicitCapture)] 30 | private static partial Regex DecodeRegex(); 31 | } 32 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day09.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2015; 2 | 3 | [Puzzle(2015, 09, CodeType.Original)] 4 | public class Day_09_Original : IPuzzle 5 | { 6 | private static readonly string[] s_separators = [" to ", " = "]; 7 | 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var edges = input.Lines 11 | .Select(x => x.Split(s_separators, StringSplitOptions.None)) 12 | .Select(x => new { Start = x[0], End = x[1], Distance = Convert.ToInt32(x[2]) }) 13 | .OrderBy(x => x.Distance) 14 | .ToList(); 15 | 16 | var points = edges.Select(x => x.Start).Concat(edges.Select(x => x.End)).Distinct().ToList(); 17 | 18 | var paths = points 19 | .Permutations() 20 | .Select(p => p.Lead(1)) 21 | .Select(p => p 22 | .Sum(e => edges.SingleOrDefault(_ => (_.Start == e.current && _.End == e.lead) || (_.Start == e.lead && _.End == e.current))?.Distance)) 23 | .ToList(); 24 | 25 | return ( 26 | paths 27 | .Min() 28 | .ToString(), 29 | paths 30 | .Max() 31 | .ToString()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day10.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2015; 2 | 3 | [Puzzle(2015, 10, CodeType.Original)] 4 | public class Day_10_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var line = input.Lines[0]; 9 | 10 | line = SuperEnumerable 11 | .Generate( 12 | line, 13 | Transform) 14 | .ElementAt(40); 15 | var partA = line.Length; 16 | 17 | line = SuperEnumerable 18 | .Generate( 19 | line, 20 | Transform) 21 | .ElementAt(10); 22 | var partB = line.Length; 23 | 24 | return (partA.ToString(), partB.ToString()); 25 | 26 | static string Transform(string str) => 27 | string.Join( 28 | "", 29 | str 30 | .RunLengthEncode() 31 | .Select(rle => $"{rle.count}{rle.value}")); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day12.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2015; 2 | 3 | [Puzzle(2015, 12, CodeType.Original)] 4 | public partial class Day_12_Original : IPuzzle 5 | { 6 | [GeneratedRegex("[,:[](-?\\d+)")] 7 | private static partial Regex NumbersRegex(); 8 | 9 | [GeneratedRegex("{[^{}]*(((?{)[^{}]*)+((?<-before>})[^{}]*)+)*(?(before)(?!))[^{}]*:\"red\"[^{}]*(((?{)[^{}]*)+((?<-before>})[^{}]*)+)*(?(before)(?!))[^{}]*}")] 10 | private static partial Regex JsonRegex(); 11 | 12 | public (string, string) Solve(PuzzleInput input) 13 | { 14 | var str = input.Text; 15 | 16 | var regex = NumbersRegex(); 17 | var partA = 18 | regex.Matches(str) 19 | .OfType() 20 | .Select(c => c.Groups[1]) 21 | .Select(c => c.Value) 22 | .Select(c => Convert.ToInt32(c)) 23 | .Sum(); 24 | 25 | var redsRegex = JsonRegex(); 26 | str = redsRegex.Replace(str, ""); 27 | 28 | var partB = 29 | regex.Matches(str) 30 | .OfType() 31 | .Select(c => c.Groups[1]) 32 | .Select(c => c.Value) 33 | .Select(c => Convert.ToInt32(c)) 34 | .Sum(); 35 | 36 | return (partA.ToString(), partB.ToString()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day13.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2015; 2 | 3 | [Puzzle(2015, 13, CodeType.Original)] 4 | public class Day_13_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var edges = input.Lines 9 | .Select(x => 10 | { 11 | var splits = x.Split(); 12 | return new { Start = splits[0], End = splits[10].TrimEnd('.'), Distance = Convert.ToInt32(splits[3]) * (splits[2] == "gain" ? +1 : -1) }; 13 | }) 14 | .OrderBy(x => x.Distance) 15 | .ToList(); 16 | 17 | var points = edges.Select(x => x.Start).Concat(edges.Select(x => x.End)).Distinct().ToList(); 18 | 19 | var best = points.Take(points.Count - 1) 20 | .Permutations() 21 | .Select(p => p.Prepend(points[^1]).Append(points[^1])) 22 | .Select(p => p.Lead(1)) 23 | .Select(p => p.Sum(e => 24 | edges 25 | .Where(_ => (_.Start == e.current && _.End == e.lead) || (_.Start == e.lead && _.End == e.current)) 26 | .Sum(_ => _.Distance))) 27 | .Max(); 28 | 29 | var partA = best; 30 | 31 | best = points 32 | .Permutations() 33 | .Select(p => p.Prepend("myself").Append("myself")) 34 | .Select(p => p.Lead(1)) 35 | .Select(p => p.Sum(e => 36 | edges 37 | .Where(_ => (_.Start == e.current && _.End == e.lead) || (_.Start == e.lead && _.End == e.current)) 38 | .Sum(_ => _.Distance))) 39 | .Max(); 40 | 41 | var partB = best; 42 | 43 | return (partA.ToString(), partB.ToString()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day17.original.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace AdventOfCode.Puzzles._2015; 4 | 5 | [Puzzle(2015, 17, CodeType.Original)] 6 | public class Day_17_Original : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var total = 150; 11 | 12 | var containers = input.Lines 13 | .Select(s => Convert.ToInt32(s)) 14 | .ToList(); 15 | 16 | var cnt = 0; 17 | var max = 1 << containers.Count; 18 | var numCombinations = 0; 19 | 20 | var minPop = int.MaxValue; 21 | var haveMinPop = 0; 22 | while (cnt < max) 23 | { 24 | var sum = 0; 25 | var bitstream = new BitArray([cnt]); 26 | foreach (var _ in bitstream.OfType().Select((b, i) => new { b, i })) 27 | { 28 | if (_.b) 29 | sum += containers[_.i]; 30 | } 31 | 32 | if (sum == total) 33 | { 34 | numCombinations++; 35 | 36 | var pop = bitstream.OfType().Count(b => b); 37 | if (pop < minPop) 38 | { 39 | minPop = pop; 40 | haveMinPop = 1; 41 | } 42 | else if (pop == minPop) 43 | { 44 | haveMinPop++; 45 | } 46 | } 47 | 48 | cnt++; 49 | } 50 | 51 | return ( 52 | numCombinations.ToString(), 53 | haveMinPop.ToString()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2015/day25.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2015; 2 | 3 | [Puzzle(2015, 25, CodeType.Original)] 4 | public partial class Day_25_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | static ulong Step(ulong x) => x * 252533 % 33554393; 9 | 10 | var matches = NumberRegex().Matches(input.Text); 11 | var row = Convert.ToInt32(matches[0].Value); 12 | var col = Convert.ToInt32(matches[1].Value); 13 | 14 | static int TotalNums(int n) => n * (n - 1) / 2; 15 | 16 | var stepCount = TotalNums(row + col) - (row - 1); 17 | 18 | var num = 20151125UL; 19 | foreach (var x in Enumerable.Range(0, stepCount - 1)) 20 | num = Step(num); 21 | 22 | return (num.ToString(), string.Empty); 23 | } 24 | 25 | [GeneratedRegex("\\d+")] 26 | private static partial Regex NumberRegex(); 27 | } 28 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/AdventOfCode.Puzzles.2016.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | AdventOfCode.Puzzles._2016 4 | disable 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/day01.original.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace AdventOfCode.Puzzles._2016; 4 | 5 | [Puzzle(2016, 01, CodeType.Original)] 6 | public class Day_01_Original : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var instructions = input.Text.Split(',').Select(x => x.Trim()).ToList(); 11 | var position = (x: 0, y: 0, dir: 0); 12 | 13 | var set = new HashSet<(int x, int y)>() { (0, 0), }; 14 | var partB = int.MinValue; 15 | 16 | foreach (var i in instructions) 17 | { 18 | var newDirection = i[0] == 'L' ? 19 | position.dir - 1 : 20 | position.dir + 1; 21 | 22 | newDirection = (newDirection + 4) % 4; 23 | var distance = Convert.ToInt32(i[1..]); 24 | 25 | if (partB == int.MinValue) 26 | { 27 | var path = newDirection switch 28 | { 29 | 0 => Enumerable.Range(1, distance).Select(i => (position.x, y: position.y + i)), 30 | 1 => Enumerable.Range(1, distance).Select(i => (x: position.x + i, position.y)), 31 | 2 => Enumerable.Range(1, distance).Select(i => (position.x, y: position.y - i)), 32 | 3 => Enumerable.Range(1, distance).Select(i => (x: position.x - i, position.y)), 33 | _ => throw new UnreachableException(), 34 | }; 35 | 36 | foreach (var p in path) 37 | { 38 | if (set.Contains(p)) 39 | partB = Math.Abs(p.x) + Math.Abs(p.y); 40 | set.Add(p); 41 | } 42 | } 43 | 44 | position = newDirection switch 45 | { 46 | 0 => (position.x, position.y + distance, newDirection), 47 | 1 => (position.x + distance, position.y, newDirection), 48 | 2 => (position.x, position.y - distance, newDirection), 49 | 3 => (position.x - distance, position.y, newDirection), 50 | _ => throw new UnreachableException(), 51 | }; 52 | } 53 | 54 | var partA = Math.Abs(position.x) + Math.Abs(position.y); 55 | return (partA.ToString(), partB.ToString()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/day03.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2016; 2 | 3 | [Puzzle(2016, 03, CodeType.Original)] 4 | public class Day_03_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var partA = input.Lines 9 | .Select(line => line.Split(' ', StringSplitOptions.RemoveEmptyEntries)) 10 | .Select(line => new { A = Convert.ToInt32(line[0]), B = Convert.ToInt32(line[1]), C = Convert.ToInt32(line[2]), }) 11 | .Count(tri => tri.A + tri.B > tri.C && tri.A + tri.C > tri.B && tri.B + tri.C > tri.A); 12 | 13 | var partB = input.Lines 14 | .Select((line, idx) => new { parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries), idx }) 15 | .GroupBy(x => x.idx / 3) 16 | .SelectMany(x => 17 | { 18 | var arr = x.Select(z => z.parts).ToArray(); 19 | return new[] 20 | { 21 | new { A = Convert.ToInt32(arr[0][0]), B = Convert.ToInt32(arr[1][0]), C = Convert.ToInt32(arr[2][0]), }, 22 | new { A = Convert.ToInt32(arr[0][1]), B = Convert.ToInt32(arr[1][1]), C = Convert.ToInt32(arr[2][1]), }, 23 | new { A = Convert.ToInt32(arr[0][2]), B = Convert.ToInt32(arr[1][2]), C = Convert.ToInt32(arr[2][2]), }, 24 | }; 25 | }) 26 | .Count(tri => tri.A + tri.B > tri.C && tri.A + tri.C > tri.B && tri.B + tri.C > tri.A); 27 | 28 | return (partA.ToString(), partB.ToString()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/day04.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2016; 2 | 3 | [Puzzle(2016, 04, CodeType.Original)] 4 | public partial class Day_04_Original : IPuzzle 5 | { 6 | [GeneratedRegex("(?[a-z-]+)-(?\\d+)[[](?\\w{5})[]]", RegexOptions.ExplicitCapture)] 7 | private static partial Regex RoomRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var regex = RoomRegex(); 12 | 13 | var validNames = 14 | input.Lines 15 | .Select(x => regex.Match(x)) 16 | .Select(x => new 17 | { 18 | name = x.Groups["name"].Value, 19 | id = Convert.ToInt32(x.Groups["id"].Value), 20 | checksum = x.Groups["checksum"].Value, 21 | }) 22 | .Where(x => 23 | { 24 | var checksum = string.Join("", x.name 25 | .GroupBy( 26 | c => c, 27 | (c, _) => new { c, cnt = _.Count(), }) 28 | .Where(c => c.c != '-') 29 | .OrderByDescending(c => c.cnt) 30 | .ThenBy(c => c.c) 31 | .Select(c => c.c) 32 | .Take(5)); 33 | return checksum == x.checksum; 34 | }) 35 | .ToList(); 36 | 37 | var partA = validNames.Sum(x => x.id); 38 | 39 | var partB = validNames 40 | .Select(x => new 41 | { 42 | x.name, 43 | x.id, 44 | newName = string.Join("", x.name 45 | .Select(c => c == '-' ? ' ' : (char)(((c - 'a' + x.id) % 26) + 'a'))) 46 | }) 47 | .First(x => x.newName.StartsWith("north")) 48 | .id; 49 | 50 | return (partA.ToString(), partB.ToString()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/day06.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2016; 2 | 3 | [Puzzle(2016, 06, CodeType.Original)] 4 | public class Day_06_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var words = input.Lines; 9 | 10 | static char ProcessLetter(IEnumerable characters, int multiplier) => 11 | characters 12 | .GroupBy( 13 | c => c, 14 | (c, _) => new { c, cnt = _.Count(), }) 15 | .OrderBy(c => c.cnt * multiplier) 16 | .Select(c => c.c) 17 | .First(); 18 | 19 | var partA = 20 | string.Join("", 21 | Enumerable.Range(0, words[0].Length) 22 | .Select(i => words.Select(w => w[i])) 23 | .Select(characters => ProcessLetter(characters, -1))); 24 | 25 | var partB = 26 | string.Join("", 27 | Enumerable.Range(0, words[0].Length) 28 | .Select(i => words.Select(w => w[i])) 29 | .Select(characters => ProcessLetter(characters, 1))); 30 | 31 | return (partA, partB); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/day13.original.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace AdventOfCode.Puzzles._2016; 4 | 5 | [Puzzle(2016, 13, CodeType.Original)] 6 | public class Day_13_Original : IPuzzle 7 | { 8 | private static bool IsWall(int x, int y, int number) 9 | { 10 | var num = (x * x) + (3 * x) + (2 * x * y) + y + (y * y) + number; 11 | var bitCount = BitOperations.PopCount((uint)num); 12 | return (bitCount % 2) == 1; 13 | } 14 | 15 | public (string, string) Solve(PuzzleInput input) 16 | { 17 | var number = Convert.ToInt32(input.Lines[0]); 18 | 19 | var partA = SuperEnumerable.GetShortestPathCost<(int x, int y), int>( 20 | (1, 1), 21 | (p, c) => p.GetCartesianNeighbors() 22 | .Where(p => !IsWall(p.x, p.y, number)) 23 | .Select(p => (p, c + 1)), 24 | (31, 39)); 25 | 26 | var count = -1; 27 | var flag = false; 28 | _ = SuperEnumerable.GetShortestPathCost<(int x, int y), int>( 29 | (1, 1), 30 | (p, c) => 31 | { 32 | flag = c > 50; 33 | count++; 34 | return p.GetCartesianNeighbors() 35 | .Where(p => !IsWall(p.x, p.y, number)) 36 | .Select(p => (p, c + 1)); 37 | }, 38 | _ => flag); 39 | 40 | return (partA.ToString(), count.ToString()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/day15.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2016; 2 | 3 | [Puzzle(2016, 15, CodeType.Original)] 4 | public partial class Day_15_Original : IPuzzle 5 | { 6 | [GeneratedRegex("Disc #(?\\d+) has (?\\d+) positions; at time=0, it is at position (?\\d+).", RegexOptions.ExplicitCapture)] 7 | private static partial Regex DiscRegex(); 8 | 9 | private sealed record Disc(int NumPositions, int InitialPosition); 10 | 11 | public (string, string) Solve(PuzzleInput input) 12 | { 13 | var regex = DiscRegex(); 14 | 15 | var discs = 16 | input.Lines 17 | .Select(s => regex.Match(s)) 18 | .Select(m => new Disc( 19 | Convert.ToInt32(m.Groups["num_positions"].Value), 20 | Convert.ToInt32(m.Groups["initial_position"].Value))) 21 | .ToList(); 22 | 23 | var partA = GetDiscTime(discs); 24 | 25 | discs.Add(new(11, 0)); 26 | var partB = GetDiscTime(discs); 27 | 28 | return (partA.ToString(), partB.ToString()); 29 | } 30 | 31 | private static int GetDiscTime(List discs) 32 | { 33 | for (var initialTime = 0; ; initialTime++) 34 | { 35 | var flag = true; 36 | for (var capsulePosition = 1; flag && capsulePosition <= discs.Count; capsulePosition++) 37 | { 38 | var disc = discs[capsulePosition - 1]; 39 | var discPosition = (initialTime + capsulePosition + disc.InitialPosition) % disc.NumPositions; 40 | if (discPosition != 0) flag = false; 41 | } 42 | 43 | if (flag) 44 | { 45 | return initialTime; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/day16.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2016; 2 | 3 | [Puzzle(2016, 16, CodeType.Original)] 4 | public class Day_16_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | return ( 9 | ExecutePart(input.Lines[0], 272), 10 | ExecutePart(input.Lines[0], 35651584)); 11 | } 12 | 13 | private static string ExecutePart(string input, int length) 14 | { 15 | var data = input.Select(c => c == '1').ToList(); 16 | 17 | static List CurveStep(IList bits) => 18 | bits.Append(false).Concat(bits.Reverse().Select(b => !b)).ToList(); 19 | 20 | while (data.Count < length) 21 | data = CurveStep(data); 22 | 23 | data = data.Take(length).ToList(); 24 | 25 | data = GenerateChecksum(data); 26 | return string.Join("", data.Take(length).Select(b => b ? '1' : '0')); 27 | } 28 | 29 | private static List GenerateChecksum(List bits) 30 | { 31 | var checksum = new List(); 32 | for (var i = 0; i < bits.Count; i += 2) 33 | checksum.Add(!(bits[i] ^ bits[i + 1])); 34 | 35 | return (checksum.Count % 2) == 0 36 | ? GenerateChecksum(checksum) 37 | : checksum; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/day17.original.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography; 2 | using System.Text; 3 | 4 | namespace AdventOfCode.Puzzles._2016; 5 | 6 | [Puzzle(2016, 17, CodeType.Original)] 7 | public class Day_17_Original : IPuzzle 8 | { 9 | 10 | #pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms 11 | #pragma warning disable CA1850 // Prefer static 'HashData' method over 'ComputeHash' 12 | public (string, string) Solve(PuzzleInput input) 13 | { 14 | using var md5 = MD5.Create(); 15 | var passcode = input.Lines[0]; 16 | 17 | IEnumerable<(int x, int y, string path)> GetNextPositions( 18 | (int x, int y, string path) state) 19 | { 20 | if (state.x == 3 && state.y == 3) 21 | yield break; 22 | 23 | var hashSrc = passcode + state.path; 24 | var bytes = Encoding.ASCII.GetBytes(hashSrc); 25 | var hash = md5.ComputeHash(bytes); 26 | 27 | if (state.x > 0 && (hash[0] >> 4) >= 0xb) yield return (state.x - 1, state.y, state.path + 'U'); 28 | if (state.x < 3 && (hash[0] & 0xf) >= 0xb) yield return (state.x + 1, state.y, state.path + 'D'); 29 | if (state.y > 0 && (hash[1] >> 4) >= 0xb) yield return (state.x, state.y - 1, state.path + 'L'); 30 | if (state.y < 3 && (hash[1] & 0xf) >= 0xb) yield return (state.x, state.y + 1, state.path + 'R'); 31 | } 32 | 33 | var paths = SuperEnumerable 34 | .TraverseBreadthFirst( 35 | (x: 0, y: 0, path: string.Empty), 36 | GetNextPositions) 37 | .Where(p => p.x == 3 && p.y == 3) 38 | .ToList(); 39 | 40 | return ( 41 | paths[0].path, 42 | paths[^1].path.Length.ToString()); 43 | } 44 | #pragma warning restore CA1850 // Prefer static 'HashData' method over 'ComputeHash' 45 | #pragma warning restore CA5351 // Do Not Use Broken Cryptographic Algorithms 46 | } 47 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/day18.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2016; 2 | 3 | [Puzzle(2016, 18, CodeType.Original)] 4 | public class Day_18_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | return ( 9 | ExecutePart(input.Lines[0], 40).ToString(), 10 | ExecutePart(input.Lines[0], 400000).ToString()); 11 | } 12 | 13 | private static int ExecutePart(string input, int rows) 14 | { 15 | var tiles = new List> 16 | { 17 | input.Select(c => c == '^').ToArray(), 18 | }; 19 | 20 | while (tiles.Count < rows) 21 | { 22 | var row = tiles[^1]; 23 | var newRow = new bool[row.Count]; 24 | 25 | for (var i = 0; i < row.Count; i++) 26 | { 27 | var left = i > 0 && row[i - 1]; 28 | var right = i < row.Count - 1 && row[i + 1]; 29 | newRow[i] = left ^ right; 30 | } 31 | 32 | tiles.Add(newRow); 33 | } 34 | 35 | return tiles.SelectMany(x => x).Count(b => !b); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/day19.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2016; 2 | 3 | [Puzzle(2016, 19, CodeType.Original)] 4 | public class Day_19_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | static int NextPowerOfTwo(int n) 9 | { 10 | n |= n >> 1; 11 | n |= n >> 2; 12 | n |= n >> 4; 13 | n |= n >> 8; 14 | n |= n >> 16; 15 | 16 | return n + 1; 17 | } 18 | 19 | static int PartAElfHoldingPresents(int n) => 20 | (n * 2 % NextPowerOfTwo(n)) + 1; 21 | 22 | static int NextPowerOfThree(int n) 23 | { 24 | var x = 3; 25 | while (x < n) 26 | x *= 3; 27 | return x; 28 | } 29 | 30 | static int PartBElfHoldingPresents(int n) 31 | { 32 | var roundUp = NextPowerOfThree(n); 33 | var roundDown = roundUp / 3; 34 | return n <= roundDown * 2 ? n - roundDown : 35 | n == roundUp ? n : 36 | n * 2 % roundUp; 37 | } 38 | 39 | var num = Convert.ToInt32(input.Text); 40 | 41 | return ( 42 | PartAElfHoldingPresents(num).ToString(), 43 | PartBElfHoldingPresents(num).ToString()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/day20.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2016; 2 | 3 | [Puzzle(2016, 20, CodeType.Original)] 4 | public partial class Day_20_Original : IPuzzle 5 | { 6 | [GeneratedRegex("(?\\d+)-(?\\d+)", RegexOptions.ExplicitCapture)] 7 | private static partial Regex AddressRangeRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var max = uint.MaxValue; 12 | var regex = AddressRangeRegex(); 13 | 14 | var blocked = 15 | input.Lines 16 | .Select(s => regex.Match(s)) 17 | .Select(m => new { from = Convert.ToUInt32(m.Groups["from"].Value), to = Convert.ToUInt32(m.Groups["to"].Value), }) 18 | .OrderBy(b => b.from) 19 | .ToList(); 20 | 21 | var first = 0u; 22 | foreach (var b in blocked) 23 | { 24 | if (b.from > first) 25 | break; 26 | 27 | first = Math.Max(b.to + 1, first); 28 | } 29 | 30 | var partA = first; 31 | 32 | first = 0u; 33 | var allowed = blocked.Take(0).ToList(); 34 | foreach (var b in blocked) 35 | { 36 | if (b.from > first) 37 | allowed.Add(new { from = first, to = b.from - 1 }); 38 | 39 | if (b.to == max) 40 | break; 41 | 42 | first = Math.Max(Math.Max(b.to, b.to + 1), first); 43 | } 44 | 45 | var partB = allowed.Select(b => (int)(b.to - b.from + 1)).Sum(); 46 | 47 | return (partA.ToString(), partB.ToString()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2016/day22.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2016; 2 | 3 | [Puzzle(2016, 22, CodeType.Original)] 4 | public partial class Day_22_Original : IPuzzle 5 | { 6 | [GeneratedRegex(@"/dev/grid/node-x(?\d+)-y(?\d+)\s+(?\d+)T\s+(?\d+)T\s+(?\d+)T\s+\d+%")] 7 | private static partial Regex GridRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var regex = GridRegex(); 12 | 13 | var nodes = 14 | input.Lines 15 | .Skip(2) 16 | .Select(s => regex.Match(s)) 17 | .Select(m => new 18 | { 19 | x = Convert.ToInt32(m.Groups["x"].Value), 20 | y = Convert.ToInt32(m.Groups["y"].Value), 21 | total = Convert.ToInt32(m.Groups["total"].Value), 22 | used = Convert.ToInt32(m.Groups["used"].Value), 23 | avail = Convert.ToInt32(m.Groups["avail"].Value), 24 | }) 25 | .ToList(); 26 | 27 | var partA = 28 | ( 29 | from a in nodes 30 | where a.used != 0 31 | from b in nodes 32 | where a.x != b.x || a.y != b.y 33 | where a.used < b.avail 34 | select new { a, b } 35 | ).Count(); 36 | 37 | // Apparently, I completed part b by hand or something? 38 | return (partA.ToString(), string.Empty); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/AdventOfCode.Puzzles.2017.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | AdventOfCode.Puzzles._2017 4 | disable 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day01.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 01, CodeType.Fastest)] 4 | public class Day_01_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var span = input.Span[..^1]; 9 | 10 | var sum = 0; 11 | 12 | var last = span[^1]; 13 | foreach (var c in span) 14 | { 15 | if (c == last) 16 | sum += c - '0'; 17 | last = c; 18 | } 19 | 20 | var partA = sum; 21 | 22 | sum = 0; 23 | for (int i = 0, j = span.Length / 2; j < span.Length; i++, j++) 24 | { 25 | if (span[i] == span[j]) 26 | sum += span[i] - '0'; 27 | } 28 | 29 | var partB = sum << 1; 30 | 31 | return (partA.ToString(), partB.ToString()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day01.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 01, CodeType.Original)] 4 | public class Day_01_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var data = input.Lines[0] 9 | .Select(x => x - '0') 10 | .ToList(); 11 | 12 | var partA = 13 | data 14 | .Append(data[0]) 15 | .Lead(1) 16 | .Where(x => x.current == x.lead) 17 | .Select(x => x.current) 18 | .Sum(); 19 | 20 | var rotInput = data.Skip(data.Count / 2).Concat(data.Take(data.Count / 2)); 21 | var partB = 22 | data.Zip(rotInput, (a, b) => new { a, b }) 23 | .Where(x => x.a == x.b) 24 | .Select(x => x.a) 25 | .Sum(); 26 | 27 | return (partA.ToString(), partB.ToString()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day02.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 02, CodeType.Fastest)] 4 | public class Day_02_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var span = input.Span; 9 | int part1 = 0, part2 = 0; 10 | Span arr = stackalloc int[16]; 11 | 12 | var j = 0; 13 | for (var i = 0; i < span.Length;) 14 | { 15 | var (x, y) = span[i..].AtoI(); 16 | arr[j++] = x; 17 | i += y; 18 | 19 | if (span[i] == '\n') 20 | { 21 | int min = arr[0], max = arr[0]; 22 | for (j = 1; j < 16; j++) 23 | { 24 | var n = arr[j]; 25 | if (n < min) min = n; 26 | if (n > max) max = n; 27 | } 28 | 29 | part1 += max - min; 30 | 31 | var flag = false; 32 | for (j = 0; !flag && j < 16; j++) 33 | { 34 | for (var k = 0; !flag && k < 16; k++) 35 | { 36 | if (j == k) continue; 37 | if (arr[j] % arr[k] == 0) 38 | { 39 | part2 += arr[j] / arr[k]; 40 | flag = true; 41 | } 42 | else if (arr[k] % arr[j] == 0) 43 | { 44 | part2 += arr[k] / arr[j]; 45 | flag = true; 46 | } 47 | } 48 | } 49 | 50 | j = 0; 51 | } 52 | 53 | i++; 54 | } 55 | 56 | return ( 57 | part1.ToString(), 58 | part2.ToString()); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day02.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 02, CodeType.Original)] 4 | public class Day_02_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var lines = input.Lines 9 | .Select(x => x.Split().Select(s => Convert.ToInt32(s)).ToList()) 10 | .ToList(); 11 | 12 | var partA = 13 | lines 14 | .Select(x => x.Max() - x.Min()) 15 | .Sum(); 16 | 17 | var partB = 18 | lines 19 | .Select(arr => ( 20 | from num in arr 21 | from div in arr 22 | where num != div 23 | where num % div == 0 24 | select num / div) 25 | .Single()) 26 | .Sum(); 27 | 28 | return (partA.ToString(), partB.ToString()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day03.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 03, CodeType.Fastest)] 4 | public class Day_03_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | // borrowed liberally from https://github.com/Voltara/advent2017-fast/blob/master/src/day03.c 9 | var bytes = input.Bytes; 10 | 11 | var number = 0; 12 | for (var i = 0; i < bytes.Length; i++) 13 | { 14 | if (bytes[i] >= '0') 15 | number = (number * 10) + bytes[i] - '0'; 16 | } 17 | 18 | var x = number - 1; 19 | var ring = (int)(Math.Sqrt((uint)x) + 1) / 2; 20 | var partA = ring + Math.Abs((x % (ring * 2)) - ring); 21 | 22 | return (partA.ToString(), DoPartB(number).ToString()); 23 | } 24 | 25 | private static long DoPartB(int number) 26 | { 27 | var arr = new long[512]; 28 | arr[0] = 1; arr[1] = 1; arr[2] = 1; 29 | arr[3] = 1; arr[4] = 1; arr[5] = 1; 30 | arr[6] = 1; arr[7] = 2; arr[8] = 2; 31 | 32 | long p = 1, q = 9; 33 | for (var length = 2; ; length += 2) 34 | { 35 | for (var side = 0; side < 4; side++) 36 | { 37 | for (var i = length; i-- > 0;) 38 | { 39 | if (arr[p] > number) 40 | { 41 | return arr[p]; 42 | } 43 | 44 | arr[q++] += arr[p]; 45 | arr[q] += arr[p]; 46 | arr[p + 1] += arr[p]; 47 | arr[q + 1] += arr[p++]; 48 | } 49 | 50 | if (side == 3) break; 51 | 52 | // Turn the corner 53 | arr[(++q) + 1] += arr[p - 1]; 54 | arr[(++q) + 1] += arr[p - 1]; 55 | arr[p] += arr[p - 2]; 56 | 57 | } 58 | 59 | // Advance to the next ring 60 | arr[q++] += arr[p]; 61 | arr[q++] += arr[p]; 62 | arr[p + 1] += arr[p - 1]; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day04.fastest.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace AdventOfCode.Puzzles._2017; 4 | 5 | [Puzzle(2017, 04, CodeType.Fastest)] 6 | public class Day_04_Fastest : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var bytes = input.Bytes; 11 | 12 | var line = new ulong[32]; 13 | var number = 0ul; 14 | var cnt = (uint)bytes.Length; 15 | int part1 = 0, part2 = 0; 16 | bool flag1 = false, flag2 = false; 17 | for (int i = 0, j = 0; i < cnt; i++) 18 | { 19 | var c = bytes[i]; 20 | if (c >= 'a') 21 | { 22 | number = (number << 8) + c; 23 | } 24 | else 25 | { 26 | var sortedNumber = SortBytes(number); 27 | for (var k = 0; !flag1 && k < j; k += 2) 28 | { 29 | if (line[k] == number) 30 | flag1 = true; 31 | } 32 | 33 | for (var k = 1; !flag2 && k < j; k += 2) 34 | { 35 | if (line[k] == sortedNumber) 36 | flag2 = true; 37 | } 38 | 39 | if (c == '\n') 40 | { 41 | if (!flag1) part1++; 42 | if (!flag2) part2++; 43 | flag1 = false; 44 | flag2 = false; 45 | j = 0; 46 | number = 0; 47 | } 48 | else 49 | { 50 | line[j++] = number; 51 | line[j++] = sortedNumber; 52 | number = 0; 53 | } 54 | } 55 | } 56 | 57 | return ( 58 | part1.ToString(), 59 | part2.ToString()); 60 | } 61 | 62 | private static ulong SortBytes(ulong bytes) 63 | { 64 | var arr = MemoryMarshal.AsBytes( 65 | MemoryMarshal.CreateSpan(ref bytes, 1)); 66 | for (var i = 0; i < 7; i++) 67 | { 68 | for (var j = i + 1; j < 8; j++) 69 | { 70 | if (arr[j] < arr[i]) 71 | (arr[i], arr[j]) = (arr[j], arr[i]); 72 | } 73 | } 74 | 75 | return bytes; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day04.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 04, CodeType.Original)] 4 | public class Day_04_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var lines = input.Lines 9 | .Select(x => x.Split()) 10 | .ToList(); 11 | 12 | var partA = 13 | lines 14 | .Where(l => l.Distinct().Count() == l.Length) 15 | .Count(); 16 | 17 | var partB = 18 | lines 19 | .Where(l => l.Select(s => new string(s.OrderBy(c => c).ToArray())).Distinct().Count() == l.Length) 20 | .Count(); 21 | 22 | return (partA.ToString(), partB.ToString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day05.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 05, CodeType.Fastest)] 4 | public class Day_05_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var span = input.Span; 9 | 10 | Span nums1 = stackalloc int[span.Length / 4]; 11 | Span nums2 = stackalloc int[span.Length / 4]; 12 | var count = 0; 13 | for (var i = 0; i < span.Length;) 14 | { 15 | var (x, y) = span[i..].AtoI(); 16 | nums1[count] = nums2[count] = x; 17 | count++; 18 | i += y + 1; 19 | } 20 | 21 | return ( 22 | DoPartA(nums1[..count]).ToString(), 23 | DoPartB(nums2[..count]).ToString()); 24 | } 25 | 26 | private static int DoPartA(Span nums) 27 | { 28 | var steps = 0; 29 | var cnt = (uint)nums.Length; 30 | for (var i = 0; i >= 0 && i < cnt; steps++) 31 | i += nums[i]++; 32 | 33 | return steps; 34 | } 35 | 36 | private static int DoPartB(Span nums) 37 | { 38 | var steps = 0; 39 | var cnt = (uint)nums.Length; 40 | for (var i = 0; i >= 0 && i < cnt; steps++) 41 | { 42 | var j = nums[i]; 43 | nums[i] += -(((j - 3) >> 31) << 1) - 1; 44 | i += j; 45 | } 46 | 47 | return steps; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day05.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 05, CodeType.Original)] 4 | public class Day_05_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var nums = input.Lines 9 | .Select(x => Convert.ToInt32(x)) 10 | .ToList(); 11 | 12 | var instructions = nums.ToList(); 13 | var ptr = 0; 14 | var count = 0; 15 | 16 | while (ptr >= 0 && ptr < instructions.Count) 17 | { 18 | var adjust = instructions[ptr]; 19 | instructions[ptr] = adjust + 1; 20 | ptr += adjust; 21 | count++; 22 | } 23 | 24 | var partA = count; 25 | 26 | instructions = nums.ToList(); 27 | ptr = 0; 28 | count = 0; 29 | 30 | while (ptr >= 0 && ptr < instructions.Count) 31 | { 32 | var adjust = instructions[ptr]; 33 | instructions[ptr] = 34 | adjust >= 3 35 | ? adjust - 1 36 | : adjust + 1; 37 | ptr += adjust; 38 | count++; 39 | } 40 | 41 | var partB = count; 42 | 43 | return (partA.ToString(), partB.ToString()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day06.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 06, CodeType.Original)] 4 | public class Day_06_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var nums = input.Text 9 | .Split() 10 | .Where(x => !string.IsNullOrWhiteSpace(x)) 11 | .Select(x => Convert.ToInt32(x)) 12 | .ToList(); 13 | 14 | var history = new List 15 | { 16 | nums.ToArray(), 17 | }; 18 | 19 | while (true) 20 | { 21 | var minElement = 22 | nums.Select((x, i) => new { x, i, }) 23 | .OrderByDescending(x => x.x) 24 | .ThenBy(x => x.i) 25 | .First(); 26 | 27 | var allInc = minElement.x / nums.Count; 28 | var extraInc = minElement.x % nums.Count; 29 | 30 | nums[minElement.i] = 0; 31 | for (var i = 1; i <= extraInc; i++) 32 | nums[(minElement.i + i) % nums.Count] += allInc + 1; 33 | for (var i = extraInc + 1; i <= nums.Count; i++) 34 | nums[(minElement.i + i) % nums.Count] += allInc; 35 | 36 | var oldInput = history 37 | .Select((old, idx) => new { idx, isMatch = old.Zip(nums, (o, i) => o == i).All(b => b), }) 38 | .FirstOrDefault(x => x.isMatch); 39 | 40 | if (oldInput != null) 41 | { 42 | return ( 43 | history.Count.ToString(), 44 | (history.Count - oldInput.idx).ToString() 45 | ); 46 | } 47 | 48 | history.Add(nums.ToArray()); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day07.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 07, CodeType.Original)] 4 | public partial class Day_07_Original : IPuzzle 5 | { 6 | [GeneratedRegex(@"^(?\w+) \((?\d+)\)( -> ((?\w+)(,\s*)?)*)?$", RegexOptions.ExplicitCapture)] 7 | private static partial Regex ProgramRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var nodes = input.Lines 12 | .Select(s => ProgramRegex().Match(s)) 13 | .Select(m => new 14 | { 15 | id = m.Groups["id"].Value, 16 | weight = Convert.ToInt32(m.Groups["weight"].Value), 17 | childids = m.Groups["childid"].Success 18 | ? m.Groups["childid"].Captures.OfType().Select(c => c.Value).ToList() 19 | : [], 20 | }) 21 | .ToList(); 22 | 23 | var root = nodes.Select(n => n.id) 24 | .Except(nodes.SelectMany(n => n.childids)) 25 | .Single(); 26 | 27 | var dict = nodes.ToDictionary(n => n.id); 28 | int GetSum(string id) 29 | { 30 | var node = dict[id]; 31 | return node.weight + node.childids.Select(GetSum).Sum(); 32 | } 33 | 34 | int GetVariance(string id) 35 | { 36 | var node = dict[id]; 37 | var sums = node.childids.Select(s => new { childid = s, sum = GetSum(s), }).ToList(); 38 | var test = sums[0].sum; 39 | var variances = sums.Skip(1).Where(s => s.sum != test).ToList(); 40 | if (variances.Count == 0) 41 | return 0; 42 | var variantId = variances.Count == 1 ? variances[0].childid : sums[0].childid; 43 | var variance = GetVariance(variantId); 44 | if (variance != 0) 45 | return variance; 46 | var adjustment = variances.Count == 1 47 | ? sums[0].sum - variances[0].sum 48 | : variances[0].sum - sums[0].sum; 49 | return dict[variantId].weight + adjustment; 50 | } 51 | 52 | var partB = GetVariance(root); 53 | return (root, partB.ToString()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day08.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 08, CodeType.Original)] 4 | public partial class Day_08_Original : IPuzzle 5 | { 6 | [GeneratedRegex("^(?\\w+) (?inc|dec) (?-?\\d+) if (?\\w+) (?.{1,2}) (?-?\\d+)$", RegexOptions.ExplicitCapture)] 7 | private static partial Regex InstructionRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var regex = InstructionRegex(); 12 | 13 | var instructions = input.Lines 14 | .Select(l => regex.Match(l)) 15 | .Select(m => new 16 | { 17 | dest_reg = m.Groups["reg_a"].Value, 18 | adj_val = (m.Groups["adj_dir"].Value == "inc" ? +1 : -1) * 19 | Convert.ToInt32(m.Groups["adj_amt"].Value), 20 | comp_reg = m.Groups["reg_b"].Value, 21 | comp_type = m.Groups["comp"].Value, 22 | comp_value = Convert.ToInt32(m.Groups["val"].Value), 23 | }) 24 | .ToList(); 25 | 26 | var comparisons = new Dictionary>() 27 | { 28 | ["=="] = (a, b) => a == b, 29 | ["!="] = (a, b) => a != b, 30 | ["<="] = (a, b) => a <= b, 31 | [">="] = (a, b) => a >= b, 32 | ["<"] = (a, b) => a < b, 33 | [">"] = (a, b) => a > b, 34 | }; 35 | 36 | var registers = new Dictionary(); 37 | 38 | var maxValue = 0; 39 | foreach (var i in instructions) 40 | { 41 | var regValue = registers.GetValueOrDefault(i.comp_reg); 42 | if (comparisons[i.comp_type](regValue, i.comp_value)) 43 | { 44 | var destRegValue = registers.GetValueOrDefault(i.dest_reg); 45 | destRegValue += i.adj_val; 46 | maxValue = Math.Max(maxValue, destRegValue); 47 | registers[i.dest_reg] = destRegValue; 48 | } 49 | } 50 | 51 | return ( 52 | registers 53 | .OrderByDescending(kvp => kvp.Value) 54 | .First() 55 | .Value 56 | .ToString(), 57 | maxValue.ToString()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day09.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 09, CodeType.Fastest)] 4 | public class Day_09_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | // borrowed liberally from https://github.com/Voltara/advent2017-fast/blob/master/src/day09.c 9 | var span = input.Span; 10 | 11 | int score = 0, garbage = 0, depth = 0, g = 0; 12 | for (var i = 0; i < span.Length; i++) 13 | { 14 | var c = span[i]; 15 | switch (g | c) 16 | { 17 | case '}': score += depth; goto case '{'; 18 | case '{': depth += '|' - c; break; 19 | case '<': 20 | case '>' | 0x80: g ^= 0x80; break; 21 | case '!' | 0x80: i++; break; 22 | default: garbage += g != 0 ? 1 : 0; break; 23 | } 24 | } 25 | 26 | return ( 27 | score.ToString(), 28 | garbage.ToString()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day09.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 09, CodeType.Original)] 4 | public class Day_09_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var str = input.Text; 9 | 10 | var index = 0; 11 | char GetNextChar() => 12 | index == str.Length 13 | ? default 14 | : str[index++]; 15 | 16 | int ParseGarbage() 17 | { 18 | var cnt = 0; 19 | while (true) 20 | { 21 | switch (GetNextChar()) 22 | { 23 | case '!': 24 | // ignore next char 25 | _ = GetNextChar(); 26 | break; 27 | 28 | case '>': 29 | return cnt; 30 | 31 | default: 32 | cnt++; 33 | break; 34 | } 35 | } 36 | } 37 | 38 | (int score, int garbage) GetScore(int level = 1) 39 | { 40 | var x = (score: level, garbage: 0); 41 | 42 | while (true) 43 | { 44 | switch (GetNextChar()) 45 | { 46 | case '}': 47 | return x; 48 | 49 | case '<': 50 | x.garbage += ParseGarbage(); 51 | break; 52 | 53 | case '{': 54 | var y = GetScore(level + 1); 55 | x.score += y.score; 56 | x.garbage += y.garbage; 57 | break; 58 | 59 | default: 60 | break; 61 | } 62 | } 63 | } 64 | 65 | // drop first { 66 | _ = GetNextChar(); 67 | 68 | var (score, garbage) = GetScore(); 69 | return ( 70 | score.ToString(), 71 | garbage.ToString()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day10.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 10, CodeType.Original)] 4 | public class Day_10_Original : IPuzzle 5 | { 6 | private static readonly int[] s_keys = [17, 31, 73, 47, 23,]; 7 | 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var nums = input.Text 11 | .Split(',') 12 | .Select(i => Convert.ToInt32(i)) 13 | .ToList(); 14 | 15 | var listCount = 256; 16 | var list = Enumerable.Range(0, listCount).ToArray(); 17 | 18 | void KnotHashRound() 19 | { 20 | var position = 0; 21 | foreach (var i in nums.Select((len, skip) => (len, skip))) 22 | { 23 | var indexes = Enumerable.Range(position, i.len) 24 | .Select(idx => idx % listCount); 25 | 26 | var rev = indexes.Select(idx => list[idx]).Reverse().ToList(); 27 | foreach (var x in indexes.Zip(rev, (idx, val) => (idx, val))) 28 | { 29 | list[x.idx] = x.val; 30 | } 31 | 32 | position = (position + i.len + i.skip) % listCount; 33 | } 34 | } 35 | 36 | KnotHashRound(); 37 | var partA = list[0] * list[1]; 38 | 39 | list = Enumerable.Range(0, listCount).ToArray(); 40 | nums = input.Text 41 | .Trim() 42 | .ToCharArray() 43 | .Select(c => (int)c) 44 | .Concat(s_keys) 45 | .ToList(); 46 | 47 | nums = Enumerable.Repeat(nums, 64) 48 | .SelectMany(i => i) 49 | .ToList(); 50 | 51 | KnotHashRound(); 52 | 53 | var partB = 54 | string.Join( 55 | "", 56 | list.Select((val, idx) => new { val, g = idx / 16, }) 57 | .GroupBy(x => x.g) 58 | .Select(x => x.Aggregate(0, (a, v) => a ^ v.val)) 59 | .Select(x => x.ToString("X2").ToLower())); 60 | 61 | return (partA.ToString(), partB); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day12.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 12, CodeType.Original)] 4 | public partial class Day_12_Original : IPuzzle 5 | { 6 | [GeneratedRegex("^(?\\w+) \\<-\\> ((?\\w+)(,\\s*)?)*$", RegexOptions.ExplicitCapture)] 7 | private static partial Regex ProgramRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var regex = ProgramRegex(); 12 | var instructions = input.Lines 13 | .Select(l => regex.Match(l)) 14 | .Select(m => new int[] { Convert.ToInt32(m.Groups["prog_a"].Value), } 15 | .Concat(m.Groups["prog_b"].Captures.OfType().Select(c => Convert.ToInt32(c.Value))) 16 | .ToList()) 17 | .ToList(); 18 | 19 | var groups = new List>(); 20 | foreach (var m in instructions) 21 | { 22 | var existingL = groups.Where(g => m.Any(id => g.Contains(id))).ToList(); 23 | if (existingL.Count > 1) 24 | { 25 | var g = existingL[0]; 26 | foreach (var g2 in existingL.Skip(1)) 27 | { 28 | g.UnionWith(g2); 29 | _ = groups.Remove(g2); 30 | } 31 | 32 | existingL = [g]; 33 | } 34 | 35 | var existing = existingL.SingleOrDefault(); 36 | if (existing != null) 37 | existing.UnionWith(m); 38 | else 39 | groups.Add(new HashSet(m)); 40 | } 41 | 42 | var partA = groups.Single(g => g.Contains(0)).Count; 43 | var partB = groups.Count; 44 | 45 | return (partA.ToString(), partB.ToString()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day13.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 13, CodeType.Original)] 4 | public partial class Day_13_Original : IPuzzle 5 | { 6 | [GeneratedRegex("^(?\\d+): (?\\d+)$", RegexOptions.ExplicitCapture)] 7 | private static partial Regex TargetRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var regex = TargetRegex(); 12 | var depths = input.Lines 13 | .Select(l => regex.Match(l)) 14 | .Select(m => new 15 | { 16 | depth = Convert.ToInt32(m.Groups["depth"].Value), 17 | range = Convert.ToInt32(m.Groups["range"].Value), 18 | }) 19 | .ToList(); 20 | 21 | var partA = 22 | depths 23 | .Where(f => f.depth % ((f.range - 1) * 2) == 0) 24 | .Select(f => f.depth * f.range) 25 | .Sum(); 26 | 27 | var partB = 28 | Enumerable.Range(0, int.MaxValue) 29 | .Select(i => 30 | { 31 | var any = depths 32 | .Any(f => (f.depth + i) % ((f.range - 1) * 2) == 0); 33 | return (i, any); 34 | }) 35 | .First(x => !x.any) 36 | .i; 37 | 38 | return (partA.ToString(), partB.ToString()); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day15.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 15, CodeType.Original)] 4 | public partial class Day_15_Original : IPuzzle 5 | { 6 | [GeneratedRegex(@"^Generator (?\w) starts with (?\d+)$", RegexOptions.ExplicitCapture)] 7 | private static partial Regex GeneratorRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var regex = GeneratorRegex(); 12 | var generators = input.Lines 13 | .Select(l => regex.Match(l)) 14 | .ToDictionary( 15 | m => m.Groups["gen"].Value, 16 | m => (ulong)Convert.ToInt32(m.Groups["init"].Value)); 17 | 18 | var partA = 19 | Enumerable.Range(0, 40_000_000) 20 | .Scan( 21 | (a: generators["A"], b: generators["B"]), 22 | (state, _) => (state.a * 16807 % 2147483647, state.b * 48271 % 2147483647)) 23 | .Skip(1) 24 | .Count(s => (ushort)s.a == (ushort)s.b); 25 | 26 | var aGenerator = SuperEnumerable 27 | .Generate(generators["A"], a => a * 16807 % 2147483647) 28 | .Where(a => a % 4 == 0); 29 | var bGenerator = SuperEnumerable 30 | .Generate(generators["B"], b => b * 48271 % 2147483647) 31 | .Where(b => b % 8 == 0); 32 | 33 | var partB = 34 | aGenerator.Zip(bGenerator, (a, b) => (a, b)) 35 | .Take(5_000_000) 36 | .Count(s => (ushort)s.a == (ushort)s.b); 37 | 38 | return (partA.ToString(), partB.ToString()); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day17.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 17, CodeType.Fastest)] 4 | public class Day_17_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | // borrowed liberally from https://github.com/Voltara/advent2017-fast/blob/master/src/day17.c 9 | var span = input.Span; 10 | 11 | var key = 0; 12 | for (var i = 0; i < span.Length && span[i] >= '0'; i++) 13 | key = (key * 10) + span[i] - '0'; 14 | 15 | var position = 0; 16 | // Find the index of the 2017th insertion 17 | for (var i = 1; i <= 2017; i++) 18 | position = ((position + key) % i) + 1; 19 | 20 | // Reverse the simulation to find the value which follows 21 | int nextValue, nextPosition = (position + 1) % 2017; 22 | for (nextValue = 2017; position != nextPosition; nextValue--) 23 | { 24 | if (position < nextPosition) 25 | nextPosition--; 26 | if ((position -= key + 1) < 0) 27 | position += nextValue; 28 | } 29 | 30 | var partA = nextValue; 31 | 32 | var position1 = position = 0; 33 | // loop runs in O(log i) 34 | for (var i = 0; i < 50_000_000; position++) 35 | { 36 | if (position == 1) 37 | position1 = i; 38 | 39 | // use n * (n + 1) concept to skip processing every item in loop 40 | var skip = ((i - position) / key) + 1; 41 | position += (skip * (key + 1)) - 1; 42 | position %= i += skip; 43 | } 44 | 45 | var partB = position1; 46 | 47 | return (partA.ToString(), partB.ToString()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2017/day17.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2017; 2 | 3 | [Puzzle(2017, 17, CodeType.Original)] 4 | public class Day_17_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var key = Convert.ToInt32(input.Text); 9 | 10 | var list = new LinkedList(); 11 | var position = list.AddFirst(0); 12 | LinkedListNode Next(LinkedListNode node) => 13 | node.Next ?? list.First; 14 | 15 | for (var i = 1; i < 2018; i++) 16 | { 17 | for (var k = 0; k < key; k++) 18 | position = Next(position); 19 | position = list.AddAfter(position, i); 20 | } 21 | 22 | return ( 23 | Next(position).Value.ToString(), 24 | string.Empty); 25 | 26 | // TotalMicroseconds = 839_018_162; 27 | 28 | // this is *such* a bad algorithm. leaving my shame for posterity 29 | // Year 2017, Day 17, Type Original : 839,018,162 µs 30 | 31 | //var loop_count = 50_000_001; 32 | //for (int i = 2018; i < loop_count; i++) 33 | //{ 34 | // for (int k = 0; k < key; k++) 35 | // position = next(position); 36 | // position = list.AddAfter(position, i); 37 | //} 38 | 39 | //Dump('B', list.Find(0).Next.Value); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2018/AdventOfCode.Puzzles.2018.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | AdventOfCode.Puzzles._2018 4 | disable 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2018/day01.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2018; 2 | 3 | [Puzzle(2018, 01, CodeType.Original)] 4 | public class Day_01_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var changes = input.Lines 9 | .Select(l => Convert.ToInt32(l)) 10 | .ToList(); 11 | 12 | var part1 = changes.Sum().ToString(); 13 | 14 | var part2 = changes.Repeat() 15 | .Scan((acc, next) => acc + next) 16 | .Duplicates() 17 | .First() 18 | .ToString(); 19 | 20 | return (part1, part2); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2018/day02.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2018; 2 | 3 | [Puzzle(2018, 02, CodeType.Original)] 4 | public class Day_02_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var (twos, threes) = input.Lines 9 | .Select(id => 10 | { 11 | var chars = id 12 | .GroupBy(c => c) 13 | .Select(x => x.Count()) 14 | .ToList(); 15 | return (two: chars.Any(x => x == 2), three: chars.Any(x => x == 3)); 16 | }) 17 | .Aggregate((twos: 0, threes: 0), (acc, next) => 18 | (acc.twos + (next.two ? 1 : 0), acc.threes + (next.three ? 1 : 0))); 19 | 20 | var part1 = (twos * threes).ToString(); 21 | 22 | var part2 = 23 | new string( 24 | input.Lines 25 | .OrderBy(x => x) 26 | .Window(2) 27 | .Select(pair => ( 28 | pair, 29 | letters: pair[0].Zip(pair[1], (l, r) => (l, r)))) 30 | .Where(x => x.letters.Count(y => y.l != y.r) == 1) 31 | .SelectMany(x => x.letters.Where(y => y.l == y.r)) 32 | .Select(x => x.l) 33 | .ToArray()); 34 | 35 | return (part1, part2); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2018/day03.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2018; 2 | 3 | [Puzzle(2018, 03, CodeType.Original)] 4 | public partial class Day_03_Original : IPuzzle 5 | { 6 | [GeneratedRegex("^#(?\\d+)\\s+@\\s+(?\\d+),(?\\d+): (?\\d+)x(?\\d+)$", RegexOptions.ExplicitCapture)] 7 | private static partial Regex ClaimsRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var regex = ClaimsRegex(); 12 | 13 | static List GetOrAdd(Dictionary<(int x, int y), List> d, (int x, int y) key) => 14 | d.TryGetValue(key, out var l) ? l : (d[key] = []); 15 | 16 | var claims = input.Lines 17 | .Select(c => regex.Match(c)) 18 | .Select(m => new 19 | { 20 | id = Convert.ToInt32(m.Groups["id"].Value), 21 | el = Convert.ToInt32(m.Groups["el"].Value), 22 | et = Convert.ToInt32(m.Groups["et"].Value), 23 | wide = Convert.ToInt32(m.Groups["wide"].Value), 24 | tall = Convert.ToInt32(m.Groups["tall"].Value), 25 | }) 26 | .ToList(); 27 | 28 | var fabric = new Dictionary<(int x, int y), List>(); 29 | foreach (var c in claims) 30 | { 31 | foreach (var x in Enumerable.Range(c.el, c.wide)) 32 | { 33 | foreach (var y in Enumerable.Range(c.et, c.tall)) 34 | GetOrAdd(fabric, (x, y)).Add(c.id); 35 | } 36 | } 37 | 38 | var part1 = fabric.Count(kvp => kvp.Value.Count > 1).ToString(); 39 | 40 | var claimsCountById = claims 41 | .ToDictionary( 42 | g => g.id, 43 | g => g.wide * g.tall); 44 | 45 | var soloFabrics = fabric 46 | .Where(kvp => kvp.Value.Count == 1) 47 | .GroupBy(kvp => kvp.Value[0]) 48 | .Select(g => (id: g.Key, count: g.Count())) 49 | .ToList(); 50 | 51 | var part2 = soloFabrics 52 | .Single(f => f.count == claimsCountById[f.id]) 53 | .id 54 | .ToString(); 55 | 56 | return (part1, part2); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2018/day05.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2018; 2 | 3 | [Puzzle(2018, 05, CodeType.Original)] 4 | public class Day_05_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var poly = input.Text; 9 | 10 | static int GetReducedPolymerLength(string polymer) 11 | { 12 | var characters = polymer 13 | .Select(c => (c, isActive: true)) 14 | .ToArray(); 15 | 16 | for (var i = 1; i < characters.Length; i++) 17 | { 18 | var j = i - 1; 19 | while (j >= 0 && !characters[j].isActive) 20 | j--; 21 | if (j >= 0 && 22 | char.IsUpper(characters[i].c) != char.IsUpper(characters[j].c) 23 | && char.ToUpper(characters[i].c) == char.ToUpper(characters[j].c)) 24 | { 25 | characters[i].isActive = false; 26 | characters[j].isActive = false; 27 | } 28 | } 29 | 30 | return characters.Where(x => x.isActive).Count(); 31 | } 32 | 33 | var part1 = GetReducedPolymerLength(poly).ToString(); 34 | 35 | var part2 = Enumerable.Range(0, 26) 36 | .Select(i => (char)(i + 'a')) 37 | .Select(c => Regex.Replace(poly, c.ToString(), "", RegexOptions.IgnoreCase)) 38 | .Min(GetReducedPolymerLength) 39 | .ToString(); 40 | 41 | return (part1, part2); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2018/day06.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2018; 2 | 3 | [Puzzle(2018, 06, CodeType.Original)] 4 | public class Day_06_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var coordinates = input.Lines 9 | .Select(s => s.Split(", ", StringSplitOptions.None)) 10 | .Select(s => s.Select(i => Convert.ToInt32(i)).ToArray()) 11 | .Select(s => (x: s[0], y: s[1])) 12 | .ToArray(); 13 | 14 | var maxX = coordinates.Max(c => c.x); 15 | var maxY = coordinates.Max(c => c.y); 16 | 17 | var grid = new int[maxX + 2, maxY + 2]; 18 | var safeCount = 0; 19 | 20 | for (var x = 0; x <= maxX + 1; x++) 21 | { 22 | for (var y = 0; y <= maxY + 1; y++) 23 | { 24 | var distances = coordinates 25 | .Select((c, i) => (i, dist: Math.Abs(c.x - x) + Math.Abs(c.y - y))) 26 | .OrderBy(c => c.dist) 27 | .ToArray(); 28 | 29 | grid[x, y] = distances[1].dist != distances[0].dist 30 | ? distances[0].i 31 | : -1; 32 | 33 | if (distances.Sum(c => c.dist) < 10000) 34 | safeCount++; 35 | } 36 | } 37 | 38 | var excluded = new List(); 39 | var counts = Enumerable.Range(-1, coordinates.Length + 1).ToDictionary(i => i, _ => 0); 40 | 41 | for (var x = 0; x <= maxX + 1; x++) 42 | { 43 | for (var y = 0; y <= maxY + 1; y++) 44 | { 45 | if (x == 0 || y == 0 || 46 | x == maxX + 1 || y == maxY + 1) 47 | { 48 | excluded.Add(grid[x, y]); 49 | } 50 | 51 | counts[grid[x, y]] += 1; 52 | } 53 | } 54 | 55 | excluded = excluded.Distinct().ToList(); 56 | 57 | var part1 = counts 58 | .Where(kvp => !excluded.Contains(kvp.Key)) 59 | .OrderByDescending(kvp => kvp.Value) 60 | .First() 61 | .Value 62 | .ToString(); 63 | 64 | var part2 = safeCount.ToString(); 65 | return (part1, part2); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2018/day08.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2018; 2 | 3 | [Puzzle(2018, 08, CodeType.Original)] 4 | public class Day_08_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var data = input.Text 9 | .Trim() 10 | .Split() 11 | .Select(int.Parse) 12 | .ToList(); 13 | 14 | var index = 0; 15 | int GetMetadataValue() 16 | { 17 | var childNodes = data[index++]; 18 | var metadataNodes = data[index++]; 19 | 20 | return 21 | Enumerable.Range(0, childNodes) 22 | .Sum(_ => GetMetadataValue()) + 23 | Enumerable.Range(0, metadataNodes) 24 | .Sum(_ => data[index++]); 25 | } 26 | 27 | var part1 = GetMetadataValue().ToString(); 28 | 29 | index = 0; 30 | int GetNodeValue() 31 | { 32 | var childNodes = data[index++]; 33 | var metadataNodes = data[index++]; 34 | 35 | if (childNodes == 0) 36 | { 37 | return Enumerable.Range(0, metadataNodes) 38 | .Sum(_ => data[index++]); 39 | } 40 | 41 | var nodes = Enumerable.Range(0, childNodes) 42 | .Select(_ => GetNodeValue()) 43 | .ToList(); 44 | 45 | return Enumerable.Range(0, metadataNodes) 46 | .Select(_ => data[index++]) 47 | .Sum(i => i <= nodes.Count 48 | ? nodes[i - 1] 49 | : 0); 50 | } 51 | 52 | var part2 = GetNodeValue().ToString(); 53 | 54 | return (part1, part2); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2018/day09.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2018; 2 | 3 | [Puzzle(2018, 09, CodeType.Original)] 4 | public class Day_09_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var data = input.Text.Split(); 9 | var numPlayers = Convert.ToInt32(data[0]); 10 | var maxPoints = Convert.ToInt32(data[6]); 11 | 12 | var players = Enumerable.Range(0, numPlayers).Select(_ => 0L).ToArray(); 13 | var marbles = new LinkedList(); 14 | marbles.AddFirst(0); 15 | 16 | var current = marbles.First; 17 | 18 | LinkedListNode NextNode(LinkedListNode node) => 19 | node.Next ?? marbles.First; 20 | LinkedListNode PrevNode(LinkedListNode node) => 21 | node.Previous ?? marbles.Last; 22 | 23 | var i = 0; 24 | void DoLoop() 25 | { 26 | if (i % 23 == 0) 27 | { 28 | for (var j = 0; j < 7; j++) 29 | current = PrevNode(current); 30 | 31 | var player = i % numPlayers; 32 | players[player] += i + current.Next.Value; 33 | marbles.Remove(current.Next); 34 | } 35 | else 36 | { 37 | current = NextNode(current); 38 | current = NextNode(current); 39 | marbles.AddAfter(current, i); 40 | } 41 | } 42 | 43 | for (i = 1; i <= maxPoints; i++) 44 | DoLoop(); 45 | 46 | var part1 = players.Max().ToString(); 47 | 48 | maxPoints *= 100; 49 | for (; i <= maxPoints; i++) 50 | DoLoop(); 51 | 52 | var part2 = players.Max().ToString(); 53 | 54 | return (part1, part2); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2018/day11.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2018; 2 | 3 | [Puzzle(2018, 11, CodeType.Original)] 4 | public class Day_11_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var serialNumber = Convert.ToInt32(input.Text); 9 | var cells = new int[301, 301]; 10 | 11 | for (var x = 1; x <= 300; x++) 12 | { 13 | var rackId = x + 10; 14 | 15 | for (var y = 1; y <= 300; y++) 16 | { 17 | var powerLevel = ((rackId * y) + serialNumber) * rackId; 18 | cells[x, y] = ((powerLevel % 1000) / 100) - 5; 19 | } 20 | } 21 | 22 | var part1 = 23 | ( 24 | from x in Enumerable.Range(1, 298) 25 | from y in Enumerable.Range(1, 298) 26 | select (x, y, sum: ( 27 | from x2 in Enumerable.Range(x, 3) 28 | from y2 in Enumerable.Range(y, 3) 29 | select cells[x2, y2]).Sum()) 30 | ) 31 | .OrderByDescending(x => x.sum) 32 | .First() 33 | .ToString(); 34 | 35 | var part2 = 36 | ( 37 | from size in Enumerable.Range(1, 30) 38 | from x in Enumerable.Range(1, 301 - size) 39 | from y in Enumerable.Range(1, 301 - size) 40 | select (x, y, size, sum: ( 41 | from x2 in Enumerable.Range(x, size) 42 | from y2 in Enumerable.Range(y, size) 43 | select cells[x2, y2]).Sum()) 44 | ) 45 | .OrderByDescending(x => x.sum) 46 | .First() 47 | .ToString(); 48 | 49 | return (part1, part2); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2018/day20.original.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace AdventOfCode.Puzzles._2018; 4 | 5 | [Puzzle(2018, 20, CodeType.Original)] 6 | public partial class Day_20_Original : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var map = BuildMap(input.Span[1..^2]); 11 | 12 | var distances = SuperEnumerable.GetShortestPaths<(int x, int y), int>( 13 | (0, 0), 14 | (pos, cost) => map[pos].Select(q => (q, cost + 1))); 15 | 16 | var part1 = distances.Max(d => d.Value.cost); 17 | var part2 = distances.Count(d => d.Value.cost >= 1000); 18 | 19 | return (part1.ToString(), part2.ToString()); 20 | } 21 | 22 | private static ILookup<(int x, int y), (int x, int y)> BuildMap(ReadOnlySpan input) 23 | { 24 | var set = new HashSet<((int x, int y) from, (int x, int y) to)>(); 25 | 26 | var pos = (x: 0, y: 0); 27 | var stack = new Stack<(int x, int y)>(); 28 | foreach (var ch in input) 29 | { 30 | var prev = pos; 31 | switch (ch) 32 | { 33 | case (byte)'N': pos = (pos.x, pos.y + 1); break; 34 | case (byte)'S': pos = (pos.x, pos.y - 1); break; 35 | case (byte)'E': pos = (pos.x + 1, pos.y); break; 36 | case (byte)'W': pos = (pos.x - 1, pos.y); break; 37 | 38 | case (byte)'(': stack.Push(pos); continue; 39 | case (byte)'|': pos = stack.Peek(); continue; 40 | 41 | // shortcut because input is known to reset on `)`. 42 | // will fail if path continues after ')'. 43 | case (byte)')': pos = stack.Pop(); continue; 44 | 45 | default: throw new UnreachableException(); 46 | } 47 | 48 | _ = set.Add((pos, prev)); 49 | _ = set.Add((prev, pos)); 50 | } 51 | 52 | return set.ToLookup(x => x.from, x => x.to); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/AdventOfCode.Puzzles.2019.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | AdventOfCode.Puzzles._2019 4 | disable 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day01.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2019; 2 | 3 | [Puzzle(2019, 01, CodeType.Fastest)] 4 | public class Day_01_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | int part1Sum = 0, part2Sum = 0, n = 0; 9 | foreach (var c in input.Bytes) 10 | { 11 | if (c == '\n') 12 | { 13 | var fuel = (n / 3) - 2; 14 | part1Sum += fuel; 15 | while (fuel > 0) 16 | { 17 | part2Sum += fuel; 18 | fuel = (fuel / 3) - 2; 19 | } 20 | 21 | n = 0; 22 | } 23 | else if (c >= '0') 24 | { 25 | n = (n * 10) + c - '0'; 26 | } 27 | } 28 | 29 | return ( 30 | part1Sum.ToString(), 31 | part2Sum.ToString()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day01.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2019; 2 | 3 | [Puzzle(2019, 01, CodeType.Original)] 4 | public class Day_01_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | static IEnumerable FuelValues(int start) => 9 | SuperEnumerable.Generate(start, s => Math.Max((s / 3) - 2, 0)) 10 | .Skip(1) 11 | .TakeWhile(s => s != 0); 12 | 13 | var numbers = input.Lines 14 | .Select(s => Convert.ToInt32(s)) 15 | .ToList(); 16 | 17 | var part1 = numbers 18 | .Select(s => FuelValues(s).First()) 19 | .Sum() 20 | .ToString(); 21 | 22 | var part2 = numbers 23 | .Select(s => FuelValues(s).Sum()) 24 | .Sum() 25 | .ToString(); 26 | 27 | return (part1, part2); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day02.fastest.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace AdventOfCode.Puzzles._2019; 4 | 5 | [Puzzle(2019, 2, CodeType.Fastest)] 6 | public class Day_02_Fastest : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | Span nums = stackalloc int[input.Bytes.Length / 2]; 11 | int numCount = 0, n = 0; 12 | foreach (var c in input.Bytes) 13 | { 14 | if (c == ',') 15 | { 16 | nums[numCount++] = n; 17 | n = 0; 18 | } 19 | else if (c >= '0') 20 | { 21 | n = (n * 10) + c - '0'; 22 | } 23 | } 24 | 25 | nums = nums[..numCount]; 26 | Span copy = stackalloc int[numCount]; 27 | nums.CopyTo(copy); 28 | copy[1] = 12; 29 | copy[2] = 2; 30 | 31 | RunProgram(copy, numCount); 32 | var part1 = copy[0].ToString(); 33 | 34 | nums.CopyTo(copy); 35 | copy[1] = 0; 36 | copy[2] = 0; 37 | 38 | RunProgram(copy, numCount); 39 | var zero = copy[0]; 40 | 41 | nums.CopyTo(copy); 42 | copy[1] = 1; 43 | copy[2] = 0; 44 | 45 | RunProgram(copy, numCount); 46 | var one = copy[0]; 47 | 48 | var perNoun = one - zero; 49 | var noun = (19690720 - zero) / perNoun; 50 | var verb = 19690720 - (zero + (perNoun * noun)); 51 | 52 | var part2 = ((noun * 100) + verb).ToString(); 53 | return (part1, part2); 54 | } 55 | 56 | [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)] 57 | private static void RunProgram(Span instructions, int instructionCount) 58 | { 59 | var ip = 0; 60 | while (ip < instructionCount && instructions[ip] != 99) 61 | { 62 | var num1 = instructions[instructions[ip + 1]]; 63 | var num2 = instructions[instructions[ip + 2]]; 64 | var res = instructions[ip] switch 65 | { 66 | 1 => num1 + num2, 67 | 2 => num1 * num2, 68 | _ => 0, 69 | }; 70 | instructions[instructions[ip + 3]] = res; 71 | 72 | ip += 4; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day02.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2019; 2 | 3 | [Puzzle(2019, 02, CodeType.Original)] 4 | public class Day_02_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var instructions = input.Text 9 | .Split(',') 10 | .Select(long.Parse) 11 | .ToArray(); 12 | 13 | instructions[1] = 12; 14 | instructions[2] = 2; 15 | var pc = new IntCodeComputer(instructions); 16 | pc.RunProgram(); 17 | 18 | var part1 = pc.Memory[0].ToString(); 19 | 20 | for (var noun = 0; ; noun++) 21 | { 22 | for (var verb = 0; verb < 100; verb++) 23 | { 24 | instructions[1] = noun; 25 | instructions[2] = verb; 26 | 27 | pc = new IntCodeComputer(instructions, null, null); 28 | pc.RunProgram(); 29 | 30 | if (pc.Memory[0] == 19690720) 31 | { 32 | var part2 = ((noun * 100) + verb).ToString(); 33 | return (part1, part2); 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day03.original.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace AdventOfCode.Puzzles._2019; 4 | 5 | [Puzzle(2019, 03, CodeType.Original)] 6 | public class Day_03_Original : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var wirePaths = input.Lines 11 | .Select(w => w 12 | .Split(',') 13 | .Scan( 14 | new[] { (x: 0, y: 0, steps: 0), }, 15 | (pos, dir) => 16 | { 17 | var number = Convert.ToInt32(dir[1..]); 18 | var last = pos.Last(); 19 | return dir[0] switch 20 | { 21 | 'R' => Enumerable.Range(1, number).Select(x => (last.x + x, last.y, last.steps + x)).ToArray(), 22 | 'L' => Enumerable.Range(1, number).Select(x => (last.x - x, last.y, last.steps + x)).ToArray(), 23 | 'U' => Enumerable.Range(1, number).Select(y => (last.x, last.y + y, last.steps + y)).ToArray(), 24 | 'D' => Enumerable.Range(1, number).Select(y => (last.x, last.y - y, last.steps + y)).ToArray(), 25 | _ => throw new UnreachableException(), 26 | }; 27 | }) 28 | .SelectMany(x => x)) 29 | .ToList(); 30 | 31 | var hash = wirePaths[0] 32 | .ToLookup(pos => (pos.x, pos.y), pos => pos.steps) 33 | .ToDictionary(g => g.Key, g => g.Min()); 34 | 35 | var intersections = wirePaths[1] 36 | .Where(pos => pos != (0, 0, 0)) 37 | .Where(pos => hash.ContainsKey((pos.x, pos.y))) 38 | .ToList(); 39 | 40 | var part1 = intersections 41 | .Select(pos => Math.Abs(pos.x) + Math.Abs(pos.y)) 42 | .Min() 43 | .ToString(); 44 | 45 | var part2 = intersections 46 | .Select(pos => pos.steps + hash[(pos.x, pos.y)]) 47 | .Min() 48 | .ToString(); 49 | 50 | return (part1, part2); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day04.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2019; 2 | 3 | [Puzzle(2019, 04, CodeType.Original)] 4 | public class Day_04_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var range = input.Text.Split('-'); 9 | var min = Convert.ToInt32(range[0]); 10 | var max = Convert.ToInt32(range[1]); 11 | 12 | var part1 = Enumerable.Range(min, max - min + 1) 13 | .Where(i => i.ToString().Window(2).All(x => x[0] <= x[1])) 14 | .Where(i => i.ToString().GroupAdjacent(c => c).Any(g => g.Count() >= 2)) 15 | .Count() 16 | .ToString(); 17 | 18 | var part2 = Enumerable.Range(min, max - min + 1) 19 | .Where(i => i.ToString().Window(2).All(x => x[0] <= x[1])) 20 | .Where(i => i.ToString().GroupAdjacent(c => c).Any(g => g.Count() == 2)) 21 | .Count() 22 | .ToString(); 23 | 24 | return (part1, part2); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day05.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2019; 2 | 3 | [Puzzle(2019, 05, CodeType.Original)] 4 | public class Day_05_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var instructions = input.Text 9 | .Split(',') 10 | .Select(long.Parse) 11 | .ToArray(); 12 | 13 | var pc = new IntCodeComputer(instructions); 14 | pc.Inputs.Enqueue(1); 15 | pc.RunProgram(); 16 | var part1 = string.Empty; 17 | while (pc.Outputs.Count > 0) 18 | { 19 | var value = pc.Outputs.Dequeue(); 20 | if (value > 0) 21 | { 22 | part1 = value.ToString(); 23 | break; 24 | } 25 | } 26 | 27 | pc = new IntCodeComputer(instructions); 28 | pc.Inputs.Enqueue(5); 29 | pc.RunProgram(); 30 | var part2 = pc.Outputs.Dequeue().ToString(); 31 | return (part1, part2); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day06.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2019; 2 | 3 | [Puzzle(2019, 06, CodeType.Original)] 4 | public class Day_06_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var directOrbits = input.Lines 9 | .Select(s => s.Split(')')) 10 | .Select(s => (orbiter: s[1], orbited: s[0])) 11 | .ToList(); 12 | 13 | var lookup1 = directOrbits.ToDictionary(s => s.orbiter); 14 | var lookup2 = directOrbits.ToLookup(s => s.orbited); 15 | 16 | var part1 = directOrbits 17 | .Select(s => 18 | { 19 | var count = 1; 20 | while (true) 21 | { 22 | if (!lookup1.TryGetValue(s.orbited, out var o)) 23 | return count; 24 | count++; 25 | s = o; 26 | } 27 | }) 28 | .Sum() 29 | .ToString(); 30 | 31 | var visited = new Dictionary(); 32 | var (_, steps) = SuperEnumerable.TraverseBreadthFirst( 33 | (orbiter: lookup1["YOU"].orbited, steps: -1), 34 | o => 35 | { 36 | if (visited.ContainsKey(o.orbiter)) 37 | return []; 38 | 39 | visited[o.orbiter] = o.steps; 40 | 41 | var tmp = lookup2[o.orbiter] 42 | .Select(r => (r.orbiter, o.steps + 1)); 43 | if (lookup1.TryGetValue(o.orbiter, out var x)) 44 | tmp = tmp.Append((x.orbited, o.steps + 1)); 45 | return tmp; 46 | }) 47 | .FirstOrDefault(x => x.orbiter == "SAN"); 48 | var part2 = steps.ToString(); 49 | return (part1, part2); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day07.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2019; 2 | 3 | [Puzzle(2019, 07, CodeType.Original)] 4 | public class Day_07_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var instructions = input.Text 9 | .Split(',') 10 | .Select(long.Parse) 11 | .ToArray(); 12 | 13 | return ( 14 | DoPart(instructions, 0), 15 | DoPart(instructions, 5)); 16 | } 17 | 18 | private static string DoPart(long[] instructions, int start) => 19 | SuperEnumerable.Permutations(Enumerable.Range(start, 5)) 20 | .Select(arr => 21 | { 22 | var computers = Enumerable.Range(0, 5) 23 | .Select(i => 24 | { 25 | var pc = new IntCodeComputer(instructions); 26 | pc.Inputs.Enqueue(arr[i]); 27 | return pc; 28 | }) 29 | .ToList(); 30 | 31 | var signal = 0L; 32 | while (computers[^1].ProgramStatus != ProgramStatus.Completed) 33 | { 34 | foreach (var c in computers) 35 | { 36 | c.Inputs.Enqueue(signal); 37 | c.RunProgram(); 38 | signal = c.Outputs.Dequeue(); 39 | } 40 | } 41 | 42 | return signal; 43 | }) 44 | .Max() 45 | .ToString(); 46 | } 47 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day08.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2019; 2 | 3 | [Puzzle(2019, 08, CodeType.Original)] 4 | public class Day_08_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var layers = input.Bytes 9 | .SkipLast(1) 10 | .Batch(25 * 6) 11 | .Select(s => s.ToList()) 12 | .ToList(); 13 | 14 | var zeroLayer = layers 15 | .OrderBy(x => x.Count(z => z == '0')) 16 | .First(); 17 | 18 | var part1 = (zeroLayer.Count(z => z == '1') * zeroLayer.Count(z => z == '2')).ToString(); 19 | 20 | var part2 = string.Join(Environment.NewLine, 21 | Enumerable.Range(0, 25 * 6) 22 | .Select(p => Enumerable.Range(0, layers.Count) 23 | .Select(l => layers[l][p]) 24 | .Aggregate('2', (c, lc) => c != '2' ? c : lc == '0' ? ' ' : lc == '1' ? '█' : (char)lc)) 25 | .Batch(25) 26 | .Select(b => string.Join("", b))); 27 | 28 | return (part1, part2); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day09.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2019; 2 | 3 | [Puzzle(2019, 09, CodeType.Original)] 4 | public class Day_09_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var instructions = input.Text 9 | .Split(',') 10 | .Select(long.Parse) 11 | .ToArray(); 12 | 13 | var pc = new IntCodeComputer(instructions, size: 640 * 1024); 14 | pc.Inputs.Enqueue(1); 15 | pc.RunProgram(); 16 | var part1 = pc.Outputs.Dequeue().ToString(); 17 | 18 | pc = new IntCodeComputer(instructions, size: 640 * 1024); 19 | pc.Inputs.Enqueue(2); 20 | pc.RunProgram(); 21 | var part2 = pc.Outputs.Dequeue().ToString(); 22 | 23 | return (part1, part2); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day13.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2019; 2 | 3 | [Puzzle(2019, 13, CodeType.Original)] 4 | public class Day_13_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var instructions = input.Text 9 | .Split(',') 10 | .Select(long.Parse) 11 | .ToArray(); 12 | 13 | var screenOffset = 639; 14 | var screenHeight = Math.Max(instructions[604], instructions[605]); 15 | var screenSize = Math.Max(instructions[620], instructions[621]); 16 | var screenWidth = screenSize / screenHeight; 17 | 18 | var scoreOffset = instructions[632]; 19 | var magicA = Math.Max(instructions[612], instructions[613]); 20 | var magicB = Math.Max(instructions[616], instructions[617]); 21 | 22 | long numBlocks = 0, score = 0; 23 | for (var y = 0; y < screenHeight; y++) 24 | { 25 | for (var x = 0; x < screenWidth; x++) 26 | { 27 | if (instructions[screenOffset + (y * screenWidth) + x] == 2) 28 | { 29 | numBlocks++; 30 | score += instructions[scoreOffset + (((((x * screenHeight) + y) * magicA) + magicB) % screenSize)]; 31 | } 32 | } 33 | } 34 | 35 | return ( 36 | numBlocks.ToString(), 37 | score.ToString()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day16.original.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace AdventOfCode.Puzzles._2019; 4 | 5 | [Puzzle(2019, 16, CodeType.Original)] 6 | public class Day_16_Original : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var signal = input.Bytes.Where(i => i != '\n').Select(i => i - 0x30).ToArray(); 11 | 12 | var transforms = BuildTransforms(signal.Length); 13 | 14 | for (var phase = 0; phase < 100; phase++) 15 | { 16 | signal = Enumerable.Range(0, signal.Length) 17 | .Select(i => Math.Abs(signal.Zip(transforms[i], (s, t) => s * t).Sum()) % 10) 18 | .ToArray(); 19 | } 20 | 21 | var part1 = string.Join("", signal.Take(8)); 22 | 23 | signal = input.Bytes.Where(i => i != '\n').Select(i => i - 0x30).ToArray(); 24 | 25 | var phases = 100; 26 | var totalLength = signal.Length * 10000; 27 | var skip = Enumerable.Range(0, 7).Aggregate(0, (n, i) => (n * 10) + signal[i]); 28 | var remainder = totalLength - skip; 29 | 30 | // https://math.stackexchange.com/questions/234304/sum-of-the-sum-of-the-sum-of-the-first-n-natural-numbers 31 | var factors = Enumerable.Range(1, remainder - 1) 32 | .Scan(new BigInteger(1), (factor, i) => factor * (i + (phases - 1)) / i) 33 | .Select(i => (int)(i % 10)) 34 | .ToList(); 35 | 36 | var final = Enumerable.Range(0, 8) 37 | .Select(i => factors 38 | .SkipLast(i) 39 | .Select((f, j) => f * signal[(skip + i + j) % signal.Length]) 40 | .Sum() % 10) 41 | .ToArray(); 42 | 43 | var part2 = string.Join("", final); 44 | return (part1, part2); 45 | } 46 | 47 | private static readonly int[] s_basePattern = [0, 1, 0, -1]; 48 | private static int[][] BuildTransforms(int count) => 49 | Enumerable.Range(1, count) 50 | .Select(i => Enumerable.Range(0, count) 51 | .Select(j => s_basePattern[(j + 1) / i % 4]) 52 | .ToArray()) 53 | .ToArray(); 54 | } 55 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day17.original.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace AdventOfCode.Puzzles._2019; 4 | 5 | [Puzzle(2019, 17, CodeType.Original)] 6 | public class Day_17_Original : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var instructions = input.Text 11 | .Split(',') 12 | .Select(long.Parse) 13 | .ToArray(); 14 | 15 | var pc = new IntCodeComputer(instructions); 16 | pc.RunProgram(); 17 | var mapData = pc.Outputs.ToList(); 18 | 19 | var map = mapData 20 | .Batch(mapData.IndexOf('\n') + 1) 21 | .Select(r => r.Select(b => (char)b).ToArray()) 22 | .ToArray(); 23 | 24 | var intersections = Enumerable.Range(1, map.Length - 2) 25 | .SelectMany(y => Enumerable.Range(1, map[0].Length - 2) 26 | .Where(x => map[y][x] == '#') 27 | .Where(x => (map[y][x - 1] == '#') && x < map[0].Length && map[y][x + 1] == '#') 28 | .Where(x => (map[y - 1][x] == '#') && y < map.Length && map[y + 1][x] == '#') 29 | .Select(x => (x, y)) 30 | ) 31 | .ToList(); 32 | var part1 = intersections 33 | .Sum(p => p.x * p.y) 34 | .ToString(); 35 | 36 | instructions[0] = 2; 37 | pc = new IntCodeComputer(instructions); 38 | foreach (var b in Encoding.ASCII.GetBytes(Script).Where(b => b != '\r')) 39 | pc.Inputs.Enqueue(b); 40 | 41 | pc.RunProgram(); 42 | var part2 = pc.Outputs.Last().ToString(); 43 | 44 | return (part1, part2); 45 | } 46 | 47 | private const string Script = 48 | """ 49 | A,C,A,B,C,B,A,C,A,B 50 | R,6,L,10,R,8,R,8 51 | R,12,L,10,R,6,L,10 52 | R,12,L,8,L,10 53 | n 54 | """; 55 | } 56 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day19.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2019; 2 | 3 | [Puzzle(2019, 19, CodeType.Original)] 4 | public class Day_19_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var instructions = input.Text 9 | .Split(',') 10 | .Select(long.Parse) 11 | .ToArray(); 12 | 13 | var map = Enumerable.Range(0, 50) 14 | .Select(y => new long[50]) 15 | .ToArray(); 16 | 17 | int x = 0, y = 0; 18 | for (y = 0; y < 50; y++) 19 | { 20 | for (x = 0; x < 50; x++) 21 | map[y][x] = RunProgram(instructions, x, y); 22 | } 23 | 24 | var part1 = map 25 | .SelectMany(r => r) 26 | .Count(x => x == 1) 27 | .ToString(); 28 | 29 | y = Enumerable.Range(0, 50) 30 | .First(y => map[y][49] == 1); 31 | for (x = 101, y = 0; ; x++) 32 | { 33 | while (true) 34 | { 35 | if (RunProgram(instructions, x, y) == 1) 36 | break; 37 | y++; 38 | } 39 | 40 | if (RunProgram(instructions, x - 99, y + 99) == 1) 41 | { 42 | var part2 = (((x - 99) * 10000) + y).ToString(); 43 | return (part1, part2); 44 | } 45 | } 46 | } 47 | 48 | private static long RunProgram(long[] instructions, int x, int y) 49 | { 50 | var pc = new IntCodeComputer(instructions); 51 | pc.Inputs.Enqueue(x); 52 | pc.Inputs.Enqueue(y); 53 | pc.RunProgram(); 54 | return pc.Outputs.Dequeue(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2019/day21.original.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace AdventOfCode.Puzzles._2019; 4 | 5 | [Puzzle(2019, 21, CodeType.Original)] 6 | public class Day_21_Original : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var instructions = input.Text 11 | .Split(',') 12 | .Select(long.Parse) 13 | .ToArray(); 14 | 15 | return ( 16 | DoPart(instructions, SpringScriptA), 17 | DoPart(instructions, SpringScriptB)); 18 | } 19 | 20 | private const string SpringScriptA = 21 | """ 22 | NOT A J 23 | NOT B T 24 | OR T J 25 | NOT C T 26 | OR T J 27 | AND D J 28 | WALK 29 | """; 30 | 31 | private const string SpringScriptB = 32 | """ 33 | NOT A J 34 | NOT B T 35 | OR T J 36 | NOT C T 37 | OR T J 38 | AND D J 39 | NOT E T 40 | NOT T T 41 | OR H T 42 | AND T J 43 | RUN 44 | """; 45 | 46 | private static string DoPart(long[] instructions, string scriptCode) 47 | { 48 | var pc = new IntCodeComputer(instructions); 49 | foreach (var b in Encoding.ASCII.GetBytes(scriptCode).Where(b => b != '\r')) 50 | pc.Inputs.Enqueue(b); 51 | 52 | pc.RunProgram(); 53 | 54 | return pc.Outputs.Any(o => o > 255) 55 | ? pc.Outputs.Where(o => o > 255).First().ToString() 56 | : Encoding.ASCII.GetString( 57 | pc.Outputs.Select(b => (byte)b).ToArray()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/AdventOfCode.Puzzles.2020.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | AdventOfCode.Puzzles._2020 4 | disable 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day01.original.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace AdventOfCode.Puzzles._2020; 4 | 5 | [Puzzle(2020, 01, CodeType.Original)] 6 | public class Day_01_Original : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var numbers = input.Lines 11 | .Select(int.Parse) 12 | .ToArray(); 13 | 14 | var part1 = string.Empty; 15 | var bitArray = new BitArray(2020); 16 | foreach (var n in numbers) 17 | { 18 | if (bitArray[2020 - n]) 19 | part1 = ((2020 - n) * n).ToString(); 20 | bitArray[n] = true; 21 | } 22 | 23 | for (var xi = 0; ; xi++) 24 | { 25 | var x = numbers[xi]; 26 | for (var yi = xi + 1; yi < numbers.Length; yi++) 27 | { 28 | var y = numbers[yi]; 29 | var z = 2020 - x - y; 30 | if (z >= 0 && bitArray[z]) 31 | { 32 | var part2 = (x * y * z).ToString(); 33 | return (part1, part2); 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day02.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 2, CodeType.Original)] 4 | public class Day_02_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | int part1 = 0, part2 = 0; 9 | 10 | var span = input.Span; 11 | for (var i = 0; i < span.Length;) 12 | { 13 | var x = span[i..].AtoI(); 14 | var min = x.value; 15 | i += x.numChars + 1; 16 | 17 | x = span[i..].AtoI(); 18 | var max = x.value; 19 | i += x.numChars + 1; 20 | 21 | var chr = span[i]; 22 | i += 2; 23 | 24 | part2 += ((span[i + min] == chr) ^ (span[i + max] == chr)) ? 1 : 0; 25 | i++; 26 | 27 | var cnt = 0; 28 | for (; i < span.Length && span[i] != '\n'; i++) 29 | cnt += span[i] == chr ? 1 : 0; 30 | part1 += cnt >= min && cnt <= max ? 1 : 0; 31 | 32 | i++; 33 | } 34 | 35 | return ( 36 | part1.ToString(), 37 | part2.ToString()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day02.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 2, CodeType.Original)] 4 | public partial class Day_02_Original : IPuzzle 5 | { 6 | [GeneratedRegex("(?\\d+)-(?\\d+) (?\\w): (?\\w+)")] 7 | private static partial Regex PasswordRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var regex = PasswordRegex(); 12 | var matches = input.Lines 13 | .Select(l => regex.Match(l)) 14 | .Select(m => new 15 | { 16 | min = int.Parse(m.Groups["min"].Value), 17 | max = int.Parse(m.Groups["max"].Value), 18 | chr = m.Groups["char"].Value[0], 19 | pass = m.Groups["pass"].Value, 20 | }) 21 | .ToArray(); 22 | 23 | var part1 = matches 24 | .Where(x => x.pass.Where(c => c == x.chr).CountBetween(x.min, x.max)) 25 | .Count() 26 | .ToString(); 27 | 28 | var part2 = matches 29 | .Where(x => x.pass[x.min - 1] == x.chr ^ x.pass[x.max - 1] == x.chr) 30 | .Count() 31 | .ToString(); 32 | 33 | return (part1, part2); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day03.fastest.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace AdventOfCode.Puzzles._2020; 4 | 5 | [Puzzle(2020, 3, CodeType.Fastest)] 6 | public class Day_03_Fastest : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)] 11 | static long GetTreesOnSlope(byte[] input, int vx, int vy) 12 | { 13 | vx *= 32; 14 | 15 | var count = 0; 16 | for (int x = 0, y = 0; x < input.Length; x += vx, y += vy) 17 | count += input[x + (y % 31)] == '#' ? 1 : 0; 18 | return count; 19 | } 20 | 21 | var part1 = GetTreesOnSlope(input.Bytes, 1, 3).ToString(); 22 | 23 | var part2 = ( 24 | GetTreesOnSlope(input.Bytes, 1, 1) * 25 | GetTreesOnSlope(input.Bytes, 1, 3) * 26 | GetTreesOnSlope(input.Bytes, 1, 5) * 27 | GetTreesOnSlope(input.Bytes, 1, 7) * 28 | GetTreesOnSlope(input.Bytes, 2, 1)).ToString(); 29 | 30 | return (part1, part2); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day03.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 3, CodeType.Original)] 4 | public class Day_03_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var map = input.Lines 9 | .Select(s => s.Select(c => c == '#').ToArray()) 10 | .ToArray(); 11 | 12 | long GetTreesOnSlope(int vx, int vy) 13 | { 14 | var count = 0; 15 | for (int x = 0, y = 0; x < map.Length; x += vx, y += vy) 16 | { 17 | if (map[x][y % map[x].Length]) 18 | count++; 19 | } 20 | 21 | return count; 22 | } 23 | 24 | var part1 = GetTreesOnSlope(1, 3).ToString(); 25 | 26 | var part2 = ( 27 | GetTreesOnSlope(1, 1) * 28 | GetTreesOnSlope(1, 3) * 29 | GetTreesOnSlope(1, 5) * 30 | GetTreesOnSlope(1, 7) * 31 | GetTreesOnSlope(2, 1)).ToString(); 32 | 33 | return (part1, part2); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day04.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 4, CodeType.Original)] 4 | public class Day_04_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var required = new[] { "byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid", }; 9 | 10 | var passports = input.Lines 11 | .Segment(string.IsNullOrWhiteSpace) 12 | .Select(l => l 13 | .SelectMany(s => s.Split()) 14 | .Where(s => !string.IsNullOrWhiteSpace(s)) 15 | .Select(s => s.Split(':')) 16 | .ToDictionary( 17 | a => a[0], 18 | a => a[1] 19 | ) 20 | ) 21 | .ToList(); 22 | 23 | var part1 = passports 24 | .Count(p => required.All(r => p.ContainsKey(r))) 25 | .ToString(); 26 | 27 | #pragma warning disable SYSLIB1045 // Convert to 'GeneratedRegexAttribute'. 28 | var isValidPassports = passports 29 | .Select(p => ( 30 | p, 31 | isValid: 32 | required.All(r => p.ContainsKey(r)) 33 | && Convert.ToInt32(p["byr"]).Between(1920, 2002) 34 | && Convert.ToInt32(p["iyr"]).Between(2010, 2020) 35 | && Convert.ToInt32(p["eyr"]).Between(2020, 2030) 36 | && IsValidHeight(p["hgt"]) 37 | && Regex.IsMatch(p["hcl"], "^#[0-9a-f]{6}$") 38 | && p["ecl"] is "amb" or "blu" or "brn" or "gry" or "grn" or "hzl" or "oth" 39 | && Regex.IsMatch(p["pid"], "^\\d{9}$"))) 40 | .ToArray(); 41 | #pragma warning restore SYSLIB1045 // Convert to 'GeneratedRegexAttribute'. 42 | 43 | var part2 = isValidPassports.Where(x => x.isValid).Count().ToString(); 44 | 45 | static bool IsValidHeight(string s) => 46 | s.Length >= 4 47 | && (s[^2..] switch 48 | { 49 | "in" => Convert.ToInt32(s[..^2]).Between(59, 76), 50 | "cm" => Convert.ToInt32(s[..^2]).Between(150, 193), 51 | _ => false, 52 | }); 53 | 54 | return (part1, part2); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day05.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 5, CodeType.Original)] 4 | public class Day_05_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var ids = input.Lines 9 | .Select(s => s 10 | .Select(c => c is 'B' or 'R') 11 | .Select((b, idx) => (b, idx)) 12 | .Aggregate(0, (i, b) => i | ((b.b ? 1 : 0) << (s.Length - b.idx - 1)))) 13 | .OrderBy(x => x) 14 | .ToArray(); 15 | 16 | var part1 = ids.Last().ToString(); 17 | 18 | var potentials = ids 19 | .Window(2) 20 | .Where(a => a[1] - a[0] == 2) 21 | .ToArray(); 22 | 23 | var part2 = (potentials[0][0] + 1).ToString(); 24 | 25 | return (part1, part2); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day06.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 6, CodeType.Original)] 4 | public class Day_06_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var answerSets = input.Lines 9 | .Segment(string.IsNullOrWhiteSpace) 10 | .ToArray(); 11 | 12 | var part1 = answerSets 13 | .Sum(l => l.SelectMany(c => c) 14 | .Distinct() 15 | .Count()) 16 | .ToString(); 17 | 18 | var part2 = answerSets 19 | .Sum(l => 20 | { 21 | var numPeople = l.Where(s => !string.IsNullOrWhiteSpace(s)).Count(); 22 | return l.SelectMany(c => c) 23 | .GroupBy( 24 | c => c, 25 | (c, _) => _.Count()) 26 | .Count(x => x == numPeople); 27 | }) 28 | .ToString(); 29 | 30 | return (part1, part2); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day07.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 7, CodeType.Original)] 4 | public partial class Day_07_Original : IPuzzle 5 | { 6 | [GeneratedRegex("^(?[\\w ]+?) bags contain ((?no other bags)|((?[\\w ]+) bags?,? ?)+).$", RegexOptions.ExplicitCapture)] 7 | private static partial Regex BagsRegex(); 8 | 9 | [GeneratedRegex("^(\\d+) (.*)$")] 10 | private static partial Regex ContainedRegex(); 11 | 12 | public (string, string) Solve(PuzzleInput input) 13 | { 14 | var regex = BagsRegex(); 15 | 16 | var bagRules = input.Lines 17 | .Select(l => regex.Match(l)) 18 | .ToDictionary( 19 | m => m.Groups["container"].Value, 20 | m => m.Groups["contained"].Captures 21 | .Select(c => ContainedRegex().Match(c.Value)) 22 | .Select(m => ( 23 | count: Convert.ToInt32(m.Groups[1].Value), 24 | color: m.Groups[2].Value)) 25 | .ToArray()); 26 | 27 | var reverse = bagRules 28 | .SelectMany( 29 | kvp => kvp.Value, 30 | (kvp, c) => (from: kvp.Key, c.color)) 31 | .ToLookup(x => x.color, x => x.from); 32 | 33 | var visited = new HashSet(); 34 | void VisitReverse(string color) 35 | { 36 | if (visited.Contains(color)) 37 | return; 38 | visited.Add(color); 39 | foreach (var c in reverse[color]) 40 | VisitReverse(c); 41 | } 42 | 43 | VisitReverse("shiny gold"); 44 | var part1 = (visited.Count - 1).ToString(); 45 | 46 | int BagTotal(string color) => 47 | 1 + bagRules[color].Sum(x => x.count * BagTotal(x.color)); 48 | var part2 = (BagTotal("shiny gold") - 1).ToString(); 49 | 50 | return (part1, part2); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day09.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 9, CodeType.Fastest)] 4 | public class Day_09_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var span = input.Span; 9 | Span arr = stackalloc long[input.Bytes.Length / 8]; 10 | var maxIndex = 0; 11 | 12 | for (var i = 0; i < span.Length;) 13 | { 14 | var (x, y) = span[i..].AtoL(); 15 | arr[maxIndex++] = x; 16 | i += y + 1; // plus 1 to ignore next char 17 | } 18 | 19 | var invalidNumber = 0L; 20 | var part1 = string.Empty; 21 | for (var i = 25; i < maxIndex; i++) 22 | { 23 | for (var j = i - 25; j < i; j++) 24 | { 25 | for (var k = j + 1; k < i; k++) 26 | { 27 | if (arr[j] + arr[k] == arr[i]) 28 | goto found_match; 29 | } 30 | } 31 | 32 | part1 = (invalidNumber = arr[i]).ToString(); 33 | break; 34 | 35 | found_match: 36 | ; 37 | } 38 | 39 | int start = 0, end = 0; 40 | var sum = arr[0]; 41 | while (true) 42 | { 43 | if (sum == invalidNumber) 44 | break; 45 | else if (sum > invalidNumber) 46 | sum -= arr[start++]; 47 | else if (sum < invalidNumber) 48 | sum += arr[++end]; 49 | } 50 | 51 | long min = arr[start], max = arr[start]; 52 | for (var i = start + 1; i <= end; i++) 53 | { 54 | (min, max) = ( 55 | Math.Min(min, arr[i]), 56 | Math.Max(max, arr[i])); 57 | } 58 | 59 | var part2 = (min + max).ToString(); 60 | 61 | return (part1, part2); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day09.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 9, CodeType.Original)] 4 | public class Day_09_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var numbers = input.Lines 9 | .Select(long.Parse) 10 | .ToArray(); 11 | 12 | var invalidNumber = 0L; 13 | var queue = new Queue(numbers.Take(25)); 14 | var part1 = string.Empty; 15 | foreach (var n in numbers.Skip(25)) 16 | { 17 | if (queue.Subsets(2) 18 | .Where(l => l[0] != l[1]) 19 | .Any(l => l[0] + l[1] == n)) 20 | { 21 | queue.Dequeue(); 22 | queue.Enqueue(n); 23 | } 24 | else 25 | { 26 | part1 = (invalidNumber = n).ToString(); 27 | break; 28 | } 29 | } 30 | 31 | Array.Reverse(numbers); 32 | for (var i = 0; ; i++) 33 | { 34 | if (numbers[i] > invalidNumber) 35 | continue; 36 | 37 | var x = numbers[i]; 38 | var (sum, min, max) = (x, x, x); 39 | for (var j = i + 1; j < numbers.Length; j++) 40 | { 41 | sum += numbers[j]; 42 | min = Math.Min(min, numbers[j]); 43 | max = Math.Max(max, numbers[j]); 44 | if (sum == invalidNumber) 45 | { 46 | var part2 = (min + max).ToString(); 47 | return (part1, part2); 48 | } 49 | 50 | if (sum > invalidNumber) 51 | break; 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day10.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 10, CodeType.Original)] 4 | public class Day_10_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var numbers = input.Lines 9 | .Select(int.Parse) 10 | .OrderBy(x => x) 11 | .ToArray(); 12 | 13 | var differences = numbers 14 | .Prepend(0) 15 | .Append(numbers[^1] + 3) 16 | .Window(2) 17 | .Select(x => x[1] - x[0]) 18 | .ToArray(); 19 | 20 | var counts = differences 21 | .GroupBy(x => x, (d, _) => (diff: d, count: _.Count())) 22 | .ToArray(); 23 | 24 | var num1 = counts.Single(x => x.diff == 1).count; 25 | var num3 = counts.Single(x => x.diff == 3).count; 26 | 27 | var part1 = (num1 * num3).ToString(); 28 | 29 | var sequences = differences 30 | .Segment((cur, prev, _) => cur != prev) 31 | .Where(x => x[0] == 1) 32 | .Select(x => x.Count switch 33 | { 34 | 1 => 1, 35 | 2 => 2, 36 | 3 => 4, 37 | 4 => 7, 38 | 5 => 15, 39 | _ => throw new InvalidOperationException("??"), 40 | }) 41 | .Aggregate(1L, (agg, x) => agg * x); 42 | 43 | var part2 = sequences.ToString(); 44 | 45 | return (part1, part2); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day13.fastest.cs: -------------------------------------------------------------------------------- 1 | using static AdventOfCode.Common.Extensions.NumberExtensions; 2 | 3 | namespace AdventOfCode.Puzzles._2020; 4 | 5 | [Puzzle(2020, 13, CodeType.Fastest)] 6 | public class Day_13_Fastest : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var span = input.Span; 11 | var (myTime, i) = span.AtoI(); 12 | i++; 13 | 14 | var minTimeAfter = (id: 0, timeAfter: int.MaxValue); 15 | var busNumber = -1; 16 | long time = 1, increment = 1; 17 | while (i < span.Length) 18 | { 19 | busNumber++; 20 | if (span[i] == 'x') 21 | { 22 | i += 2; 23 | continue; 24 | } 25 | 26 | var (id, x) = span[i..].AtoI(); 27 | i += x + 1; 28 | 29 | var valueAfter = id - (myTime % id); 30 | if (valueAfter < minTimeAfter.timeAfter) 31 | minTimeAfter = (id, valueAfter); 32 | 33 | if (busNumber == 0) 34 | { 35 | time = increment = id; 36 | continue; 37 | } 38 | 39 | var modValue = id - (busNumber % id); 40 | while (time % id != modValue) 41 | time += increment; 42 | increment = Lcm(increment, id); 43 | } 44 | 45 | var part1 = (minTimeAfter.id * minTimeAfter.timeAfter).ToString(); 46 | var part2 = time.ToString(); 47 | return (part1, part2); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day13.original.cs: -------------------------------------------------------------------------------- 1 | using static AdventOfCode.Common.Extensions.NumberExtensions; 2 | 3 | namespace AdventOfCode.Puzzles._2020; 4 | 5 | [Puzzle(2020, 13, CodeType.Original)] 6 | public class Day_13_Original : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var lines = input.Lines; 11 | var times = lines[1].Split(','); 12 | 13 | var myEarliestTime = int.Parse(lines[0]); 14 | var part1 = times 15 | .Where(s => s is not "x") 16 | .Select(int.Parse) 17 | .Select(b => (bus: b, firstTimeAfter: (((myEarliestTime / b) + 1) * b) - myEarliestTime)) 18 | .PartialSortBy(1, x => x.firstTimeAfter) 19 | .Select(x => x.bus * x.firstTimeAfter) 20 | .First() 21 | .ToString(); 22 | 23 | var earliestTime = long.Parse(times[0]); 24 | var increment = earliestTime; 25 | for (var i = 1; i < times.Length; i++) 26 | { 27 | if (times[i] is "x") continue; 28 | 29 | var curTime = long.Parse(times[i]); 30 | var modValue = curTime - (i % curTime); 31 | while (earliestTime % curTime != modValue) 32 | earliestTime += increment; 33 | increment = Lcm(increment, curTime); 34 | } 35 | 36 | var part2 = earliestTime.ToString(); 37 | 38 | return (part1, part2); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day15.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 15, CodeType.Original)] 4 | public class Day_15_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var numbers = input.Text 9 | .Split(',') 10 | .Select(int.Parse) 11 | .ToArray(); 12 | 13 | var spokenTimes = new int[30_000_000]; 14 | Array.Fill(spokenTimes, -1); 15 | 16 | var i = 1; 17 | for (; i < numbers.Length + 1; i++) 18 | spokenTimes[numbers[i - 1]] = i; 19 | 20 | var curNumber = 0; 21 | for (; i < 2020; i++) 22 | { 23 | var prevTime = spokenTimes[curNumber]; 24 | spokenTimes[curNumber] = i; 25 | curNumber = prevTime != -1 ? i - prevTime : 0; 26 | } 27 | 28 | var part1 = curNumber.ToString(); 29 | 30 | for (; i < 30_000_000; i++) 31 | { 32 | var prevTime = spokenTimes[curNumber]; 33 | spokenTimes[curNumber] = i; 34 | curNumber = prevTime != -1 ? i - prevTime : 0; 35 | } 36 | 37 | var part2 = curNumber.ToString(); 38 | 39 | return (part1, part2); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day19.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 19, CodeType.Original)] 4 | public class Day_19_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var segments = input.Lines 9 | .Segment(string.IsNullOrWhiteSpace) 10 | .ToArray(); 11 | 12 | var rulesBase = segments[0] 13 | .Select(x => x.Split(':', StringSplitOptions.TrimEntries)) 14 | .ToDictionary(x => x[0], x => x[1]); 15 | var processed = new Dictionary(); 16 | 17 | string BuildRegex(string input) 18 | { 19 | if (processed.TryGetValue(input, out var s)) 20 | return s; 21 | 22 | var orig = rulesBase[input]; 23 | if (orig.StartsWith('\"')) 24 | return processed[input] = orig.Replace("\"", ""); 25 | 26 | if (!orig.Contains('|')) 27 | return processed[input] = string.Join("", orig.Split().Select(BuildRegex)); 28 | 29 | return processed[input] = 30 | "(" + 31 | string.Join("", orig.Split().Select(x => x == "|" ? x : BuildRegex(x))) + 32 | ")"; 33 | } 34 | 35 | var regex = new Regex("^" + BuildRegex("0") + "$"); 36 | var part1 = segments[1].Count(regex.IsMatch).ToString(); 37 | 38 | regex = new Regex($@"^({BuildRegex("42")})+(?{BuildRegex("42")})+(?{BuildRegex("31")})+(?(open)(?!))$"); 39 | var part2 = segments[1].Count(regex.IsMatch).ToString(); 40 | 41 | return (part1, part2); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day21.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 21, CodeType.Original)] 4 | public partial class Day_21_Original : IPuzzle 5 | { 6 | [GeneratedRegex("^((?\\w+) )+\\(contains ((?\\w+)(, )?)+\\)$", RegexOptions.ExplicitCapture)] 7 | private static partial Regex IngredientRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var regex = IngredientRegex(); 12 | var recipes = input.Lines 13 | .Select(l => regex.Match(l)) 14 | .Select(m => ( 15 | ingredients: m.Groups["ingredient"].Captures.Select(c => c.Value).ToList(), 16 | allergens: m.Groups["allergen"].Captures.Select(c => c.Value).ToList())) 17 | .ToList(); 18 | 19 | var allergenMap = new Dictionary(); 20 | var allergens = recipes.SelectMany(r => r.allergens).Distinct().ToList(); 21 | do 22 | { 23 | foreach (var a in allergens.ToList()) 24 | { 25 | var candidates = recipes.First(r => r.allergens.Contains(a)).ingredients.ToHashSet(); 26 | foreach (var r in recipes.Where(r => r.allergens.Contains(a)).Skip(1)) 27 | candidates.IntersectWith(r.ingredients); 28 | if (candidates.Count == 1) 29 | { 30 | var i = allergenMap[a] = candidates.Single(); 31 | foreach (var r in recipes) 32 | r.ingredients.Remove(i); 33 | allergens.Remove(a); 34 | } 35 | } 36 | } while (allergens.Count != 0); 37 | 38 | var part1 = recipes.SelectMany(r => r.ingredients).Count().ToString(); 39 | var part2 = string.Join(",", allergenMap.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value)); 40 | 41 | return (part1, part2); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2020/day25.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2020; 2 | 3 | [Puzzle(2020, 25, CodeType.Original)] 4 | public class Day_25_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var span = input.Span; 9 | var x = span.AtoI(); 10 | var key1 = x.value; 11 | 12 | span = span[(x.numChars + 1)..]; 13 | x = span.AtoI(); 14 | var key2 = x.value; 15 | 16 | var loopSize = GetLoopSize(key1); 17 | var eKey = GetKey(key2, loopSize); 18 | 19 | var part1 = eKey.ToString(); 20 | 21 | return (part1, string.Empty); 22 | } 23 | 24 | private static int GetLoopSize(int publicKey) 25 | { 26 | var sn = 7L; 27 | var value = 1L; 28 | var i = 0; 29 | 30 | while (value != publicKey) 31 | { 32 | value = (value * sn) % 20201227; 33 | i++; 34 | } 35 | 36 | return i; 37 | } 38 | 39 | private static int GetKey(int sn, int loopSize) 40 | { 41 | var value = 1L; 42 | for (var i = 0; i < loopSize; i++) 43 | value = (value * sn) % 20201227; 44 | 45 | return (int)value; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2021/AdventOfCode.Puzzles.2021.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | AdventOfCode.Puzzles._2021 4 | disable 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2021/day01.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2021; 2 | 3 | [Puzzle(2021, 1, CodeType.Fastest)] 4 | public class Day_01_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | Span numbers = stackalloc int[4]; 9 | numbers[0] = numbers[1] = numbers[2] = numbers[3] = int.MaxValue; 10 | int numA = 0, numB = 0; 11 | 12 | var span = input.Span; 13 | for (var i = 0; i < span.Length;) 14 | { 15 | var (value, numChars) = span[i..].AtoI(); 16 | i += numChars + 1; 17 | 18 | (numbers[0], numbers[1], numbers[2], numbers[3]) = 19 | (numbers[1], numbers[2], numbers[3], value); 20 | 21 | if (numbers[3] > numbers[2]) numA++; 22 | if (numbers[3] > numbers[0]) numB++; 23 | } 24 | 25 | return (numA.ToString(), numB.ToString()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2021/day01.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2021; 2 | 3 | [Puzzle(2021, 1, CodeType.Original)] 4 | public class Day_01_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var depths = input.Lines.Select(int.Parse); 9 | 10 | var part1 = depths.Window(2) 11 | .Where(x => x.Last() > x.First()) 12 | .Count() 13 | .ToString(); 14 | 15 | var part2 = depths.Window(4) 16 | .Where(x => x.Last() > x.First()) 17 | .Count() 18 | .ToString(); 19 | 20 | return (part1, part2); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2021/day02.original.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace AdventOfCode.Puzzles._2021; 4 | 5 | [Puzzle(2021, 2, CodeType.Original)] 6 | public partial class Day_02_Original : IPuzzle 7 | { 8 | [GeneratedRegex("(?forward|down|up) (?\\d+)")] 9 | private static partial Regex InstructionRegex(); 10 | 11 | public (string, string) Solve(PuzzleInput input) 12 | { 13 | // `(?) defines a group named xxx 14 | // (x|y|z) = match one of x, y, or z 15 | // \d+ = digits 16 | var regex = InstructionRegex(); 17 | var (depth, hor, aim) = input.Lines 18 | // use regex to collect the direction and number 19 | .Select(l => regex.Match(l)) 20 | // extract direction and integer conversion 21 | .Select(m => ( 22 | i: m.Groups["dir"].Value, 23 | n: Convert.ToInt32(m.Groups["n"].Value))) 24 | // start at (0, 0, 0), and update for each instruction 25 | .Aggregate((depth: 0L, hor: 0L, aim: 0L), (p, m) => 26 | m.i switch 27 | { 28 | // aim remains the same, forward movement based on n 29 | // depth based on aim 30 | "forward" => (p.depth + (p.aim * m.n), p.hor + m.n, p.aim), 31 | // depth and forward remain the same, adjust aim 32 | "down" => (p.depth, p.hor, p.aim + m.n), 33 | "up" => (p.depth, p.hor, p.aim - m.n), 34 | _ => throw new UnreachableException(), 35 | }); 36 | 37 | // aim == parta depth 38 | return ( 39 | (hor * aim).ToString(), 40 | (hor * depth).ToString()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2021/day06.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2021; 2 | 3 | [Puzzle(2021, 6, CodeType.Fastest)] 4 | public class Day_06_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | Span fish = stackalloc long[9]; 9 | 10 | var span = input.Span; 11 | for (var i = 0; i < span.Length;) 12 | { 13 | var (value, numChars) = span[i..].AtoI(); 14 | fish[value]++; 15 | i += numChars + 1; 16 | } 17 | 18 | // comment and idea copied from @ensce (https://www.reddit.com/r/adventofcode/comments/r9z49j/2021_day_6_solutions/hnfhi24/) 19 | // we will model a circular shift register, with an additional feedback: 20 | // 0123456 78 21 | // ┌──[ ]─<─(+)───[ ]──┐ 22 | // └──────>────────┴─────>────┘ 23 | 24 | for (var i = 0; i < 80; i++) 25 | fish[(i + 7) % 9] += fish[i % 9]; 26 | 27 | var totalFish = 0L; 28 | foreach (var f in fish) 29 | totalFish += f; 30 | var part1 = totalFish.ToString(); 31 | 32 | for (var i = 80; i < 256; i++) 33 | fish[(i + 7) % 9] += fish[i % 9]; 34 | 35 | totalFish = 0L; 36 | foreach (var f in fish) 37 | totalFish += f; 38 | var part2 = totalFish.ToString(); 39 | 40 | return (part1, part2); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2021/day06.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2021; 2 | 3 | [Puzzle(2021, 6, CodeType.Original)] 4 | public class Day_06_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var fish = input.Text 9 | .Split(',') 10 | .Select(int.Parse) 11 | // don't keep track of each fish individually 12 | // only keep track of how many of each age 13 | .GroupBy(x => x) 14 | .ToDictionary(g => g.Key, g => (long)g.Count()); 15 | 16 | // handles a single day cycle 17 | // each day decrements except for special cases 18 | static Dictionary DayCycle(Dictionary fish) => 19 | new() 20 | { 21 | // all of the 0 ages go to 8 as new fish 22 | [8] = fish.GetValueOrDefault(0), 23 | [7] = fish.GetValueOrDefault(8), 24 | // 0 ages go to 6, along with 7 ages 25 | [6] = fish.GetValueOrDefault(0) + fish.GetValueOrDefault(7), 26 | [5] = fish.GetValueOrDefault(6), 27 | [4] = fish.GetValueOrDefault(5), 28 | [3] = fish.GetValueOrDefault(4), 29 | [2] = fish.GetValueOrDefault(3), 30 | [1] = fish.GetValueOrDefault(2), 31 | [0] = fish.GetValueOrDefault(1), 32 | }; 33 | 34 | // run first 80 days 35 | for (var i = 0; i < 80; i++) 36 | fish = DayCycle(fish); 37 | var part1 = fish.Values.Sum().ToString(); 38 | 39 | // run 80-256 days 40 | for (var i = 80; i < 256; i++) 41 | fish = DayCycle(fish); 42 | var part2 = fish.Values.Sum().ToString(); 43 | 44 | return (part1, part2); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2021/day07.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2021; 2 | 3 | [Puzzle(2021, 7, CodeType.Original)] 4 | public class Day_2021_07_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var crabs = input.Text.Split(',') 9 | .Select(int.Parse) 10 | .ToList(); 11 | 12 | var part1 = 13 | Enumerable.Range(0, crabs.Max()) 14 | // for each position, get the sum of the 15 | // absolute difference between each crab 16 | // and that position 17 | .Select(c => crabs.Sum(c2 => Math.Abs(c2 - c))) 18 | // get the minimum total sum 19 | .Min() 20 | .ToString(); 21 | 22 | var part2 = 23 | // start with all possible positions 24 | Enumerable.Range(0, crabs.Max()) 25 | // for each position, get the sum of the fuel used 26 | .Select(c => crabs 27 | // absolute difference 28 | .Select(c2 => Math.Abs(c2 - c)) 29 | // fuel: sum of numbers 1..n 30 | .Sum(n => n * (n + 1) / 2)) 31 | // minimum total sum 32 | .Min() 33 | .ToString(); 34 | 35 | return (part1, part2); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2021/day09.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2021; 2 | 3 | [Puzzle(2021, 9, CodeType.Original)] 4 | public class Day_2021_09_Original : IPuzzle 5 | { 6 | public (string part1, string part2) Solve(PuzzleInput input) 7 | { 8 | var map = input.Bytes.GetMap(); 9 | 10 | // visit every point 11 | var lowPoints = map.GetMapPoints() 12 | // check if point is surrounded by points strictly greater 13 | .Where(z => z.p.GetCartesianNeighbors(map) 14 | .All(q => z.item < map[q.y][q.x])) 15 | // save this list, we'll need it later 16 | .ToList(); 17 | 18 | // take the value at each point, add one, and sum them 19 | var part1 = lowPoints 20 | .Select(p => p.item - (byte)'0' + 1) 21 | .Sum() 22 | .ToString(); 23 | 24 | var part2 = lowPoints 25 | // for each point, do a BFS search to flood-fill the basin 26 | .Select(p => 27 | { 28 | // keep track of how big the basin is 29 | var s = 0; 30 | 31 | // fill the basin 32 | map.FloodFill( 33 | p.p, 34 | (q, i) => i != '9', 35 | (_, _) => s++); 36 | 37 | // we know the size of the basin, return it 38 | return s; 39 | }) 40 | .ToList() 41 | // get the largest numbers 42 | .OrderByDescending(x => x) 43 | // take the top three of them 44 | .Take(3) 45 | // calculate the product of these numbers 46 | .Aggregate(1L, (a, b) => a * b) 47 | .ToString(); 48 | 49 | return (part1, part2); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2021/day12.original.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | 3 | namespace AdventOfCode.Puzzles._2021; 4 | 5 | [Puzzle(2021, 12, CodeType.Original)] 6 | public class Day_12_Original : IPuzzle 7 | { 8 | public (string part1, string part2) Solve(PuzzleInput input) 9 | { 10 | var edges = input.Lines 11 | .Select(l => l.Split('-')) 12 | .SelectMany(l => (new[] { (l[0], l[1]), (l[1], l[0]), })) 13 | .Where(x => x.Item2 != "start") 14 | .Where(x => x.Item1 != "end") 15 | .ToLookup(x => x.Item1, x => x.Item2); 16 | 17 | var paths = SuperEnumerable 18 | .TraverseDepthFirst( 19 | (cur: "start", visited: ImmutableHashSet.Empty), 20 | l => edges[l.cur] 21 | .Where(e => e == "end" 22 | || char.IsUpper(e[0]) 23 | || !l.visited.Contains(e)) 24 | .Select(e => (e, char.IsLower(e[0]) ? l.visited.Add(e) : l.visited))) 25 | .Where(e => e.cur == "end") 26 | .Count(); 27 | 28 | var part1 = paths.ToString(); 29 | 30 | paths = SuperEnumerable 31 | .TraverseDepthFirst( 32 | (cur: "start", visitedTwice: false, visited: ImmutableHashSet.Empty), 33 | l => edges[l.cur] 34 | .Where(e => e == "end" 35 | || !l.visitedTwice 36 | || char.IsUpper(e[0]) 37 | || !l.visited.Contains(e)) 38 | .Select(e => ( 39 | e, 40 | l.visitedTwice || (char.IsLower(e[0]) && l.visited.Contains(e)), 41 | char.IsLower(e[0]) ? l.visited.Add(e) : l.visited))) 42 | .Where(e => e.cur == "end") 43 | .Count(); 44 | 45 | var part2 = paths.ToString(); 46 | 47 | return (part1, part2); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2021/day15.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2021; 2 | 3 | [Puzzle(2021, 15, CodeType.Original)] 4 | public class Day_15_Original : IPuzzle 5 | { 6 | public (string part1, string part2) Solve(PuzzleInput input) 7 | { 8 | var map = input.Bytes.GetIntMap(); 9 | var sideLength = map.Length; 10 | var destination = (x: sideLength - 1, y: sideLength - 1); 11 | var risk = SuperEnumerable.GetShortestPathCost<(int, int), int>( 12 | (0, 0), 13 | (p, c) => p.GetCartesianNeighbors(map) 14 | .Select(q => (q, c + map[q.y][q.x])), 15 | destination); 16 | var part1 = risk.ToString(); 17 | 18 | destination = ((sideLength * 5) - 1, (sideLength * 5) - 1); 19 | int GetRisk(int x, int y) 20 | { 21 | var increase = (y / sideLength) + (x / sideLength); 22 | (x, y) = (x % sideLength, y % sideLength); 23 | return ((map[y][x] - 1 + increase) % 9) + 1; 24 | } 25 | 26 | risk = SuperEnumerable.GetShortestPathCost<(int, int), int>( 27 | (0, 0), 28 | (p, c) => p.GetCartesianNeighbors() 29 | .Where(q => q.y >= 0 && q.y <= destination.y 30 | && q.x >= 0 && q.x <= destination.x) 31 | .Select(q => (q, c + GetRisk(q.x, q.y))), 32 | destination); 33 | var part2 = risk.ToString(); 34 | 35 | return (part1, part2); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2021/day24.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2021; 2 | 3 | [Puzzle(2021, 24, CodeType.Original)] 4 | public class Day_24_Original : IPuzzle 5 | { 6 | public (string part1, string part2) Solve(PuzzleInput input) 7 | { 8 | var groups = input.Lines 9 | .Where(x => !string.IsNullOrWhiteSpace(x)) 10 | .Batch(18) 11 | .Select(g => 12 | { 13 | var a = Convert.ToInt32(g[4].Split()[^1]); 14 | var b = Convert.ToInt32(g[5].Split()[^1]); 15 | var c = Convert.ToInt32(g[15].Split()[^1]); 16 | return (a: a == 26, b, c); 17 | }) 18 | .Index(); 19 | 20 | var stack = new Stack<(int i, int c)>(); 21 | var highDigits = new int[14]; 22 | var lowDigits = new int[14]; 23 | foreach (var (i, (a, b, c)) in groups) 24 | { 25 | if (a) 26 | { 27 | var (j, d) = stack.Pop(); 28 | var diff = b + d; 29 | if (diff > 0) 30 | { 31 | highDigits[i] = 9; 32 | highDigits[j] = 9 - diff; 33 | 34 | lowDigits[j] = 1; 35 | lowDigits[i] = 1 + diff; 36 | } 37 | else 38 | { 39 | highDigits[j] = 9; 40 | highDigits[i] = 9 + diff; 41 | 42 | lowDigits[i] = 1; 43 | lowDigits[j] = 1 - diff; 44 | } 45 | } 46 | else 47 | { 48 | stack.Push((i, c)); 49 | } 50 | } 51 | 52 | var part1 = string.Join("", highDigits); 53 | var part2 = string.Join("", lowDigits); 54 | return (part1, part2); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2021/day25.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2021; 2 | 3 | [Puzzle(2021, 25, CodeType.Original)] 4 | public class Day_25_Original : IPuzzle 5 | { 6 | public (string part1, string part2) Solve(PuzzleInput input) 7 | { 8 | var map = input.Bytes.GetMap(); 9 | 10 | var yLength = map.Length; 11 | var xLength = map[0].Length; 12 | 13 | bool Step(byte[][] map) 14 | { 15 | var anyMove = false; 16 | 17 | var moveInstructions = Enumerable.Range(0, yLength) 18 | .SelectMany(y => Enumerable.Range(0, xLength) 19 | .Where(x => map[y][x] == '>' && map[y][(x + 1) % xLength] == '.') 20 | .Select(x => (x, y))) 21 | .ToList(); 22 | 23 | if (moveInstructions.Count != 0) 24 | anyMove = true; 25 | foreach (var (x, y) in moveInstructions) 26 | { 27 | (map[y][x], map[y][(x + 1) % xLength]) = 28 | ((byte)'.', (byte)'>'); 29 | } 30 | 31 | moveInstructions = Enumerable.Range(0, yLength) 32 | .SelectMany(y => Enumerable.Range(0, xLength) 33 | .Where(x => map[y][x] == 'v' && map[(y + 1) % yLength][x] == '.') 34 | .Select(x => (x, y))) 35 | .ToList(); 36 | 37 | if (moveInstructions.Count != 0) 38 | anyMove = true; 39 | foreach (var (x, y) in moveInstructions) 40 | { 41 | (map[y][x], map[(y + 1) % yLength][x]) = 42 | ((byte)'.', (byte)'v'); 43 | } 44 | 45 | return anyMove; 46 | } 47 | 48 | var cnt = 1; 49 | while (Step(map)) 50 | cnt++; 51 | 52 | return (cnt.ToString(), string.Empty); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/AdventOfCode.Puzzles.2022.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | AdventOfCode.Puzzles._2022 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day01.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 01, CodeType.Fastest)] 4 | public class Day_01_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | Span numbers = stackalloc int[3]; 9 | var elf = 0; 10 | 11 | var span = input.Span; 12 | for (var i = 0; i < span.Length;) 13 | { 14 | if (span[i] == '\n') 15 | { 16 | if (elf > numbers[2]) 17 | numbers[2] = elf; 18 | if (elf > numbers[1]) 19 | { 20 | (numbers[1], numbers[2]) = 21 | (elf, numbers[1]); 22 | } 23 | 24 | if (elf > numbers[0]) 25 | { 26 | (numbers[0], numbers[1]) = 27 | (elf, numbers[0]); 28 | } 29 | 30 | elf = 0; 31 | i++; 32 | } 33 | 34 | var (value, numChars) = span[i..].AtoI(); 35 | i += numChars + 1; 36 | 37 | elf += value; 38 | } 39 | 40 | return ( 41 | numbers[0].ToString(), 42 | (numbers[0] + numbers[1] + numbers[2]).ToString()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day01.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 01, CodeType.Original)] 4 | public class Day_01_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var elves = input.Lines 9 | .Split(string.Empty) 10 | .Select(g => g.Select(int.Parse).Sum()) 11 | .ToList(); 12 | 13 | var part1 = elves.Max().ToString(); 14 | var part2 = elves.PartialSort(3, OrderByDirection.Descending) 15 | .Sum() 16 | .ToString(); 17 | 18 | return (part1, part2); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day02.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 2, CodeType.Original)] 4 | public class Day_02_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var part1 = input.Lines 9 | .Select(l => _part1Map[l]) 10 | .Sum() 11 | .ToString(); 12 | 13 | var part2 = input.Lines 14 | .Select(l => _part2Map[l]) 15 | .Sum() 16 | .ToString(); 17 | 18 | return (part1, part2); 19 | } 20 | 21 | private readonly Dictionary _part1Map = new() 22 | { 23 | ["A X"] = 1 + 3, 24 | ["A Y"] = 2 + 6, 25 | ["A Z"] = 3 + 0, 26 | ["B X"] = 1 + 0, 27 | ["B Y"] = 2 + 3, 28 | ["B Z"] = 3 + 6, 29 | ["C X"] = 1 + 6, 30 | ["C Y"] = 2 + 0, 31 | ["C Z"] = 3 + 3, 32 | }; 33 | 34 | private readonly Dictionary _part2Map = new() 35 | { 36 | ["A X"] = 3 + 0, 37 | ["A Y"] = 1 + 3, 38 | ["A Z"] = 2 + 6, 39 | ["B X"] = 1 + 0, 40 | ["B Y"] = 2 + 3, 41 | ["B Z"] = 3 + 6, 42 | ["C X"] = 2 + 0, 43 | ["C Y"] = 3 + 3, 44 | ["C Z"] = 1 + 6, 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day03.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 3, CodeType.Fastest)] 4 | public class Day_03_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var part1 = Part1(input.Lines); 9 | var part2 = Part2(input.Lines); 10 | return (part1, part2); 11 | } 12 | 13 | private static int GetValue(char c) => 14 | c > 'Z' ? c - 'a' + 1 : c - 'A' + 27; 15 | 16 | private static string Part1(string[] input) 17 | { 18 | var sum = 0; 19 | foreach (var l in input) 20 | { 21 | var left = l.AsSpan()[..(l.Length / 2)]; 22 | var right = l.AsSpan()[(l.Length / 2)..]; 23 | 24 | foreach (var c in left) 25 | { 26 | if (right.Contains(c)) 27 | { 28 | sum += GetValue(c); 29 | break; 30 | } 31 | } 32 | } 33 | 34 | return sum.ToString(); 35 | } 36 | 37 | private static string Part2(string[] input) 38 | { 39 | var sum = 0; 40 | for (var i = 0; i < input.Length; i += 3) 41 | { 42 | foreach (var c in input[i]) 43 | { 44 | if (input[i + 1].Contains(c) 45 | && input[i + 2].Contains(c)) 46 | { 47 | sum += GetValue(c); 48 | break; 49 | } 50 | } 51 | } 52 | 53 | return sum.ToString(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day03.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 3, CodeType.Original)] 4 | public class Day_03_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var part1 = input.Lines 9 | .Select(x => x.Batch(x.Length / 2)) 10 | .Select(x => x.First().Intersect(x.Last())) 11 | .SelectMany(x => x) 12 | .Select(x => char.IsLower(x) ? x - 'a' + 1 : x - 'A' + 27) 13 | .Sum() 14 | .ToString(); 15 | 16 | var part2 = input.Lines 17 | .Batch(3) 18 | .Select(x => x[0].Intersect(x[1]).Intersect(x[2])) 19 | .SelectMany(x => x) 20 | .Select(x => char.IsLower(x) ? x - 'a' + 1 : x - 'A' + 27) 21 | .Sum() 22 | .ToString(); 23 | 24 | return (part1, part2); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day04.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 4, CodeType.Fastest)] 4 | public partial class Day_04_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var span = input.Span; 9 | 10 | var part1 = 0; 11 | var part2 = 0; 12 | for (var i = 0; i < span.Length;) 13 | { 14 | var (lo1, c) = span[i..].AtoI(); 15 | i += c + 1; 16 | (var hi1, c) = span[i..].AtoI(); 17 | i += c + 1; 18 | (var lo2, c) = span[i..].AtoI(); 19 | i += c + 1; 20 | (var hi2, c) = span[i..].AtoI(); 21 | i += c + 1; 22 | 23 | if ((lo1 <= lo2 && hi2 <= hi1) 24 | || (lo2 <= lo1 && hi1 <= hi2)) 25 | { 26 | part1++; 27 | } 28 | 29 | if ((hi1 >= lo2 && lo1 <= hi2) 30 | || (hi2 >= lo1 && lo2 <= hi1)) 31 | { 32 | part2++; 33 | } 34 | } 35 | 36 | return (part1.ToString(), part2.ToString()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day04.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 4, CodeType.Original)] 4 | public partial class Day_04_Original : IPuzzle 5 | { 6 | [GeneratedRegex("(\\d+)-(\\d+),(\\d+)-(\\d+)")] 7 | private static partial Regex RangeRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var regex = RangeRegex(); 12 | var ranges = input.Lines 13 | .Select(x => regex.Match(x)) 14 | .Select(m => ( 15 | int.Parse(m.Groups[1].Value), 16 | int.Parse(m.Groups[2].Value), 17 | int.Parse(m.Groups[3].Value), 18 | int.Parse(m.Groups[4].Value))) 19 | .Select(x => ( 20 | Enumerable.Range(x.Item1, x.Item2 - x.Item1 + 1).ToList(), 21 | Enumerable.Range(x.Item3, x.Item4 - x.Item3 + 1).ToList())) 22 | .ToList(); 23 | 24 | var part1 = ranges 25 | .Where(x => 26 | { 27 | var intersect = x.Item1.Intersect(x.Item2).ToList(); 28 | return intersect.CollectionEqual(x.Item1) 29 | || intersect.CollectionEqual(x.Item2); 30 | }) 31 | .Count() 32 | .ToString(); 33 | 34 | var part2 = ranges 35 | .Where(x => x.Item1.Intersect(x.Item2).Any()) 36 | .Count() 37 | .ToString(); 38 | 39 | return (part1, part2); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day05.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 5, CodeType.Original)] 4 | public partial class Day_05_Original : IPuzzle 5 | { 6 | [GeneratedRegex(@"move (\d+) from (\d+) to (\d+)")] 7 | private static partial Regex InstructionRegex(); 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var segments = input.Lines 12 | .Split(string.Empty); 13 | var mapLines = segments.First().ToList(); 14 | 15 | var instructions = input.Lines 16 | .SkipUntil(string.IsNullOrWhiteSpace) 17 | .Select(x => InstructionRegex().Match(x)) 18 | .Select(m => ( 19 | cnt: int.Parse(m.Groups[1].Value), 20 | from: int.Parse(m.Groups[2].Value), 21 | to: int.Parse(m.Groups[3].Value))) 22 | .ToList(); 23 | 24 | var stacks = BuildStacks(input.Lines); 25 | foreach (var (cnt, from, to) in instructions) 26 | { 27 | for (var i = 0; i < cnt; i++) 28 | stacks[to - 1].Push(stacks[from - 1].Pop()); 29 | } 30 | 31 | var part1 = string.Join("", stacks.Select(s => s.Peek())); 32 | 33 | stacks = BuildStacks(input.Lines); 34 | foreach (var (cnt, from, to) in instructions) 35 | { 36 | var tmp = new Stack(); 37 | for (var i = 0; i < cnt; i++) 38 | tmp.Push(stacks[from - 1].Pop()); 39 | for (var i = 0; i < cnt; i++) 40 | stacks[to - 1].Push(tmp.Pop()); 41 | } 42 | 43 | var part2 = string.Join("", stacks.Select(s => s.Peek())); 44 | 45 | return (part1, part2); 46 | } 47 | 48 | private static List> BuildStacks(string[] lines) => 49 | lines.TakeWhile(l => l[1] != '1') 50 | .Transpose() 51 | .Select(l => l.Reverse()) 52 | .Where(l => l.First() is >= 'A' and <= 'Z') 53 | .Select(l => new Stack(l.Where(c => c != ' '))) 54 | .ToList(); 55 | } 56 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day06.fastest.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace AdventOfCode.Puzzles._2022; 4 | 5 | [Puzzle(2022, 6, CodeType.Fastest)] 6 | public partial class Day_06_Fastest : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) => 9 | ( 10 | GetIndex(input.Bytes, 4).ToString(), 11 | GetIndex(input.Bytes, 14).ToString()); 12 | 13 | [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] 14 | private static int GetIndex(ReadOnlySpan bytes, int numDistinct) 15 | { 16 | for (var i = numDistinct - 1; ; i++) 17 | { 18 | for (var j = i - numDistinct + 1; j <= i; j++) 19 | { 20 | var c = bytes[j]; 21 | for (var k = j + 1; k <= i; k++) 22 | { 23 | if (c == bytes[k]) 24 | goto next; 25 | } 26 | } 27 | 28 | // if we make it through without goto, then we're done 29 | return i + 1; 30 | 31 | next: 32 | ; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day06.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 6, CodeType.Original)] 4 | public partial class Day_06_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) => 7 | ( 8 | GetIndex(input.Text, 4).ToString(), 9 | GetIndex(input.Text, 14).ToString() 10 | ); 11 | 12 | private static int GetIndex(string text, int numDistinct) => 13 | text.Window(numDistinct) 14 | .Index() 15 | .First(x => x.Item.Distinct().Count() == numDistinct) 16 | .Index + numDistinct; 17 | } 18 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day07.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 7, CodeType.Fastest)] 4 | public partial class Day_07_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | // 640k should be enough for anyone 9 | Span sizes = stackalloc int[256]; 10 | var sizesIndex = 0; 11 | Span stack = stackalloc int[16]; 12 | var stackIndex = 0; 13 | var currentSize = 0; 14 | 15 | foreach (var l in input.Lines) 16 | { 17 | if (l.Equals("$ cd ..", StringComparison.Ordinal)) 18 | { 19 | sizes[sizesIndex++] = currentSize; 20 | currentSize += stack[--stackIndex]; 21 | } 22 | else if (l.StartsWith("$ cd ", StringComparison.Ordinal)) 23 | { 24 | stack[stackIndex++] = currentSize; 25 | currentSize = 0; 26 | } 27 | else if (l[0] is >= '0' and <= '9') 28 | { 29 | var (size, _) = l.AsSpan().AtoI(); 30 | currentSize += size; 31 | } 32 | } 33 | 34 | while (stackIndex > 0) 35 | { 36 | sizes[sizesIndex++] = currentSize; 37 | currentSize += stack[--stackIndex]; 38 | } 39 | 40 | sizes[sizesIndex] = currentSize; 41 | sizes = sizes[..(sizesIndex + 1)]; 42 | 43 | var needed = sizes[sizesIndex] - 40_000_000; 44 | var part1 = 0; 45 | var part2 = int.MaxValue; 46 | foreach (var s in sizes) 47 | { 48 | if (s < 100_000) 49 | part1 += s; 50 | if (s >= needed && s < part2) 51 | part2 = s; 52 | } 53 | 54 | return (part1.ToString(), part2.ToString()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day07.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 7, CodeType.Original)] 4 | public partial class Day_07_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var cwd = string.Empty; 9 | var dirs = new Dictionary>(); 10 | 11 | foreach (var l in input.Lines) 12 | { 13 | if (l is "$ cd ..") 14 | { 15 | var previousSlash = cwd.LastIndexOf('/', cwd.Length - 2) + 1; 16 | var name = cwd[previousSlash..^1]; 17 | var parent = cwd[..previousSlash]; 18 | 19 | dirs[parent][name] = dirs[cwd].Values.Sum(); 20 | 21 | cwd = parent; 22 | } 23 | else if (l.StartsWith("$ cd ")) 24 | { 25 | var path = l[5..]; 26 | cwd = path.StartsWith('/') ? path : $"{cwd}{path}/"; 27 | } 28 | else if (l.StartsWith("dir")) 29 | { 30 | dirs.GetOrAdd(cwd, _ => [])[l[4..]] = 0; 31 | } 32 | else if (!l.StartsWith("$ ls")) 33 | { 34 | var size = int.Parse(l.Split()[0]); 35 | var name = l.Split()[1]; 36 | 37 | dirs.GetOrAdd(cwd, _ => [])[name] = size; 38 | } 39 | } 40 | 41 | while (cwd != "/") 42 | { 43 | var previousSlash = cwd.LastIndexOf('/', cwd.Length - 2) + 1; 44 | var name = cwd[previousSlash..^1]; 45 | var parent = cwd[..previousSlash]; 46 | 47 | dirs[parent][name] = dirs[cwd].Values.Sum(); 48 | 49 | cwd = parent; 50 | } 51 | 52 | var part1 = dirs.Values.Select(v => v.Values.Sum()) 53 | .Where(x => x <= 100_000) 54 | .Sum() 55 | .ToString(); 56 | 57 | var unused = 70_000_000 - dirs["/"].Values.Sum(); 58 | var needed = 30_000_000 - unused; 59 | 60 | var part2 = dirs.Values.Select(v => v.Values.Sum()) 61 | .Where(x => x >= needed) 62 | .Min() 63 | .ToString(); 64 | 65 | return (part1, part2); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day08.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 8, CodeType.Fastest)] 4 | public partial class Day_08_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var height = input.Lines.Length; 9 | var width = input.Lines[0].Length; 10 | 11 | var part1 = (height * 2) + (width * 2) - 4; 12 | var part2 = 0; 13 | 14 | for (int y = 1, ty = 0; y < height - 1; y++, ty += width - 2) 15 | { 16 | for (var x = 1; x < width - 1; x++) 17 | { 18 | var score = 1; 19 | var visible = false; 20 | var h = input.Lines[y][x]; 21 | 22 | // w 23 | var (v, j) = (true, 0); 24 | for (j = x - 1; v && j >= 0; j--) 25 | { 26 | if (input.Lines[y][j] >= h) 27 | v = false; 28 | } 29 | 30 | score *= x - j - 1; 31 | visible |= v; 32 | 33 | // e 34 | v = true; 35 | for (j = x + 1; v && j < width; j++) 36 | { 37 | if (input.Lines[y][j] >= h) 38 | v = false; 39 | } 40 | 41 | score *= j - x - 1; 42 | visible |= v; 43 | 44 | // n 45 | v = true; 46 | for (j = y - 1; v && j >= 0; j--) 47 | { 48 | if (input.Lines[j][x] >= h) 49 | v = false; 50 | } 51 | 52 | score *= y - j - 1; 53 | visible |= v; 54 | 55 | // s 56 | v = true; 57 | for (j = y + 1; v && j < height; j++) 58 | { 59 | if (input.Lines[j][x] >= h) 60 | v = false; 61 | } 62 | 63 | score *= j - y - 1; 64 | visible |= v; 65 | 66 | if (visible) 67 | part1++; 68 | if (score > part2) 69 | part2 = score; 70 | } 71 | } 72 | 73 | return (part1.ToString(), part2.ToString()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day09.fastest.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace AdventOfCode.Puzzles._2022; 4 | 5 | [Puzzle(2022, 9, CodeType.Fastest)] 6 | public partial class Day_09_Fastest : IPuzzle 7 | { 8 | public (string part1, string part2) Solve(PuzzleInput input) 9 | { 10 | Span snake = new Vector2[10]; 11 | var part1 = new HashSet(input.Bytes.Length / 4) { new(0, 0), }; 12 | var part2 = new HashSet(input.Bytes.Length / 4) { new(0, 0), }; 13 | 14 | foreach (var l in input.Lines) 15 | { 16 | var (cnt, _) = l.AsSpan()[2..].AtoI(); 17 | var dir = l[0] switch 18 | { 19 | 'U' => new Vector2(0, -1), 20 | 'D' => new Vector2(0, +1), 21 | 'L' => new Vector2(-1, 0), 22 | 'R' => new Vector2(+1, 0), 23 | _ => new Vector2(0, 0), 24 | }; 25 | 26 | for (var i = 0; i < cnt; i++) 27 | { 28 | snake[0] += dir; 29 | 30 | for (var j = 1; j < 10; j++) 31 | { 32 | var move = snake[j - 1] - snake[j]; 33 | 34 | move = move.Length() < 2 35 | ? Vector2.Zero 36 | : Vector2.Clamp(move, -Vector2.One, Vector2.One); 37 | 38 | if (move == Vector2.Zero) 39 | break; 40 | 41 | snake[j] += move; 42 | } 43 | 44 | part1.Add(snake[1]); 45 | part2.Add(snake[^1]); 46 | } 47 | } 48 | 49 | return (part1.Count.ToString(), part2.Count.ToString()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day10.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 10, CodeType.Fastest)] 4 | public partial class Day_10_Fastest : IPuzzle 5 | { 6 | public (string part1, string part2) Solve(PuzzleInput input) 7 | { 8 | var sum = 0; 9 | var reg = 1; 10 | var add = 0; 11 | var inst = 0; 12 | var delay = 1; 13 | 14 | Span screen = stackalloc char[(41 * 6) - 1]; 15 | for (var j = 40; j < screen.Length; j += 41) 16 | screen[j] = '\n'; 17 | 18 | for (int y = 0, j = 0; j < screen.Length; y += 40, j += 41) 19 | { 20 | for (var x = 0; x < 40; x++) 21 | { 22 | if (--delay == 0) 23 | { 24 | reg += add; 25 | var l = input.Lines[inst++]; 26 | if (!l.Equals("noop", StringComparison.OrdinalIgnoreCase)) 27 | { 28 | delay = 2; 29 | (add, _) = l.AsSpan()[5..].AtoI(); 30 | } 31 | else 32 | { 33 | (delay, add) = (1, 0); 34 | } 35 | } 36 | 37 | if (x == 19) 38 | sum += reg * (y + x + 1); 39 | 40 | var c = Math.Abs(x - reg) <= 1 ? '█' : ' '; 41 | screen[j + x] = c; 42 | } 43 | } 44 | 45 | return (sum.ToString(), new string(screen)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day10.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 10, CodeType.Original)] 4 | public partial class Day_10_Original : IPuzzle 5 | { 6 | public (string part1, string part2) Solve(PuzzleInput input) 7 | { 8 | var x = 1; 9 | var cycle = 0; 10 | var sum = 0; 11 | 12 | foreach (var l in input.Lines) 13 | { 14 | if (l == "noop") 15 | { 16 | cycle++; 17 | if (cycle % 40 == 20) 18 | sum += x * cycle; 19 | } 20 | else 21 | { 22 | cycle += 2; 23 | if (cycle % 40 == 20) 24 | { 25 | sum += x * cycle; 26 | } 27 | else if (cycle % 40 == 21) 28 | { 29 | sum += x * (cycle - 1); 30 | } 31 | 32 | var (amt, _) = l.AsSpan()[5..].AtoI(); 33 | x += amt; 34 | } 35 | 36 | if (cycle > 220) break; 37 | } 38 | 39 | var screen = new[] 40 | { 41 | new char[40], 42 | new char[40], 43 | new char[40], 44 | new char[40], 45 | new char[40], 46 | new char[40], 47 | }; 48 | var e = input.Lines.GetEnumerator(); 49 | e.MoveNext(); 50 | var inAdd = false; 51 | for (cycle = 0, x = 1; cycle < 240; cycle++) 52 | { 53 | var c = Math.Abs((cycle % 40) - x) <= 1 ? '█' : ' '; 54 | screen[cycle / 40][cycle % 40] = c; 55 | 56 | if (e.Current.ToString() == "noop") 57 | { 58 | e.MoveNext(); 59 | } 60 | else if (!inAdd) 61 | { 62 | inAdd = true; 63 | } 64 | else 65 | { 66 | inAdd = false; 67 | x += int.Parse(e.Current.ToString()![5..]); 68 | e.MoveNext(); 69 | } 70 | } 71 | 72 | var part2 = string.Join(Environment.NewLine, 73 | screen.Select(l => string.Join("", l))); 74 | return (sum.ToString(), part2); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day12.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2022; 2 | 3 | [Puzzle(2022, 12, CodeType.Original)] 4 | public partial class Day_12_Original : IPuzzle 5 | { 6 | public (string part1, string part2) Solve(PuzzleInput input) 7 | { 8 | var map = input.Bytes.GetMap(); 9 | 10 | var start = (x: 0, y: 0); 11 | var end = start; 12 | for (var y = 0; y < map.Length; y++) 13 | { 14 | for (var x = 0; x < map[y].Length; x++) 15 | { 16 | if (map[y][x] == (byte)'S') 17 | { 18 | start = (x, y); 19 | } 20 | else if (map[y][x] == (byte)'E') 21 | { 22 | end = (x, y); 23 | } 24 | } 25 | } 26 | 27 | map[start.y][start.x] = (byte)'a'; 28 | map[end.y][end.x] = (byte)'z'; 29 | 30 | var costs = SuperEnumerable.GetShortestPaths<(int x, int y), int>( 31 | end, 32 | (p, c) => p.GetCartesianNeighbors(map) 33 | .Where(q => map[p.y][p.x] - map[q.y][q.x] <= 1) 34 | .Select(q => (q, c + 1))); 35 | 36 | var part1 = costs[start].cost.ToString(); 37 | 38 | var part2 = map.GetMapPoints() 39 | .Where(x => x.item == (byte)'a') 40 | .Select(x => costs.TryGetValue(x.p, out var cost) ? cost.cost : int.MaxValue) 41 | .Min() 42 | .ToString(); 43 | 44 | return (part1, part2); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day13.original.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Text.Json; 3 | using System.Text.Json.Nodes; 4 | 5 | namespace AdventOfCode.Puzzles._2022; 6 | 7 | [Puzzle(2022, 13, CodeType.Original)] 8 | public partial class Day_13_Original : IPuzzle 9 | { 10 | public (string part1, string part2) Solve(PuzzleInput input) 11 | { 12 | var packets = input.Lines 13 | .Where(x => !string.IsNullOrEmpty(x)) 14 | .Select(l => JsonSerializer.Deserialize(l)) 15 | .ToList(); 16 | 17 | var part1 = packets 18 | .Batch(2) 19 | .Index() 20 | .Where(x => CompareItem(x.Item[0], x.Item[1]) < 0) 21 | .Select(x => x.Index + 1) 22 | .Sum() 23 | .ToString(); 24 | 25 | var part2 = new[] { (JsonValue)2, (JsonValue)6, } 26 | .Select((s, i) => packets.Count(p => CompareItem(p, s) < 0) + 1 + i) 27 | .Aggregate(1, (a, b) => a * b) 28 | .ToString(); 29 | 30 | return (part1, part2); 31 | } 32 | 33 | private int CompareItem(JsonNode? left, JsonNode? right) => 34 | (left, right) switch 35 | { 36 | (JsonNode l, null) => +1, 37 | (null, JsonNode r) => -1, 38 | (JsonValue l, JsonValue r) => 39 | Comparer.Default.Compare(l.GetValue(), r.GetValue()), 40 | (JsonValue l, JsonArray r) => 41 | CompareItem(new JsonArray(l.GetValue()), r), 42 | (JsonArray l, JsonValue r) => 43 | CompareItem(l, new JsonArray(r.GetValue())), 44 | (JsonArray l, JsonArray r) => 45 | l.ZipLongest(r, CompareItem) 46 | .SkipWhile(x => x == 0) 47 | .FirstOrDefault(), 48 | _ => throw new UnreachableException(), 49 | }; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2022/day25.original.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace AdventOfCode.Puzzles._2022; 4 | 5 | [Puzzle(2022, 25, CodeType.Original)] 6 | public class Day_25_Original : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | static long ParseSnafu(string snafu) 11 | { 12 | var value = 0L; 13 | var scale = 1L; 14 | foreach (var c in snafu.Reverse()) 15 | { 16 | var n = c switch 17 | { 18 | '2' => 2, 19 | '1' => 1, 20 | '0' => 0, 21 | '-' => -1, 22 | '=' => -2, 23 | _ => throw new UnreachableException(), 24 | }; 25 | 26 | value += scale * n; 27 | scale *= 5; 28 | } 29 | 30 | return value; 31 | } 32 | 33 | static string ToSnafu(long value) 34 | { 35 | var digits = new char[32]; 36 | var i = 0; 37 | for (; value != 0; i++) 38 | { 39 | var rem = (int)(value % 5); 40 | value /= 5; 41 | 42 | if (rem == 3) 43 | { 44 | digits[i] = '='; 45 | value += 1; 46 | } 47 | else if (rem == 4) 48 | { 49 | digits[i] = '-'; 50 | value += 1; 51 | } 52 | else 53 | { 54 | digits[i] = (char)(rem + '0'); 55 | } 56 | } 57 | 58 | return string.Join("", digits.Reverse().Where(d => d != 0)); 59 | } 60 | 61 | var sum = input.Lines 62 | .Select(ParseSnafu) 63 | .Sum(); 64 | var part1 = ToSnafu(sum); 65 | var part2 = string.Empty; 66 | return (part1, part2); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/AdventOfCode.Puzzles.2023.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | AdventOfCode.Puzzles._2023 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day01.original.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace AdventOfCode.Puzzles._2023; 4 | 5 | [Puzzle(2023, 01, CodeType.Original)] 6 | public partial class Day_01_Original : IPuzzle 7 | { 8 | [GeneratedRegex("\\d")] 9 | private static partial Regex DigitRegex(); 10 | 11 | [GeneratedRegex("\\d|one|two|three|four|five|six|seven|eight|nine")] 12 | private static partial Regex DigitStringRegexLeft(); 13 | 14 | [GeneratedRegex("\\d|one|two|three|four|five|six|seven|eight|nine", RegexOptions.RightToLeft)] 15 | private static partial Regex DigitStringRegexRight(); 16 | 17 | public (string, string) Solve(PuzzleInput input) 18 | { 19 | var regex = DigitRegex(); 20 | 21 | var part1 = input.Lines 22 | .Select(l => regex.Matches(l)) 23 | .Select(m => 24 | (int.Parse(m.First().Value) * 10) 25 | + int.Parse(m.Last().Value)) 26 | .Sum() 27 | .ToString(); 28 | 29 | var regex1 = DigitStringRegexLeft(); 30 | var regex2 = DigitStringRegexRight(); 31 | 32 | static int ParseNumber(string s) => 33 | char.IsDigit(s[0]) ? s[0] - '0' : 34 | s switch 35 | { 36 | "one" => 1, 37 | "two" => 2, 38 | "three" => 3, 39 | "four" => 4, 40 | "five" => 5, 41 | "six" => 6, 42 | "seven" => 7, 43 | "eight" => 8, 44 | "nine" => 9, 45 | _ => throw new UnreachableException(), 46 | }; 47 | 48 | var part2 = input.Lines 49 | .Select(l => 50 | (ParseNumber(DigitStringRegexLeft().Match(l).Value) * 10) 51 | + ParseNumber(DigitStringRegexRight().Match(l).Value)) 52 | .Sum() 53 | .ToString(); 54 | 55 | return (part1, part2); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day02.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2023; 2 | 3 | [Puzzle(2023, 02, CodeType.Fastest)] 4 | public partial class Day_02_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var part1 = 0; 9 | var part2 = 0; 10 | var span = input.Span; 11 | 12 | var id = 0; 13 | while (span.Length > 0) 14 | { 15 | id++; 16 | span = span[(id switch { >= 100 => 10, >= 10 => 9, _ => 8, })..]; 17 | 18 | var maxRed = 0; 19 | var maxGreen = 0; 20 | var maxBlue = 0; 21 | 22 | while (true) 23 | { 24 | var (num, n) = span.AtoI(); 25 | span = span[(n + 1)..]; 26 | 27 | switch (span[0]) 28 | { 29 | case (byte)'r': 30 | { 31 | maxRed = Math.Max(maxRed, num); 32 | span = span[3..]; 33 | break; 34 | } 35 | case (byte)'b': 36 | { 37 | maxBlue = Math.Max(maxBlue, num); 38 | span = span[4..]; 39 | break; 40 | } 41 | case (byte)'g': 42 | { 43 | maxGreen = Math.Max(maxGreen, num); 44 | span = span[5..]; 45 | break; 46 | } 47 | default: 48 | break; 49 | } 50 | 51 | if (span[0] == (byte)'\n') 52 | break; 53 | 54 | span = span[2..]; 55 | } 56 | 57 | span = span[1..]; 58 | 59 | if (maxRed <= 12 60 | && maxGreen <= 13 61 | && maxBlue <= 14) 62 | { 63 | part1 += id; 64 | } 65 | 66 | part2 += maxRed * maxGreen * maxBlue; 67 | } 68 | 69 | return (part1.ToString(), part2.ToString()); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day02.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2023; 2 | 3 | [Puzzle(2023, 02, CodeType.Original)] 4 | public partial class Day_02_Original : IPuzzle 5 | { 6 | [GeneratedRegex(@"^Game (?\d+): ((?[^;]*)(; )?)*$", RegexOptions.ExplicitCapture)] 7 | private static partial Regex GameRegex(); 8 | [GeneratedRegex(@"(\d+) (\w+)")] 9 | private static partial Regex SetRegex(); 10 | 11 | public (string, string) Solve(PuzzleInput input) 12 | { 13 | var games = input.Lines 14 | .Select(l => GameRegex().Match(l)) 15 | .Select(m => new 16 | { 17 | id = int.Parse(m.Groups["gameid"].Value), 18 | sets = m.Groups["sets"] 19 | .Captures 20 | .Select(c => SetRegex().Matches(c.Value) 21 | .OfType() 22 | .Select(m => (num: int.Parse(m.Groups[1].Value), Color: m.Groups[2].Value)) 23 | .GroupBy( 24 | x => x.Color, 25 | (k, g) => (color: k, num: g.Sum(x => x.num))) 26 | .ToDictionary(x => x.color, x => x.num)) 27 | .ToList(), 28 | }) 29 | .ToList(); 30 | 31 | var part1 = games 32 | .Where(g => g.sets.All(s => 33 | s.GetValueOrDefault("red") <= 12 34 | && s.GetValueOrDefault("green") <= 13 35 | && s.GetValueOrDefault("blue") <= 14)) 36 | .Sum(g => g.id) 37 | .ToString(); 38 | 39 | var part2 = games 40 | .Select(g => g.sets.Max(s => s.GetValueOrDefault("red", 1)) * 41 | g.sets.Max(s => s.GetValueOrDefault("green", 1)) * 42 | g.sets.Max(s => s.GetValueOrDefault("blue", 1))) 43 | .Sum() 44 | .ToString(); 45 | 46 | return (part1, part2); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day04.fastest.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace AdventOfCode.Puzzles._2023; 4 | 5 | [Puzzle(2023, 04, CodeType.Fastest)] 6 | public sealed partial class Day_04_Fastest : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var part1 = 0; 11 | var part2 = 0; 12 | 13 | Span winning = stackalloc ulong[2]; 14 | Span mine = stackalloc ulong[2]; 15 | Span multipliers = stackalloc int[10]; 16 | 17 | foreach (var line in input.Span.EnumerateLines()) 18 | { 19 | if (line.Length == 0) 20 | break; 21 | 22 | winning[0] = 0; 23 | winning[1] = 0; 24 | mine[0] = 0; 25 | mine[1] = 0; 26 | 27 | for (int x = 10, n = 0; n < 10; x += 3, n++) 28 | { 29 | var num = ((line[x] | 0x10) - '0') * 10; 30 | num += line[x + 1] - '0'; 31 | 32 | winning[num / 64] |= 1UL << (num % 64); 33 | } 34 | 35 | for (int x = 42, n = 0; n < 25; x += 3, n++) 36 | { 37 | var num = ((line[x] | 0x10) - '0') * 10; 38 | num += line[x + 1] - '0'; 39 | 40 | mine[num / 64] |= 1UL << (num % 64); 41 | } 42 | 43 | var count = BitOperations.PopCount(winning[0] & mine[0]) 44 | + BitOperations.PopCount(winning[1] & mine[1]); 45 | 46 | part1 += (1 << count) >> 1; 47 | 48 | var cards = multipliers[0] + 1; 49 | part2 += cards; 50 | 51 | multipliers[1..10].CopyTo(multipliers); 52 | multipliers[9] = 0; 53 | for (var i = 0; i < count; i++) 54 | multipliers[i] += cards; 55 | } 56 | 57 | return (part1.ToString(), part2.ToString()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day04.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2023; 2 | 3 | [Puzzle(2023, 04, CodeType.Original)] 4 | public partial class Day_04_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var games = input.Lines 9 | .Select(l => l.Split('|', ':')) 10 | .Select((s, i) => s[2] 11 | .Split(' ', StringSplitOptions.RemoveEmptyEntries) 12 | .Select(int.Parse) 13 | .Intersect( 14 | s[1] 15 | .Split(' ', StringSplitOptions.RemoveEmptyEntries) 16 | .Select(int.Parse)) 17 | .Count()) 18 | .ToList(); 19 | 20 | var part1 = games 21 | .Select(x => (long)Math.Pow(2, x - 1)) 22 | .Sum(); 23 | 24 | var counts = games.Select(x => 1).ToList(); 25 | for (var i = 0; i < games.Count; i++) 26 | { 27 | for (int j = i + 1, n = 0; j < counts.Count && n < games[i]; j++, n++) 28 | counts[j] += counts[i]; 29 | } 30 | 31 | var part2 = counts.Sum(); 32 | 33 | return (part1.ToString(), part2.ToString()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day06.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2023; 2 | 3 | [Puzzle(2023, 06, CodeType.Fastest)] 4 | public sealed partial class Day_06_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var span = input.Span; 9 | 10 | var time = 0L; 11 | var distance = 0L; 12 | 13 | Span times = stackalloc int[4]; 14 | Span distances = stackalloc int[4]; 15 | 16 | var line = span[..span.IndexOf((byte)'\n')]; 17 | span = span[(line.Length + 1)..]; 18 | 19 | var i = 0; 20 | while (line.Length > 0) 21 | { 22 | line = line[line.IndexOfAnyInRange((byte)'0', (byte)'9')..]; 23 | (times[i++], var n) = line.AtoI(); 24 | 25 | for (var j = 0; j < n; j++) 26 | time = (time * 10) + line[j] - '0'; 27 | 28 | line = line[n..]; 29 | } 30 | 31 | line = span[..span.IndexOf((byte)'\n')]; 32 | span = span[(line.Length + 1)..]; 33 | 34 | i = 0; 35 | while (line.Length > 0) 36 | { 37 | line = line[line.IndexOfAnyInRange((byte)'0', (byte)'9')..]; 38 | (distances[i++], var n) = line.AtoI(); 39 | 40 | for (var j = 0; j < n; j++) 41 | distance = (distance * 10) + line[j] - '0'; 42 | 43 | line = line[n..]; 44 | } 45 | 46 | static long GetWinPossibilities(long time, long distance) 47 | { 48 | var radical = Math.Sqrt(((double)time * time) - (4 * distance)); 49 | var root1 = (long)Math.Ceiling((time + radical) / 2); 50 | var root2 = (long)Math.Floor((time - radical) / 2); 51 | return root1 - root2 - 1; 52 | } 53 | 54 | var part1 = 1L; 55 | for (i = 0; i < 4; i++) 56 | part1 *= GetWinPossibilities(times[i], distances[i]); 57 | var part2 = GetWinPossibilities(time, distance); 58 | 59 | return (part1.ToString(), part2.ToString()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day06.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2023; 2 | 3 | [Puzzle(2023, 06, CodeType.Original)] 4 | public partial class Day_06_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var times = input.Lines[0][12..].Split([" "], StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList(); 9 | var distances = input.Lines[1][12..].Split([" "], StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList(); 10 | 11 | var part1 = times.Zip(distances) 12 | .Select(x => 13 | Enumerable.Range(1, x.First) 14 | .Select(i => i * (x.First - i)) 15 | .Count(i => i > x.Second)) 16 | .Aggregate(1L, (a, b) => a * b); 17 | 18 | var time = int.Parse(string.Concat(input.Lines[0][12..].Split([" "], StringSplitOptions.RemoveEmptyEntries))); 19 | var distance = long.Parse(string.Concat(input.Lines[1][12..].Split([" "], StringSplitOptions.RemoveEmptyEntries))); 20 | 21 | var part2 = Enumerable.Range(1, time) 22 | .Select(i => (long)i * (time - i)) 23 | .Count(i => i > distance); 24 | 25 | return (part1.ToString(), part2.ToString()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day09.fastest.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using System.Runtime.Intrinsics; 3 | 4 | namespace AdventOfCode.Puzzles._2023; 5 | 6 | [Puzzle(2023, 09, CodeType.Fastest)] 7 | public sealed partial class Day_09_Fastest : IPuzzle 8 | { 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var span = input.Span; 12 | var part1 = 0; 13 | var part2 = 0; 14 | 15 | Span array = stackalloc int[32]; 16 | 17 | foreach (var l in span.EnumerateLines()) 18 | { 19 | if (l.Length == 0) 20 | break; 21 | 22 | var j = 0; 23 | var line = l; 24 | while (true) 25 | { 26 | (array[j++], var n) = line.AtoI(); 27 | if (n == line.Length) break; 28 | line = line[(n + 1)..]; 29 | } 30 | 31 | var ints = array[..j]; 32 | part1 += ints[j - 1]; 33 | part2 += ints[0]; 34 | var isNeg = true; 35 | while (true) 36 | { 37 | ref var intsRef = ref MemoryMarshal.GetReference(ints); 38 | ref var intsOneRef = ref MemoryMarshal.GetReference(ints[1..]); 39 | 40 | nuint vectorEnd = (uint)(ints.Length - 1); 41 | if (vectorEnd >= (uint)(Vector128.Count + 1)) 42 | { 43 | vectorEnd -= vectorEnd % (uint)Vector128.Count; 44 | 45 | for (nuint k = 0; k < vectorEnd; k += (uint)Vector128.Count) 46 | { 47 | var result = Vector128.LoadUnsafe(ref intsOneRef, k) 48 | - Vector128.LoadUnsafe(ref intsRef, k); 49 | result.StoreUnsafe(ref intsRef, k); 50 | } 51 | } 52 | else 53 | { 54 | vectorEnd = 0; 55 | } 56 | 57 | for (var k = (int)vectorEnd; k < ints.Length - 1; k++) 58 | ints[k] = ints[k + 1] - ints[k]; 59 | 60 | ints = ints[..^1]; 61 | 62 | part1 += ints[^1]; 63 | part2 += isNeg ? -ints[0] : +ints[0]; 64 | isNeg = !isNeg; 65 | 66 | if (ints[0] == ints[^1]) 67 | break; 68 | } 69 | } 70 | 71 | return (part1.ToString(), part2.ToString()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day09.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2023; 2 | 3 | [Puzzle(2023, 09, CodeType.Original)] 4 | public partial class Day_09_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var longs = input.Lines 9 | .Select(l => l.Split() 10 | .Select(long.Parse) 11 | .ToList() 12 | ) 13 | .ToList(); 14 | 15 | var part1 = longs 16 | .Select(l => l[^1] + GetNextValue(l)) 17 | .Sum(); 18 | 19 | var part2 = longs 20 | .Select(l => l[0] - GetPreviousValue(l)) 21 | .Sum(); 22 | 23 | return (part1.ToString(), part2.ToString()); 24 | } 25 | 26 | private static long GetNextValue(List ints) 27 | { 28 | var differences = ints.Window(2) 29 | .Select(w => w[1] - w[0]) 30 | .ToList(); 31 | if (differences.All(d => d == 0)) 32 | return 0; 33 | 34 | var next = GetNextValue(differences); 35 | return differences[^1] + next; 36 | } 37 | 38 | private static long GetPreviousValue(List ints) 39 | { 40 | var differences = ints.Window(2) 41 | .Select(w => w[1] - w[0]) 42 | .ToList(); 43 | 44 | if (differences.All(d => d == 0)) 45 | return 0; 46 | 47 | var prev = GetPreviousValue(differences); 48 | return differences[0] - prev; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day11.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2023; 2 | 3 | [Puzzle(2023, 11, CodeType.Fastest)] 4 | public sealed partial class Day_11_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var span = input.Span; 9 | 10 | var width = span.IndexOf((byte)'\n'); 11 | Span cols = stackalloc int[width]; 12 | 13 | var part1 = 0; 14 | var part2 = 0L; 15 | 16 | var galaxies = 0; 17 | var yDistanceP1 = 0; 18 | var yDistanceP2 = 0L; 19 | foreach (var line in span.EnumerateLines(width)) 20 | { 21 | span = line; 22 | 23 | var x = 0; 24 | var gap = true; 25 | 26 | while (true) 27 | { 28 | var n = span.IndexOf((byte)'#'); 29 | if (n < 0) 30 | break; 31 | 32 | part1 += yDistanceP1; 33 | part2 += yDistanceP2; 34 | 35 | gap = false; 36 | galaxies++; 37 | cols[x + n]++; 38 | x += n + 1; 39 | span = span[(n + 1)..]; 40 | } 41 | 42 | yDistanceP1 += galaxies; 43 | yDistanceP2 += galaxies; 44 | 45 | if (gap) 46 | { 47 | yDistanceP1 += galaxies; 48 | yDistanceP2 += galaxies * 999_999L; 49 | } 50 | } 51 | 52 | galaxies = 0; 53 | var xDistanceP1 = 0; 54 | var xDistanceP2 = 0L; 55 | foreach (var col in cols) 56 | { 57 | part1 += xDistanceP1 * col; 58 | part2 += xDistanceP2 * col; 59 | 60 | galaxies += col; 61 | xDistanceP1 += galaxies; 62 | xDistanceP2 += galaxies; 63 | 64 | if (col == 0) 65 | { 66 | xDistanceP1 += galaxies; 67 | xDistanceP2 += galaxies * 999_999L; 68 | } 69 | } 70 | 71 | return (part1.ToString(), part2.ToString()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day11.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2023; 2 | 3 | [Puzzle(2023, 11, CodeType.Original)] 4 | public partial class Day_11_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var blankRows = input.Lines.Index() 9 | .Where(x => x.Item.All(b => b == '.')) 10 | .Select(x => x.Index) 11 | .ToList(); 12 | 13 | var blankCols = Enumerable.Range(0, input.Lines[0].Length) 14 | .Where(i => input.Lines.All(l => l[i] == '.')) 15 | .ToList(); 16 | 17 | var stars = input.Bytes.GetMap() 18 | .GetMapPoints() 19 | .Where(p => p.item == '#') 20 | .Select(p => p.p) 21 | .ToList(); 22 | 23 | var part1 = 0; 24 | for (var x = 0; x < stars.Count; x++) 25 | { 26 | var p1 = stars[x]; 27 | for (var y = x + 1; y < stars.Count; y++) 28 | { 29 | var p2 = stars[y]; 30 | 31 | var baseManhattan = Math.Abs(p1.x - p2.x) + Math.Abs(p1.y - p2.y); 32 | baseManhattan += blankRows.Count(r => r.Between(p1.y, p2.y)); 33 | baseManhattan += blankCols.Count(r => r.Between(p1.x, p2.x)); 34 | 35 | part1 += baseManhattan; 36 | } 37 | } 38 | 39 | var part2 = 0L; 40 | for (var x = 0; x < stars.Count; x++) 41 | { 42 | var p1 = stars[x]; 43 | for (var y = x + 1; y < stars.Count; y++) 44 | { 45 | var p2 = stars[y]; 46 | 47 | long baseManhattan = Math.Abs(p1.x - p2.x) + Math.Abs(p1.y - p2.y); 48 | baseManhattan += blankRows.Count(r => r.Between(p1.y, p2.y)) * 999_999L; 49 | baseManhattan += blankCols.Count(r => r.Between(p1.x, p2.x)) * 999_999L; 50 | 51 | part2 += baseManhattan; 52 | } 53 | } 54 | 55 | return (part1.ToString(), part2.ToString()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day15.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2023; 2 | 3 | [Puzzle(2023, 15, CodeType.Original)] 4 | public partial class Day_15_Original : IPuzzle 5 | { 6 | private sealed record Lens 7 | { 8 | public required string Name { get; set; } 9 | public int Length { get; set; } 10 | } 11 | 12 | private static readonly char[] s_separator = ['-', '=']; 13 | 14 | public (string, string) Solve(PuzzleInput input) 15 | { 16 | var instructions = input.Lines[0] 17 | .Split(',') 18 | .ToList(); 19 | 20 | var part1 = instructions 21 | .Select(x => x.Aggregate(0, Hash)) 22 | .Sum(); 23 | 24 | var boxes = new Dictionary>(); 25 | foreach (var i in instructions) 26 | { 27 | var label = i.Split(s_separator)[0]; 28 | var hash = label.Aggregate(0, Hash); 29 | var list = boxes.GetOrAdd(hash, _ => []); 30 | 31 | if (i[^1] == '-') 32 | { 33 | _ = list.RemoveAll(x => x.Name == label); 34 | } 35 | else 36 | { 37 | var length = int.Parse(i.Split('=')[1]); 38 | var lens = list.Find(x => x.Name == label); 39 | if (lens != null) 40 | lens!.Length = length; 41 | else 42 | list.Add(new() { Name = label, Length = length, }); 43 | } 44 | } 45 | 46 | var part2 = boxes 47 | .Select(kvp => kvp.Value 48 | .Index() 49 | .Select(x => (long)(x.Index + 1) * x.Item.Length) 50 | .Sum() * (kvp.Key + 1)) 51 | .Sum(); 52 | 53 | return (part1.ToString(), part2.ToString()); 54 | } 55 | 56 | private static int Hash(int a, char b) 57 | { 58 | return ((a + (byte)b) * 17) % 256; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day18.fastest.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace AdventOfCode.Puzzles._2023; 4 | 5 | [Puzzle(2023, 18, CodeType.Fastest)] 6 | public sealed partial class Day_18_Fastest : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | long ap1 = 0, dp1 = 0, ap2 = 0, dp2 = 0; 11 | (long x, long y) pos1 = (0, 0), pos2 = (0, 0); 12 | 13 | foreach (var l in input.Span.EnumerateLines()) 14 | { 15 | if (l.Length == 0) 16 | break; 17 | 18 | var num = l[2] - '0'; 19 | if (l[3] != ' ') 20 | num = (num * 10) + l[3] - '0'; 21 | 22 | var q = l[0] switch 23 | { 24 | (byte)'U' => (x: pos1.x, y: pos1.y - num), 25 | (byte)'D' => (x: pos1.x, y: pos1.y + num), 26 | (byte)'L' => (x: pos1.x - num, y: pos1.y), 27 | (byte)'R' => (x: pos1.x + num, y: pos1.y), 28 | _ => throw new UnreachableException(), 29 | }; 30 | 31 | ap1 += (pos1.x * q.y) - (q.x * pos1.y); 32 | dp1 += num; 33 | pos1 = q; 34 | 35 | var span = l[(num >= 10 ? 7 : 6)..]; 36 | 37 | num = 0; 38 | for (var i = 0; i < 5; i++) 39 | num = (num * 16) + AtoI16(span[i]); 40 | 41 | static int AtoI16(byte b) => 42 | (b & 0xF) + (9 * (b >> 6)); 43 | 44 | q = span[5] switch 45 | { 46 | (byte)'0' => (x: pos2.x + num, y: pos2.y), 47 | (byte)'1' => (x: pos2.x, y: pos2.y + num), 48 | (byte)'2' => (x: pos2.x - num, y: pos2.y), 49 | (byte)'3' => (x: pos2.x, y: pos2.y - num), 50 | _ => throw new UnreachableException(), 51 | }; 52 | 53 | ap2 += (pos2.x * q.y) - (q.x * pos2.y); 54 | dp2 += num; 55 | pos2 = q; 56 | } 57 | 58 | var part1 = Math.Abs(ap1 / 2) + (dp1 / 2) + 1; 59 | var part2 = Math.Abs(ap2 / 2) + (dp2 / 2) + 1; 60 | 61 | return (part1.ToString(), part2.ToString()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2023/day18.original.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace AdventOfCode.Puzzles._2023; 4 | 5 | [Puzzle(2023, 18, CodeType.Original)] 6 | public partial class Day_18_Original : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var part1 = GetArea(input.Lines 11 | .Select(x => x.Split()) 12 | .Select(l => (int.Parse(l[1]), l[0][0]))); 13 | 14 | var part2 = GetArea(input.Lines 15 | .Select(x => x.Split()) 16 | .Select(l => ConvertHex(l[2]))); 17 | 18 | return (part1.ToString(), part2.ToString()); 19 | } 20 | 21 | private static long GetArea(IEnumerable<(int num, char dir)> corners) 22 | { 23 | var p = (x: 0L, y: 0L); 24 | var area = 0L; 25 | var dist = 0L; 26 | 27 | foreach (var (num, dir) in corners) 28 | { 29 | var q = dir switch 30 | { 31 | 'U' => (x: p.x, y: p.y - num), 32 | 'D' => (x: p.x, y: p.y + num), 33 | 'L' => (x: p.x - num, y: p.y), 34 | 'R' => (x: p.x + num, y: p.y), 35 | _ => throw new UnreachableException(), 36 | }; 37 | 38 | area += (p.x * q.y) - (q.x * p.y); 39 | dist += num; 40 | 41 | p = q; 42 | } 43 | 44 | return Math.Abs(area / 2) + (dist / 2) + 1; 45 | } 46 | 47 | private static (int num, char dir) ConvertHex(string hex) 48 | { 49 | var dir = hex[^2] switch 50 | { 51 | '0' => 'R', 52 | '1' => 'D', 53 | '2' => 'L', 54 | '3' => 'U', 55 | _ => throw new UnreachableException(), 56 | }; 57 | 58 | var num = Convert.ToInt32(hex[2..7], 16); 59 | return (num, dir); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/AdventOfCode.Puzzles.2024.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | AdventOfCode.Puzzles._2024 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day01.fastest.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using System.Runtime.Intrinsics; 3 | 4 | namespace AdventOfCode.Puzzles._2024; 5 | 6 | [Puzzle(2024, 01, CodeType.Fastest)] 7 | public partial class Day_01_Fastest : IPuzzle 8 | { 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | Span list1 = new int[input.Bytes.Length / 8]; 12 | Span list2 = new int[input.Bytes.Length / 8]; 13 | 14 | var idx = 0; 15 | foreach (var line in input.Span[..^1].EnumerateLines()) 16 | { 17 | int i = 0, n = 0; 18 | 19 | while (line[i] != ' ') 20 | n = (n * 10) + (line[i++] - '0'); 21 | 22 | list1[idx] = n; 23 | 24 | i += 3; 25 | n = 0; 26 | while (i < line.Length) 27 | n = (n * 10) + (line[i++] - '0'); 28 | 29 | list2[idx] = n; 30 | 31 | idx++; 32 | } 33 | 34 | list1 = list1[..idx]; 35 | list2 = list2[..idx]; 36 | 37 | list1.Sort(); 38 | list2.Sort(); 39 | 40 | var vec1 = MemoryMarshal.Cast>(list1); 41 | var vec2 = MemoryMarshal.Cast>(list2); 42 | 43 | var part1 = Vector256.Zero; 44 | var part2 = Vector256.Zero; 45 | var l1Idx = 0; 46 | for (var i = 0; i < vec1.Length && i < vec2.Length; i++) 47 | { 48 | var v2 = vec2[i]; 49 | part1 += Vector256.Abs(vec1[i] - v2); 50 | 51 | var max = v2.GetElement(Vector256.Count - 1); 52 | while (l1Idx < list1.Length && list1[l1Idx] <= max) 53 | { 54 | var v1 = Vector256.Create(list1[l1Idx]); 55 | part2 += Vector256.BitwiseAnd(v1, Vector256.Equals(v1, v2)); 56 | 57 | if (list1[l1Idx] == max) 58 | break; 59 | 60 | l1Idx++; 61 | } 62 | } 63 | 64 | return (Vector256.Sum(part1).ToString(), Vector256.Sum(part2).ToString()); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day01.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 01, CodeType.Original)] 4 | public partial class Day_01_Original : IPuzzle 5 | { 6 | [GeneratedRegex(@"(\d+)\s+(\d+)")] 7 | private static partial Regex NumbersRegex { get; } 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var list = input.Lines 12 | .Select(l => NumbersRegex.Match(l)) 13 | .Select(m => new 14 | { 15 | int1 = int.Parse(m.Groups[1].Value), 16 | int2 = int.Parse(m.Groups[2].Value), 17 | }) 18 | .ToList(); 19 | 20 | var list1 = list.Select(l => l.int1).Order().ToList(); 21 | var list2 = list.Select(l => l.int2).Order().ToList(); 22 | 23 | var part1 = list1.Zip(list2, (a, b) => Math.Abs(a - b)).Sum().ToString(); 24 | 25 | var count = list2.CountBy(x => x).ToDictionary(x => x.Key, x => x.Value); 26 | 27 | var part2 = list.Sum(l => l.int1 * count.GetValueOrDefault(l.int1)).ToString(); 28 | 29 | return (part1, part2); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day02.fastest.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 02, CodeType.Fastest)] 4 | public partial class Day_02_Fastest : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var part1 = 0; 9 | var part2 = 0; 10 | 11 | Span numbers = new int[16]; 12 | Span scratch = new int[16]; 13 | 14 | foreach (var line in input.Span[..^1].EnumerateLines()) 15 | { 16 | var idx = 0; 17 | var n = 0; 18 | foreach (var c in line) 19 | { 20 | if (c is (byte)' ') 21 | { 22 | numbers[idx++] = n; 23 | n = 0; 24 | } 25 | else 26 | { 27 | n = (n * 10) + (c - '0'); 28 | } 29 | } 30 | 31 | numbers[idx++] = n; 32 | var levels = numbers[..idx]; 33 | 34 | var isSafe1 = IsSafe1(levels); 35 | part1 += isSafe1; 36 | part2 += isSafe1 == 1 ? 1 : IsSafe2(levels, scratch); 37 | } 38 | 39 | return (part1.ToString(), part2.ToString()); 40 | } 41 | 42 | private static int IsSafe1(Span levels) 43 | { 44 | static bool IsValid(int delta) => delta is >= 1 and <= 3; 45 | 46 | if (levels[1] >= levels[0]) 47 | { 48 | for (var i = 0; i < levels.Length - 1; i++) 49 | { 50 | if (!IsValid(levels[i + 1] - levels[i])) 51 | return 0; 52 | } 53 | } 54 | else 55 | { 56 | for (var i = 0; i < levels.Length - 1; i++) 57 | { 58 | if (!IsValid(levels[i] - levels[i + 1])) 59 | return 0; 60 | } 61 | } 62 | 63 | return 1; 64 | } 65 | 66 | private static int IsSafe2(Span levels, Span scratch) 67 | { 68 | var newLevels = scratch[..(levels.Length - 1)]; 69 | 70 | for (var i = 0; i < levels.Length; i++) 71 | { 72 | levels[..i].CopyTo(newLevels); 73 | levels[(i + 1)..].CopyTo(newLevels[i..]); 74 | 75 | if (IsSafe1(newLevels) == 1) 76 | return 1; 77 | } 78 | 79 | return 0; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day02.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 02, CodeType.Original)] 4 | public partial class Day_02_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var reports = input.Lines 9 | .Select(l => l.Split().Select(int.Parse).ToArray()) 10 | .ToList(); 11 | 12 | var part1 = reports.Count(IsSafe).ToString(); 13 | var part2 = reports.Count(IsSafe2).ToString(); 14 | return (part1, part2); 15 | } 16 | 17 | private static bool IsSafe(int[] levels) 18 | { 19 | static bool IsValid(int a, int b) => a - b is >= 1 and <= 3; 20 | 21 | return 22 | levels.Window(2).All(w => IsValid(w[0], w[1])) 23 | || levels.Window(2).All(w => IsValid(w[1], w[0])); 24 | } 25 | 26 | private static bool IsSafe2(int[] levels) 27 | { 28 | for (var i = 0; i < levels.Length; i++) 29 | { 30 | if (IsSafe([.. levels[..i], .. levels[(i + 1)..]])) 31 | return true; 32 | } 33 | 34 | return false; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day03.fastest.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace AdventOfCode.Puzzles._2024; 4 | 5 | [Puzzle(2024, 03, CodeType.Fastest)] 6 | public partial class Day_03_Fastest : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var part1 = 0; 11 | var part2 = 0; 12 | 13 | var span = input.Span; 14 | var nextIdx = span.IndexOfAny((byte)'d', (byte)'m'); 15 | var enabled = true; 16 | 17 | while (nextIdx >= 0) 18 | { 19 | span = span[nextIdx..]; 20 | 21 | if (span[..4].SequenceEqual("do()"u8)) 22 | { 23 | span = span[4..]; 24 | enabled = true; 25 | } 26 | else if (span[..7].SequenceEqual("don't()"u8)) 27 | { 28 | span = span[7..]; 29 | enabled = false; 30 | } 31 | else if (span[..4].SequenceEqual("mul("u8)) 32 | { 33 | var idx = 4; 34 | var result = ParseMul(span, ref idx); 35 | span = span[idx..]; 36 | 37 | part1 += result; 38 | if (enabled) 39 | part2 += result; 40 | } 41 | else 42 | { 43 | span = span[1..]; 44 | } 45 | 46 | nextIdx = span.IndexOfAny((byte)'d', (byte)'m'); 47 | } 48 | 49 | return (part1.ToString(), part2.ToString()); 50 | } 51 | 52 | private static int ParseMul(ReadOnlySpan span, ref int i) 53 | { 54 | var num1 = ParseNumber(span, ref i); 55 | if (span[i - 1] != ',') 56 | return 0; 57 | 58 | var num2 = ParseNumber(span, ref i); 59 | if (span[i - 1] != ')') 60 | return 0; 61 | 62 | return num1 * num2; 63 | } 64 | 65 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 66 | private static int ParseNumber(ReadOnlySpan input, ref int i) 67 | { 68 | var a = 0; 69 | var c = 0; 70 | while (i < input.Length && (c = input[i++]) is >= (byte)'0' and <= (byte)'9') 71 | a = (a * 10) + (c - '0'); 72 | return a; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day03.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 03, CodeType.Original)] 4 | public partial class Day_03_Original : IPuzzle 5 | { 6 | [GeneratedRegex(@"mul\((\d+),(\d+)\)")] 7 | private static partial Regex MulRegex(); 8 | 9 | [GeneratedRegex(@"(?do\(\))|(?mul\((?\d+),(?\d+)\))|(?don't\(\))")] 10 | private static partial Regex InstructionsRegex(); 11 | 12 | public (string, string) Solve(PuzzleInput input) 13 | { 14 | var part1 = MulRegex().Matches(input.Text) 15 | .Select(m => long.Parse(m.Groups[1].ValueSpan) * long.Parse(m.Groups[2].ValueSpan)) 16 | .Sum() 17 | .ToString(); 18 | 19 | var sum = 0L; 20 | var state = true; 21 | foreach (Match m in InstructionsRegex().Matches(input.Text)) 22 | { 23 | switch (state, m.Groups["do"].Success, m.Groups["mul"].Success, m.Groups["dont"].Success) 24 | { 25 | case (false, true, _, _): 26 | state = true; 27 | break; 28 | 29 | case (true, _, _, true): 30 | state = false; 31 | break; 32 | 33 | case (true, _, true, _): 34 | { 35 | sum += long.Parse(m.Groups["mul1"].ValueSpan) * long.Parse(m.Groups["mul2"].ValueSpan); 36 | break; 37 | } 38 | 39 | default: 40 | break; 41 | } 42 | } 43 | 44 | var part2 = sum.ToString(); 45 | 46 | return (part1, part2); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day04.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 04, CodeType.Original)] 4 | public partial class Day_04_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var map = input.Bytes.GetMap(); 9 | var count = 0; 10 | 11 | for (var y = 0; y < map.Length; y++) 12 | { 13 | for (var x = 0; x < map[y].Length; x++) 14 | { 15 | if (map[y][x] is not (byte)'X') 16 | continue; 17 | 18 | foreach (var (dx, dy) in MapExtensions.Adjacent) 19 | { 20 | var (nx, ny) = (x + dx, y + dy); 21 | 22 | if (nx < 0 || ny < 0 || nx >= map[y].Length || ny >= map.Length) 23 | continue; 24 | if (map[ny][nx] != (byte)'M') 25 | continue; 26 | 27 | (nx, ny) = (nx + dx, ny + dy); 28 | 29 | if (nx < 0 || ny < 0 || nx >= map[y].Length || ny >= map.Length) 30 | continue; 31 | if (map[ny][nx] != (byte)'A') 32 | continue; 33 | 34 | (nx, ny) = (nx + dx, ny + dy); 35 | 36 | if (nx < 0 || ny < 0 || nx >= map[y].Length || ny >= map.Length) 37 | continue; 38 | if (map[ny][nx] != (byte)'S') 39 | continue; 40 | 41 | count++; 42 | } 43 | } 44 | } 45 | 46 | var part1 = count.ToString(); 47 | 48 | count = 0; 49 | 50 | for (var y = 0; y < map.Length; y++) 51 | { 52 | for (var x = 0; x < map[y].Length; x++) 53 | { 54 | if (x == 0 || y == 0 || x == map[y].Length - 1 || y == map.Length - 1) 55 | continue; 56 | 57 | if (map[y][x] is not (byte)'A') 58 | continue; 59 | 60 | if ( 61 | (map[y - 1][x - 1], map[y + 1][x + 1]) is ((byte)'M', (byte)'S') or ((byte)'S', (byte)'M') 62 | && (map[y - 1][x + 1], map[y + 1][x - 1]) is ((byte)'M', (byte)'S') or ((byte)'S', (byte)'M') 63 | ) 64 | { 65 | count++; 66 | } 67 | } 68 | } 69 | 70 | var part2 = count.ToString(); 71 | 72 | return (part1, part2); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day05.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 05, CodeType.Original)] 4 | public partial class Day_05_Original : IPuzzle 5 | { 6 | [GeneratedRegex(@"^(\d+)\|(\d+)$")] 7 | private static partial Regex OrderingRegex { get; } 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var sections = input.Lines.Split(string.Empty).ToList(); 12 | 13 | var regex1 = OrderingRegex; 14 | var beforeInstructions = sections[0] 15 | .Select(l => regex1.Match(l)) 16 | .ToLookup(x => int.Parse(x.Groups[1].Value), x => int.Parse(x.Groups[2].Value)); 17 | 18 | var updates = sections[1] 19 | .Select(l => l.Split(',').Select(p => int.Parse(p)).ToList()) 20 | .ToList(); 21 | 22 | var part1 = updates 23 | .Where(l => IsValidUpdate(l, beforeInstructions)) 24 | .Sum(l => l[l.Count / 2]) 25 | .ToString(); 26 | 27 | var part2 = updates 28 | .Where(l => !IsValidUpdate(l, beforeInstructions)) 29 | .Select(l => CorrectList(l, beforeInstructions)) 30 | .Sum(l => l[l.Count / 2]) 31 | .ToString(); 32 | 33 | return (part1, part2); 34 | } 35 | 36 | private static bool IsValidUpdate(List l, ILookup beforeInstructions) 37 | { 38 | for (var i = 1; i < l.Count; i++) 39 | { 40 | for (var j = 0; j < i; j++) 41 | { 42 | if (beforeInstructions[l[i]].Contains(l[j])) 43 | return false; 44 | } 45 | } 46 | 47 | return true; 48 | } 49 | 50 | private static List CorrectList(List l, ILookup beforeInstructions) 51 | { 52 | var newList = new List(); 53 | 54 | while (l.Count != 0) 55 | { 56 | for (var i = 0; i < l.Count; i++) 57 | { 58 | if (!l.Any(j => beforeInstructions[j].Contains(l[i]))) 59 | { 60 | newList.Add(l[i]); 61 | l.RemoveAt(i); 62 | break; 63 | } 64 | } 65 | } 66 | 67 | return newList; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day08.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 08, CodeType.Original)] 4 | public partial class Day_08_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var map = input.Bytes.GetMap(); 9 | 10 | var antennas = map.GetMapPoints() 11 | .Where(p => p.item != '.') 12 | .ToLookup(p => p.item, p => p.p); 13 | 14 | var part1 = antennas 15 | .SelectMany(g => g.Subsets(2) 16 | .SelectMany(w => new[] 17 | { 18 | (x: w[0].x - (w[1].x - w[0].x), y: w[0].y - (w[1].y - w[0].y)), 19 | (x: w[1].x - (w[0].x - w[1].x), y: w[1].y - (w[0].y - w[1].y)), 20 | }) 21 | ) 22 | .Distinct() 23 | .Count(p => p.IsValid(map)) 24 | .ToString(); 25 | 26 | var part2 = antennas 27 | .SelectMany(g => g.Subsets(2) 28 | .SelectMany(w => Enumerable.Range(0, 30) 29 | .SelectMany(i => new[] 30 | { 31 | (x: w[0].x - (w[1].x - w[0].x) * i, y: w[0].y - (w[1].y - w[0].y) * i), 32 | (x: w[1].x - (w[0].x - w[1].x) * i, y: w[1].y - (w[0].y - w[1].y) * i), 33 | }) 34 | ) 35 | ) 36 | .Distinct() 37 | .Count(p => p.IsValid(map)) 38 | .ToString(); 39 | 40 | return (part1, part2); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day10.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 10, CodeType.Original)] 4 | public partial class Day_10_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var map = input.Bytes.GetIntMap(); 9 | 10 | var zeros = map.GetMapPoints() 11 | .Where(p => p.item == 0) 12 | .ToList(); 13 | 14 | var part1 = 0; 15 | var part2 = 0; 16 | 17 | var distinct = new HashSet<(int, int)>(); 18 | foreach (var (p, item) in zeros) 19 | { 20 | distinct.Clear(); 21 | 22 | part2 += SuperEnumerable 23 | .TraverseBreadthFirst( 24 | p, 25 | p => p.GetCartesianNeighbors(map) 26 | .Where(q => map[q.y][q.x] == map[p.y][p.x] + 1) 27 | ) 28 | .Where(p => map[p.y][p.x] == 9) 29 | .Do(p => distinct.Add(p)) 30 | .Count(); 31 | 32 | part1 += distinct.Count; 33 | } 34 | 35 | return (part1.ToString(), part2.ToString()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day14.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 14, CodeType.Original)] 4 | public partial class Day_14_Original : IPuzzle 5 | { 6 | [GeneratedRegex(@"p=(\d+),(\d+) v=(-?\d+),(-?\d+)")] 7 | private static partial Regex RobotRegex { get; } 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var robots = input.Lines 12 | .Select(l => RobotRegex.Match(l)) 13 | .Select(m => 14 | ( 15 | px: int.Parse(m.Groups[1].Value), 16 | py: int.Parse(m.Groups[2].Value), 17 | vx: int.Parse(m.Groups[3].Value) + 101, 18 | vy: int.Parse(m.Groups[4].Value) + 103 19 | ) 20 | ) 21 | .ToArray(); 22 | 23 | var part1 = robots 24 | .Select(r => 25 | ( 26 | x: (r.px + (r.vx * 100)) % 101, 27 | y: (r.py + (r.vy * 100)) % 103 28 | ) 29 | ) 30 | .GroupBy( 31 | r => (r.x, r.y) switch 32 | { 33 | ( < 50, < 51) => 1, 34 | ( > 50, < 51) => 2, 35 | ( < 50, > 51) => 3, 36 | ( > 50, > 51) => 4, 37 | _ => 5, 38 | }, 39 | (k, g) => (k, c: g.Count()) 40 | ) 41 | .Where(x => x.k < 5) 42 | .Aggregate(1L, (a, b) => a * b.c); 43 | 44 | var part2 = 0; 45 | while (!robots.CountBy(r => (r.px, r.py)).All(k => k.Value == 1)) 46 | { 47 | part2++; 48 | for (var i = 0; i < robots.Length; i++) 49 | { 50 | ref var r = ref robots[i]; 51 | r = (px: (r.px + r.vx) % 101, py: (r.py + r.vy) % 103, r.vx, r.vy); 52 | } 53 | } 54 | 55 | return (part1.ToString(), part2.ToString()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day18.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 18, CodeType.Original)] 4 | public partial class Day_18_Original : IPuzzle 5 | { 6 | [GeneratedRegex(@"(\d+),(\d+)")] 7 | private static partial Regex CoordinateRegex { get; } 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var errors = input.Lines 12 | .Select(l => CoordinateRegex.Match(l)) 13 | .Select(m => 14 | ( 15 | x: int.Parse(m.Groups[1].Value), 16 | y: int.Parse(m.Groups[2].Value) 17 | ) 18 | ) 19 | .ToList(); 20 | 21 | var part1 = GetShortestPathCost(errors.Take(1024).ToHashSet()); 22 | 23 | var lo = 1025; 24 | var hi = errors.Count - 1; 25 | var mid = (lo + hi) / 2; 26 | while (lo < hi) 27 | { 28 | try 29 | { 30 | GetShortestPathCost(errors.Take(mid).ToHashSet()); 31 | lo = mid + 1; 32 | mid = (lo + hi) / 2; 33 | } 34 | catch (InvalidOperationException) 35 | { 36 | hi = mid - 1; 37 | mid = (lo + hi) / 2; 38 | } 39 | } 40 | 41 | var (x, y) = errors[mid]; 42 | return (part1.ToString(), $"{x},{y}"); 43 | } 44 | 45 | private static int GetShortestPathCost(HashSet<(int x, int y)> walls) => 46 | SuperEnumerable 47 | .GetShortestPathCost<(int x, int y), int>( 48 | (0, 0), 49 | (p, c) => p.GetCartesianNeighbors() 50 | .Where(p => p.x.Between(0, 70) && p.y.Between(0, 70)) 51 | .Where(p => !walls.Contains(p)) 52 | .Select(p => (p, c + 1)), 53 | (70, 70) 54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day19.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 19, CodeType.Original)] 4 | public partial class Day_19_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var splits = input.Lines.Split(string.Empty).ToList(); 9 | var available = splits[0][0].Split(", ").ToList(); 10 | 11 | var possibles = splits[1] 12 | .Select(p => CountPossible(available, p, [])) 13 | .ToList(); 14 | 15 | var part1 = possibles.Count(p => p > 0); 16 | var part2 = possibles.Sum(); 17 | 18 | return (part1.ToString(), part2.ToString()); 19 | } 20 | 21 | private static long CountPossible(List available, ReadOnlySpan span, Dictionary cache) 22 | { 23 | if (span is "") 24 | return 1; 25 | 26 | if (cache.TryGetValue(span.Length, out var result)) 27 | return result; 28 | 29 | var sum = 0L; 30 | foreach (var a in available) 31 | { 32 | if (span.StartsWith(a)) 33 | sum += CountPossible(available, span[a.Length..], cache); 34 | } 35 | 36 | return cache[span.Length] = sum; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day20.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 20, CodeType.Original)] 4 | public partial class Day_20_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var map = input.Bytes.GetMap(); 9 | 10 | var start = map.GetMapPoints().First(p => p.item == 'S').p; 11 | 12 | var paths = SuperEnumerable.GetShortestPaths<(int x, int y), int>( 13 | start, 14 | (p, c) => p.GetCartesianNeighbors() 15 | .Where(q => map[q.y][q.x] != '#') 16 | .Select(q => (q, c + 1)) 17 | ); 18 | 19 | var part1 = GetCheatCount(paths, 2); 20 | var part2 = GetCheatCount(paths, 20); 21 | 22 | return (part1.ToString(), part2.ToString()); 23 | } 24 | 25 | private static int GetCheatCount(IReadOnlyDictionary<(int x, int y), ((int x, int y) previousState, int cost)> paths, int maxLength) 26 | { 27 | var count = 0; 28 | foreach (var (x, y) in paths.Keys) 29 | { 30 | var startCost = paths[(x, y)].cost; 31 | 32 | for (var dy = -maxLength; dy <= +maxLength; dy++) 33 | { 34 | var mindx = Math.Abs(dy) - maxLength; 35 | var maxdx = -mindx; 36 | for (var dx = mindx; dx <= maxdx; dx++) 37 | { 38 | if (!paths.TryGetValue((x + dx, y + dy), out var value)) 39 | continue; 40 | 41 | var deltaCost = value.cost - startCost; 42 | deltaCost -= Math.Abs(dy) + Math.Abs(dx); 43 | if (deltaCost >= 100) 44 | count++; 45 | } 46 | } 47 | } 48 | 49 | return count; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day22.original.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace AdventOfCode.Puzzles._2024; 4 | 5 | [Puzzle(2024, 22, CodeType.Original)] 6 | public partial class Day_22_Original : IPuzzle 7 | { 8 | public (string, string) Solve(PuzzleInput input) 9 | { 10 | var part1 = 0L; 11 | var prices = new Dictionary<(int, int, int, int), int>(); 12 | var seen = new HashSet<(int, int, int, int)>(); 13 | 14 | foreach (var l in input.Lines) 15 | { 16 | seen.Clear(); 17 | 18 | var num = long.Parse(l); 19 | var (d1, d2, d3, d4) = (0, 0, 0, 0); 20 | 21 | for (var i = 0; i < 2000; i++) 22 | { 23 | var x = GetNextNumber(num); 24 | (num, d1, d2, d3, d4) = (x, ((int)x % 10) - ((int)num % 10), d1, d2, d3); 25 | 26 | if (i >= 3 && seen.Add((d1, d2, d3, d4))) 27 | { 28 | ref var z = ref CollectionsMarshal.GetValueRefOrAddDefault(prices, (d1, d2, d3, d4), out _); 29 | z += (int)x % 10; 30 | } 31 | } 32 | 33 | part1 += (int)num; 34 | } 35 | 36 | var part2 = prices.Values.Max(); 37 | 38 | return (part1.ToString(), part2.ToString()); 39 | } 40 | 41 | private static long GetNextNumber(long secret) 42 | { 43 | var num = ((secret * 64) ^ secret) % 16777216; 44 | num = (num / 32) ^ num; 45 | num = ((num * 2048) ^ num) % 16777216; 46 | return num; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day23.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 23, CodeType.Original)] 4 | public partial class Day_23_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var connections = input.Lines 9 | .Select(l => l.Split('-')) 10 | .SelectMany(s => new[] 11 | { 12 | (s[0], s[1]), 13 | (s[1], s[0]), 14 | }) 15 | .ToLookup(x => x.Item1, x => x.Item2); 16 | 17 | var part1 = DoPart1(connections); 18 | var part2 = DoPart2(connections); 19 | 20 | return (part1, part2); 21 | } 22 | 23 | private static string DoPart1(ILookup connections) 24 | { 25 | var groups = new HashSet<(string, string, string)>(); 26 | foreach (var node in connections) 27 | { 28 | foreach (var secondary in node) 29 | { 30 | foreach (var z in connections[secondary].Intersect(node) 31 | .Select(x => new[] { node.Key, secondary, x }.Order().ToList()) 32 | .Select(x => (x[0], x[1], x[2]))) 33 | { 34 | groups.Add(z); 35 | } 36 | } 37 | } 38 | 39 | return groups 40 | .Count(x => x.Item1.StartsWith('t') || x.Item2.StartsWith('t') || x.Item3.StartsWith('t')) 41 | .ToString(); 42 | } 43 | 44 | private static string DoPart2(ILookup connections) 45 | { 46 | var groups = new List>(); 47 | 48 | foreach (var n in connections) 49 | { 50 | var next = n.Key; 51 | foreach (var g in groups) 52 | { 53 | if (g.TrueForAll(node => connections[node].Contains(next))) 54 | g.Add(next); 55 | } 56 | 57 | groups.Add([next]); 58 | } 59 | 60 | return string.Join( 61 | ',', 62 | groups 63 | .MaxBy(g => g.Count)! 64 | .Order() 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day24.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 24, CodeType.Original)] 4 | public partial class Day_24_Original : IPuzzle 5 | { 6 | [GeneratedRegex(@"(?\w{3}) (?AND|XOR|OR) (?\w{3}) -> (?\w{3})", RegexOptions.Compiled)] 7 | private static partial Regex LineRegex { get; } 8 | 9 | public (string, string) Solve(PuzzleInput input) 10 | { 11 | var split = input.Lines.Split(string.Empty).ToList(); 12 | var wires = split[0] 13 | .Select(x => x.Split(": ")) 14 | .ToDictionary(x => x[0], x => new Lazy(() => x[1] == "1")); 15 | 16 | foreach (var m in split[1].Select(m => LineRegex.Match(m))) 17 | { 18 | var i1 = m.Groups["i1"].Value; 19 | var i2 = m.Groups["i2"].Value; 20 | var op = m.Groups["op"].Value; 21 | 22 | wires[m.Groups["o"].Value] = new Lazy( 23 | () => op switch 24 | { 25 | "AND" => wires[i1].Value & wires[i2].Value, 26 | "OR" => wires[i1].Value | wires[i2].Value, 27 | _ => wires[i1].Value ^ wires[i2].Value, 28 | } 29 | ); 30 | } 31 | 32 | var part1 = 0L; 33 | foreach (var (key, value) in wires.Where(kvp => kvp.Key.StartsWith('z'))) 34 | { 35 | var bit = int.Parse(key.AsSpan()[1..]); 36 | if (value.Value) 37 | part1 |= 1L << bit; 38 | } 39 | 40 | var part2 = 0; 41 | 42 | return (part1.ToString(), part2.ToString()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /AdventOfCode.Puzzles/2024/day25.original.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Puzzles._2024; 2 | 3 | [Puzzle(2024, 25, CodeType.Original)] 4 | public partial class Day_25_Original : IPuzzle 5 | { 6 | public (string, string) Solve(PuzzleInput input) 7 | { 8 | var locks = new List>(); 9 | var keys = new List>(); 10 | 11 | foreach (var grid in input.Lines.Split(string.Empty)) 12 | { 13 | if (grid[0][0] is '#') 14 | { 15 | var ys = Enumerable.Range(0, grid[0].Length) 16 | .Select(x => Enumerable.Range(1, 5).TakeWhile(y => grid[y][x] is '#').Count()) 17 | .ToList(); 18 | locks.Add(ys); 19 | } 20 | else 21 | { 22 | var ys = Enumerable.Range(0, grid[0].Length) 23 | .Select(x => SuperEnumerable.Sequence(5, 1).TakeWhile(y => grid[y][x] is '#').Count()) 24 | .ToList(); 25 | keys.Add(ys); 26 | } 27 | } 28 | 29 | var part1 = locks.SelectMany(l => keys.Where(k => l.Zip(k).All(x => x.First + x.Second <= 5))).Count(); 30 | 31 | return (part1.ToString(), ""); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AdventOfCode.Runner/BenchmarkInputProvider.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Runner; 2 | 3 | public static class BenchmarkInputProvider 4 | { 5 | public static PuzzleInput GetRawInput(int year, int day) 6 | { 7 | var inputFile = $"../../../../../../../Inputs/{year}/day{day:00}.input.txt"; 8 | 9 | return new( 10 | File.ReadAllBytes(inputFile), 11 | File.ReadAllText(inputFile), 12 | File.ReadAllLines(inputFile)); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AdventOfCode.Runner/Program.docopt.txt: -------------------------------------------------------------------------------- 1 | Advent of Code Runner. 2 | 3 | Usage: 4 | AdventOfCode.Runner.exe 5 | [-o | -f] 6 | --year=YEAR [--day=DAY] 7 | [-b] [-s] 8 | AdventOfCode.Runner.exe (-h | --help) 9 | 10 | Options: 11 | -h --help Show this screen. 12 | -o --original Run Original code solution 13 | -f --fastest Run Fastest code solution 14 | -y YEAR, --year=YEAR Run a specific year 15 | -d DAY, --day=DAY Run a specific day 16 | -b --benchmark Benchmark selected puzzles 17 | -s --silent Disable Console output 18 | -------------------------------------------------------------------------------- /AdventOfCode.Runner/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "AdventOfCode.Runner": { 4 | "commandName": "Project", 5 | "workingDirectory": "$(ProjectDir)" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /AdventOfCode.Runner/PuzzleBenchmarkRunner.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using BenchmarkDotNet.Attributes; 3 | 4 | namespace AdventOfCode.Runner; 5 | 6 | [MemoryDiagnoser(false)] 7 | public class PuzzleBenchmarkRunner 8 | where TPuzzle : IPuzzle, new() 9 | { 10 | private readonly TPuzzle _puzzle = new(); 11 | private PuzzleInput? _rawInput; 12 | 13 | [GlobalSetup] 14 | public void Setup() 15 | { 16 | var attribute = typeof(TPuzzle).GetCustomAttribute()!; 17 | _rawInput = BenchmarkInputProvider.GetRawInput(attribute.Year, attribute.Day); 18 | } 19 | 20 | [Benchmark] 21 | public (string, string) Solve() => _puzzle.Solve(_rawInput!); 22 | } 23 | -------------------------------------------------------------------------------- /AdventOfCode.Runner/PuzzleResult.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCode.Runner; 2 | 3 | public record PuzzleResult( 4 | PuzzleModel Puzzle, 5 | string Part1, 6 | string Part2, 7 | TimeSpan Elapsed); 8 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | latest 5 | net9.0 6 | 7 | enable 8 | enable 9 | True 10 | 11 | latest-all 12 | true 13 | true 14 | 15 | true 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2022 Turning Code, LLC 4 | Copyright (c) 2022 Tim van den Essen 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | --------------------------------------------------------------------------------