Initial Commit
This commit is contained in:
264
2022/Day14CSharp/Program.cs
Normal file
264
2022/Day14CSharp/Program.cs
Normal file
@@ -0,0 +1,264 @@
|
||||
using System.Drawing;
|
||||
|
||||
Part01();
|
||||
Part02();
|
||||
|
||||
void Part01()
|
||||
{
|
||||
var exampleCave = new Cave("example-input.txt");
|
||||
exampleCave.PrintCave();
|
||||
int result = exampleCave.DropUntilOverflow();
|
||||
exampleCave.PrintCave();
|
||||
Console.WriteLine("Example Number of Sand: {0}", result);
|
||||
|
||||
var puzzleCave = new Cave("puzzle-input.txt");
|
||||
puzzleCave.PrintCave();
|
||||
result = puzzleCave.DropUntilOverflow();
|
||||
puzzleCave.PrintCave();
|
||||
Console.WriteLine("Puzzle Number of Sand: {0}", result);
|
||||
}
|
||||
|
||||
void Part02()
|
||||
{
|
||||
var exampleCave = new Cave("example-input.txt");
|
||||
exampleCave.PrintCave();
|
||||
int result = exampleCave.DropUntilSourceIsPlugged();
|
||||
exampleCave.PrintCave();
|
||||
Console.WriteLine("Example Number of Sand: {0}", result);
|
||||
|
||||
var puzzleCave = new Cave("puzzle-input.txt");
|
||||
puzzleCave.PrintCave();
|
||||
result = puzzleCave.DropUntilSourceIsPlugged();
|
||||
puzzleCave.PrintCave();
|
||||
Console.WriteLine("Puzzle Number of Sand: {0}", result);
|
||||
}
|
||||
|
||||
class Cave
|
||||
{
|
||||
public enum BlockType
|
||||
{
|
||||
None,
|
||||
Sand,
|
||||
Rock,
|
||||
SandSource
|
||||
}
|
||||
public Dictionary<Point, BlockType> CaveData = new Dictionary<Point, BlockType>();
|
||||
public Point SandSource { get; set; } = new Point(500, 0);
|
||||
|
||||
public Cave(string filename)
|
||||
{
|
||||
using (StreamReader reader = System.IO.File.OpenText(filename))
|
||||
{
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
string? line = reader.ReadLine();
|
||||
if (line == null) { throw new InvalidDataException(); }
|
||||
|
||||
var vectors = line.Split("->", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
Point lastPoint = ReadPoint(vectors[0]);
|
||||
for (int i = 1; i < vectors.Length; i++)
|
||||
{
|
||||
Point nextPoint = ReadPoint(vectors[i]);
|
||||
CaveData[nextPoint] = BlockType.Rock;
|
||||
|
||||
int dir;
|
||||
if (lastPoint.X != nextPoint.X)
|
||||
{
|
||||
if (lastPoint.X < nextPoint.X)
|
||||
{
|
||||
dir = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = -1;
|
||||
}
|
||||
|
||||
while (lastPoint.X != nextPoint.X)
|
||||
{
|
||||
CaveData[lastPoint] = BlockType.Rock;
|
||||
lastPoint.X += dir;
|
||||
}
|
||||
}
|
||||
else if (lastPoint.Y != nextPoint.Y)
|
||||
{
|
||||
if (lastPoint.Y < nextPoint.Y)
|
||||
{
|
||||
dir = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = -1;
|
||||
}
|
||||
|
||||
while (lastPoint.Y != nextPoint.Y)
|
||||
{
|
||||
CaveData[lastPoint] = BlockType.Rock;
|
||||
lastPoint.Y += dir;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CaveData.ContainsKey(SandSource))
|
||||
{
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
|
||||
CaveData[SandSource] = BlockType.SandSource;
|
||||
FindBounds();
|
||||
TrueBottom = Bounds.Y + Bounds.Height + 2;
|
||||
}
|
||||
|
||||
public void PrintCave()
|
||||
{
|
||||
PrintCave(new Point(-1, -1));
|
||||
}
|
||||
|
||||
public void PrintCave(Point sand)
|
||||
{
|
||||
int x_min = Bounds.Left, x_max = x_min + Bounds.Width, y_min = Bounds.Top, y_max = y_min + Bounds.Height;
|
||||
|
||||
for (int y = y_min; y <= y_max; y++)
|
||||
{
|
||||
for (int x = x_min; x <= x_max; x++)
|
||||
{
|
||||
var point = new Point(x, y);
|
||||
|
||||
if (sand == point)
|
||||
{
|
||||
Console.Write('o');
|
||||
}
|
||||
else if (CaveData.ContainsKey(point))
|
||||
{
|
||||
var item = CaveData[point];
|
||||
|
||||
if (item == BlockType.Rock)
|
||||
{
|
||||
Console.Write("#");
|
||||
}
|
||||
else if (item == BlockType.Sand)
|
||||
{
|
||||
Console.Write("o");
|
||||
}
|
||||
else if (item == BlockType.SandSource)
|
||||
{
|
||||
Console.Write("+");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write('.');
|
||||
}
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
public int DropUntilOverflow()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
while(!DropSand()) { count++; }
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public int DropUntilSourceIsPlugged()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
while (CaveData[SandSource] != BlockType.Sand)
|
||||
{
|
||||
DropSand(false);
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public bool DropSand(bool returnEarly = true, bool printEachStep = false)
|
||||
{
|
||||
Point sandPosition = new Point(SandSource.X, SandSource.Y);
|
||||
|
||||
do
|
||||
{
|
||||
if (printEachStep) PrintCave(sandPosition);
|
||||
|
||||
Point down = new Point(sandPosition.X, sandPosition.Y + 1);
|
||||
Point downLeft = new Point(sandPosition.X - 1, sandPosition.Y + 1);
|
||||
Point downRight = new Point(sandPosition.X + 1, sandPosition.Y + 1);
|
||||
|
||||
if (!CaveData.ContainsKey(down) && down.Y != TrueBottom)
|
||||
{
|
||||
sandPosition = down;
|
||||
}
|
||||
else if (!CaveData.ContainsKey(downLeft) && downLeft.Y != TrueBottom)
|
||||
{
|
||||
sandPosition = downLeft;
|
||||
}
|
||||
else if (!CaveData.ContainsKey(downRight) && downRight.Y != TrueBottom)
|
||||
{
|
||||
sandPosition = downRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cant go anywhere, so need to stop
|
||||
CaveData[sandPosition] = BlockType.Sand;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fell off the world
|
||||
if (!Bounds.Contains(sandPosition))
|
||||
{
|
||||
FindBounds();
|
||||
if (returnEarly)
|
||||
return true;
|
||||
}
|
||||
|
||||
} while (true);
|
||||
}
|
||||
|
||||
private Rectangle Bounds { get; set; }
|
||||
private int TrueBottom { get; set; }
|
||||
|
||||
private void FindBounds()
|
||||
{
|
||||
int x_min = int.MaxValue;
|
||||
int x_max = int.MinValue;
|
||||
int y_min = 0; // sand always starts at 0
|
||||
int y_max = int.MinValue;
|
||||
|
||||
foreach (var item in CaveData)
|
||||
{
|
||||
if (item.Value == BlockType.None) throw new InvalidDataException();
|
||||
|
||||
x_min = Int32.Min(item.Key.X, x_min);
|
||||
x_max = Int32.Max(item.Key.X, x_max);
|
||||
y_min = Int32.Min(item.Key.Y, y_min);
|
||||
y_max = Int32.Max(item.Key.Y, y_max);
|
||||
}
|
||||
|
||||
Bounds = new Rectangle(x_min, y_min, x_max-x_min, y_max-y_min);
|
||||
}
|
||||
|
||||
private Point ReadPoint(string s)
|
||||
{
|
||||
Point p = new Point();
|
||||
var split = s.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
p.X = Int32.Parse(split[0]);
|
||||
p.Y = Int32.Parse(split[1]);
|
||||
|
||||
return p;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user