Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Day 11 #48

Merged
merged 5 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .run/Day11 example.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Day11 example" type="DotNetProject" factoryName=".NET Project"
folderName="Day11">
<option name="EXE_PATH" value="$PROJECT_DIR$/Day11 - Cosmic Expansion/bin/Debug/net8.0/Day11.exe"/>
<option name="PROGRAM_PARAMETERS" value="example.txt"/>
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/Day11 - Cosmic Expansion/bin/Debug/net8.0"/>
<option name="PASS_PARENT_ENVS" value="1"/>
<option name="USE_EXTERNAL_CONSOLE" value="0"/>
<option name="USE_MONO" value="0"/>
<option name="RUNTIME_ARGUMENTS" value=""/>
<option name="PROJECT_PATH" value="$PROJECT_DIR$/Day11 - Cosmic Expansion/Day11.csproj"/>
<option name="PROJECT_EXE_PATH_TRACKING" value="1"/>
<option name="PROJECT_ARGUMENTS_TRACKING" value="1"/>
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1"/>
<option name="PROJECT_KIND" value="DotNetCore"/>
<option name="PROJECT_TFM" value="net8.0"/>
<method v="2">
<option name="Build"/>
</method>
</configuration>
</component>
20 changes: 20 additions & 0 deletions .run/Day11.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Day11" type="DotNetProject" factoryName=".NET Project" folderName="Day11">
<option name="EXE_PATH" value="$PROJECT_DIR$/Day11 - Cosmic Expansion/bin/Debug/net8.0/Day11.exe"/>
<option name="PROGRAM_PARAMETERS" value=""/>
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/Day11 - Cosmic Expansion/bin/Debug/net8.0"/>
<option name="PASS_PARENT_ENVS" value="1"/>
<option name="USE_EXTERNAL_CONSOLE" value="0"/>
<option name="USE_MONO" value="0"/>
<option name="RUNTIME_ARGUMENTS" value=""/>
<option name="PROJECT_PATH" value="$PROJECT_DIR$/Day11 - Cosmic Expansion/Day11.csproj"/>
<option name="PROJECT_EXE_PATH_TRACKING" value="1"/>
<option name="PROJECT_ARGUMENTS_TRACKING" value="1"/>
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1"/>
<option name="PROJECT_KIND" value="DotNetCore"/>
<option name="PROJECT_TFM" value="net8.0"/>
<method v="2">
<option name="Build"/>
</method>
</configuration>
</component>
7 changes: 7 additions & 0 deletions AdventOfCode2023.sln
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Day09", "Day09 - Mirage Mai
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Day10", "Day10 - Pipe Maze\Day10.csproj", "{D237B79E-9D78-4F99-B9BA-43B52609AAAE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Day11", "Day11 - Cosmic Expansion\Day11.csproj", "{28DC51A6-39A7-4180-B890-D5B5D0AF71EC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -92,6 +94,10 @@ Global
{D237B79E-9D78-4F99-B9BA-43B52609AAAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D237B79E-9D78-4F99-B9BA-43B52609AAAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D237B79E-9D78-4F99-B9BA-43B52609AAAE}.Release|Any CPU.Build.0 = Release|Any CPU
{28DC51A6-39A7-4180-B890-D5B5D0AF71EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{28DC51A6-39A7-4180-B890-D5B5D0AF71EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{28DC51A6-39A7-4180-B890-D5B5D0AF71EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{28DC51A6-39A7-4180-B890-D5B5D0AF71EC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CE8086B8-A3E4-40E0-859F-607F95D25514} = {F6C05A63-6269-425F-B877-9E9F0BC1FC26}
Expand All @@ -104,5 +110,6 @@ Global
{78787B01-0E1E-472E-8B58-4FFD864FC1F6} = {F6C05A63-6269-425F-B877-9E9F0BC1FC26}
{1E0917F9-35B3-4474-B335-E72C6BDFE667} = {F6C05A63-6269-425F-B877-9E9F0BC1FC26}
{D237B79E-9D78-4F99-B9BA-43B52609AAAE} = {F6C05A63-6269-425F-B877-9E9F0BC1FC26}
{28DC51A6-39A7-4180-B890-D5B5D0AF71EC} = {F6C05A63-6269-425F-B877-9E9F0BC1FC26}
EndGlobalSection
EndGlobal
18 changes: 18 additions & 0 deletions Day11 - Cosmic Expansion/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch (my input)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/bin/Debug/net8.0/Day11.dll",
"args": [
"input.txt"
],
"cwd": "${workspaceFolder}",
"console": "internalConsole",
"stopAtEntry": false
}
]
}
21 changes: 21 additions & 0 deletions Day11 - Cosmic Expansion/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"group": {
"kind": "build",
"isDefault": true
},
"args": [
"build",
"${workspaceFolder}/Day11.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
]
}
22 changes: 22 additions & 0 deletions Day11 - Cosmic Expansion/Day11.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>AdventOfCode.Year2023.Day11</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="mMosiur.AdventOfCode.Abstractions" Version="4.4.1"/>
<PackageReference Include="mMosiur.AdventOfCode.Common" Version="0.1.3"/>
</ItemGroup>

<ItemGroup>
<None Update="*.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
63 changes: 63 additions & 0 deletions Day11 - Cosmic Expansion/Day11Solver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using AdventOfCode.Abstractions;
using AdventOfCode.Common.Geometry;
using AdventOfCode.Year2023.Day11.Puzzle;

namespace AdventOfCode.Year2023.Day11;

public sealed class Day11Solver : DaySolver
{
public override int Year => 2023;
public override int Day => 11;
public override string Title => "Cosmic Expansion";

private readonly IReadOnlyCollection<Point> _initialPositions;
private readonly Day11SolverOptions _options;

public Day11Solver(Day11SolverOptions options) : base(options)
{
_options = options;
var inputReader = new InputReader(options.GalaxyChar);
_initialPositions = inputReader.ReadGalaxyPositions(Input);
}

public Day11Solver(Action<Day11SolverOptions> configure)
: this(DaySolverOptions.FromConfigureAction(configure))
{
}

public Day11Solver() : this(new Day11SolverOptions())
{
}

public override string SolvePart1()
{
var galaxyMap = new GalaxyMap(_initialPositions);
galaxyMap.Expand(_options.PartOneExpansionMagnitude);
long sum = SumDistancesBetweenGalaxies(galaxyMap);
return sum.ToString();
}

public override string SolvePart2()
{
var galaxyMap = new GalaxyMap(_initialPositions);
galaxyMap.Expand(_options.PartTwoExpansionMagnitude);
long sum = SumDistancesBetweenGalaxies(galaxyMap);
return sum.ToString();
}

private static long SumDistancesBetweenGalaxies(GalaxyMap galaxyMap)
{
long sum = 0;
for (int i = 0; i < galaxyMap.Galaxies.Count; i++)
{
var g1 = galaxyMap.Galaxies[i];
for (int j = i + 1; j < galaxyMap.Galaxies.Count; j++)
{
var g2 = galaxyMap.Galaxies[j];
sum += MathG.ManhattanDistance(g1.Position, g2.Position);
}
}

return sum;
}
}
11 changes: 11 additions & 0 deletions Day11 - Cosmic Expansion/Day11SolverOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using AdventOfCode.Abstractions;

namespace AdventOfCode.Year2023.Day11;

public sealed class Day11SolverOptions : DaySolverOptions
{
public char GalaxyChar { get; set; } = '#';

public int PartOneExpansionMagnitude { get; set; } = 2;
public int PartTwoExpansionMagnitude { get; set; } = 1_000_000;
}
1 change: 1 addition & 0 deletions Day11 - Cosmic Expansion/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Point = AdventOfCode.Common.Geometry.Point2D<long>;
42 changes: 42 additions & 0 deletions Day11 - Cosmic Expansion/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Diagnostics;
using AdventOfCode;
using AdventOfCode.Year2023.Day11;

try
{
string? filepath = args.Length switch
{
0 => null,
1 => args[0],
_ => throw new CommandLineException(
$"Program was called with too many arguments. Proper usage: \"dotnet run [<input filepath>]\"."
)
};

Day11Solver solver = new(options => { options.InputFilepath = filepath ?? options.InputFilepath; });

Console.WriteLine($"--- Day {solver.Day}: {solver.Title} ---");

Console.Write("Part one: ");
string part1 = solver.SolvePart1();
Console.WriteLine(part1);

Console.Write("Part two: ");
string part2 = solver.SolvePart2();
Console.WriteLine(part2);
}
catch (AdventOfCodeException e)
{
string errorPrefix = e switch
{
CommandLineException => "Command line error",
InputException => "Input error",
DaySolverException => "Day solver error",
_ => throw new UnreachableException($"Unknown exception type \"{e.GetType()}\".")
};

Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine($"{errorPrefix}: {e.Message}");
Console.ResetColor();
Environment.Exit(1);
}
11 changes: 11 additions & 0 deletions Day11 - Cosmic Expansion/Puzzle/Galaxy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace AdventOfCode.Year2023.Day11.Puzzle;

internal interface IGalaxy
{
Point Position { get; }
}

internal sealed class Galaxy(Point position) : IGalaxy
{
public Point Position { get; set; } = position;
}
95 changes: 95 additions & 0 deletions Day11 - Cosmic Expansion/Puzzle/GalaxyMap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
namespace AdventOfCode.Year2023.Day11.Puzzle;

internal sealed class GalaxyMap
{
private const int ExpandListInitialCapacity = 10;

private readonly List<Galaxy> _galaxies;
private long _maxColumn;
private long _maxRow;

public GalaxyMap(IEnumerable<Point> galaxyPositions)
{
_galaxies = galaxyPositions.Select(p => new Galaxy(p)).ToList();
_maxRow = _galaxies.Max(g => g.Position.X);
_maxColumn = _galaxies.Max(g => g.Position.Y);
}

public IReadOnlyList<IGalaxy> Galaxies => _galaxies;

public void Expand(int expansionMagnitude)
{
ExpandRows(expansionMagnitude);
ExpandColumns(expansionMagnitude);
}

private void ExpandRows(int expansionMagnitude)
{
var galaxiesPerRow = new List<Galaxy>?[_maxRow + 1];
foreach (var galaxy in _galaxies)
{
long row = galaxy.Position.X;
var rowList = galaxiesPerRow[row];
if (rowList is null)
{
rowList = new List<Galaxy>(ExpandListInitialCapacity);
galaxiesPerRow[row] = rowList;
}

rowList.Add(galaxy);
}

int rowOffset = 0;
for (int row = 0; row <= _maxRow; row++)
{
var rowList = galaxiesPerRow[row];
if (rowList is null)
{
rowOffset = rowOffset + expansionMagnitude - 1;
continue;
}

foreach (var galaxy in rowList)
{
galaxy.Position = new(row + rowOffset, galaxy.Position.Y);
}
}

_maxRow += rowOffset;
}

private void ExpandColumns(int expansionMagnitude)
{
var galaxiesPerColumn = new List<Galaxy>?[_maxColumn + 1];
foreach (var galaxy in _galaxies)
{
long column = galaxy.Position.Y;
var columnList = galaxiesPerColumn[column];
if (columnList is null)
{
columnList = new List<Galaxy>(ExpandListInitialCapacity);
galaxiesPerColumn[column] = columnList;
}

columnList.Add(galaxy);
}

int columnOffset = 0;
for (int column = 0; column <= _maxColumn; column++)
{
var columnList = galaxiesPerColumn[column];
if (columnList is null)
{
columnOffset = columnOffset + expansionMagnitude - 1;
continue;
}

foreach (var galaxy in columnList)
{
galaxy.Position = new(galaxy.Position.X, column + columnOffset);
}
}

_maxColumn += columnOffset;
}
}
35 changes: 35 additions & 0 deletions Day11 - Cosmic Expansion/Puzzle/InputReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace AdventOfCode.Year2023.Day11.Puzzle;

internal sealed class InputReader
{
private const int InitialGalaxyListSize = 500;
private readonly char _galaxyChar;

public InputReader(char galaxyChar)
{
_galaxyChar = galaxyChar;
}

public IReadOnlyCollection<Point> ReadGalaxyPositions(string input)
{
var list = new List<Point>(InitialGalaxyListSize);
int row = 0;
foreach (var lineSpan in input.AsSpan().EnumerateLines())
{
int column = 0;
foreach (char c in lineSpan)
{
if (c == _galaxyChar)
{
list.Add(new(row, column));
}

column++;
}

row++;
}

return list;
}
}
Loading
Loading