├── .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 |
--------------------------------------------------------------------------------