174 lines
4.7 KiB
C#
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);
|
|
} |