Compare commits
21 Commits
a92c9b4478
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 7056c1516e | |||
| 07510227e9 | |||
| 5f45853889 | |||
| 55a8ea0281 | |||
| e56befa18b | |||
| 9f1a2d2300 | |||
| a0c97e4b75 | |||
| 629b13abef | |||
| 4f4ccf7117 | |||
| 625a9e5ad5 | |||
| ef959284a5 | |||
| bba775fd4e | |||
| f16899ff3c | |||
| 6606f40df9 | |||
| 199b940ff9 | |||
| 63eb4d01b0 | |||
| a33843ae1b | |||
| e08a60614a | |||
| 6a9c813d08 | |||
| ba7e6d4be0 | |||
| a4cb169566 |
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -76,6 +76,8 @@
|
|||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Superpower" Version="3.0.0" />
|
<PackageReference Include="MaybeError" Version="1.2.0" />
|
||||||
|
<PackageReference Include="Superpower" Version="3.1.1-dev-00257" />
|
||||||
|
<PackageReference Include="ZLinq" Version="1.5.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,25 +1,102 @@
|
|||||||
using System;
|
using AdventOfCode.Utils.Models;
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace AdventOfCode.Problems.AOC2024.Day10;
|
namespace AdventOfCode.Problems.AOC2024.Day10;
|
||||||
//[ProblemInfo(2024, 10, "Hoof It")]
|
[ProblemInfo(2024, 10, "Hoof It")]
|
||||||
internal class HoofIt : Problem
|
internal class HoofIt : Problem<int, int>
|
||||||
{
|
{
|
||||||
|
private int[][] _data = [];
|
||||||
|
|
||||||
|
public static Vec2<int>[] DIRS = [
|
||||||
|
new(0, -1),
|
||||||
|
new(1, 0),
|
||||||
|
new(0, 1),
|
||||||
|
new(-1, 0),
|
||||||
|
];
|
||||||
|
|
||||||
public override void CalculatePart1()
|
public override void CalculatePart1()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
for (int y = 0; y < _data.Length; y++)
|
||||||
|
{
|
||||||
|
var row = _data[y];
|
||||||
|
for (int x = 0; x < row.Length; x++)
|
||||||
|
{
|
||||||
|
var h = row[x];
|
||||||
|
if (h != 0)
|
||||||
|
continue;
|
||||||
|
var (s,_) = GetScore(new(x, y));
|
||||||
|
Part1 += s;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void CalculatePart2()
|
public override void CalculatePart2()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
for (int y = 0; y < _data.Length; y++)
|
||||||
|
{
|
||||||
|
var row = _data[y];
|
||||||
|
for (int x = 0; x < row.Length; x++)
|
||||||
|
{
|
||||||
|
var h = row[x];
|
||||||
|
if (h != 0)
|
||||||
|
continue;
|
||||||
|
var (_, s) = GetScore(new(x, y));
|
||||||
|
Part2 += s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public (int score, int scoreDistinct) GetScore(Vec2<int> pos)
|
||||||
|
{
|
||||||
|
return GetScore(pos, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public (int score, int scoreDistinct) GetScore(Vec2<int> pos, HashSet<Vec2<int>> visited)
|
||||||
|
{
|
||||||
|
var curHeight = _data[pos.Y][pos.X];
|
||||||
|
if (curHeight == 9)
|
||||||
|
{
|
||||||
|
if(visited.Contains(pos))
|
||||||
|
return (0, 1);
|
||||||
|
visited.Add(pos);
|
||||||
|
return (1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var score = 0;
|
||||||
|
var scoreDistinct = 0;
|
||||||
|
foreach (var dir in DIRS)
|
||||||
|
{
|
||||||
|
var n = pos + dir;
|
||||||
|
if (!IsInBounds(n))
|
||||||
|
continue;
|
||||||
|
var h = _data[n.Y][n.X];
|
||||||
|
if (h - curHeight != 1)
|
||||||
|
continue;
|
||||||
|
var (s, d)= GetScore(n, visited);
|
||||||
|
score += s;
|
||||||
|
scoreDistinct += d;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (score, scoreDistinct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsInBounds(Vec2<int> pos)
|
||||||
|
{
|
||||||
|
if (pos.X < 0 || pos.Y < 0)
|
||||||
|
return false;
|
||||||
|
if(pos.X >= _data.Length || pos.Y >= _data[0].Length)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void LoadInput()
|
public override void LoadInput()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
_data = ReadInputLines("input.txt").Select(l => l.Select(v => v - '0').ToArray()).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,115 @@
|
|||||||
using System;
|
using Superpower.Model;
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||||
|
|
||||||
namespace AdventOfCode.Problems.AOC2024.Day11;
|
namespace AdventOfCode.Problems.AOC2024.Day11;
|
||||||
//[ProblemInfo(2024, 11, "Plutonian Pebbles")]
|
|
||||||
internal class PlutonianPebbles : Problem
|
[ProblemInfo(2024, 11, "Plutonian Pebbles")]
|
||||||
|
public class PlutonianPebbles : Problem<long, long>
|
||||||
{
|
{
|
||||||
|
private List<long> _data = [];
|
||||||
|
private readonly Dictionary<(long, long), long> _depthLookup = [];
|
||||||
|
|
||||||
public override void CalculatePart1()
|
public override void CalculatePart1()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
Part1 = _data.Sum(v => ProcessStoneRecursive(v, 25));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void CalculatePart2()
|
public override void CalculatePart2()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
Part2 = _data.Sum(v => ProcessStoneRecursive(v, 75));
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ProcessStoneRecursive(long stone, long target, long curDepth = 0)
|
||||||
|
{
|
||||||
|
if (curDepth == target)
|
||||||
|
return 1;
|
||||||
|
var d = target - curDepth;
|
||||||
|
if(_depthLookup.TryGetValue((stone, d), out var c))
|
||||||
|
return c;
|
||||||
|
long result;
|
||||||
|
if (stone == 0)
|
||||||
|
result = ProcessStoneRecursive(1, target, curDepth + 1);
|
||||||
|
else if (FastSplit(stone, out var left, out var right))
|
||||||
|
result = ProcessStoneRecursive(left, target, curDepth + 1) + ProcessStoneRecursive(right, target, curDepth + 1);
|
||||||
|
else
|
||||||
|
result = ProcessStoneRecursive(stone * 2024, target, curDepth + 1);
|
||||||
|
|
||||||
|
_depthLookup.Add((stone, d), result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long Run(long count)
|
||||||
|
{
|
||||||
|
var a = _data.ToList();
|
||||||
|
var b = new List<long>(a.Count);
|
||||||
|
for (long i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
foreach (var stone in a)
|
||||||
|
ProcessStone(stone, b);
|
||||||
|
|
||||||
|
(a, b) = (b, a);
|
||||||
|
b.Clear();
|
||||||
|
}
|
||||||
|
return a.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProcessStone(long stone, List<long> data)
|
||||||
|
{
|
||||||
|
if (stone == 0)
|
||||||
|
{
|
||||||
|
data.Add(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (FastSplit(stone, out var left, out var right))
|
||||||
|
{
|
||||||
|
data.Add(left);
|
||||||
|
data.Add(right);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data.Add(stone * 2024);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<long> Split(long stone, int len)
|
||||||
|
{
|
||||||
|
var v = stone.ToString();
|
||||||
|
return [long.Parse(v[..(len / 2)]), long.Parse(v[(len / 2)..])];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool FastSplit(long stone, out long left, out long right)
|
||||||
|
{
|
||||||
|
|
||||||
|
var len = stone.DigitCount();
|
||||||
|
if (len % 2 != 0)
|
||||||
|
{
|
||||||
|
left = 0;
|
||||||
|
right = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var l = QuickMath.FastPow10(len / 2);
|
||||||
|
var a = stone / l;
|
||||||
|
|
||||||
|
(left, right) = (a, stone - (a * l));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsEvenDigits(long value, out int len)
|
||||||
|
{
|
||||||
|
var v = len = value.ToString().Length;
|
||||||
|
return v % 2 == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void LoadInput()
|
public override void LoadInput()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
_data = ReadInputText("input.txt").Split(' ').Select(long.Parse).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
301
AdventOfCode/Problems/AOC2024/Day12/GardenGroups.cs
Normal file
301
AdventOfCode/Problems/AOC2024/Day12/GardenGroups.cs
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
using AdventOfCode.Utils.Models;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Frozen;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||||
|
|
||||||
|
namespace AdventOfCode.Problems.AOC2024.Day12;
|
||||||
|
|
||||||
|
[ProblemInfo(2024, 12, "Garden Groups")]
|
||||||
|
internal class GardenGroups : Problem<int, int>
|
||||||
|
{
|
||||||
|
private char[][] _data = [];
|
||||||
|
|
||||||
|
public static readonly Vec2<int>[] DIRS = [
|
||||||
|
new(0,1),
|
||||||
|
new(1,0),
|
||||||
|
new(0,-1),
|
||||||
|
new(-1,0),
|
||||||
|
];
|
||||||
|
|
||||||
|
public override void CalculatePart1()
|
||||||
|
{
|
||||||
|
var r = FindPlots(_data);
|
||||||
|
Part1 = r.Sum(plot => plot.area.Count * plot.perimeter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CalculatePart2()
|
||||||
|
{
|
||||||
|
var plots = FindPlots(_data);
|
||||||
|
var r = plots.Select(plot => (plot.plant, area: plot.area.Count, sides: CountSides(GroupSides(plot.outline, plot.area), plot.area)));
|
||||||
|
foreach (var (plant, area, perimeter, outline) in plots)
|
||||||
|
{
|
||||||
|
Console.WriteLine();
|
||||||
|
var groups = GroupSides(outline, area);
|
||||||
|
Console.WriteLine($"{plant}: {CountSides(groups, area)}, {groups.Count}");
|
||||||
|
DrawPlot(area, groups, plant);
|
||||||
|
}
|
||||||
|
Part2 = r.Sum(v => v.area * v.sides);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<List<Vec2<int>>> GroupSides(List<Vec2<int>> outline, List<Vec2<int>> area)
|
||||||
|
{
|
||||||
|
var result = new List<List<Vec2<int>>>();
|
||||||
|
var visited = new HashSet<Vec2<int>>();
|
||||||
|
var open = new HashSet<Vec2<int>>(outline);
|
||||||
|
|
||||||
|
while (open.Count > 0)
|
||||||
|
{
|
||||||
|
var p = open.First();
|
||||||
|
open.Remove(p);
|
||||||
|
if(visited.Contains(p))
|
||||||
|
continue;
|
||||||
|
visited.Add(p);
|
||||||
|
var group = new List<Vec2<int>>() { p };
|
||||||
|
GetGroup(p, group);
|
||||||
|
result.Add(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetGroup(Vec2<int> point, List<Vec2<int>> group)
|
||||||
|
{
|
||||||
|
var up = DIRS[0];
|
||||||
|
var right = DIRS[1];
|
||||||
|
if(outline.Contains(point + up) || outline.Contains(point - up))
|
||||||
|
{
|
||||||
|
ProcessDirection(point, up, group);
|
||||||
|
ProcessDirection(point, -up, group);
|
||||||
|
}
|
||||||
|
else if(outline.Contains(point + right) || outline.Contains(point - right))
|
||||||
|
{
|
||||||
|
ProcessDirection(point, right, group);
|
||||||
|
ProcessDirection(point, -right, group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessDirection(Vec2<int> point, Vec2<int> dir, List<Vec2<int>> group)
|
||||||
|
{
|
||||||
|
var n = point + dir;
|
||||||
|
if (!outline.Contains(n) || visited.Contains(n))
|
||||||
|
return;
|
||||||
|
//if (!area.Contains(n + dir.YX) && !area.Contains(n - dir.YX))
|
||||||
|
// return;
|
||||||
|
visited.Add(n);
|
||||||
|
group.Add(n);
|
||||||
|
ProcessDirection(n, dir, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawPlot(List<Vec2<int>> area, List<List<Vec2<int>>> outline, char plant)
|
||||||
|
{
|
||||||
|
var (min, max) = GetBounds(outline.SelectMany(v => v).ToList());
|
||||||
|
|
||||||
|
int Sides(Vec2<int> point, List<Vec2<int>> group)
|
||||||
|
{
|
||||||
|
var s = 0;
|
||||||
|
foreach (var dir in DIRS)
|
||||||
|
{
|
||||||
|
var n = point + dir;
|
||||||
|
if (area.Contains(n))
|
||||||
|
s++;
|
||||||
|
if(group.Count > 1 && outline.Any(g => group != g && g.Contains(n)))
|
||||||
|
s--;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleColor[] colors = [
|
||||||
|
ConsoleColor.Red,
|
||||||
|
ConsoleColor.DarkGreen,
|
||||||
|
ConsoleColor.Blue,
|
||||||
|
ConsoleColor.DarkRed,
|
||||||
|
ConsoleColor.Magenta,
|
||||||
|
ConsoleColor.DarkCyan,
|
||||||
|
ConsoleColor.DarkBlue,
|
||||||
|
ConsoleColor.DarkMagenta,
|
||||||
|
ConsoleColor.DarkYellow
|
||||||
|
];
|
||||||
|
|
||||||
|
for (int y = min.Y; y <= max.Y; y++)
|
||||||
|
{
|
||||||
|
for (int x = min.X; x <= max.X; x++)
|
||||||
|
{
|
||||||
|
Console.ResetColor();
|
||||||
|
var p = new Vec2<int>(x,y);
|
||||||
|
if (area.Contains(p))
|
||||||
|
{
|
||||||
|
Console.BackgroundColor = ConsoleColor.Black;
|
||||||
|
Console.Write(plant);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var curSideGroup = outline.FirstOrDefault(v => v.Contains(p));
|
||||||
|
if (curSideGroup != null)
|
||||||
|
{
|
||||||
|
var idx = outline.IndexOf(curSideGroup);
|
||||||
|
Console.BackgroundColor = colors[idx % colors.Length];
|
||||||
|
var s = Sides(p, curSideGroup);
|
||||||
|
if(curSideGroup.Count > 1 && IsInclosed(curSideGroup, outline, area))
|
||||||
|
Console.Write('&');
|
||||||
|
else
|
||||||
|
Console.Write(s);
|
||||||
|
}else
|
||||||
|
Console.Write(' ');
|
||||||
|
}
|
||||||
|
Console.ResetColor();
|
||||||
|
}
|
||||||
|
Console.ResetColor();
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
Console.ResetColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawPoints(List<Vec2<int>> data, char display)
|
||||||
|
{
|
||||||
|
var (min, max) = GetBounds(data);
|
||||||
|
|
||||||
|
var output = new StringBuilder();
|
||||||
|
for (int y = min.Y; y <= max.Y; y++)
|
||||||
|
{
|
||||||
|
for (int x = min.X; x <= max.X; x++)
|
||||||
|
{
|
||||||
|
var p = new Vec2<int>(x,y);
|
||||||
|
if (data.Contains(p))
|
||||||
|
output.Append(display);
|
||||||
|
else
|
||||||
|
output.Append(' ');
|
||||||
|
|
||||||
|
}
|
||||||
|
output.AppendLine();
|
||||||
|
}
|
||||||
|
Console.WriteLine(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (Vec2<int> min, Vec2<int> max) GetBounds(List<Vec2<int>> points)
|
||||||
|
{
|
||||||
|
var min = Vec2<int>.Splat(int.MaxValue);
|
||||||
|
var max = Vec2<int>.Splat(int.MinValue);
|
||||||
|
foreach (var pos in points)
|
||||||
|
{
|
||||||
|
if (pos.X < min.X)
|
||||||
|
min.X = pos.X;
|
||||||
|
if (pos.Y < min.Y)
|
||||||
|
min.Y = pos.Y;
|
||||||
|
|
||||||
|
if (pos.X > max.X)
|
||||||
|
max.X = pos.X;
|
||||||
|
if (pos.Y > max.Y)
|
||||||
|
max.Y = pos.Y;
|
||||||
|
}
|
||||||
|
return (min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInclosed(List<Vec2<int>> side, List<List<Vec2<int>>> sides, List<Vec2<int>> area)
|
||||||
|
{
|
||||||
|
var otherSides = sides.Where(g => g != side).SelectMany(s => s).ToFrozenSet();
|
||||||
|
foreach (var point in side)
|
||||||
|
{
|
||||||
|
foreach (var dir in DIRS)
|
||||||
|
{
|
||||||
|
var n = point + dir;
|
||||||
|
if (side.Contains(n))
|
||||||
|
continue;
|
||||||
|
if (!area.Contains(n))
|
||||||
|
return false;
|
||||||
|
if (otherSides.Contains(n))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int CountSides(List<List<Vec2<int>>> groups, List<Vec2<int>> area)
|
||||||
|
{
|
||||||
|
int Sides(Vec2<int> point, List<Vec2<int>> group)
|
||||||
|
{
|
||||||
|
var s = 0;
|
||||||
|
foreach (var dir in DIRS)
|
||||||
|
{
|
||||||
|
var n = point + dir;
|
||||||
|
if(area.Contains(n))
|
||||||
|
s++;
|
||||||
|
if (group.Count > 1 && groups.Any(g => group != g && g.Contains(n)))
|
||||||
|
s--;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return groups.Sum(s => s.Select(p => Sides(p, s)).Max() + (s.Count > 1 && IsInclosed(s, groups, area) ? 1 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<(char plant, List<Vec2<int>> area, int perimeter, List<Vec2<int>> outline)> FindPlots(char[][] data)
|
||||||
|
{
|
||||||
|
var visited = new HashSet<Vec2<int>>(data.Length * data[0].Length);
|
||||||
|
|
||||||
|
var results = new List<(char plant, List<Vec2<int>>, int perimeter, List<Vec2<int>> outline)>();
|
||||||
|
|
||||||
|
for (int y = 0; y < data.Length; y++)
|
||||||
|
{
|
||||||
|
var row = data[y];
|
||||||
|
for (int x = 0; x < row.Length; x++)
|
||||||
|
{
|
||||||
|
var p = new Vec2<int>(x, y);
|
||||||
|
if (visited.Contains(p))
|
||||||
|
continue;
|
||||||
|
var members = new List<Vec2<int>>();
|
||||||
|
var plant = data[y][x];
|
||||||
|
var perimeter = 0;
|
||||||
|
var outline = new List<Vec2<int>>();
|
||||||
|
GetMembers(data, plant, p, visited, members, ref perimeter, outline);
|
||||||
|
results.Add((plant, members, perimeter, outline));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetMembers(char[][] data, char plant, Vec2<int> point, HashSet<Vec2<int>> visited, List<Vec2<int>> members, ref int perimeter, List<Vec2<int>> outline)
|
||||||
|
{
|
||||||
|
if (visited.Contains(point))
|
||||||
|
return;
|
||||||
|
visited.Add(point);
|
||||||
|
members.Add(point);
|
||||||
|
|
||||||
|
foreach (var dir in DIRS)
|
||||||
|
{
|
||||||
|
var n = dir + point;
|
||||||
|
if (!IsInBounds(n, data))
|
||||||
|
{
|
||||||
|
perimeter += 1;
|
||||||
|
outline.Add(n);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (data[n.Y][n.X] != plant)
|
||||||
|
{
|
||||||
|
perimeter += 1;
|
||||||
|
outline.Add(n);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
GetMembers(data, plant, n, visited, members, ref perimeter, outline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInBounds(Vec2<int> pos, char[][] data)
|
||||||
|
{
|
||||||
|
if (pos.X < 0 || pos.Y < 0)
|
||||||
|
return false;
|
||||||
|
if (pos.X >= data.Length || pos.Y >= data[0].Length)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LoadInput()
|
||||||
|
{
|
||||||
|
_data = ReadInputLines("sample3.txt").Select(ln => ln.ToCharArray()).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,16 @@ internal class DiskFragmenter : Problem<long, long>
|
|||||||
public override void CalculatePart2()
|
public override void CalculatePart2()
|
||||||
{
|
{
|
||||||
var blocks = ExpandBlocks(_data);
|
var blocks = ExpandBlocks(_data);
|
||||||
|
var empty = blocks.Where(b => b.isEmpty).Sum(b => b.length);
|
||||||
|
var files = blocks.Where(b => !b.isEmpty).Sum(b => b.length);
|
||||||
CompactV2(blocks);
|
CompactV2(blocks);
|
||||||
|
var empty2 = blocks.Where(b => b.isEmpty).Sum(b => b.length);
|
||||||
|
var files2 = blocks.Where(b => !b.isEmpty).Sum(b => b.length);
|
||||||
|
|
||||||
|
if (empty != empty2)
|
||||||
|
Console.WriteLine("Empty space does not match");
|
||||||
|
if (files != files2)
|
||||||
|
Console.WriteLine($"Files space does not match Befor: {files} -> {files2}");
|
||||||
//Print(blocks);
|
//Print(blocks);
|
||||||
// Too High: 8838426222802
|
// Too High: 8838426222802
|
||||||
Part2 = ComputeHashV2(blocks);
|
Part2 = ComputeHashV2(blocks);
|
||||||
@@ -174,10 +183,16 @@ internal class DiskFragmenter : Problem<long, long>
|
|||||||
}
|
}
|
||||||
//Extend Right Block
|
//Extend Right Block
|
||||||
else if (idx + 1 < blocks.Count && blocks[idx + 1].isEmpty)
|
else if (idx + 1 < blocks.Count && blocks[idx + 1].isEmpty)
|
||||||
|
{
|
||||||
blocks[idx + 1].length += block.length;
|
blocks[idx + 1].length += block.length;
|
||||||
|
blocks.RemoveAt(idx);
|
||||||
|
}
|
||||||
//Extend Left Block
|
//Extend Left Block
|
||||||
else if (idx - 1 > 0 && blocks[idx - 1].isEmpty)
|
else if (idx - 1 > 0 && blocks[idx - 1].isEmpty)
|
||||||
|
{
|
||||||
blocks[idx - 1].length += block.length;
|
blocks[idx - 1].length += block.length;
|
||||||
|
blocks.RemoveAt(idx);
|
||||||
|
}
|
||||||
//Insert new Empty Block
|
//Insert new Empty Block
|
||||||
else
|
else
|
||||||
blocks[idx] = new Block(block.length);
|
blocks[idx] = new Block(block.length);
|
||||||
|
|||||||
69
AdventOfCode/Problems/AOC2025/Day1/SecretEntrance.cs
Normal file
69
AdventOfCode/Problems/AOC2025/Day1/SecretEntrance.cs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using ZLinq;
|
||||||
|
|
||||||
|
namespace AdventOfCode.Problems.AOC2025.Day1;
|
||||||
|
|
||||||
|
[ProblemInfo(2025, 1, "Secret Entrance")]
|
||||||
|
internal class SecretEntrance : Problem<int, int>
|
||||||
|
{
|
||||||
|
public const int LOCK_SIZE = 100;
|
||||||
|
|
||||||
|
public int[] Input { get; set; } = [];
|
||||||
|
public override void CalculatePart1()
|
||||||
|
{
|
||||||
|
var c = 0;
|
||||||
|
var v = 50;
|
||||||
|
foreach (var item in Input)
|
||||||
|
{
|
||||||
|
v += item;
|
||||||
|
v = v.Mod(LOCK_SIZE);
|
||||||
|
if (v == 0)
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
Part1 = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CalculatePart2()
|
||||||
|
{
|
||||||
|
var c = 0;
|
||||||
|
var v = 50;
|
||||||
|
foreach (var item in Input)
|
||||||
|
{
|
||||||
|
var vStart = v;
|
||||||
|
|
||||||
|
v += item;
|
||||||
|
if (item > 0)
|
||||||
|
c += (int)Math.Floor(v / (float)LOCK_SIZE);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var d = v / (float)LOCK_SIZE;
|
||||||
|
var fl = Math.Floor(d);
|
||||||
|
c += (int)Math.Abs(fl) - (vStart == 0 ? 1 : 0);
|
||||||
|
if (fl == d)
|
||||||
|
c += 1;
|
||||||
|
}
|
||||||
|
v = v.Mod(LOCK_SIZE);
|
||||||
|
}
|
||||||
|
Part2 = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LoadInput()
|
||||||
|
{
|
||||||
|
Input = ReadInputLines("input.txt")
|
||||||
|
.AsValueEnumerable()
|
||||||
|
.Select(l =>
|
||||||
|
{
|
||||||
|
return l[0] switch
|
||||||
|
{
|
||||||
|
'L' => -int.Parse(l[1..]),
|
||||||
|
'R' => int.Parse(l[1..]),
|
||||||
|
_ => throw new NotImplementedException()
|
||||||
|
};
|
||||||
|
}).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
8
AdventOfCode/Problems/AOC2025/Day1/test.out
Normal file
8
AdventOfCode/Problems/AOC2025/Day1/test.out
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[-100]: 1 | start: 50 v: 50
|
||||||
|
[100]: 1 | start: 50 v: 50
|
||||||
|
[-150]: 2 | start: 50 v: 0
|
||||||
|
[150]: 1 | start: 0 v: 50
|
||||||
|
[-500]: 5 | start: 50 v: 50
|
||||||
|
[500]: 5 | start: 50 v: 50
|
||||||
|
[-550]: 6 | start: 50 v: 0
|
||||||
|
[550]: 5 | start: 0 v: 5
|
||||||
100
AdventOfCode/Problems/AOC2025/Day2/GiftShop.cs
Normal file
100
AdventOfCode/Problems/AOC2025/Day2/GiftShop.cs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ZLinq;
|
||||||
|
|
||||||
|
namespace AdventOfCode.Problems.AOC2025.Day2;
|
||||||
|
|
||||||
|
[ProblemInfo(2025, 2, "Gift Shop")]
|
||||||
|
internal class GiftShop : Problem<long, long>
|
||||||
|
{
|
||||||
|
private IdRange[] _ranges = [];
|
||||||
|
public override void CalculatePart1()
|
||||||
|
{
|
||||||
|
var v = _ranges.SelectMany(GetDoubleSequences);
|
||||||
|
//Console.WriteLine(v.AsJoinedString());
|
||||||
|
Part1 = v.Sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long[] GetDoubleSequences(IdRange range)
|
||||||
|
{
|
||||||
|
range = range.Snap();
|
||||||
|
var minDigits = range.Min.DigitCount() / 2;
|
||||||
|
var maxDigits = range.Max.DigitCount() / 2;
|
||||||
|
|
||||||
|
var min = GetMinValue((int)minDigits, range.Min);
|
||||||
|
var max = GetMaxValue((int)maxDigits, range.Max);
|
||||||
|
//Console.WriteLine($"{min}-{max}");
|
||||||
|
if (max < min)
|
||||||
|
return [];
|
||||||
|
var n = (max - min) + 1;
|
||||||
|
var result = new long[n];
|
||||||
|
for (long i = min; i <= max; i++)
|
||||||
|
{
|
||||||
|
result[i - min] = (i * QuickMath.FastPow10(minDigits)) + i;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long SnapToUpNearestValidRange(long value)
|
||||||
|
{
|
||||||
|
var dc = value.DigitCount();
|
||||||
|
if (dc.IsEven())
|
||||||
|
return value;
|
||||||
|
return QuickMath.FastPow10(dc);
|
||||||
|
}
|
||||||
|
public static long SnapToDownNearestValidRange(long value)
|
||||||
|
{
|
||||||
|
var dc = value.DigitCount();
|
||||||
|
if (dc.IsEven())
|
||||||
|
return value;
|
||||||
|
return QuickMath.FastPow10(dc - 1) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long GetMinValue(int digits, long value)
|
||||||
|
{
|
||||||
|
var val = long.Parse(value.ToString()[..^digits]);
|
||||||
|
while ((val * QuickMath.FastPow10(digits)) + val < value)
|
||||||
|
{
|
||||||
|
val++;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long GetMaxValue(int digits, long value)
|
||||||
|
{
|
||||||
|
var val = long.Parse(value.ToString()[..^digits]);
|
||||||
|
while ((val * QuickMath.FastPow10(digits)) + val > value)
|
||||||
|
{
|
||||||
|
val--;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CalculatePart2()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LoadInput()
|
||||||
|
{
|
||||||
|
var text = ReadInputText("input.txt");
|
||||||
|
_ranges = text.Split(',')
|
||||||
|
.AsValueEnumerable()
|
||||||
|
.Select(r => r.Split('-').Select(long.Parse))
|
||||||
|
.Select(r => new IdRange(r.First(), r.Last()))
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public record IdRange(long Min, long Max)
|
||||||
|
{
|
||||||
|
public IdRange Snap()
|
||||||
|
{
|
||||||
|
return new IdRange(SnapToUpNearestValidRange(Min), SnapToDownNearestValidRange(Max));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
65
AdventOfCode/Problems/AOC2025/Day3/Lobby.cs
Normal file
65
AdventOfCode/Problems/AOC2025/Day3/Lobby.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ZLinq;
|
||||||
|
|
||||||
|
namespace AdventOfCode.Problems.AOC2025.Day3;
|
||||||
|
|
||||||
|
[ProblemInfo(2025, 3, "Lobby")]
|
||||||
|
internal class Lobby : Problem<long, long>
|
||||||
|
{
|
||||||
|
private (int val, int idx)[][] _batteryBanks = [];
|
||||||
|
|
||||||
|
public override void CalculatePart1()
|
||||||
|
{
|
||||||
|
Part1 = _batteryBanks.AsValueEnumerable().Select(bank =>
|
||||||
|
{
|
||||||
|
var batteries = GetViableBatteries(bank);
|
||||||
|
return GetPower(batteries);
|
||||||
|
}).Sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void CalculatePart2()
|
||||||
|
{
|
||||||
|
Console.WriteLine();
|
||||||
|
var b = _batteryBanks.AsValueEnumerable().Select(bank =>
|
||||||
|
{
|
||||||
|
var batteries = GetViableBatteries(bank, 12);
|
||||||
|
return GetPower(batteries);
|
||||||
|
});
|
||||||
|
Part2 = b.Sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long GetPower(int[] values)
|
||||||
|
{
|
||||||
|
return values.Select((v, idx) =>
|
||||||
|
{
|
||||||
|
var mag = (long)Math.Pow(10, values.Length - idx - 1);
|
||||||
|
return v * mag;
|
||||||
|
}).Sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] GetViableBatteries((int val, int idx)[] source, int count = 2)
|
||||||
|
{
|
||||||
|
var batteries = new int[count];
|
||||||
|
var offset = 0;
|
||||||
|
for (int i = count; i > 0; i--)
|
||||||
|
{
|
||||||
|
var tgt = i - 1;
|
||||||
|
var (val, idx) = source[offset..^tgt].MaxBy(v => v.val);
|
||||||
|
offset = idx + 1;
|
||||||
|
batteries[count - i] = val;
|
||||||
|
}
|
||||||
|
return batteries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LoadInput()
|
||||||
|
{
|
||||||
|
_batteryBanks = ReadInputLines("input.txt")
|
||||||
|
.AsValueEnumerable()
|
||||||
|
.Select(l => l.AsValueEnumerable().Select((v, idx) => (v - '0', idx)).ToArray())
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
62
AdventOfCode/Problems/AOC2025/Day4/PrintingDeparment.cs
Normal file
62
AdventOfCode/Problems/AOC2025/Day4/PrintingDeparment.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using AdventOfCode.Utils.Models;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AdventOfCode.Problems.AOC2025.Day4;
|
||||||
|
[ProblemInfo(2025, 4, "Printing Department")]
|
||||||
|
internal class PrintingDeparment: Problem<int, int>
|
||||||
|
{
|
||||||
|
private string[] _data = [];
|
||||||
|
private Vec2<int> _size;
|
||||||
|
|
||||||
|
public override void CalculatePart1()
|
||||||
|
{
|
||||||
|
var c = 0;
|
||||||
|
for (int y = 0; y < _size.Y; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < _size.X; x++)
|
||||||
|
{
|
||||||
|
var pos = new Vec2<int>(x, y);
|
||||||
|
if (_data[pos.Y][pos.X] != '@')
|
||||||
|
continue;
|
||||||
|
var n = CountNeighbors(pos);
|
||||||
|
if (n < 4)
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Part1 = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CountNeighbors(Vec2<int> pos)
|
||||||
|
{
|
||||||
|
var c = 0;
|
||||||
|
for (int y = pos.Y-1; y <= pos.Y + 1; y++)
|
||||||
|
{
|
||||||
|
if (y < 0 || y >= _size.Y)
|
||||||
|
continue;
|
||||||
|
for (int x = pos.X - 1; x <= pos.X + 1; x++)
|
||||||
|
{
|
||||||
|
if (x < 0 || x >= _size.X)
|
||||||
|
continue;
|
||||||
|
if (pos.X == x && pos.Y == y)
|
||||||
|
continue;
|
||||||
|
if (_data[y][x] == '@')
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CalculatePart2()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LoadInput()
|
||||||
|
{
|
||||||
|
_data = ReadInputLines("input.txt");
|
||||||
|
_size = new Vec2<int>(_data[0].Length, _data.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
85
AdventOfCode/Problems/AOC2025/Day5/Cafeteria.cs
Normal file
85
AdventOfCode/Problems/AOC2025/Day5/Cafeteria.cs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ZLinq;
|
||||||
|
|
||||||
|
namespace AdventOfCode.Problems.AOC2025.Day5;
|
||||||
|
[ProblemInfo(2025, 5, "Cafeteria")]
|
||||||
|
internal class Cafeteria : Problem<long, long>
|
||||||
|
{
|
||||||
|
private (long start, long end)[] _ranges = [];
|
||||||
|
private long[] _values = [];
|
||||||
|
|
||||||
|
public override void CalculatePart1()
|
||||||
|
{
|
||||||
|
Part1 = _values.AsValueEnumerable().Count(v => _ranges.AsValueEnumerable().Any(r => IsInRange(r, v)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInRange((long start, long end) range, long value)
|
||||||
|
{
|
||||||
|
return (range.start <= value && range.end >= value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CalculatePart2()
|
||||||
|
{
|
||||||
|
var merged = MergeRanges(_ranges);
|
||||||
|
merged.Print();
|
||||||
|
Console.WriteLine("----");
|
||||||
|
MergeRanges(merged.ToArray()).Print();
|
||||||
|
//merged.Print();
|
||||||
|
Part2 = merged.Select(r => r.end - r.start + 1).Sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<(long start, long end)> MergeRanges((long start, long end)[] ranges)
|
||||||
|
{
|
||||||
|
var result = new List<(long start, long end)>(ranges.Length);
|
||||||
|
var used = new HashSet<int>();
|
||||||
|
for (int i = 0; i < ranges.Length; i++)
|
||||||
|
{
|
||||||
|
if (used.Contains(i))
|
||||||
|
continue;
|
||||||
|
var range = ranges[i];
|
||||||
|
|
||||||
|
for (int j = (i + 1); j < ranges.Length; j++)
|
||||||
|
{
|
||||||
|
if (used.Contains(j))
|
||||||
|
continue;
|
||||||
|
var range2 = ranges[j];
|
||||||
|
if(IsOverlapping(range, range2))
|
||||||
|
{
|
||||||
|
range = Merge(range, range2);
|
||||||
|
used.Add(j);
|
||||||
|
j = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Add(range);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsOverlapping((long start, long end) a, (long start, long end) b)
|
||||||
|
{
|
||||||
|
return IsInRange(a, b.start) || IsInRange(a, b.end) || IsInRange(b, a.start) || IsInRange(b, a.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (long start, long end) Merge((long start, long end) a, (long start, long end) b)
|
||||||
|
{
|
||||||
|
return (a.start.Min(b.start), a.end.Max(b.end));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void LoadInput()
|
||||||
|
{
|
||||||
|
var lines = ReadInputLines("input.txt");
|
||||||
|
_ranges = lines
|
||||||
|
.TakeWhile(l => !string.IsNullOrWhiteSpace(l))
|
||||||
|
.Select(l => l.Split('-').Select(long.Parse))
|
||||||
|
.Select(v => (start: v.First(), end: v.Last()))
|
||||||
|
.ToArray();
|
||||||
|
_values = lines[(_ranges.Length + 1)..]
|
||||||
|
.Select(long.Parse)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
88
AdventOfCode/Problems/AOC2025/Day6/TrashCompactor.cs
Normal file
88
AdventOfCode/Problems/AOC2025/Day6/TrashCompactor.cs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace AdventOfCode.Problems.AOC2025.Day6;
|
||||||
|
[ProblemInfo(2025, 6, "Trash Compactor")]
|
||||||
|
public partial class TrashCompactor : Problem<long, long>
|
||||||
|
{
|
||||||
|
private long[][] _values = [];
|
||||||
|
private string[] _operators = [];
|
||||||
|
private IEnumerable<(char op, long[] values)> _part2Data = [];
|
||||||
|
|
||||||
|
public override void CalculatePart1()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _operators.Length; i++)
|
||||||
|
{
|
||||||
|
var op = _operators[i];
|
||||||
|
var col = _values.Select(r => r[i]).ToArray();
|
||||||
|
Part1 += op switch
|
||||||
|
{
|
||||||
|
"+" => col.Aggregate((a, b) => a + b),
|
||||||
|
"*" => col.Aggregate((a, b) => a * b),
|
||||||
|
_ => throw new InvalidOperationException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CalculatePart2()
|
||||||
|
{
|
||||||
|
foreach (var (op, values) in _part2Data)
|
||||||
|
{
|
||||||
|
Part2 += op switch
|
||||||
|
{
|
||||||
|
'+' => values.Aggregate((a, b) => a + b),
|
||||||
|
'*' => values.Aggregate((a, b) => a * b),
|
||||||
|
_ => throw new InvalidOperationException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LoadInput()
|
||||||
|
{
|
||||||
|
var lines = ReadInputLines("input.txt");
|
||||||
|
ParsePart1(lines);
|
||||||
|
ParsePart2(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParsePart1(string[] lines)
|
||||||
|
{
|
||||||
|
_values = lines[..^1].Select(l => LineMatch().Matches(l).Select(v => long.Parse(v.Value)).ToArray()).ToArray();
|
||||||
|
_operators = LineMatch().Matches(lines[^1]).Select(v => v.Value).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParsePart2(string[] lines)
|
||||||
|
{
|
||||||
|
var valueLines = lines[..^1];
|
||||||
|
var opLines = lines[^1];
|
||||||
|
|
||||||
|
var opPos = 0;
|
||||||
|
var len = 1;
|
||||||
|
|
||||||
|
var data = new List<(char op, string[] values)>();
|
||||||
|
|
||||||
|
for (int i = 1; i < opLines.Length; i++)
|
||||||
|
{
|
||||||
|
var curChar = opLines[i];
|
||||||
|
if (curChar != ' ' || i == opLines.Length - 1)
|
||||||
|
{
|
||||||
|
if (i == opLines.Length - 1)
|
||||||
|
len = opLines.Length - opPos + 1;
|
||||||
|
var op = opLines[opPos];
|
||||||
|
var values = valueLines.Select(v => v[opPos..(opPos + len - 1)]).ToArray();
|
||||||
|
data.Add((op, values));
|
||||||
|
|
||||||
|
len = 1;
|
||||||
|
opPos = i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_part2Data = data.Select(v => (v.op, v.values.Transpose().Select(long.Parse).ToArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[GeneratedRegex(@"(\S+)")]
|
||||||
|
private static partial Regex LineMatch();
|
||||||
|
}
|
||||||
23
AdventOfCode/Problems/AOC2025/Day7/Laboratories.cs
Normal file
23
AdventOfCode/Problems/AOC2025/Day7/Laboratories.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AdventOfCode.Problems.AOC2025.Day7;
|
||||||
|
[ProblemInfo(2025, 7, "Laboratories")]
|
||||||
|
internal class Laboratories : Problem<long, long>
|
||||||
|
{
|
||||||
|
public override void CalculatePart1()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CalculatePart2()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LoadInput()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
48
AdventOfCode/Problems/AOC2025/Day9/MovieTheater.cs
Normal file
48
AdventOfCode/Problems/AOC2025/Day9/MovieTheater.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using AdventOfCode.Utils.Models;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AdventOfCode.Problems.AOC2025.Day9;
|
||||||
|
|
||||||
|
[ProblemInfo(2025, 9, "Movie Theater")]
|
||||||
|
internal class MovieTheater : Problem<long, long>
|
||||||
|
{
|
||||||
|
private Vec2<long>[] _input = [];
|
||||||
|
|
||||||
|
public override void CalculatePart1()
|
||||||
|
{
|
||||||
|
for (long i = 0; i < _input.Length; i++)
|
||||||
|
{
|
||||||
|
var a = _input[i];
|
||||||
|
for (long j = (i + 1); j < _input.Length; j++)
|
||||||
|
{
|
||||||
|
var b = _input[j];
|
||||||
|
var area = CalculateArea(a, b);
|
||||||
|
if (area > Part1)
|
||||||
|
{
|
||||||
|
Part1 = area;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long CalculateArea(Vec2<long> a, Vec2<long> b)
|
||||||
|
{
|
||||||
|
var rect = (a - b).Abs() + 1;
|
||||||
|
var area = Math.Abs(rect.X * rect.Y);
|
||||||
|
//Console.WriteLine($"{a} -> {b} : {rect} = {area}");
|
||||||
|
return area;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CalculatePart2()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LoadInput()
|
||||||
|
{
|
||||||
|
_input = ReadInputLines("input.txt").Select(l => l.Split(',').Select(long.Parse)).Select(v => new Vec2<long>(v.First(), v.Last())).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,4 +4,4 @@ global using AdventOfCode.Utils;
|
|||||||
|
|
||||||
|
|
||||||
var runner = new AOCRunner();
|
var runner = new AOCRunner();
|
||||||
runner.RenderInteractiveMenu();
|
runner.WithDay(7).RenderInteractiveMenu();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace AdventOfCode.Runner;
|
namespace AdventOfCode.Runner;
|
||||||
|
|
||||||
public static class ExtraMath
|
public static class ExtraMath
|
||||||
{
|
{
|
||||||
public static T GCF<T>(this T a, T b) where T : INumber<T>
|
public static T GCF<T>(this T a, T b) where T : INumber<T>
|
||||||
@@ -19,8 +20,38 @@ public static class ExtraMath
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T LCM<T>(this T a, T b) where T: INumber<T>
|
public static T LCM<T>(this T a, T b) where T : INumber<T>
|
||||||
{
|
{
|
||||||
return (a / GCF(a, b)) * b;
|
return (a / GCF(a, b)) * b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static T Max<T>(this T a, T b) where T : INumber<T>
|
||||||
|
{
|
||||||
|
return T.Max(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Min<T>(this T a, T b) where T : INumber<T>
|
||||||
|
{
|
||||||
|
return T.Min(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Mod<T>(this T value, T divisor) where T : INumber<T>
|
||||||
|
{
|
||||||
|
T remainder = value % divisor;
|
||||||
|
|
||||||
|
if (remainder < T.Zero)
|
||||||
|
return remainder + divisor;
|
||||||
|
else
|
||||||
|
return remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsEven<T>(this T value) where T : INumber<T>
|
||||||
|
{
|
||||||
|
return T.IsEvenInteger(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsOdd<T>(this T value) where T : INumber<T>
|
||||||
|
{
|
||||||
|
return T.IsOddInteger(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace AdventOfCode.Utils;
|
namespace AdventOfCode.Utils;
|
||||||
public static class Extensions
|
public static class Extensions
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
public static string AsJoinedString<T>(this IEnumerable<T> data, string delim = ", ")
|
public static string AsJoinedString<T>(this IEnumerable<T> data, string delim = ", ")
|
||||||
{
|
{
|
||||||
return string.Join(delim, data);
|
return string.Join(delim, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,13 @@ namespace AdventOfCode.Utils.Models;
|
|||||||
|
|
||||||
public record struct Vec2<T>(T X, T Y) where T : INumber<T>
|
public record struct Vec2<T>(T X, T Y) where T : INumber<T>
|
||||||
{
|
{
|
||||||
|
public static Vec2<T> Zero => new (T.Zero, T.Zero);
|
||||||
|
public static Vec2<T> One => new (T.One, T.One);
|
||||||
|
|
||||||
|
public readonly Vec2<T> YX => new(Y, X);
|
||||||
|
public readonly Vec2<T> YY => new(Y, Y);
|
||||||
|
public readonly Vec2<T> XX => new(X, X);
|
||||||
|
public static Vec2<T> Splat(T v) => new(v, v);
|
||||||
public static Vec2<T> operator +(Vec2<T> left, Vec2<T> right) => new Vec2<T>(left.X + right.X, left.Y + right.Y);
|
public static Vec2<T> operator +(Vec2<T> left, Vec2<T> right) => new Vec2<T>(left.X + right.X, left.Y + right.Y);
|
||||||
public static Vec2<T> operator -(Vec2<T> left, Vec2<T> right) => new Vec2<T>(left.X - right.X, left.Y - right.Y);
|
public static Vec2<T> operator -(Vec2<T> left, Vec2<T> right) => new Vec2<T>(left.X - right.X, left.Y - right.Y);
|
||||||
public static Vec2<T> operator -(Vec2<T> vec) => new Vec2<T>(-vec.X, -vec.Y);
|
public static Vec2<T> operator -(Vec2<T> vec) => new Vec2<T>(-vec.X, -vec.Y);
|
||||||
@@ -11,16 +18,35 @@ public record struct Vec2<T>(T X, T Y) where T : INumber<T>
|
|||||||
public static Vec2<T> operator *(T left, Vec2<T> right) => new Vec2<T>(right.X * left, right.Y * left);
|
public static Vec2<T> operator *(T left, Vec2<T> right) => new Vec2<T>(right.X * left, right.Y * left);
|
||||||
public static Vec2<T> operator /(Vec2<T> left, T right) => new Vec2<T>(left.X / right, left.Y / right);
|
public static Vec2<T> operator /(Vec2<T> left, T right) => new Vec2<T>(left.X / right, left.Y / right);
|
||||||
|
|
||||||
public T DistanceSq(Vec2<T> other)
|
public static implicit operator Vec2<T>(T value)
|
||||||
|
{
|
||||||
|
return new(value, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly T DistanceSq(Vec2<T> other)
|
||||||
{
|
{
|
||||||
var a = other.X - this.X;
|
var a = other.X - this.X;
|
||||||
var b = other.Y - this.Y;
|
var b = other.Y - this.Y;
|
||||||
return (a * a) + (b * b);
|
return (a * a) + (b * b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly Vec2<T> Min(Vec2<T> other) => new(T.Min(X, other.X), T.Min(Y, other.Y));
|
||||||
|
|
||||||
|
public readonly Vec2<T> Max(Vec2<T> other) => new(T.Max(X, other.X), T.Max(Y, other.Y));
|
||||||
|
|
||||||
|
public readonly Vec2<T> Abs() => new(T.Abs(X), T.Abs(Y));
|
||||||
|
|
||||||
|
public override readonly string ToString()
|
||||||
|
{
|
||||||
|
return $"({X}, {Y})";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record struct Vec3<T>(T X, T Y, T Z) where T : INumber<T>
|
public record struct Vec3<T>(T X, T Y, T Z) where T : INumber<T>
|
||||||
{
|
{
|
||||||
|
public static Vec3<T> Zero => new(T.Zero, T.Zero, T.Zero);
|
||||||
|
public static Vec3<T> One => new(T.One, T.One, T.One);
|
||||||
|
public static Vec3<T> Splat(T v) => new(v, v, v);
|
||||||
public static Vec3<T> operator +(Vec3<T> left, Vec3<T> right) => new Vec3<T>(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
|
public static Vec3<T> operator +(Vec3<T> left, Vec3<T> right) => new Vec3<T>(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
|
||||||
public static Vec3<T> operator -(Vec3<T> left, Vec3<T> right) => new Vec3<T>(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
|
public static Vec3<T> operator -(Vec3<T> left, Vec3<T> right) => new Vec3<T>(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
|
||||||
public static Vec3<T> operator -(Vec3<T> vec) => new Vec3<T>(-vec.X, -vec.Y, -vec.Z);
|
public static Vec3<T> operator -(Vec3<T> vec) => new Vec3<T>(-vec.X, -vec.Y, -vec.Z);
|
||||||
@@ -28,11 +54,26 @@ public record struct Vec3<T>(T X, T Y, T Z) where T : INumber<T>
|
|||||||
public static Vec3<T> operator *(T left, Vec3<T> right) => new Vec3<T>(right.X * left, right.Y * left, right.Z * left);
|
public static Vec3<T> operator *(T left, Vec3<T> right) => new Vec3<T>(right.X * left, right.Y * left, right.Z * left);
|
||||||
public static Vec3<T> operator /(Vec3<T> left, T right) => new Vec3<T>(left.X / right, left.Y / right, left.Z / right);
|
public static Vec3<T> operator /(Vec3<T> left, T right) => new Vec3<T>(left.X / right, left.Y / right, left.Z / right);
|
||||||
|
|
||||||
public T DistanceSq(Vec3<T> other)
|
public static implicit operator Vec3<T>(T value)
|
||||||
|
{
|
||||||
|
return new(value, value, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly T DistanceSq(Vec3<T> other)
|
||||||
{
|
{
|
||||||
var a = other.X - this.X;
|
var a = other.X - this.X;
|
||||||
var b = other.Y - this.Y;
|
var b = other.Y - this.Y;
|
||||||
var c = other.Z - this.Z;
|
var c = other.Z - this.Z;
|
||||||
return (a * a) + (b * b) + (c * c);
|
return (a * a) + (b * b) + (c * c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly Vec3<T> Min(Vec3<T> other) => new(T.Min(X, other.X), T.Min(Y, other.Y), T.Min(Z, other.Z));
|
||||||
|
|
||||||
|
public readonly Vec3<T> Max(Vec3<T> other) => new(T.Max(X, other.X), T.Max(Y, other.Y), T.Max(Z, other.Z));
|
||||||
|
public readonly Vec3<T> Abs() => new(T.Abs(X), T.Abs(Y), T.Abs(Z));
|
||||||
|
|
||||||
|
public override readonly string ToString()
|
||||||
|
{
|
||||||
|
return $"({X}, {Y}, {Z})";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
37
AdventOfCode/Utils/QuickMath.cs
Normal file
37
AdventOfCode/Utils/QuickMath.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
namespace AdventOfCode.Utils;
|
||||||
|
|
||||||
|
public static class QuickMath
|
||||||
|
{
|
||||||
|
private static readonly long[] pow10Long = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000, 10000000000000000, 100000000000000000, 1000000000000000000];
|
||||||
|
private static readonly int[] pow10int = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000];
|
||||||
|
|
||||||
|
public static long FastPow10(long exp)
|
||||||
|
{
|
||||||
|
return pow10Long[exp];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int FastPow10(int exp)
|
||||||
|
{
|
||||||
|
return pow10int[exp];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly long[] longCorrectionTable= [9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, 9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999, 9999999999999999, 99999999999999999, 999999999999999999];
|
||||||
|
private static readonly int[] intCorrectionTable = [9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999];
|
||||||
|
public static long DigitCount(this long value)
|
||||||
|
{
|
||||||
|
var l2 = 63 - long.LeadingZeroCount(value | 1);
|
||||||
|
var ans = ((9 * l2) >> 5);
|
||||||
|
if (value > longCorrectionTable[ans])
|
||||||
|
ans += 1;
|
||||||
|
return ans + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int DigitCount(this int value)
|
||||||
|
{
|
||||||
|
var l2 = 31 - int.LeadingZeroCount(value | 1);
|
||||||
|
var ans = ((9 * l2) >> 5);
|
||||||
|
if (value > intCorrectionTable[ans])
|
||||||
|
ans += 1;
|
||||||
|
return ans + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user