Finish Day 08
This commit is contained in:
parent
d9bc639366
commit
00bfb7d46e
11 changed files with 308 additions and 1 deletions
11
.vscode/launch.json
vendored
11
.vscode/launch.json
vendored
|
|
@ -80,6 +80,17 @@
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "aoc-2024-08 Debug",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "dotnet: build aoc-2024-08",
|
||||||
|
"program": "${workspaceFolder}/artifacts/bin/aoc-2024-08/debug/aoc-2024-08.dll",
|
||||||
|
"args": ["part-one", "data/2024/08/dev.txt"],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"console": "internalConsole"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
8
.vscode/tasks.json
vendored
8
.vscode/tasks.json
vendored
|
|
@ -58,6 +58,14 @@
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"label": "dotnet: build aoc-2024-07"
|
"label": "dotnet: build aoc-2024-07"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "dotnet",
|
||||||
|
"task": "build aoc-2024-08.csproj",
|
||||||
|
"file": "src/2024/08/aoc-2024-08.csproj",
|
||||||
|
"group": "build",
|
||||||
|
"problemMatcher": [],
|
||||||
|
"label": "dotnet: build aoc-2024-08"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.0.31903.59
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
|
@ -19,6 +19,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "aoc-2024-06", "src\2024\06\
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "aoc-2024-07", "src\2024\07\aoc-2024-07.csproj", "{58941BB2-E4AC-40F0-AA92-BEF51DEFC859}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "aoc-2024-07", "src\2024\07\aoc-2024-07.csproj", "{58941BB2-E4AC-40F0-AA92-BEF51DEFC859}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "aoc-2024-08", "src\2024\08\aoc-2024-08.csproj", "{44BBC1CF-D2FC-4906-9691-B439EC9EFB8C}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "core", "src\core\core.csproj", "{9E2BD5D6-55DD-4760-AD30-75B168F03F60}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -56,6 +60,14 @@ Global
|
||||||
{58941BB2-E4AC-40F0-AA92-BEF51DEFC859}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{58941BB2-E4AC-40F0-AA92-BEF51DEFC859}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{58941BB2-E4AC-40F0-AA92-BEF51DEFC859}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{58941BB2-E4AC-40F0-AA92-BEF51DEFC859}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{58941BB2-E4AC-40F0-AA92-BEF51DEFC859}.Release|Any CPU.Build.0 = Release|Any CPU
|
{58941BB2-E4AC-40F0-AA92-BEF51DEFC859}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{44BBC1CF-D2FC-4906-9691-B439EC9EFB8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{44BBC1CF-D2FC-4906-9691-B439EC9EFB8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{44BBC1CF-D2FC-4906-9691-B439EC9EFB8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{44BBC1CF-D2FC-4906-9691-B439EC9EFB8C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{9E2BD5D6-55DD-4760-AD30-75B168F03F60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9E2BD5D6-55DD-4760-AD30-75B168F03F60}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9E2BD5D6-55DD-4760-AD30-75B168F03F60}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9E2BD5D6-55DD-4760-AD30-75B168F03F60}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{FAF70800-E2C3-4AD7-B433-86C1F20380F7} = {37CA8017-085A-4F6A-BADB-535F929C10B9}
|
{FAF70800-E2C3-4AD7-B433-86C1F20380F7} = {37CA8017-085A-4F6A-BADB-535F929C10B9}
|
||||||
|
|
@ -65,5 +77,6 @@ Global
|
||||||
{D108A6AB-B974-4BD9-B97A-CB1D1A2F3920} = {37CA8017-085A-4F6A-BADB-535F929C10B9}
|
{D108A6AB-B974-4BD9-B97A-CB1D1A2F3920} = {37CA8017-085A-4F6A-BADB-535F929C10B9}
|
||||||
{EEC6EF36-EE16-4DB4-9AE8-CF0234751458} = {37CA8017-085A-4F6A-BADB-535F929C10B9}
|
{EEC6EF36-EE16-4DB4-9AE8-CF0234751458} = {37CA8017-085A-4F6A-BADB-535F929C10B9}
|
||||||
{58941BB2-E4AC-40F0-AA92-BEF51DEFC859} = {37CA8017-085A-4F6A-BADB-535F929C10B9}
|
{58941BB2-E4AC-40F0-AA92-BEF51DEFC859} = {37CA8017-085A-4F6A-BADB-535F929C10B9}
|
||||||
|
{44BBC1CF-D2FC-4906-9691-B439EC9EFB8C} = {37CA8017-085A-4F6A-BADB-535F929C10B9}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
58
src/2024/08/Program.cs
Normal file
58
src/2024/08/Program.cs
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
using ConsoleAppFramework;
|
||||||
|
|
||||||
|
using core;
|
||||||
|
|
||||||
|
var builder = ConsoleApp.Create();
|
||||||
|
builder.Add("part-one", static ([Argument, FileExists] string file) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Result: {ReadFile(file, false)}");
|
||||||
|
});
|
||||||
|
builder.Add("part-two", static ([Argument, FileExists] string file) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Result: {ReadFile(file, true)}");
|
||||||
|
});
|
||||||
|
builder.Run(args);
|
||||||
|
|
||||||
|
static int ReadFile(string path, bool resonant)
|
||||||
|
{
|
||||||
|
SymbolGrid grid = new();
|
||||||
|
grid.Load(path);
|
||||||
|
ScenarioMap map = new(grid);
|
||||||
|
HashSet<Vector2I> antinodes = [];
|
||||||
|
foreach (var (key, set) in map.Antennas)
|
||||||
|
{
|
||||||
|
for (int l = set.Length - 1; l > 0; l--)
|
||||||
|
{
|
||||||
|
for (int r = 0; r < l; r++)
|
||||||
|
{
|
||||||
|
var d = set[l] - set[r];
|
||||||
|
for (int i = resonant ? 1 : 2; resonant || i < 3; i++)
|
||||||
|
{
|
||||||
|
bool valid = false;
|
||||||
|
var fl = set[l] - d * i;
|
||||||
|
if (grid.IsValid(fl))
|
||||||
|
{
|
||||||
|
valid = true;
|
||||||
|
antinodes.Add(fl);
|
||||||
|
}
|
||||||
|
|
||||||
|
var fr = set[r] + d * i;
|
||||||
|
if (grid.IsValid(fr))
|
||||||
|
{
|
||||||
|
valid = true;
|
||||||
|
antinodes.Add(fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return antinodes.Count;
|
||||||
|
}
|
||||||
31
src/2024/08/ScenarioMap.cs
Normal file
31
src/2024/08/ScenarioMap.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System.Collections.Frozen;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
using core;
|
||||||
|
|
||||||
|
record class ScenarioMap
|
||||||
|
{
|
||||||
|
private readonly SymbolGrid _grid;
|
||||||
|
|
||||||
|
public FrozenDictionary<char, ImmutableArray<Vector2I>> Antennas { get; }
|
||||||
|
|
||||||
|
public ScenarioMap(SymbolGrid grid)
|
||||||
|
{
|
||||||
|
_grid = grid;
|
||||||
|
Dictionary<char, HashSet<Vector2I>> antennas = [];
|
||||||
|
foreach (var (position, symbol) in grid)
|
||||||
|
{
|
||||||
|
if (char.IsLetterOrDigit(symbol))
|
||||||
|
{
|
||||||
|
(CollectionsMarshal.GetValueRefOrAddDefault(
|
||||||
|
antennas,
|
||||||
|
symbol,
|
||||||
|
out _
|
||||||
|
) ??= []).Add(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Antennas = antennas.ToFrozenDictionary(c => c.Key, c => (ImmutableArray<Vector2I>)[.. c.Value]);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/2024/08/aoc-2024-08.csproj
Normal file
15
src/2024/08/aoc-2024-08.csproj
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\core\core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<RootNamespace>aoc_2024_08</RootNamespace>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
8
src/core/FileExistsAttribute.cs
Normal file
8
src/core/FileExistsAttribute.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace core;
|
||||||
|
|
||||||
|
public class FileExistsAttribute : ValidationAttribute
|
||||||
|
{
|
||||||
|
public override bool IsValid(object? value) => value is string path && File.Exists(path);
|
||||||
|
}
|
||||||
126
src/core/SymbolGrid.cs
Normal file
126
src/core/SymbolGrid.cs
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.IO.MemoryMappedFiles;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace core;
|
||||||
|
|
||||||
|
public class SymbolGrid
|
||||||
|
{
|
||||||
|
private char[]? _map;
|
||||||
|
|
||||||
|
[DisallowNull]
|
||||||
|
public char? this[int x, int y]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
EnsureMap();
|
||||||
|
return IsValid(x, y) ? _map[y * Height + x] : null;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
EnsureMap();
|
||||||
|
if (IsValid(x, y))
|
||||||
|
{
|
||||||
|
_map[y * Height + x] = value.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DisallowNull]
|
||||||
|
public char? this[Vector2I i]
|
||||||
|
{
|
||||||
|
get => this[i.X, i.Y];
|
||||||
|
set => this[i.X, i.Y] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Width { get; private set; }
|
||||||
|
|
||||||
|
public int Height { get; private set; }
|
||||||
|
|
||||||
|
public void Load(string file)
|
||||||
|
{
|
||||||
|
using var fileView = MemoryMappedFile.CreateFromFile(file, FileMode.Open);
|
||||||
|
using var accessor = fileView.CreateViewAccessor();
|
||||||
|
(Width, var stride, Height) = Parse(accessor);
|
||||||
|
_map = new char[Width * Height];
|
||||||
|
for (int x = 0; x < Width; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < Height; y++)
|
||||||
|
{
|
||||||
|
_map[y * Height + x] = (char)accessor.ReadByte(y * stride + x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static (int Width, int Stride, int Height) Parse(MemoryMappedViewAccessor map)
|
||||||
|
{
|
||||||
|
bool hasNewLine = false;
|
||||||
|
int? width = null, stride = null;
|
||||||
|
for (int i = 0; i < map.Capacity; i++)
|
||||||
|
{
|
||||||
|
if ((char)map.ReadByte(i) is '\r' or '\n')
|
||||||
|
{
|
||||||
|
if (!hasNewLine)
|
||||||
|
{
|
||||||
|
width = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasNewLine = true;
|
||||||
|
}
|
||||||
|
else if (hasNewLine)
|
||||||
|
{
|
||||||
|
stride = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (width!.Value, stride!.Value, (int)((map.Capacity + width.Value) / stride.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SymbolEnumerator GetEnumerator() => new(this);
|
||||||
|
|
||||||
|
public bool IsValid(Vector2I p) => IsValid(p.X, p.Y);
|
||||||
|
|
||||||
|
public bool IsValid(int x, int y)
|
||||||
|
{
|
||||||
|
EnsureMap();
|
||||||
|
return x >= 0 && x < Width && y >= 0 && y < Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref struct SymbolEnumerator
|
||||||
|
{
|
||||||
|
private readonly SymbolGrid _grid;
|
||||||
|
private readonly int _length;
|
||||||
|
private int? _current;
|
||||||
|
|
||||||
|
internal SymbolEnumerator(SymbolGrid grid)
|
||||||
|
{
|
||||||
|
_grid = grid;
|
||||||
|
_length = grid.Width * grid.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public (Vector2I Position, char Symbol) Current { get; private set; }
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
_current = _current.HasValue ? _current + 1 : 0;
|
||||||
|
if (_current == _length)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Current = (_grid.ToVector(_current.Value), _grid._map![_current.Value]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector2I ToVector(int index) => new()
|
||||||
|
{
|
||||||
|
Y = index / Height,
|
||||||
|
X = index % Height
|
||||||
|
};
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_map))]
|
||||||
|
private void EnsureMap() => ArgumentNullException.ThrowIfNull(_map);
|
||||||
|
}
|
||||||
28
src/core/Vector2I.cs
Normal file
28
src/core/Vector2I.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace core;
|
||||||
|
|
||||||
|
public record struct Vector2I(int X, int Y) :
|
||||||
|
IAdditionOperators<Vector2I, Vector2I, Vector2I>,
|
||||||
|
ISubtractionOperators<Vector2I, Vector2I, Vector2I>,
|
||||||
|
IMultiplyOperators<Vector2I, int, Vector2I>
|
||||||
|
{
|
||||||
|
public readonly double Length => Math.ReciprocalSqrtEstimate(SquareLength);
|
||||||
|
|
||||||
|
public readonly int SquareLength => X * X + Y * Y;
|
||||||
|
|
||||||
|
public static Vector2I operator +(Vector2I left, Vector2I right)
|
||||||
|
{
|
||||||
|
return new(left.X + right.X, left.Y + right.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2I operator -(Vector2I left, Vector2I right)
|
||||||
|
{
|
||||||
|
return new(left.X - right.X, left.Y - right.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2I operator *(Vector2I left, int right)
|
||||||
|
{
|
||||||
|
return new(left.X * right, left.Y * right);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/core/core.csproj
Normal file
9
src/core/core.csproj
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue