Compare commits
19 Commits
a92c9b4478
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f45853889 | |||
| 55a8ea0281 | |||
| e56befa18b | |||
| 9f1a2d2300 | |||
| a0c97e4b75 | |||
| 629b13abef | |||
| 4f4ccf7117 | |||
| 625a9e5ad5 | |||
| ef959284a5 | |||
| bba775fd4e | |||
| f16899ff3c | |||
| 6606f40df9 | |||
| 199b940ff9 | |||
| 63eb4d01b0 | |||
| a33843ae1b | |||
| e08a60614a | |||
| 6a9c813d08 | |||
| ba7e6d4be0 | |||
| a4cb169566 |
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
@@ -76,6 +76,8 @@
|
||||
|
||||
|
||||
<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>
|
||||
</Project>
|
||||
|
||||
@@ -1,25 +1,102 @@
|
||||
using System;
|
||||
using AdventOfCode.Utils.Models;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdventOfCode.Problems.AOC2024.Day10;
|
||||
//[ProblemInfo(2024, 10, "Hoof It")]
|
||||
internal class HoofIt : Problem
|
||||
[ProblemInfo(2024, 10, "Hoof It")]
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
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.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
|
||||
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()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Part1 = _data.Sum(v => ProcessStoneRecursive(v, 25));
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
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);
|
||||
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);
|
||||
// Too High: 8838426222802
|
||||
Part2 = ComputeHashV2(blocks);
|
||||
@@ -174,10 +183,16 @@ internal class DiskFragmenter : Problem<long, long>
|
||||
}
|
||||
//Extend Right Block
|
||||
else if (idx + 1 < blocks.Count && blocks[idx + 1].isEmpty)
|
||||
{
|
||||
blocks[idx + 1].length += block.length;
|
||||
blocks.RemoveAt(idx);
|
||||
}
|
||||
//Extend Left Block
|
||||
else if (idx - 1 > 0 && blocks[idx - 1].isEmpty)
|
||||
{
|
||||
blocks[idx - 1].length += block.length;
|
||||
blocks.RemoveAt(idx);
|
||||
}
|
||||
//Insert new Empty Block
|
||||
else
|
||||
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();
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdventOfCode.Runner;
|
||||
|
||||
public static class ExtraMath
|
||||
{
|
||||
public static T GCF<T>(this T a, T b) where T : INumber<T>
|
||||
@@ -19,8 +20,38 @@ public static class ExtraMath
|
||||
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;
|
||||
}
|
||||
|
||||
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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdventOfCode.Utils;
|
||||
public static class Extensions
|
||||
{
|
||||
|
||||
|
||||
public static string AsJoinedString<T>(this IEnumerable<T> data, string delim = ", ")
|
||||
{
|
||||
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 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> vec) => new Vec2<T>(-vec.X, -vec.Y);
|
||||
@@ -17,10 +24,18 @@ public record struct Vec2<T>(T X, T Y) where T : INumber<T>
|
||||
var b = other.Y - this.Y;
|
||||
return (a * a) + (b * b);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"({X}, {Y})";
|
||||
}
|
||||
}
|
||||
|
||||
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> vec) => new Vec3<T>(-vec.X, -vec.Y, -vec.Z);
|
||||
@@ -35,4 +50,9 @@ public record struct Vec3<T>(T X, T Y, T Z) where T : INumber<T>
|
||||
var c = other.Z - this.Z;
|
||||
return (a * a) + (b * b) + (c * c);
|
||||
}
|
||||
|
||||
public override 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