Skip to content

Commit

Permalink
Added day 9 solution (#7)
Browse files Browse the repository at this point in the history
* Added day 9 scaffolding

* Added part 1 README

* Solved part 1

* Solver part 2

* Normalized line-ending

* Remove my inputs from repo

* Remove puzzle text from README

* Move day 9 to solved solution folder

* Added Rider run files
  • Loading branch information
mMosiur authored Apr 2, 2024
1 parent df85caf commit 8b64d7b
Show file tree
Hide file tree
Showing 16 changed files with 376 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .run/Day09 example.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Day09 example" type="DotNetProject" factoryName=".NET Project"
folderName="Day09">
<option name="EXE_PATH" value="$PROJECT_DIR$/Day09 - Mirage Maintenance/bin/Debug/net8.0/Day09.exe"/>
<option name="PROGRAM_PARAMETERS" value="example.txt"/>
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/Day09 - Mirage Maintenance/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$/Day09 - Mirage Maintenance/Day09.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/Day09.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Day09" type="DotNetProject" factoryName=".NET Project" folderName="Day09">
<option name="EXE_PATH" value="$PROJECT_DIR$/Day09 - Mirage Maintenance/bin/Debug/net8.0/Day09.exe"/>
<option name="PROGRAM_PARAMETERS" value=""/>
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/Day09 - Mirage Maintenance/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$/Day09 - Mirage Maintenance/Day09.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 @@ -34,6 +34,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Day07", "Day07 - Camel Card
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Day08", "Day08 - Haunted Wasteland\Day08.csproj", "{78787B01-0E1E-472E-8B58-4FFD864FC1F6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Day09", "Day09 - Mirage Maintenance\Day09.csproj", "{1E0917F9-35B3-4474-B335-E72C6BDFE667}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -79,6 +81,10 @@ Global
{78787B01-0E1E-472E-8B58-4FFD864FC1F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{78787B01-0E1E-472E-8B58-4FFD864FC1F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{78787B01-0E1E-472E-8B58-4FFD864FC1F6}.Release|Any CPU.Build.0 = Release|Any CPU
{1E0917F9-35B3-4474-B335-E72C6BDFE667}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E0917F9-35B3-4474-B335-E72C6BDFE667}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E0917F9-35B3-4474-B335-E72C6BDFE667}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E0917F9-35B3-4474-B335-E72C6BDFE667}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CE8086B8-A3E4-40E0-859F-607F95D25514} = {F6C05A63-6269-425F-B877-9E9F0BC1FC26}
Expand All @@ -89,5 +95,6 @@ Global
{6BA7E3DC-B970-457B-84FA-50034501273B} = {F6C05A63-6269-425F-B877-9E9F0BC1FC26}
{0A495922-31C5-4E5D-84AB-95262108E1D9} = {F6C05A63-6269-425F-B877-9E9F0BC1FC26}
{78787B01-0E1E-472E-8B58-4FFD864FC1F6} = {F6C05A63-6269-425F-B877-9E9F0BC1FC26}
{1E0917F9-35B3-4474-B335-E72C6BDFE667} = {F6C05A63-6269-425F-B877-9E9F0BC1FC26}
EndGlobalSection
EndGlobal
18 changes: 18 additions & 0 deletions Day09 - Mirage Maintenance/.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/Day09.dll",
"args": [
"input.txt"
],
"cwd": "${workspaceFolder}",
"console": "internalConsole",
"stopAtEntry": false
}
]
}
21 changes: 21 additions & 0 deletions Day09 - Mirage Maintenance/.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}/Day09.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
]
}
22 changes: 22 additions & 0 deletions Day09 - Mirage Maintenance/Day09.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.Day09</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="mMosiur.AdventOfCode.Abstractions" Version="4.4.0" />
<PackageReference Include="mMosiur.AdventOfCode.Common" Version="0.1.0" />
</ItemGroup>

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

</Project>
52 changes: 52 additions & 0 deletions Day09 - Mirage Maintenance/Day09Solver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using AdventOfCode.Abstractions;
using AdventOfCode.Year2023.Day09.Puzzle.Oasis;

namespace AdventOfCode.Year2023.Day09;

public sealed class Day09Solver : DaySolver
{
public override int Year => 2023;
public override int Day => 9;
public override string Title => "Mirage Maintenance";

private readonly ReportReader _reportReader;
private Report? _report;

public Day09Solver(Day09SolverOptions options) : base(options)
{
_reportReader = new();
}

public Day09Solver(Action<Day09SolverOptions> configure)
: this(DaySolverOptions.FromConfigureAction(configure))
{
}

public Day09Solver() : this(new Day09SolverOptions())
{
}

public override string SolvePart1()
{
_report ??= _reportReader.ReadReport(InputLines);

int result = _report
.Histories
.Select(h => h.PredictNextValue())
.Sum();

return result.ToString();
}

public override string SolvePart2()
{
_report ??= _reportReader.ReadReport(InputLines);

int result = _report
.Histories
.Select(h => h.ExtrapolatePreviousValue())
.Sum();

return result.ToString();
}
}
7 changes: 7 additions & 0 deletions Day09 - Mirage Maintenance/Day09SolverOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using AdventOfCode.Abstractions;

namespace AdventOfCode.Year2023.Day09;

public sealed class Day09SolverOptions : DaySolverOptions
{
}
45 changes: 45 additions & 0 deletions Day09 - Mirage Maintenance/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Diagnostics;
using AdventOfCode;
using AdventOfCode.Year2023.Day09;

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>]\"."
)
};

Day09Solver 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);
}
8 changes: 8 additions & 0 deletions Day09 - Mirage Maintenance/Puzzle/Oasis/Report.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace AdventOfCode.Year2023.Day09.Puzzle.Oasis;

internal sealed class Report(IEnumerable<ValueHistory> valueHistories)
{
private readonly List<ValueHistory> _histories = valueHistories.ToList();

public IReadOnlyList<ValueHistory> Histories => _histories;
}
30 changes: 30 additions & 0 deletions Day09 - Mirage Maintenance/Puzzle/Oasis/ReportReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using AdventOfCode.Common.SpanExtensions;

namespace AdventOfCode.Year2023.Day09.Puzzle.Oasis;

internal sealed class ReportReader
{
public Report ReadReport(IEnumerable<string> inputLines)
{
var valueHistories = inputLines.Select(l => ReadReportLine(l));
return new Report(valueHistories);
}

private static ValueHistory ReadReportLine(ReadOnlySpan<char> line)
{
line = line.Trim();
int valueCount = line.Count(' ') + 1;
var values = new List<int>(valueCount);
foreach (var numberSpan in line.Split(' '))
{
if (!int.TryParse(numberSpan, out int number))
{
throw new InputException($"Invalid number format '{numberSpan}'.");
}

values.Add(number);
}

return new ValueHistory(values);
}
}
91 changes: 91 additions & 0 deletions Day09 - Mirage Maintenance/Puzzle/Oasis/ValueHistory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System.Collections;

namespace AdventOfCode.Year2023.Day09.Puzzle.Oasis;

internal sealed class ValueHistory(IEnumerable<int> values)
: IReadOnlyList<int>
{
private readonly int[] _valueHistory = values.ToArray();
private int? _previousValue;
private int? _nextValue;

public int Count => _valueHistory.Length;

public int this[int index] => _valueHistory[index];

public IEnumerator<int> GetEnumerator() => _valueHistory.AsEnumerable().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

public int PredictNextValue()
{
_nextValue ??= InternalPredictNextValue();
return _nextValue.Value;
}

public int ExtrapolatePreviousValue()
{
_previousValue ??= InternalExtrapolatePreviousValue();
return _previousValue.Value;
}

private int InternalPredictNextValue()
{
Span<int> span = stackalloc int[Count];
_valueHistory.CopyTo(span);

int end = Count;

while (true)
{
end--;
int anyValueNonZero = 0;
for (int i = 0; i < end; i++)
{
int diff = span[i + 1] - span[i];
anyValueNonZero |= diff;
span[i] = diff;
}

if (anyValueNonZero == 0) break;
}

while (end < Count)
{
span[end] += span[end - 1];
end++;
}

return span[^1];
}

private int InternalExtrapolatePreviousValue()
{
Span<int> span = stackalloc int[Count];
_valueHistory.CopyTo(span);

int start = -1;

while (true)
{
start++;
int anyValueNonZero = 0;
for (int i = span.Length - 1; i > start; i--)
{
int diff = span[i] - span[i - 1];
anyValueNonZero |= diff;
span[i] = diff;
}

if (anyValueNonZero == 0) break;
}

while (start >= 0)
{
span[start] -= span[start + 1];
start--;
}


return span[0];
}
}
5 changes: 5 additions & 0 deletions Day09 - Mirage Maintenance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# [Day 9: Mirage Maintenance](https://adventofcode.com/2023/day/9)

You analyze environmental data from an oasis using the Oasis And Sand Instability Sensor (OASIS).
The sensor provides a report of values and their changes over time.
You're tasked with predicting the next value in each history by analyzing the differences between consecutive values and extrapolating.
Loading

0 comments on commit 8b64d7b

Please sign in to comment.