Files
AOC_2024/dotnet/08/08a.cs
2024-12-10 14:36:10 -06:00

174 lines
4.7 KiB
C#

Main1();
Main2();
void Main1()
{
var map = LoadMap(Path.Join("..", "..", "08a.txt"));
HashSet<Point> antinodes = new();
foreach (var (ch, points) in map.Antennae)
{
for (int i = 0; i < points.Count-1; i++)
{
for (int j = i+1; j < points.Count; j++)
{
antinodes.UnionWith(points[i].GetAntinodes(points[j]).Where(map.Validate));
}
}
}
Console.WriteLine($"Solution {antinodes.Count}");
}
void Main2()
{
var map = LoadMap(Path.Join("..", "..", "08a.txt"));
HashSet<Point> antinodes = new();
foreach (var (ch, points) in map.Antennae)
{
for (int i = 0; i < points.Count-1; i++)
{
for (int j = i+1; j < points.Count; j++)
{
antinodes.UnionWith(points[i].GetAntinodes2(points[j], map));
}
}
}
Console.WriteLine($"Solution {antinodes.Count}");
}
Map LoadMap(string filepath)
{
var lines = File.ReadAllLines(filepath)
.Where(l => !string.IsNullOrWhiteSpace(l))
.Select(s => s.Trim())
.ToList();
Map map = new();
foreach (var (line, row) in lines.Select((l, i) => (l, i)))
{
foreach (var (c, col) in line.Select((ch, i) => (ch, i)))
{
if (c != '.')
{
Point p = new(row, col);
if (map.Antennae.TryGetValue(c, out var points))
{
points.Add(p);
}
else
{
map.Antennae[c] = new(Enumerable.Repeat(p, 1));
}
}
}
}
map.Width = lines[0].Length;
map.Height = lines.Count;
return map;
}
public static class Stuff
{
//I forgot the good algorithm
public static int TerribleGcf(int first, int second)
{
int gcf = 1;
while (first % 2 == 0 && second % 2 == 0)
{
gcf *= 2;
first /= 2;
second /= 2;
}
for (int prime = 3; prime < first && prime < second; prime += 2)
{
while (first % prime == 0 && second % prime == 0)
{
gcf *= prime;
first /= prime;
second /= prime;
}
}
return gcf;
}
//I had to look up the right way
public static int EuclideanGcf(int first, int second)
{
if (first == 0 || second == 0)
return 0;
first = Math.Abs(first);
second = Math.Abs(second);
while (first != second)
{
if (second > first)
{
first = first ^ second;
second = first ^ second;
first = first ^ second;
}
first = first - second;
}
return first;
}
}
class Map
{
public Dictionary<char, List<Point>> Antennae = new();
public int Width;
public int Height;
public Map()
{
}
public bool Validate(Point p)
=> p.Row >= 0 && p.Row < Width && p.Col >= 0 && p.Col < Height;
}
record struct Point(int Row, int Col)
{
public static Vector operator -(Point first, Point second)
=> new(first.Row - second.Row, first.Col - second.Col);
public static Point operator +(Point first, Vector second)
=> new(first.Row + second.Row, first.Col + second.Col);
public static Point operator -(Point first, Vector second)
=> new(first.Row - second.Row, first.Col - second.Col);
public readonly IEnumerable<Point> GetAntinodes(Point other)
{
var diff = this - other;
yield return this + diff;
yield return other - diff;
if (diff.Row % 3 == 0 && diff.Col % 3 == 0)
{
Console.WriteLine("inline");
yield return other + (diff / 3);
yield return other + (diff * 2 / 3);
}
}
public IEnumerable<Point> GetAntinodes2(Point other, Map map)
{
var diff = this - other;
// diff /= Stuff.TerribleGcf(diff.Row, diff.Col);
diff /= Stuff.EuclideanGcf(diff.Row, diff.Col);
var running = this;
while (map.Validate(running))
{
yield return running;
running -= diff;
}
running = this + diff;
while (map.Validate(running))
{
yield return running;
running += diff;
}
}
}
record struct Vector(int Row, int Col)
{
public static Vector operator +(Vector first, Vector second)
=> new(first.Row + second.Row, first.Col + second.Col);
public static Vector operator *(Vector first, int second)
=> new(first.Row * second, first.Col * second);
public static Vector operator /(Vector first, int second)
=> new(first.Row / second, first.Col / second);
}