feat: solved day 14 part 1
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
namespace RestroomRedoubt.Tests;
|
||||
|
||||
public class RobotTests
|
||||
{
|
||||
[Test]
|
||||
[MethodDataSource(nameof(FromTestCases))]
|
||||
public async Task From_WhenCalledWithInput_ItShouldReturnExpectedRobot(FromTestCase testCase)
|
||||
{
|
||||
var expected = Robot.From(
|
||||
testCase.ExpectedPosition.X,
|
||||
testCase.ExpectedPosition.Y,
|
||||
testCase.ExpectedVelocity.X,
|
||||
testCase.ExpectedVelocity.Y
|
||||
);
|
||||
|
||||
var result = Robot.From(testCase.Input);
|
||||
|
||||
await Assert.That(result).IsEqualTo(expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[MethodDataSource(nameof(MoveTestCases))]
|
||||
public async Task Move_WhenCalled_ItShouldMoveRobotToExpectedPosition(MoveTestCase testCase)
|
||||
{
|
||||
var robot = Robot.From(
|
||||
testCase.CurrentPosition.X,
|
||||
testCase.CurrentPosition.Y,
|
||||
testCase.Velocity.X,
|
||||
testCase.Velocity.Y
|
||||
);
|
||||
|
||||
var result = robot.Move(testCase.Area.Width, testCase.Area.Height);
|
||||
|
||||
await Assert.That(result).IsEqualTo(testCase.ExpectedNextPosition);
|
||||
}
|
||||
|
||||
public static IEnumerable<Func<MoveTestCase>> MoveTestCases()
|
||||
{
|
||||
var testVelocity = (2, -3);
|
||||
var testArea = (11, 7);
|
||||
|
||||
yield return () => new((2, 4), testVelocity, testArea, (4, 1));
|
||||
yield return () => new((4, 1), testVelocity, testArea, (6, 5));
|
||||
yield return () => new((6, 5), testVelocity, testArea, (8, 2));
|
||||
yield return () => new((8, 2), testVelocity, testArea, (10, 6));
|
||||
yield return () => new((10, 6), testVelocity, testArea, (1, 3));
|
||||
}
|
||||
|
||||
public record MoveTestCase(
|
||||
(int X, int Y) CurrentPosition,
|
||||
(int X, int Y) Velocity,
|
||||
(int Width, int Height) Area,
|
||||
(int X, int Y) ExpectedNextPosition
|
||||
);
|
||||
|
||||
public static IEnumerable<Func<FromTestCase>> FromTestCases()
|
||||
{
|
||||
yield return () => new("p=0,4 v=3,-3", (0, 4), (3, -3));
|
||||
yield return () => new("p=6,3 v=-1,-3", (6, 3), (-1, -3));
|
||||
yield return () => new("p=10,3 v=-1,2", (10, 3), (-1, 2));
|
||||
yield return () => new("p=2,0 v=2,-1", (2, 0), (2, -1));
|
||||
yield return () => new("p=0,0 v=1,3", (0, 0), (1, 3));
|
||||
yield return () => new("p=3,0 v=-2,-2", (3, 0), (-2, -2));
|
||||
yield return () => new("p=7,6 v=-1,-3", (7, 6), (-1, -3));
|
||||
yield return () => new("p=3,0 v=-1,-2", (3, 0), (-1, -2));
|
||||
yield return () => new("p=9,3 v=2,3", (9, 3), (2, 3));
|
||||
yield return () => new("p=7,3 v=-1,2", (7, 3), (-1, 2));
|
||||
yield return () => new("p=2,4 v=2,-3", (2, 4), (2, -3));
|
||||
yield return () => new("p=9,5 v=-3,-3", (9, 5), (-3, -3));
|
||||
}
|
||||
|
||||
public record FromTestCase(string Input, (int X, int Y) ExpectedPosition, (int X, int Y) ExpectedVelocity);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
namespace RestroomRedoubt.Tests;
|
||||
|
||||
public class SimulationTests
|
||||
{
|
||||
private readonly string[] _exampleInput = [
|
||||
"p=0,4 v=3,-3",
|
||||
"p=6,3 v=-1,-3",
|
||||
"p=10,3 v=-1,2",
|
||||
"p=2,0 v=2,-1",
|
||||
"p=0,0 v=1,3",
|
||||
"p=3,0 v=-2,-2",
|
||||
"p=7,6 v=-1,-3",
|
||||
"p=3,0 v=-1,-2",
|
||||
"p=9,3 v=2,3",
|
||||
"p=7,3 v=-1,2",
|
||||
"p=2,4 v=2,-3",
|
||||
"p=9,5 v=-3,-3",
|
||||
];
|
||||
|
||||
private async Task<string[]> GetPuzzleInput()
|
||||
{
|
||||
return await File.ReadAllLinesAsync(Path.Combine(AppContext.BaseDirectory, "INPUT.txt"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Run_WhenCalledWithPuzzleInput_ItShouldReturnExpectedValue()
|
||||
{
|
||||
var input = await GetPuzzleInput();
|
||||
|
||||
var result = Simulation.From(101, 103, input).Run(100);
|
||||
|
||||
await Assert.That(result).IsEqualTo(224554908);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Run_WhenCalledWithExampleInput_ItShouldReturnExpectedValue()
|
||||
{
|
||||
var result = Simulation.From(11, 7, _exampleInput).Run(100);
|
||||
|
||||
await Assert.That(result).IsEqualTo(12);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
if (args.Length is 0)
|
||||
{
|
||||
@@ -18,7 +20,139 @@ var input = await File.ReadAllLinesAsync(args[0]);
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
|
||||
// TODO: Implement solution
|
||||
var result = Simulation.From(101, 103, input).Run(100);
|
||||
|
||||
stopwatch.Stop();
|
||||
Console.WriteLine($". ({stopwatch.ElapsedMilliseconds}ms)");
|
||||
Console.WriteLine($"The safety factor will be {result}. ({stopwatch.ElapsedMilliseconds}ms)");
|
||||
|
||||
class Simulation
|
||||
{
|
||||
private readonly List<Robot> _robots;
|
||||
private readonly int _width;
|
||||
private readonly int _height;
|
||||
private readonly List<Quadrant> _quadrants;
|
||||
|
||||
private Simulation(int width, int height, List<Robot> robots)
|
||||
{
|
||||
_width = width;
|
||||
_robots = robots;
|
||||
_height = height;
|
||||
|
||||
var middleColumn = _width / 2;
|
||||
var middleRow = _height / 2;
|
||||
|
||||
var topLeftQuadrant = new Quadrant(0, middleColumn - 1, 0, middleRow - 1);
|
||||
var topRightQuadrant = new Quadrant(middleColumn + 1, _width - 1, 0, middleRow - 1);
|
||||
var bottomLeftQuadrant = new Quadrant(0, middleColumn - 1, middleRow + 1, _height - 1);
|
||||
var bottomRightQuadrant = new Quadrant(middleColumn + 1, _width - 1, middleRow + 1, _height - 1);
|
||||
_quadrants = [topLeftQuadrant, topRightQuadrant, bottomLeftQuadrant, bottomRightQuadrant];
|
||||
}
|
||||
|
||||
public static Simulation From(int width, int height, string[] input) => new(width, height, input.Select(Robot.From).ToList());
|
||||
|
||||
public int Run(int times)
|
||||
{
|
||||
for (int i = 0; i < times; i++)
|
||||
{
|
||||
foreach (var robot in _robots)
|
||||
{
|
||||
robot.Move(_width, _height);
|
||||
}
|
||||
|
||||
Debug(i);
|
||||
}
|
||||
|
||||
return _quadrants
|
||||
.Select(quadrant => _robots.Count(r => r.IsIn(quadrant)))
|
||||
.Aggregate(1, (current, count) => current * count);
|
||||
}
|
||||
|
||||
private void Debug(int time)
|
||||
{
|
||||
var lines = new StringBuilder();
|
||||
|
||||
for (var currentColumn = 0; currentColumn < _width; currentColumn++)
|
||||
{
|
||||
var row = new StringBuilder();
|
||||
|
||||
for (int currentRow = 0; currentRow < _height; currentRow++)
|
||||
{
|
||||
if (_robots.Any(r => r.IsIn(currentColumn, currentRow)))
|
||||
{
|
||||
row.Append('R');
|
||||
}
|
||||
else
|
||||
{
|
||||
row.Append('.');
|
||||
}
|
||||
}
|
||||
|
||||
lines.AppendLine(row.ToString());
|
||||
}
|
||||
|
||||
File.WriteAllText(Path.Combine(AppContext.BaseDirectory, $"OUTPUT_{time}.txt"), lines.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
partial record Robot
|
||||
{
|
||||
private int PositionX { get; set; }
|
||||
private int PositionY { get; set; }
|
||||
private int VelocityX { get; }
|
||||
private int VelocityY { get; }
|
||||
|
||||
private Robot(int positionX, int positionY, int velocityX, int velocityY)
|
||||
{
|
||||
PositionX = positionX;
|
||||
PositionY = positionY;
|
||||
VelocityX = velocityX;
|
||||
VelocityY = velocityY;
|
||||
}
|
||||
|
||||
public static Robot From(
|
||||
int positionX,
|
||||
int positionY,
|
||||
int velocityX,
|
||||
int velocityY
|
||||
) => new(positionX, positionY, velocityX, velocityY);
|
||||
|
||||
public static Robot From(string input)
|
||||
{
|
||||
var matches = RobotRegex().Match(input);
|
||||
|
||||
if (matches.Groups.Count is not 5)
|
||||
{
|
||||
throw new ArgumentException("The given robot input is missing values");
|
||||
}
|
||||
|
||||
return new(
|
||||
int.Parse(matches.Groups[1].Value),
|
||||
int.Parse(matches.Groups[2].Value),
|
||||
int.Parse(matches.Groups[3].Value),
|
||||
int.Parse(matches.Groups[4].Value)
|
||||
);
|
||||
}
|
||||
|
||||
public (int X, int Y) Move(int MaxX, int MaxY)
|
||||
{
|
||||
PositionX = (PositionX + VelocityX + MaxX) % MaxX;
|
||||
PositionY = (PositionY + VelocityY + MaxY) % MaxY;
|
||||
|
||||
return (PositionX, PositionY);
|
||||
}
|
||||
|
||||
public bool IsIn(Quadrant quadrant)
|
||||
{
|
||||
return PositionX >= quadrant.MinX &&
|
||||
PositionX <= quadrant.MaxX &&
|
||||
PositionY >= quadrant.MinY &&
|
||||
PositionY <= quadrant.MaxY;
|
||||
}
|
||||
|
||||
public bool IsIn(int x, int y) => PositionX == x && PositionY == y;
|
||||
|
||||
[GeneratedRegex(@"p=(-?\d+),(-?\d+) v=(-?\d+),(-?\d+)")]
|
||||
private static partial Regex RobotRegex();
|
||||
}
|
||||
|
||||
record Quadrant(int MinX, int MaxX, int MinY, int MaxY);
|
||||
Reference in New Issue
Block a user