Initial Commit
This commit is contained in:
264
2022/Day09CSharp/Program.cs
Normal file
264
2022/Day09CSharp/Program.cs
Normal file
@@ -0,0 +1,264 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
using System.Reflection;
|
||||
|
||||
Part01();
|
||||
Part02();
|
||||
|
||||
void Part01()
|
||||
{
|
||||
Simulation exampleSim = new Simulation(2);
|
||||
Simulation puzzleSim = new Simulation(2);
|
||||
|
||||
exampleSim.LoadDataFile("example-input.txt");
|
||||
exampleSim.SimulateAll(0, 5, 0, 5);
|
||||
Console.WriteLine("Part01, Example Visited: " + exampleSim.TailVisitedCount);
|
||||
|
||||
puzzleSim.LoadDataFile("puzzle-input.txt");
|
||||
puzzleSim.SimulateAll(-50, 50, -50, 50);
|
||||
Console.WriteLine("Part01, Puzzle Visited: " + puzzleSim.TailVisitedCount);
|
||||
}
|
||||
|
||||
void Part02()
|
||||
{
|
||||
Simulation exampleSim = new Simulation(10);
|
||||
Simulation example2Sim = new Simulation(10);
|
||||
Simulation puzzleSim = new Simulation(10);
|
||||
|
||||
exampleSim.LoadDataFile("example-input.txt");
|
||||
exampleSim.SimulateAll(0, 6, 0, 5, false);
|
||||
Console.WriteLine("Part02, Example Visited: " + exampleSim.TailVisitedCount);
|
||||
|
||||
example2Sim.LoadDataFile("example-input2.txt");
|
||||
example2Sim.SimulateAll(-15,15,-10,10, false);
|
||||
Console.WriteLine("Part02, Example2 Visited: " + example2Sim.TailVisitedCount);
|
||||
|
||||
puzzleSim.LoadDataFile("puzzle-input.txt");
|
||||
puzzleSim.SimulateAll(-50, 50, -50, 50);
|
||||
Console.WriteLine("Part02, Puzzle Visited: " + puzzleSim.TailVisitedCount);
|
||||
}
|
||||
|
||||
class Position
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
|
||||
public Position() : this(0,0) { }
|
||||
public Position(int x, int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public Position(Position other) : this(other.x, other.y) { }
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (!(obj is Position)) return false;
|
||||
Position p = (Position)obj;
|
||||
|
||||
return p.x == x & p.y == y;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return x ^ y;
|
||||
}
|
||||
|
||||
public double distanceFrom(Position p)
|
||||
{
|
||||
return Math.Sqrt(Math.Pow(p.x - x, 2) + Math.Pow(p.y - y, 2));
|
||||
}
|
||||
|
||||
public void distanceFrom(Position p, out int x, out int y)
|
||||
{
|
||||
x = p.x - this.x;
|
||||
y = p.y - this.y;
|
||||
}
|
||||
}
|
||||
|
||||
class RopeBridge
|
||||
{
|
||||
public Position Head {
|
||||
get
|
||||
{
|
||||
return rope[0];
|
||||
}
|
||||
}
|
||||
|
||||
public Position Tail
|
||||
{
|
||||
get
|
||||
{
|
||||
return rope[rope.Count - 1];
|
||||
}
|
||||
set
|
||||
{
|
||||
rope[rope.Count - 1] = value;
|
||||
}
|
||||
}
|
||||
|
||||
List<Position> rope = new List<Position>();
|
||||
|
||||
public RopeBridge(int bridgeLength)
|
||||
{
|
||||
for (int i = 0; i < bridgeLength; i++)
|
||||
{
|
||||
rope.Add(new Position());
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateKnot(Position parent, int index)
|
||||
{
|
||||
double distance = rope[index - 1].distanceFrom(rope[index]);
|
||||
|
||||
if (distance >= 2)
|
||||
{
|
||||
int x, y;
|
||||
rope[index].distanceFrom(parent, out x, out y);
|
||||
|
||||
if (x > 0) rope[index].x++;
|
||||
if (y > 0) rope[index].y++;
|
||||
if (x < 0) rope[index].x--;
|
||||
if (y < 0) rope[index].y--;
|
||||
|
||||
// Only update if it actually moved
|
||||
if (index + 1 < rope.Count)
|
||||
{
|
||||
UpdateKnot(rope[index], index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveHead(char direction)
|
||||
{
|
||||
Position oldHead = new Position(Head);
|
||||
switch (direction)
|
||||
{
|
||||
case 'U':
|
||||
Head.y++;
|
||||
break;
|
||||
case 'D':
|
||||
Head.y--;
|
||||
break;
|
||||
case 'L':
|
||||
Head.x--;
|
||||
break;
|
||||
case 'R':
|
||||
Head.x++;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
|
||||
UpdateKnot(Head, 1);
|
||||
}
|
||||
|
||||
public void PrintBridge(int x_min, int x_max, int y_min, int y_max)
|
||||
{
|
||||
for (int j = y_max; j >= y_min; j--)
|
||||
{
|
||||
for (int i = x_min; i < x_max; i++)
|
||||
{
|
||||
var index = rope.IndexOf(new Position(i, j));
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
var query = rope.Where(pos => pos.x == i && pos.y == j);
|
||||
|
||||
if (query.Count() > 1)
|
||||
{
|
||||
for (index = 0; index < rope.Count; index++)
|
||||
{
|
||||
if (rope[index].x == i && rope[index].y == j)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
Console.Write('H');
|
||||
}
|
||||
else if (index + 1 == rope.Count)
|
||||
{
|
||||
Console.Write('T');
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write(index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write('.');
|
||||
}
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Simulation
|
||||
{
|
||||
RopeBridge bridge;
|
||||
Dictionary<Position, bool> visited = new Dictionary<Position, bool>();
|
||||
List<Tuple<char, int>> simulationSteps = new List<Tuple<char, int>>();
|
||||
|
||||
public Simulation(int bridgeLength)
|
||||
{
|
||||
bridge = new RopeBridge(bridgeLength);
|
||||
}
|
||||
|
||||
public void LoadDataFile(string filename)
|
||||
{
|
||||
using (StreamReader reader = System.IO.File.OpenText(filename))
|
||||
{
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
string? line = reader.ReadLine();
|
||||
if (line == null) throw new InvalidDataException();
|
||||
|
||||
var split = line.Split(' ');
|
||||
if (!Char.IsAsciiLetter(split[0][0])) throw new InvalidDataException();
|
||||
if (!Char.IsAsciiDigit(split[1][0])) throw new InvalidDataException();
|
||||
|
||||
simulationSteps.Add(new Tuple<char, int>(split[0][0], Int32.Parse(split[1])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int TailVisitedCount
|
||||
{
|
||||
get { return visited.Count; }
|
||||
}
|
||||
|
||||
public void SimulateAll(int x_min, int x_max, int y_min, int y_max, bool print = false)
|
||||
{
|
||||
if (print) bridge.PrintBridge(x_min, x_max, y_min, y_max);
|
||||
|
||||
foreach (var pair in simulationSteps)
|
||||
{
|
||||
if (print) Console.WriteLine(String.Format(" === {0} {1} ===", pair.Item1, pair.Item2));
|
||||
|
||||
Simulate(pair.Item1, pair.Item2, x_min, x_max, y_min, y_max, print);
|
||||
}
|
||||
}
|
||||
|
||||
public void Simulate(char direction, int count, int x_min, int x_max, int y_min, int y_max, bool print = false)
|
||||
{
|
||||
// Visit initial state always
|
||||
visited.TryAdd(new Position(bridge.Tail), true);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
bridge.MoveHead(direction);
|
||||
visited.TryAdd(new Position(bridge.Tail), true);
|
||||
|
||||
if (print) bridge.PrintBridge(x_min, x_max, y_min, y_max);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user