mirror of
https://github.com/parnic/advent-of-code-2023.git
synced 2025-06-16 16:50:14 -05:00
Initial commit, prep
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/target
|
||||||
|
/.vs/
|
||||||
|
*.user
|
||||||
|
/bin/
|
||||||
|
/obj/
|
||||||
|
*.exe
|
10
.idea/.idea.advent-of-code-2023/.idea/.gitignore
generated
vendored
Normal file
10
.idea/.idea.advent-of-code-2023/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/.idea.advent-of-code-2023.iml
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
/modules.xml
|
||||||
|
/contentModel.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
1
.idea/.idea.advent-of-code-2023/.idea/.name
generated
Normal file
1
.idea/.idea.advent-of-code-2023/.idea/.name
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
advent-of-code-2023
|
4
.idea/.idea.advent-of-code-2023/.idea/encodings.xml
generated
Normal file
4
.idea/.idea.advent-of-code-2023/.idea/encodings.xml
generated
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||||
|
</project>
|
8
.idea/.idea.advent-of-code-2023/.idea/indexLayout.xml
generated
Normal file
8
.idea/.idea.advent-of-code-2023/.idea/indexLayout.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/.idea.advent-of-code-2023/.idea/vcs.xml
generated
Normal file
6
.idea/.idea.advent-of-code-2023/.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
8
GlobalSuppressions.cs
Normal file
8
GlobalSuppressions.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// This file is used by Code Analysis to maintain SuppressMessage
|
||||||
|
// attributes that are applied to this project.
|
||||||
|
// Project-level suppressions either have no target or are given
|
||||||
|
// a specific target and scoped to a namespace, type, member, etc.
|
||||||
|
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
[assembly: SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "<Pending>", Scope = "member", Target = "~F:aoc2023.DayTemplate.lines")]
|
32
Properties/launchSettings.json
Normal file
32
Properties/launchSettings.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"all days": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "all"
|
||||||
|
},
|
||||||
|
"current day": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": ""
|
||||||
|
},
|
||||||
|
"current day part 1": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "-part1"
|
||||||
|
},
|
||||||
|
"current day part 2": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "-part2"
|
||||||
|
},
|
||||||
|
"all days part 1": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "all -part1"
|
||||||
|
},
|
||||||
|
"all days part 2": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "all -part2"
|
||||||
|
},
|
||||||
|
"specific day": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Advent of Code 2023
|
||||||
|
|
||||||
|
My solutions to [Advent of Code 2023](https://adventofcode.com/2023).
|
36
advent-of-code-2023.csproj
Normal file
36
advent-of-code-2023.csproj
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<RootNamespace>aoc2023</RootNamespace>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ProduceReferenceAssembly>False</ProduceReferenceAssembly>
|
||||||
|
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<WarningLevel>9999</WarningLevel>
|
||||||
|
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||||
|
<NoWarn>1701;1702;8981</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<WarningLevel>9999</WarningLevel>
|
||||||
|
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||||
|
<NoWarn>1701;1702;8981</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="inputs\01.txt" />
|
||||||
|
<None Remove="inputs\01a.txt" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="inputs\01.txt" />
|
||||||
|
<EmbeddedResource Include="inputs\01a.txt" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
25
advent-of-code-2023.sln
Normal file
25
advent-of-code-2023.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "advent-of-code-2023", "advent-of-code-2023.csproj", "{1B54D933-507B-4F44-9BE3-F1794B593AF7}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{1B54D933-507B-4F44-9BE3-F1794B593AF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1B54D933-507B-4F44-9BE3-F1794B593AF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1B54D933-507B-4F44-9BE3-F1794B593AF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1B54D933-507B-4F44-9BE3-F1794B593AF7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {17D280F0-AD9F-481E-8687-28AAB4A54437}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
7
global.json
Normal file
7
global.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"sdk": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"rollForward": "latestMajor",
|
||||||
|
"allowPrerelease": true
|
||||||
|
}
|
||||||
|
}
|
2253
inputs/01.txt
Normal file
2253
inputs/01.txt
Normal file
File diff suppressed because it is too large
Load Diff
14
inputs/01a.txt
Normal file
14
inputs/01a.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
1000
|
||||||
|
2000
|
||||||
|
3000
|
||||||
|
|
||||||
|
4000
|
||||||
|
|
||||||
|
5000
|
||||||
|
6000
|
||||||
|
|
||||||
|
7000
|
||||||
|
8000
|
||||||
|
9000
|
||||||
|
|
||||||
|
10000
|
23
src/01.cs
Normal file
23
src/01.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
namespace aoc2023;
|
||||||
|
|
||||||
|
internal class Day01 : Day
|
||||||
|
{
|
||||||
|
internal override void Parse()
|
||||||
|
{
|
||||||
|
var lines = Util.Parsing.ReadAllLines($"{GetDay()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override string Part1()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
return $"<+white>";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override string Part2()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
return $"<+white>";
|
||||||
|
}
|
||||||
|
}
|
65
src/Day.cs
Normal file
65
src/Day.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
namespace aoc2023;
|
||||||
|
|
||||||
|
internal abstract class Day : IDisposable
|
||||||
|
{
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Logger.Log("");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Go(bool runPart1, bool runPart2)
|
||||||
|
{
|
||||||
|
Logger.Log($"<reverse>{GetType().Name}<r>");
|
||||||
|
|
||||||
|
using (new Timer("Parsing"))
|
||||||
|
{
|
||||||
|
Parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runPart1)
|
||||||
|
{
|
||||||
|
using var stopwatch = new Timer();
|
||||||
|
var response = Part1();
|
||||||
|
stopwatch.Stop();
|
||||||
|
if (!string.IsNullOrEmpty(response))
|
||||||
|
{
|
||||||
|
Logger.Log($"<+black>> part1: {response}<r>");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stopwatch.Disabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runPart2)
|
||||||
|
{
|
||||||
|
using var stopwatch = new Timer();
|
||||||
|
var response = Part2();
|
||||||
|
stopwatch.Stop();
|
||||||
|
if (!string.IsNullOrEmpty(response))
|
||||||
|
{
|
||||||
|
Logger.Log($"<+black>> part2: {response}<r>");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stopwatch.Disabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal int GetDayNum()
|
||||||
|
{
|
||||||
|
if (int.TryParse(GetType().Name["Day".Length..], out int dayNum))
|
||||||
|
{
|
||||||
|
return dayNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string GetDay() => $"{GetDayNum():00}";
|
||||||
|
|
||||||
|
internal virtual void Parse() { }
|
||||||
|
internal virtual string Part1() { return string.Empty; }
|
||||||
|
internal virtual string Part2() { return string.Empty; }
|
||||||
|
}
|
41
src/Extensions.cs
Normal file
41
src/Extensions.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace aoc2023;
|
||||||
|
|
||||||
|
internal static class Extensions
|
||||||
|
{
|
||||||
|
public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
|
||||||
|
{
|
||||||
|
foreach (T item in enumeration)
|
||||||
|
{
|
||||||
|
action(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (double elapsed, string unit) ConvertToHumanReadable(this Stopwatch stopwatch)
|
||||||
|
{
|
||||||
|
var elapsed = 1.0d * stopwatch.ElapsedTicks / Stopwatch.Frequency;
|
||||||
|
var unit = "s";
|
||||||
|
if (elapsed < 0.001)
|
||||||
|
{
|
||||||
|
elapsed *= 1e+6;
|
||||||
|
unit = "us";
|
||||||
|
}
|
||||||
|
else if (elapsed < 1)
|
||||||
|
{
|
||||||
|
elapsed *= 1000;
|
||||||
|
unit = "ms";
|
||||||
|
}
|
||||||
|
else if (elapsed < 60)
|
||||||
|
{
|
||||||
|
unit = "s";
|
||||||
|
}
|
||||||
|
else if (elapsed < 60 * 60)
|
||||||
|
{
|
||||||
|
elapsed /= 60;
|
||||||
|
unit = "m";
|
||||||
|
}
|
||||||
|
|
||||||
|
return (elapsed, unit);
|
||||||
|
}
|
||||||
|
}
|
72
src/Logger.cs
Normal file
72
src/Logger.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace aoc2023;
|
||||||
|
|
||||||
|
internal class Logger
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<string, string> colorCodes = new()
|
||||||
|
{
|
||||||
|
{ "r", "\u001b[0m" },
|
||||||
|
{ "black", "\u001b[30m" },
|
||||||
|
{ "red", "\u001b[31m" },
|
||||||
|
{ "green", "\u001b[32m" },
|
||||||
|
{ "yellow", "\u001b[33m" },
|
||||||
|
{ "blue", "\u001b[34m" },
|
||||||
|
{ "magenta", "\u001b[35m" },
|
||||||
|
{ "cyan", "\u001b[36m" },
|
||||||
|
{ "white", "\u001b[37m" },
|
||||||
|
{ "+black", "\u001b[30;1m" },
|
||||||
|
{ "+red", "\u001b[31;1m" },
|
||||||
|
{ "+green", "\u001b[32;1m" },
|
||||||
|
{ "+yellow", "\u001b[33;1m" },
|
||||||
|
{ "+blue", "\u001b[34;1m" },
|
||||||
|
{ "+magenta", "\u001b[35;1m" },
|
||||||
|
{ "+cyan", "\u001b[36;1m" },
|
||||||
|
{ "+white", "\u001b[37;1m" },
|
||||||
|
{ "bgBlack", "\u001b[40m" },
|
||||||
|
{ "bgRed", "\u001b[41m" },
|
||||||
|
{ "bgGreen", "\u001b[42m" },
|
||||||
|
{ "bgYellow", "\u001b[43m" },
|
||||||
|
{ "bgBlue", "\u001b[44m" },
|
||||||
|
{ "bgMagenta", "\u001b[45m" },
|
||||||
|
{ "bgCyan", "\u001b[46m" },
|
||||||
|
{ "bgWhite", "\u001b[47m" },
|
||||||
|
{ "+bgBlack", "\u001b[40;1m" },
|
||||||
|
{ "+bgRed", "\u001b[41;1m" },
|
||||||
|
{ "+bgGreen", "\u001b[42;1m" },
|
||||||
|
{ "+bgYellow", "\u001b[43;1m" },
|
||||||
|
{ "+bgBlue", "\u001b[44;1m" },
|
||||||
|
{ "+bgMagenta", "\u001b[45;1m" },
|
||||||
|
{ "+bgCyan", "\u001b[46;1m" },
|
||||||
|
{ "+bgWhite", "\u001b[47;1m" },
|
||||||
|
{ "bold", "\u001b[1m" },
|
||||||
|
{ "underline", "\u001b[4m" },
|
||||||
|
{ "reverse", "\u001b[7m" },
|
||||||
|
};
|
||||||
|
|
||||||
|
public static void Log(string msg)
|
||||||
|
{
|
||||||
|
Console.WriteLine(InsertColorCodes(msg));
|
||||||
|
Debug.WriteLine(StripColorCodes(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string InsertColorCodes(string msg)
|
||||||
|
{
|
||||||
|
foreach (var code in colorCodes)
|
||||||
|
{
|
||||||
|
msg = msg.Replace($"<{code.Key}>", code.Value, StringComparison.CurrentCultureIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string StripColorCodes(string msg)
|
||||||
|
{
|
||||||
|
foreach (var code in colorCodes)
|
||||||
|
{
|
||||||
|
msg = msg.Replace($"<{code.Key}>", string.Empty, StringComparison.CurrentCultureIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
}
|
23
src/Template.cs
Normal file
23
src/Template.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
namespace aoc2023;
|
||||||
|
|
||||||
|
internal class DayTemplate : Day
|
||||||
|
{
|
||||||
|
internal override void Parse()
|
||||||
|
{
|
||||||
|
var lines = Util.Parsing.ReadAllLines($"{GetDay()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override string Part1()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
return $"<+white>";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override string Part2()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
return $"<+white>";
|
||||||
|
}
|
||||||
|
}
|
48
src/Timer.cs
Normal file
48
src/Timer.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace aoc2023;
|
||||||
|
|
||||||
|
internal class Timer : IDisposable
|
||||||
|
{
|
||||||
|
private readonly Stopwatch stopwatch = Stopwatch.StartNew();
|
||||||
|
private readonly string? name;
|
||||||
|
private bool stopped;
|
||||||
|
public bool Disabled { get; set; }
|
||||||
|
|
||||||
|
public Timer(string? inName = null)
|
||||||
|
{
|
||||||
|
name = inName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
if (stopped)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stopwatch.Stop();
|
||||||
|
stopped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
if (Disabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (elapsed, unit) = stopwatch.ConvertToHumanReadable();
|
||||||
|
var color = "<red>";
|
||||||
|
if (unit == "us" || (unit == "ms" && elapsed < 10))
|
||||||
|
{
|
||||||
|
color = "<green>";
|
||||||
|
}
|
||||||
|
else if (unit == "ms" && elapsed < 250)
|
||||||
|
{
|
||||||
|
color = "<yellow>";
|
||||||
|
}
|
||||||
|
Logger.Log($"<cyan>{name}{(!string.IsNullOrEmpty(name) ? " t" : "T")}ook {color}{elapsed:N1}{unit}<r>");
|
||||||
|
}
|
||||||
|
}
|
49
src/Util/Bisect.cs
Normal file
49
src/Util/Bisect.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
namespace aoc2023.Util;
|
||||||
|
|
||||||
|
public static class Bisect
|
||||||
|
{
|
||||||
|
// Bisect takes a known-good low and known-bad high value as the bounds
|
||||||
|
// to bisect, and a function to test each value for success or failure.
|
||||||
|
// If the function succeeds, the value is adjusted toward the maximum,
|
||||||
|
// and if the function fails, the value is adjusted toward the minimum.
|
||||||
|
// The final value is returned when the difference between the success
|
||||||
|
// and the failure is less than or equal to the acceptance threshold
|
||||||
|
// (usually 1, for integers).
|
||||||
|
public static double Find(double low, double high, double threshold, Func<double, bool> tryFunc)
|
||||||
|
{
|
||||||
|
while (System.Math.Abs(high - low) > threshold)
|
||||||
|
{
|
||||||
|
var currVal = low + ((high - low) / 2);
|
||||||
|
var success = tryFunc(currVal);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
low = currVal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
high = currVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return low;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Find(long low, long high, long threshold, Func<long, bool> tryFunc)
|
||||||
|
{
|
||||||
|
while (System.Math.Abs(high - low) > threshold)
|
||||||
|
{
|
||||||
|
var currVal = low + ((high - low) / 2);
|
||||||
|
var success = tryFunc(currVal);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
low = currVal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
high = currVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return low;
|
||||||
|
}
|
||||||
|
}
|
39
src/Util/Combinatorics.cs
Normal file
39
src/Util/Combinatorics.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
namespace aoc2023.Util;
|
||||||
|
|
||||||
|
public static class Combinatorics
|
||||||
|
{
|
||||||
|
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IList<T> list)
|
||||||
|
{
|
||||||
|
Action<IList<T>, int>? helper = null;
|
||||||
|
List<IEnumerable<T>> res = new();
|
||||||
|
|
||||||
|
helper = (arr, n) =>
|
||||||
|
{
|
||||||
|
if (n == 1)
|
||||||
|
{
|
||||||
|
var tmp = new T[arr.Count];
|
||||||
|
arr.CopyTo(tmp, 0);
|
||||||
|
res.Add(tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (var i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
// ReSharper disable once AccessToModifiedClosure
|
||||||
|
helper!(arr, n - 1);
|
||||||
|
if (n % 2 == 1)
|
||||||
|
{
|
||||||
|
(arr[i], arr[n - 1]) = (arr[n - 1], arr[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(arr[0], arr[n - 1]) = (arr[n - 1], arr[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
helper(list, list.Count);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
65
src/Util/Math.cs
Normal file
65
src/Util/Math.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
namespace aoc2023.Util;
|
||||||
|
|
||||||
|
public static class Math
|
||||||
|
{
|
||||||
|
public static ulong GCD(ulong a, ulong b)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (b == 0)
|
||||||
|
{
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
var a1 = a;
|
||||||
|
a = b;
|
||||||
|
b = a1 % b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ulong LCM(params ulong[] nums)
|
||||||
|
{
|
||||||
|
var num = nums.Length;
|
||||||
|
switch (num)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
case 1:
|
||||||
|
return nums[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = lcm(nums[0], nums[1]);
|
||||||
|
for (var i = 2; i < num; i++)
|
||||||
|
{
|
||||||
|
ret = lcm(nums[i], ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ulong lcm(ulong a, ulong b)
|
||||||
|
{
|
||||||
|
return (a * b) / GCD(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long Modulo(long numer, long denom)
|
||||||
|
{
|
||||||
|
// long q = numer / denom;
|
||||||
|
long r = numer % denom;
|
||||||
|
if (r < 0)
|
||||||
|
{
|
||||||
|
if (denom > 0)
|
||||||
|
{
|
||||||
|
// q = q - 1;
|
||||||
|
r = r + denom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// q = q + 1;
|
||||||
|
r = r - denom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
91
src/Util/Parsing.cs
Normal file
91
src/Util/Parsing.cs
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace aoc2023.Util;
|
||||||
|
|
||||||
|
public static class Parsing
|
||||||
|
{
|
||||||
|
private static readonly char[] StripPreamble = { (char)8745, (char)9559, (char)9488, };
|
||||||
|
private static readonly Encoding[] StripBOMsFromEncodings = { Encoding.UTF8, Encoding.Unicode, Encoding.BigEndianUnicode, };
|
||||||
|
private static void ReadData(string inputName, Action<string> processor)
|
||||||
|
{
|
||||||
|
if (Console.IsInputRedirected)
|
||||||
|
{
|
||||||
|
bool processedSomething = false;
|
||||||
|
for (int i = 0; Console.In.ReadLine() is { } line; i++)
|
||||||
|
{
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
if (line[0..StripPreamble.Length].SequenceEqual(StripPreamble))
|
||||||
|
{
|
||||||
|
line = line[StripPreamble.Length..];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var encoding in StripBOMsFromEncodings)
|
||||||
|
{
|
||||||
|
if (line.StartsWith(encoding.GetString(encoding.GetPreamble()), StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
line = line.Replace(encoding.GetString(encoding.GetPreamble()), "", StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processor(line);
|
||||||
|
if (!string.IsNullOrEmpty(line))
|
||||||
|
{
|
||||||
|
processedSomething = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (processedSomething)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var filename = $"inputs/{inputName}.txt";
|
||||||
|
if (File.Exists(filename))
|
||||||
|
{
|
||||||
|
if (Directory.Exists(Path.GetDirectoryName(filename)!) && File.Exists(filename))
|
||||||
|
{
|
||||||
|
foreach (var line in File.ReadLines(filename))
|
||||||
|
{
|
||||||
|
processor(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeof(Logger) is not technically correct since what we need is the "default namespace,"
|
||||||
|
// but "default namespace" is a Project File concept, not a C#/.NET concept, so it's not
|
||||||
|
// accessible at runtime. instead, we assume Logger is also part of the "default namespace"
|
||||||
|
var resourceName = $"{typeof(Logger).Namespace}.inputs.{inputName}.txt";
|
||||||
|
using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
|
||||||
|
using StreamReader reader = new(stream!);
|
||||||
|
while (reader.ReadLine() is { } readLine)
|
||||||
|
{
|
||||||
|
processor(readLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string ReadAllText(string filename)
|
||||||
|
{
|
||||||
|
string contents = string.Empty;
|
||||||
|
ReadData(filename, (line) => contents = line);
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static IEnumerable<string> ReadAllLines(string filename)
|
||||||
|
{
|
||||||
|
List<string> lines = new();
|
||||||
|
ReadData(filename, (line) => lines.Add(line));
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static IEnumerable<long> ReadAllLinesAsInts(string filename)
|
||||||
|
{
|
||||||
|
return ReadAllLines(filename).Select(long.Parse);
|
||||||
|
}
|
||||||
|
}
|
35
src/Util/Testing.cs
Normal file
35
src/Util/Testing.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace aoc2023.Util;
|
||||||
|
|
||||||
|
public static class Testing
|
||||||
|
{
|
||||||
|
internal static void StartTestSet(string name)
|
||||||
|
{
|
||||||
|
Logger.Log($"<underline>test: {name}<r>");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void StartTest(string label)
|
||||||
|
{
|
||||||
|
Logger.Log($"<magenta>{label}<r>");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void TestCondition(Func<bool> a, bool printResult = true)
|
||||||
|
{
|
||||||
|
if (a.Invoke() == false)
|
||||||
|
{
|
||||||
|
Debug.Assert(false);
|
||||||
|
if (printResult)
|
||||||
|
{
|
||||||
|
Logger.Log("<red>x<r>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (printResult)
|
||||||
|
{
|
||||||
|
Logger.Log("<green>✓<r>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
162
src/Util/Vec2.cs
Normal file
162
src/Util/Vec2.cs
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
namespace aoc2023.Util;
|
||||||
|
|
||||||
|
public readonly struct ivec2 : IEquatable<ivec2>, IComparable<ivec2>, IComparable
|
||||||
|
{
|
||||||
|
public readonly long x = 0;
|
||||||
|
public readonly long y = 0;
|
||||||
|
|
||||||
|
public static readonly ivec2 ZERO = new ivec2(0, 0);
|
||||||
|
public static readonly ivec2 ONE = new ivec2(1, 1);
|
||||||
|
|
||||||
|
public static readonly ivec2 LEFT = new ivec2(-1, 0);
|
||||||
|
public static readonly ivec2 RIGHT = new ivec2(1, 0);
|
||||||
|
public static readonly ivec2 UP = new ivec2(0, -1);
|
||||||
|
public static readonly ivec2 DOWN = new ivec2(0, 1);
|
||||||
|
public static readonly ivec2[] FOURWAY = {RIGHT, LEFT, UP, DOWN};
|
||||||
|
public static readonly ivec2[] EIGHTWAY = {UP, UP + RIGHT, RIGHT, RIGHT + DOWN, DOWN, DOWN + LEFT, LEFT, LEFT + UP};
|
||||||
|
|
||||||
|
public ivec2(long xv, long yv)
|
||||||
|
{
|
||||||
|
x = xv;
|
||||||
|
y = yv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsZero() => x == 0 && y == 0;
|
||||||
|
public long Sum => x + y;
|
||||||
|
public long Product => x * y;
|
||||||
|
public long MaxElement => System.Math.Max(x, y);
|
||||||
|
|
||||||
|
public ivec2 GetRotatedLeft() => new ivec2(y, -x);
|
||||||
|
|
||||||
|
public ivec2 GetRotatedRight() => new ivec2(-y, x);
|
||||||
|
|
||||||
|
public long Dot(ivec2 v) => (x * v.x) + (y * v.y);
|
||||||
|
public long LengthSquared => (x * x) + (y * y);
|
||||||
|
public float Length => MathF.Sqrt(LengthSquared);
|
||||||
|
|
||||||
|
public long ManhattanDistance => Abs(this).Sum;
|
||||||
|
public long ManhattanDistanceTo(ivec2 other) => System.Math.Abs(x - other.x) + System.Math.Abs(y - other.y);
|
||||||
|
|
||||||
|
public ivec2 GetBestDirectionTo(ivec2 p)
|
||||||
|
{
|
||||||
|
ivec2 diff = p - this;
|
||||||
|
if (diff.IsZero())
|
||||||
|
{
|
||||||
|
return ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
ivec2 dir = diff / Abs(diff).MaxElement;
|
||||||
|
return Sign(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get a point in the 8 cells around me closest to p
|
||||||
|
public ivec2 GetNearestNeighbor(ivec2 p)
|
||||||
|
{
|
||||||
|
ivec2 dir = GetBestDirectionTo(p);
|
||||||
|
return this + dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ivec2> GetOrthogonalNeighbors()
|
||||||
|
{
|
||||||
|
foreach (var dir in FOURWAY)
|
||||||
|
{
|
||||||
|
yield return this + dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ivec2> GetNeighbors()
|
||||||
|
{
|
||||||
|
foreach (var dir in EIGHTWAY)
|
||||||
|
{
|
||||||
|
yield return this + dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long this[long i] => (i == 0) ? x : y;
|
||||||
|
|
||||||
|
public static ivec2 operator +(ivec2 v) => v;
|
||||||
|
public static ivec2 operator -(ivec2 v) => new ivec2(-v.x, -v.y);
|
||||||
|
public static ivec2 operator +(ivec2 a, ivec2 b) => new ivec2(a.x + b.x, a.y + b.y);
|
||||||
|
public static ivec2 operator -(ivec2 a, ivec2 b) => new ivec2(a.x - b.x, a.y - b.y);
|
||||||
|
public static ivec2 operator *(ivec2 a, ivec2 b) => new ivec2(a.x * b.x, a.y * b.y);
|
||||||
|
public static ivec2 operator *(long a, ivec2 v) => new ivec2(a * v.x, a * v.y);
|
||||||
|
public static ivec2 operator *(ivec2 v, long a) => new ivec2(a * v.x, a * v.y);
|
||||||
|
public static ivec2 operator /(ivec2 v, long a) => new ivec2(v.x / a, v.y / a);
|
||||||
|
public static bool operator ==(ivec2 a, ivec2 b) => (a.x == b.x) && (a.y == b.y);
|
||||||
|
public static bool operator !=(ivec2 a, ivec2 b) => (a.x != b.x) || (a.y != b.y);
|
||||||
|
public static bool operator <(ivec2 a, ivec2 b) => (a.x < b.x) && (a.y < b.y);
|
||||||
|
public static bool operator <=(ivec2 a, ivec2 b) => (a.x <= b.x) && (a.y <= b.y);
|
||||||
|
public static bool operator >(ivec2 a, ivec2 b) => (a.x > b.x) && (a.y > b.y);
|
||||||
|
public static bool operator >=(ivec2 a, ivec2 b) => (a.x >= b.x) && (a.y >= b.y);
|
||||||
|
|
||||||
|
public bool Equals(ivec2 other)
|
||||||
|
{
|
||||||
|
return x == other.x && y == other.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is ivec2 other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(ivec2 other)
|
||||||
|
{
|
||||||
|
if (this < other)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this > other)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(object? obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj)) return 1;
|
||||||
|
return obj is ivec2 other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(ivec2)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ivec2 Sign(ivec2 v) => new ivec2(System.Math.Sign(v.x), System.Math.Sign(v.y));
|
||||||
|
public static ivec2 Min(ivec2 a, ivec2 b) => new ivec2(System.Math.Min(a.x, b.x), System.Math.Min(a.y, b.y));
|
||||||
|
public static ivec2 Max(ivec2 a, ivec2 b) => new ivec2(System.Math.Max(a.x, b.x), System.Math.Max(a.y, b.y));
|
||||||
|
|
||||||
|
public static ivec2 Clamp(ivec2 v, ivec2 lh, ivec2 rh) => Min(rh, Max(lh, v));
|
||||||
|
|
||||||
|
public static ivec2 Abs(ivec2 v) => new ivec2(System.Math.Abs(v.x), System.Math.Abs(v.y));
|
||||||
|
|
||||||
|
public static ivec2 Mod(ivec2 val, long den)
|
||||||
|
{
|
||||||
|
long x = val.x % den;
|
||||||
|
long y = val.y % den;
|
||||||
|
|
||||||
|
if (x < 0)
|
||||||
|
{
|
||||||
|
x += den;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y < 0)
|
||||||
|
{
|
||||||
|
y += den;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ivec2(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long Dot(ivec2 a, ivec2 b) => (a.x * b.x) + (a.y * b.y);
|
||||||
|
|
||||||
|
public static ivec2 Parse(string s)
|
||||||
|
{
|
||||||
|
string[] parts = s.Split(',', 2);
|
||||||
|
long x = long.Parse(parts[0]);
|
||||||
|
long y = long.Parse(parts[1]);
|
||||||
|
return new ivec2(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode() => HashCode.Combine(x, y);
|
||||||
|
|
||||||
|
public override string ToString() => $"{x},{y}";
|
||||||
|
}
|
171
src/Util/Vec3.cs
Normal file
171
src/Util/Vec3.cs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
namespace aoc2023.Util;
|
||||||
|
|
||||||
|
public readonly struct ivec3 : IEquatable<ivec3>, IComparable<ivec3>, IComparable
|
||||||
|
{
|
||||||
|
public readonly long x = 0;
|
||||||
|
public readonly long y = 0;
|
||||||
|
public readonly long z = 0;
|
||||||
|
|
||||||
|
public static readonly ivec3 ZERO = new ivec3(0, 0, 0);
|
||||||
|
public static readonly ivec3 ONE = new ivec3(1, 1, 1);
|
||||||
|
|
||||||
|
public static readonly ivec3 LEFT = new ivec3(-1, 0, 0);
|
||||||
|
public static readonly ivec3 RIGHT = new ivec3(1, 0, 0);
|
||||||
|
public static readonly ivec3 UP = new ivec3(0, -1, 0);
|
||||||
|
public static readonly ivec3 DOWN = new ivec3(0, 1, 0);
|
||||||
|
public static readonly ivec3 FORWARD = new ivec3(0, 0, 1);
|
||||||
|
public static readonly ivec3 BACKWARD = new ivec3(0, 0, -1);
|
||||||
|
public static readonly ivec3[] DIRECTIONS = {LEFT, RIGHT, UP, DOWN, FORWARD, BACKWARD};
|
||||||
|
|
||||||
|
public ivec3(long xv, long yv, long zv)
|
||||||
|
{
|
||||||
|
x = xv;
|
||||||
|
y = yv;
|
||||||
|
z = zv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsZero() => x == 0 && y == 0 && z == 0;
|
||||||
|
public long Sum => x + y + z;
|
||||||
|
public long Product => x * y * z;
|
||||||
|
public long MaxElement => System.Math.Max(x, System.Math.Max(y, z));
|
||||||
|
public long MinElement => System.Math.Min(x, System.Math.Min(y, z));
|
||||||
|
|
||||||
|
public ivec3 GetRotatedLeft() => new ivec3(y, -x, z);
|
||||||
|
|
||||||
|
public ivec3 GetRotatedRight() => new ivec3(-y, x, z);
|
||||||
|
|
||||||
|
public long Dot(ivec3 v) => (x * v.x) + (y * v.y) + (z * v.z);
|
||||||
|
public long LengthSquared => (x * x) + (y * y) + (z * z);
|
||||||
|
public float Length => MathF.Sqrt(LengthSquared);
|
||||||
|
|
||||||
|
public long ManhattanDistance => Abs(this).Sum;
|
||||||
|
public long ManhattanDistanceTo(ivec3 other) => System.Math.Abs(x - other.x) + System.Math.Abs(y - other.y) + System.Math.Abs(z - other.z);
|
||||||
|
|
||||||
|
public bool IsTouching(ivec3 other) => ManhattanDistanceTo(other) == 1;
|
||||||
|
|
||||||
|
public IEnumerable<ivec3> GetNeighbors(ivec3? min = null, ivec3? max = null)
|
||||||
|
{
|
||||||
|
foreach (var d in DIRECTIONS)
|
||||||
|
{
|
||||||
|
var n = this + d;
|
||||||
|
if ((min == null || n >= min) && (max == null || n <= max))
|
||||||
|
{
|
||||||
|
yield return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ivec3 GetBestDirectionTo(ivec3 p)
|
||||||
|
{
|
||||||
|
ivec3 diff = p - this;
|
||||||
|
if (diff.IsZero())
|
||||||
|
{
|
||||||
|
return ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
ivec3 dir = diff / Abs(diff).MaxElement;
|
||||||
|
return Sign(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get a point in the 8 cells around me closest to p
|
||||||
|
public ivec3 GetNearestNeighbor(ivec3 p)
|
||||||
|
{
|
||||||
|
ivec3 dir = GetBestDirectionTo(p);
|
||||||
|
return this + dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long this[long i] => (i == 0) ? x : (i == 1) ? y : z;
|
||||||
|
|
||||||
|
public static ivec3 operator +(ivec3 v) => v;
|
||||||
|
public static ivec3 operator -(ivec3 v) => new ivec3(-v.x, -v.y, -v.z);
|
||||||
|
public static ivec3 operator +(ivec3 a, ivec3 b) => new ivec3(a.x + b.x, a.y + b.y, a.z + b.z);
|
||||||
|
public static ivec3 operator -(ivec3 a, ivec3 b) => new ivec3(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||||
|
public static ivec3 operator *(ivec3 a, ivec3 b) => new ivec3(a.x * b.x, a.y * b.y, a.z * b.z);
|
||||||
|
public static ivec3 operator *(long a, ivec3 v) => new ivec3(a * v.x, a * v.y, a * v.z);
|
||||||
|
public static ivec3 operator *(ivec3 v, long a) => new ivec3(a * v.x, a * v.y, a * v.z);
|
||||||
|
public static ivec3 operator /(ivec3 v, long a) => new ivec3(v.x / a, v.y / a, v.z / a);
|
||||||
|
public static bool operator ==(ivec3 a, ivec3 b) => (a.x == b.x) && (a.y == b.y) && (a.z == b.z);
|
||||||
|
public static bool operator !=(ivec3 a, ivec3 b) => (a.x != b.x) || (a.y != b.y) || (a.z != b.z);
|
||||||
|
public static bool operator <(ivec3 a, ivec3 b) => (a.x < b.x) && (a.y < b.y) && (a.z < b.z);
|
||||||
|
public static bool operator <=(ivec3 a, ivec3 b) => (a.x <= b.x) && (a.y <= b.y) && (a.z <= b.z);
|
||||||
|
public static bool operator >(ivec3 a, ivec3 b) => (a.x > b.x) && (a.y > b.y) && (a.z > b.z);
|
||||||
|
public static bool operator >=(ivec3 a, ivec3 b) => (a.x >= b.x) && (a.y >= b.y) && (a.z >= b.z);
|
||||||
|
|
||||||
|
public bool Equals(ivec3 other)
|
||||||
|
{
|
||||||
|
return x == other.x && y == other.y && z == other.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is ivec3 other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(ivec3 other)
|
||||||
|
{
|
||||||
|
if (this < other)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this > other)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(object? obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj)) return 1;
|
||||||
|
return obj is ivec3 other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(ivec3)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ivec3 Sign(ivec3 v) => new ivec3(System.Math.Sign(v.x), System.Math.Sign(v.y), System.Math.Sign(v.z));
|
||||||
|
public static ivec3 Min(ivec3 a, ivec3 b) => new ivec3(System.Math.Min(a.x, b.x), System.Math.Min(a.y, b.y), System.Math.Min(a.z, b.z));
|
||||||
|
public static ivec3 Max(ivec3 a, ivec3 b) => new ivec3(System.Math.Max(a.x, b.x), System.Math.Max(a.y, b.y), System.Math.Max(a.z, b.z));
|
||||||
|
|
||||||
|
public static ivec3 Clamp(ivec3 v, ivec3 lh, ivec3 rh) => Min(rh, Max(lh, v));
|
||||||
|
|
||||||
|
public static ivec3 Abs(ivec3 v) => new ivec3(System.Math.Abs(v.x), System.Math.Abs(v.y), System.Math.Abs(v.z));
|
||||||
|
|
||||||
|
public static ivec3 Mod(ivec3 val, long den)
|
||||||
|
{
|
||||||
|
long x = val.x % den;
|
||||||
|
long y = val.y % den;
|
||||||
|
long z = val.z % den;
|
||||||
|
|
||||||
|
if (x < 0)
|
||||||
|
{
|
||||||
|
x += den;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y < 0)
|
||||||
|
{
|
||||||
|
y += den;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z < 0)
|
||||||
|
{
|
||||||
|
z += den;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ivec3(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long Dot(ivec3 a, ivec3 b) => (a.x * b.x) + (a.y * b.y) + (a.z * b.z);
|
||||||
|
|
||||||
|
public static ivec3 Parse(string s)
|
||||||
|
{
|
||||||
|
string[] parts = s.Split(',', 3);
|
||||||
|
long x = long.Parse(parts[0]);
|
||||||
|
long y = long.Parse(parts[1]);
|
||||||
|
long z = long.Parse(parts[2]);
|
||||||
|
return new ivec3(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode() => HashCode.Combine(x, y, z);
|
||||||
|
|
||||||
|
public override string ToString() => $"{x},{y},{z}";
|
||||||
|
}
|
78
src/main.cs
Normal file
78
src/main.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
using aoc2023;
|
||||||
|
|
||||||
|
using aoc2023.Timer t = new("Full program");
|
||||||
|
var types = System.Reflection.Assembly
|
||||||
|
.GetExecutingAssembly()
|
||||||
|
.GetTypes()
|
||||||
|
.Where(ty => ty.IsSubclassOf(typeof(Day)) && !ty.IsAbstract && ty.Name != "DayTemplate")
|
||||||
|
.OrderBy(ty => ty.Name).ToList();
|
||||||
|
|
||||||
|
bool runAll = false;
|
||||||
|
bool? runPart1 = null;
|
||||||
|
bool? runPart2 = null;
|
||||||
|
List<string> desiredDays = new();
|
||||||
|
foreach (var arg in args)
|
||||||
|
{
|
||||||
|
if (arg.Equals("-part1", StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
runPart1 = true;
|
||||||
|
}
|
||||||
|
else if (arg.Equals("-part2", StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
runPart2 = true;
|
||||||
|
}
|
||||||
|
else if (arg.Equals("all", StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
runAll = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
desiredDays.Add(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runPart1 != null || runPart2 != null)
|
||||||
|
{
|
||||||
|
runPart1 ??= false;
|
||||||
|
runPart2 ??= false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runAll)
|
||||||
|
{
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
using var day = (Day)Activator.CreateInstance(type)!;
|
||||||
|
day.Go(runPart1 ?? true, runPart2 ?? true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (desiredDays.Count == 0)
|
||||||
|
{
|
||||||
|
desiredDays.Add("");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var desiredDay in desiredDays)
|
||||||
|
{
|
||||||
|
Day? day = null;
|
||||||
|
if (string.IsNullOrEmpty(desiredDay))
|
||||||
|
{
|
||||||
|
day = (Day) Activator.CreateInstance(types.Last())!;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var type = types.FirstOrDefault(x => x.Name == $"Day{desiredDay.PadLeft(2, '0')}");
|
||||||
|
if (type == null)
|
||||||
|
{
|
||||||
|
Logger.Log($"Unknown day <cyan>{desiredDay}<r>");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
day = (Day?) Activator.CreateInstance(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
day?.Go(runPart1 ?? true, runPart2 ?? true);
|
||||||
|
day?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user