Add AoC 2025 project structure and first solutions
This commit is contained in:
parent
c83642d286
commit
1e98d90c33
|
|
@ -0,0 +1,9 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace AdvenOfCode.Contracts;
|
||||
|
||||
public interface IPuzzleSolver<T>
|
||||
{
|
||||
public T SolvePart1(string puzzleInputPath);
|
||||
public T SolvePart2(string puzzleInputPath);
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AoC_2025", "AoC_2025", "{05EBAA1C-B33B-4AFE-8635-A58D7CA509A7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AoC_2025", "AoC_2025\AoC_2025.csproj", "{4F395AE3-DABB-4546-A4D0-5A62425FE168}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AoC_2025.Tests", "AoC_2025.Tests\AoC_2025.Tests.csproj", "{197D9628-C2D1-4B33-9DB8-134F87F79904}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AoC_2025.Runner", "AoC_2025.Runner\AoC_2025.Runner.csproj", "{FAB5E28F-706A-4DE1-B5FD-54E31C3A8405}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvenOfCode.Contracts", "AdvenOfCode.Contracts\AdvenOfCode.Contracts.csproj", "{0249A329-D5C1-4699-88BE-A668B362432E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4F395AE3-DABB-4546-A4D0-5A62425FE168}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4F395AE3-DABB-4546-A4D0-5A62425FE168}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4F395AE3-DABB-4546-A4D0-5A62425FE168}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4F395AE3-DABB-4546-A4D0-5A62425FE168}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{197D9628-C2D1-4B33-9DB8-134F87F79904}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{197D9628-C2D1-4B33-9DB8-134F87F79904}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{197D9628-C2D1-4B33-9DB8-134F87F79904}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{197D9628-C2D1-4B33-9DB8-134F87F79904}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FAB5E28F-706A-4DE1-B5FD-54E31C3A8405}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FAB5E28F-706A-4DE1-B5FD-54E31C3A8405}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FAB5E28F-706A-4DE1-B5FD-54E31C3A8405}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FAB5E28F-706A-4DE1-B5FD-54E31C3A8405}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0249A329-D5C1-4699-88BE-A668B362432E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0249A329-D5C1-4699-88BE-A668B362432E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0249A329-D5C1-4699-88BE-A668B362432E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0249A329-D5C1-4699-88BE-A668B362432E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{4F395AE3-DABB-4546-A4D0-5A62425FE168} = {05EBAA1C-B33B-4AFE-8635-A58D7CA509A7}
|
||||
{197D9628-C2D1-4B33-9DB8-134F87F79904} = {05EBAA1C-B33B-4AFE-8635-A58D7CA509A7}
|
||||
{FAB5E28F-706A-4DE1-B5FD-54E31C3A8405} = {05EBAA1C-B33B-4AFE-8635-A58D7CA509A7}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AoC_2025\AoC_2025.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// See https://aka.ms/new-console-template for more information
|
||||
|
||||
using System.Globalization;
|
||||
using AoC_2025;
|
||||
|
||||
var day01 = new Day01();
|
||||
const string day01Path = @"C:\Users\p01004051\Documents\AoC-PuzzleInputs\2025\Prod\day01.txt";
|
||||
Console.WriteLine(day01.SolvePart1(day01Path));
|
||||
Console.WriteLine(day01.SolvePart2(day01Path));
|
||||
Console.WriteLine();
|
||||
|
||||
var day02 = new Day02();
|
||||
const string day02Path = @"C:\Users\p01004051\Documents\AoC-PuzzleInputs\2025\Prod\day02.txt";
|
||||
Console.WriteLine(day02.SolvePart1(day02Path));
|
||||
Console.WriteLine(day02.SolvePart2(day02Path));
|
||||
Console.WriteLine();
|
||||
|
||||
var day03 = new Day03();
|
||||
const string day03Path = @"C:\Users\p01004051\Documents\AoC-PuzzleInputs\2025\Prod\day03.txt";
|
||||
Console.WriteLine(day03.SolvePart1(day03Path));
|
||||
Console.WriteLine(day03.SolvePart2(day03Path));
|
||||
Console.WriteLine();
|
||||
|
||||
var day04 = new Day04();
|
||||
const string day04Path = @"C:\Users\p01004051\Documents\AoC-PuzzleInputs\2025\Prod\day04.txt";
|
||||
Console.WriteLine(day04.SolvePart1(day04Path));
|
||||
Console.WriteLine(day04.SolvePart2(day04Path));
|
||||
Console.WriteLine();
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0"/>
|
||||
<PackageReference Include="xunit" Version="2.9.2"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AoC_2025\AoC_2025.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
using AdvenOfCode.Contracts;
|
||||
|
||||
namespace AoC_2025.Tests;
|
||||
|
||||
public class Day01Test
|
||||
{
|
||||
private readonly IPuzzleSolver<int> _sut;
|
||||
private const string TestInputPath = @"C:\Users\p01004051\Documents\AoC-PuzzleInputs\2025\Test\day01.txt";
|
||||
private const string ProdInputPath = @"C:\Users\p01004051\Documents\AoC-PuzzleInputs\2025\Prod\day01.txt";
|
||||
|
||||
public Day01Test()
|
||||
{
|
||||
_sut = new Day01();
|
||||
}
|
||||
[Fact]
|
||||
public void Part01_Test_equals_3()
|
||||
{
|
||||
var actual = _sut.SolvePart1(TestInputPath);
|
||||
|
||||
Assert.Equal(3, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Part01_Prod_equals_1097()
|
||||
{
|
||||
var actual = _sut.SolvePart1(ProdInputPath);
|
||||
|
||||
Assert.Equal(1097, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Part02_Test_equals_16()
|
||||
{
|
||||
var actual = _sut.SolvePart2(TestInputPath);
|
||||
|
||||
Assert.Equal(16, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Part02_Prod_equals_7101()
|
||||
{
|
||||
var actual = _sut.SolvePart2(ProdInputPath);
|
||||
|
||||
Assert.Equal(7101, actual);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
using AdvenOfCode.Contracts;
|
||||
|
||||
namespace AoC_2025.Tests;
|
||||
|
||||
public class Day02Test
|
||||
{
|
||||
private readonly IPuzzleSolver<long> _sut;
|
||||
private const string TestInputPath = @"C:\Users\p01004051\Documents\AoC-PuzzleInputs\2025\Test\day02.txt";
|
||||
private const string ProdInputPath = @"C:\Users\p01004051\Documents\AoC-PuzzleInputs\2025\Prod\day02.txt";
|
||||
|
||||
public Day02Test()
|
||||
{
|
||||
_sut = new Day02();
|
||||
}
|
||||
[Fact]
|
||||
public void Part01_Test_equals_1227775554()
|
||||
{
|
||||
var actual = _sut.SolvePart1(TestInputPath);
|
||||
|
||||
Assert.Equal(1227775554, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Part01_Prod_equals_13919717792()
|
||||
{
|
||||
var actual = _sut.SolvePart1(ProdInputPath);
|
||||
|
||||
Assert.Equal(13919717792, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Part02_Test_equals_4174379265()
|
||||
{
|
||||
var actual = _sut.SolvePart2(TestInputPath);
|
||||
|
||||
Assert.Equal(4174379265, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Part02_Prod_equals_14582313461()
|
||||
{
|
||||
var actual = _sut.SolvePart2(ProdInputPath);
|
||||
|
||||
Assert.Equal(14582313461, actual);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
using AdvenOfCode.Contracts;
|
||||
|
||||
namespace AoC_2025.Tests;
|
||||
|
||||
public class Day03Test
|
||||
{
|
||||
private readonly IPuzzleSolver<long> _sut;
|
||||
private const string TestInputPath = @"C:\Users\p01004051\Documents\AoC-PuzzleInputs\2025\Test\day03.txt";
|
||||
private const string ProdInputPath = @"C:\Users\p01004051\Documents\AoC-PuzzleInputs\2025\Prod\day03.txt";
|
||||
|
||||
public Day03Test()
|
||||
{
|
||||
_sut = new Day03();
|
||||
}
|
||||
[Fact]
|
||||
public void Part01_Test_equals_357()
|
||||
{
|
||||
var actual = _sut.SolvePart1(TestInputPath);
|
||||
|
||||
Assert.Equal(357, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Part01_Prod_equals_16812()
|
||||
{
|
||||
var actual = _sut.SolvePart1(ProdInputPath);
|
||||
|
||||
Assert.Equal(16812, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Part02_Test_equals_3121910778619()
|
||||
{
|
||||
var actual = _sut.SolvePart2(TestInputPath);
|
||||
|
||||
Assert.Equal(3121910778619, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Part02_Prod_equals_166345822896410()
|
||||
{
|
||||
var actual = _sut.SolvePart2(ProdInputPath);
|
||||
|
||||
Assert.Equal(166345822896410, actual);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
using AdvenOfCode.Contracts;
|
||||
|
||||
namespace AoC_2025.Tests;
|
||||
|
||||
public class Day04Test
|
||||
{
|
||||
private readonly IPuzzleSolver<long> _sut;
|
||||
private const string TestInputPath = @"C:\Users\p01004051\Documents\AoC-PuzzleInputs\2025\Test\day04.txt";
|
||||
private const string ProdInputPath = @"C:\Users\p01004051\Documents\AoC-PuzzleInputs\2025\Prod\day04.txt";
|
||||
|
||||
public Day04Test()
|
||||
{
|
||||
_sut = new Day04();
|
||||
}
|
||||
[Fact]
|
||||
public void Part01_Test_equals_13()
|
||||
{
|
||||
var actual = _sut.SolvePart1(TestInputPath);
|
||||
|
||||
Assert.Equal(13, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Part01_Prod_equals_1411()
|
||||
{
|
||||
var actual = _sut.SolvePart1(ProdInputPath);
|
||||
|
||||
Assert.Equal(1411, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Part02_Test_equals_43()
|
||||
{
|
||||
var actual = _sut.SolvePart2(TestInputPath);
|
||||
|
||||
Assert.Equal(43, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Part02_Prod_equals_8557()
|
||||
{
|
||||
var actual = _sut.SolvePart2(ProdInputPath);
|
||||
|
||||
Assert.Equal(8557, actual);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AdvenOfCode.Contracts\AdvenOfCode.Contracts.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AdvenOfCode.Contracts;
|
||||
|
||||
namespace AoC_2025;
|
||||
|
||||
public class Day01 : IPuzzleSolver<int>
|
||||
{
|
||||
private string[] ParsePuzzleInput(string path)
|
||||
{
|
||||
var puzzleInput = File.ReadAllLines(path)
|
||||
.Where(l => !string.IsNullOrWhiteSpace(l))
|
||||
.ToArray();
|
||||
return puzzleInput;
|
||||
}
|
||||
|
||||
public int SolvePart1(string pathToPuzzleInput)
|
||||
{
|
||||
var rotationInstructions = ParsePuzzleInput(pathToPuzzleInput);
|
||||
var dialPosition = 50;
|
||||
var timesZeroWasHit = 0;
|
||||
foreach (var rotationAmount in rotationInstructions.Select(ParseRotationAmount))
|
||||
{
|
||||
dialPosition = (dialPosition + rotationAmount) % 100;
|
||||
if (dialPosition == 0)
|
||||
timesZeroWasHit++;
|
||||
}
|
||||
return timesZeroWasHit;
|
||||
}
|
||||
|
||||
public int SolvePart2(string pathToPuzzleInput)
|
||||
{
|
||||
var rotationInstructions = ParsePuzzleInput(pathToPuzzleInput);
|
||||
var dialPosition = 50;
|
||||
var timesZeroWasHit = 0;
|
||||
foreach (var rotationAmount in rotationInstructions.Select(ParseRotationAmount))
|
||||
{
|
||||
var actualRotationAmount = 0;
|
||||
if (rotationAmount < 0)
|
||||
{
|
||||
(var fullTurns, actualRotationAmount) = DivMod(rotationAmount, -100);
|
||||
timesZeroWasHit += fullTurns;
|
||||
if (dialPosition != 0 && dialPosition + actualRotationAmount <= 0)
|
||||
timesZeroWasHit++;
|
||||
}
|
||||
else
|
||||
{
|
||||
(var fullTurns, actualRotationAmount) = DivMod(rotationAmount, 100);
|
||||
timesZeroWasHit += fullTurns;
|
||||
if (dialPosition + actualRotationAmount >= 100)
|
||||
timesZeroWasHit++;
|
||||
}
|
||||
|
||||
dialPosition = Mod(dialPosition + actualRotationAmount, 100);
|
||||
}
|
||||
return timesZeroWasHit;
|
||||
}
|
||||
|
||||
private (int div, int mod) DivMod(int number, int divisor)
|
||||
{
|
||||
return (number / divisor, Mod(number, divisor));
|
||||
}
|
||||
|
||||
private int Mod(int number, int divident)
|
||||
{
|
||||
var mod = number % divident;
|
||||
if (number < 0 && divident > 0)
|
||||
{
|
||||
mod = divident + mod;
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
private static bool HasPassedZero(bool hasOverflow, int dialPosition)
|
||||
{
|
||||
return dialPosition != 0 && hasOverflow;
|
||||
}
|
||||
|
||||
private static (int nextDialPosition, bool passedZero) GetNextDialPosition(int rotationAmount, int dialPosition)
|
||||
{
|
||||
var actualRotation = rotationAmount % 100;
|
||||
var nextDialPosition = dialPosition + actualRotation;
|
||||
var hasOverflow = nextDialPosition is > 99 or < 1;
|
||||
nextDialPosition %= 100;
|
||||
if (nextDialPosition < 0)
|
||||
{
|
||||
nextDialPosition = 100 + nextDialPosition;
|
||||
}
|
||||
return (nextDialPosition, hasOverflow);
|
||||
}
|
||||
|
||||
private static int ParseRotationAmount(string puzzleInput)
|
||||
{
|
||||
var direction = puzzleInput[..1];
|
||||
var rotationAmount = int.Parse(puzzleInput[1..]);
|
||||
if (direction == "L")
|
||||
{
|
||||
rotationAmount *= -1;
|
||||
}
|
||||
|
||||
return rotationAmount;
|
||||
}
|
||||
|
||||
private static int CountFullRotations(int rotationAmount)
|
||||
{
|
||||
var fullRotations = Math.Abs(rotationAmount / 100);
|
||||
|
||||
return fullRotations;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
using AdvenOfCode.Contracts;
|
||||
|
||||
namespace AoC_2025;
|
||||
|
||||
public class Day02 : IPuzzleSolver<long>
|
||||
{
|
||||
private string[] ParsePuzzleInput(string path)
|
||||
{
|
||||
var puzzleInput = File.ReadAllText(path)
|
||||
.Trim()
|
||||
.Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||
return puzzleInput;
|
||||
}
|
||||
|
||||
public long SolvePart1(string pathToPuzzleInput)
|
||||
{
|
||||
var idRanges = ParsePuzzleInput(pathToPuzzleInput);
|
||||
var invalidIds = idRanges.SelectMany(range => FindInvalidIds(range));
|
||||
var sum = invalidIds.Sum();
|
||||
return sum;
|
||||
}
|
||||
|
||||
public long SolvePart2(string pathToPuzzleInput)
|
||||
{
|
||||
var idRanges = ParsePuzzleInput(pathToPuzzleInput);
|
||||
var invalidIds = idRanges.SelectMany(range => FindInvalidSegmentedIds(range));
|
||||
var sum = invalidIds.Sum();
|
||||
return sum;
|
||||
}
|
||||
|
||||
private IEnumerable<long> FindInvalidIds(string range)
|
||||
{
|
||||
var (start, end) = Parse(range);
|
||||
var halvableIds = FindHalvableIds(start, end);
|
||||
var invalidIds = GetInvalidIds(halvableIds);
|
||||
return invalidIds;
|
||||
}
|
||||
|
||||
private IEnumerable<long> FindInvalidSegmentedIds(string range)
|
||||
{
|
||||
var (start, end) = Parse(range);
|
||||
var idsAsAllSegments = GetIdAsAllSegments(start, end);
|
||||
var invalidIdSegments = FindIdsWhereAllSegmentsAreEqual(idsAsAllSegments);
|
||||
var invalidIds = MergeSegments(invalidIdSegments);
|
||||
var invalidIdNumbers = invalidIds.Select(id => long.Parse(id));
|
||||
return invalidIdNumbers;
|
||||
}
|
||||
|
||||
private (long start, long end) Parse(string range)
|
||||
{
|
||||
var parts = range.Split('-', StringSplitOptions.RemoveEmptyEntries);
|
||||
return (long.Parse(parts[0]), long.Parse(parts[1]));
|
||||
}
|
||||
|
||||
private IEnumerable<string> FindHalvableIds(long start, long end)
|
||||
{
|
||||
var ids = Range(start, end);
|
||||
var idStrings = ids.Select(id => id.ToString());
|
||||
var halvableIds = idStrings.Where(id => (id.Length % 2) == 0);
|
||||
return halvableIds;
|
||||
}
|
||||
|
||||
private IEnumerable<long> GetInvalidIds(IEnumerable<string> halvableIds)
|
||||
{
|
||||
var idParts = halvableIds.Select(id => (id[..(id.Length / 2)], id[(id.Length / 2)..]));
|
||||
var invalidIds = idParts.Where(parts=> parts.Item1 == parts.Item2);
|
||||
var invalidNumberedIds = invalidIds.Select(id => long.Parse(id.Item1 + id.Item2));
|
||||
return invalidNumberedIds;
|
||||
}
|
||||
|
||||
private IEnumerable<long> Range(long start, long end)
|
||||
{
|
||||
for (var i = start; i <= end; i++)
|
||||
{
|
||||
yield return i;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IEnumerable<IEnumerable<string>>> GetIdAsAllSegments(long start, long end)
|
||||
{
|
||||
var ids = Range(start, end);
|
||||
var idStrings = ids.Select(id => id.ToString());
|
||||
var idSegments = idStrings.Select(id => GetSegments(id));
|
||||
return idSegments;
|
||||
}
|
||||
|
||||
private IEnumerable<IEnumerable<string>> GetSegments(string id)
|
||||
{
|
||||
for (int i = id.Length / 2; i > 0; i--)
|
||||
{
|
||||
if (id.Length % i == 0)
|
||||
{
|
||||
yield return id.Chunk(i).Select(chunks => new string(chunks));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IEnumerable<string>> FindIdsWhereAllSegmentsAreEqual(IEnumerable<IEnumerable<IEnumerable<string>>> idAllSegments)
|
||||
{
|
||||
var segmentsWithOneAllMatching = FilterForAnyAllSegmentsEqual(idAllSegments);
|
||||
var idSegments = GetFirstForEachSegments(segmentsWithOneAllMatching);
|
||||
return idSegments;
|
||||
}
|
||||
|
||||
private static IEnumerable<IEnumerable<string>> GetFirstForEachSegments(IEnumerable<IEnumerable<IEnumerable<string>>> segmentsWithOneAllMatching)
|
||||
{
|
||||
var idSegments = segmentsWithOneAllMatching
|
||||
.Select(segments => segments.First());
|
||||
return idSegments;
|
||||
}
|
||||
|
||||
private IEnumerable<string> MergeSegments(IEnumerable<IEnumerable<string>> segments)
|
||||
{
|
||||
return segments.Select(segment => string.Concat(segment));
|
||||
}
|
||||
|
||||
private IEnumerable<IEnumerable<IEnumerable<string>>> FilterForAnyAllSegmentsEqual(IEnumerable<IEnumerable<IEnumerable<string>>> idAllSegments)
|
||||
{
|
||||
var segmentsWithOneAllMatching = idAllSegments
|
||||
.Where(idSegments => idSegments.Any(segments => CheckAllSegmentsEqual(segments)));
|
||||
return segmentsWithOneAllMatching;
|
||||
}
|
||||
|
||||
private bool CheckAllSegmentsEqual(IEnumerable<string> segments)
|
||||
{
|
||||
var (allEqual, _) = segments.Aggregate(
|
||||
(allEqual: true, prev: ""),
|
||||
(tuple, segment) => (tuple.allEqual && (tuple.prev == "" || tuple.prev == segment), segment));
|
||||
return allEqual;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AdvenOfCode.Contracts;
|
||||
|
||||
namespace AoC_2025;
|
||||
|
||||
public class Day03 : IPuzzleSolver<long>
|
||||
{
|
||||
private string[] ParsePuzzleInput(string path)
|
||||
{
|
||||
var puzzleInput = File.ReadAllLines(path)
|
||||
.Where(line => !string.IsNullOrWhiteSpace(line))
|
||||
.ToArray();
|
||||
return puzzleInput;
|
||||
}
|
||||
|
||||
public long SolvePart1(string pathToPuzzleInput)
|
||||
{
|
||||
var batterieBankStrings = ParsePuzzleInput(pathToPuzzleInput);
|
||||
var batterieBanks = batterieBankStrings.Select(bbs => ParseBatterieBank(bbs));
|
||||
var voltages = batterieBanks.Select(bb => FindMaxVoltage(bb));
|
||||
var sumVoltages = voltages.Sum();
|
||||
return sumVoltages;
|
||||
}
|
||||
|
||||
public long SolvePart2(string pathToPuzzleInput)
|
||||
{
|
||||
const int voltageLength = 12;
|
||||
var batterieBankStrings = ParsePuzzleInput(pathToPuzzleInput);
|
||||
var batterieBanks = batterieBankStrings.Select(bbs => ParseBatterieBank(bbs));
|
||||
var voltages = batterieBanks.Select(bb => GetMaxSuperVoltage(bb, voltageLength));
|
||||
var sumVoltages = voltages.Sum();
|
||||
return sumVoltages;
|
||||
}
|
||||
|
||||
private int[] ParseBatterieBank(string batterieBank)
|
||||
{
|
||||
return batterieBank
|
||||
.Select(c => new string(c, 1))
|
||||
.Select(value => int.Parse(value))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private long FindMaxVoltage(Span<int> batterieBank)
|
||||
{
|
||||
var (firstNumber, position) = GetMax(batterieBank[..^1]);
|
||||
var (secondNumber, _) = GetMax(batterieBank[(position + 1)..]);
|
||||
var voltage = Combine(firstNumber, secondNumber);
|
||||
return voltage;
|
||||
}
|
||||
|
||||
private long Combine(long first, long second)
|
||||
{
|
||||
return (first * 10) + second;
|
||||
}
|
||||
|
||||
private long GetMaxSuperVoltage(Span<int> batterieBank, int voltageLength)
|
||||
{
|
||||
var indexedVoltageLength = voltageLength - 1;
|
||||
var currentBankPosition = 0;
|
||||
var superVoltage = 0L;
|
||||
for (var i = 0; i < voltageLength; i++)
|
||||
{
|
||||
var (max, numberPosition) = GetMax(batterieBank[currentBankPosition..^(indexedVoltageLength - i)]);
|
||||
superVoltage = Combine(superVoltage, max);
|
||||
currentBankPosition += numberPosition + 1;
|
||||
}
|
||||
|
||||
return superVoltage;
|
||||
}
|
||||
|
||||
private (int max, int currentPosition) GetMax(Span<int> batterieBank)
|
||||
{
|
||||
var max = batterieBank[0];
|
||||
var currentPosition = 0;
|
||||
for (var i = 1; i < batterieBank.Length; i++)
|
||||
{
|
||||
if (max < batterieBank[i])
|
||||
{
|
||||
max = batterieBank[i];
|
||||
currentPosition = i;
|
||||
}
|
||||
}
|
||||
|
||||
return (max, currentPosition);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AdvenOfCode.Contracts;
|
||||
using Coordinate = (int x, int y);
|
||||
|
||||
namespace AoC_2025;
|
||||
|
||||
public class Day04 : IPuzzleSolver<long>
|
||||
{
|
||||
private string[] ParsePuzzleInput(string path)
|
||||
{
|
||||
var puzzleInput = File.ReadAllLines(path)
|
||||
.Where(line => !string.IsNullOrWhiteSpace(line))
|
||||
.Select(line => line.Trim())
|
||||
.ToArray();
|
||||
return puzzleInput;
|
||||
}
|
||||
|
||||
public long SolvePart1(string pathToPuzzleInput)
|
||||
{
|
||||
var paperrollGrid = ParsePuzzleInput(pathToPuzzleInput);
|
||||
var accessiblePaperrolls = GetAccessiblePaperrolls(paperrollGrid);
|
||||
var countAccessibleRolls = accessiblePaperrolls.Count();
|
||||
return countAccessibleRolls;
|
||||
}
|
||||
|
||||
public long SolvePart2(string pathToPuzzleInput)
|
||||
{
|
||||
var paperrollGrid = ParsePuzzleInput(pathToPuzzleInput);
|
||||
var rollCoordinates = GetRollCoordinates(paperrollGrid);
|
||||
var countAccessibleRolls = RecursiveCountAllRemovableRolls(rollCoordinates);
|
||||
return countAccessibleRolls;
|
||||
}
|
||||
|
||||
private IEnumerable<Coordinate> GetAccessiblePaperrolls(IEnumerable<string> paperrollGrid)
|
||||
{
|
||||
var rollCoordinates = GetRollCoordinates(paperrollGrid);
|
||||
var rollsWithNeighbours = GetNeighbours(rollCoordinates);
|
||||
var accessiblePaperrolls = FilterForLessThan(rollsWithNeighbours, 4);
|
||||
return accessiblePaperrolls;
|
||||
}
|
||||
|
||||
private int RecursiveCountAllRemovableRolls(HashSet<Coordinate> coordinates)
|
||||
{
|
||||
var rollsWithNeighbours = GetNeighbours(coordinates);
|
||||
var accessiblePaperrolls = FilterForLessThan(rollsWithNeighbours, 4).ToArray();
|
||||
var countAccessibleRolls = accessiblePaperrolls.Length;
|
||||
coordinates.ExceptWith(accessiblePaperrolls);
|
||||
return countAccessibleRolls == 0
|
||||
? 0
|
||||
: countAccessibleRolls + RecursiveCountAllRemovableRolls(coordinates);
|
||||
}
|
||||
|
||||
private HashSet<Coordinate> GetRollCoordinates(IEnumerable<string> paperrollGrid)
|
||||
{
|
||||
var coordinates = paperrollGrid
|
||||
.SelectMany((gridLine, xIndex) => GetCoordinates(gridLine, xIndex))
|
||||
.ToHashSet();
|
||||
return coordinates;
|
||||
}
|
||||
|
||||
private IEnumerable<Coordinate> GetCoordinates(string gridLine, int xIndex)
|
||||
{
|
||||
var indexedCharacters = gridLine.Select((character, yIndex) => (character, yIndex));
|
||||
var validRolls = indexedCharacters.Where(tuple => tuple.character == '@');
|
||||
var rollCoordinates = validRolls.Select(tuple => (xIndex, tuple.yIndex));
|
||||
return rollCoordinates;
|
||||
}
|
||||
|
||||
private IEnumerable<(Coordinate coordinate, Coordinate[] neighbours)> GetNeighbours(HashSet<Coordinate> rollCoordinates)
|
||||
{
|
||||
var coordsWithNeighbourCount = rollCoordinates
|
||||
.Select(coord => (coord, GetNeighbours(coord, rollCoordinates)));
|
||||
return coordsWithNeighbourCount;
|
||||
}
|
||||
|
||||
private Coordinate[] GetNeighbours(Coordinate coordinate, HashSet<Coordinate> coordinates)
|
||||
{
|
||||
Coordinate[] neighbourDirections =
|
||||
[
|
||||
(-1, -1), (-1, 0), (-1, 1),
|
||||
(0, -1), (0, 1),
|
||||
(1, -1), (1, 0), (1, 1),
|
||||
];
|
||||
var possibleNeighbours = neighbourDirections
|
||||
.Select(direction => (coordinate.x + direction.x, coordinate.y + direction.y));
|
||||
var actualNeighbours = possibleNeighbours
|
||||
.Where(coord => coordinates.Contains(coord))
|
||||
.ToArray();
|
||||
return actualNeighbours;
|
||||
}
|
||||
|
||||
private IEnumerable<Coordinate> FilterForLessThan(IEnumerable<(Coordinate coordinate, Coordinate[] neighbours)> coordinatesWithNeighbours,
|
||||
int lessThan)
|
||||
{
|
||||
var coordinatesWithLess = coordinatesWithNeighbours
|
||||
.Where(entry => entry.neighbours.Count() < lessThan)
|
||||
.Select(entry => entry.coordinate);
|
||||
return coordinatesWithLess;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue