feat: complete day 2
This commit is contained in:
@@ -0,0 +1,56 @@
|
|||||||
|
namespace CeresSearch.Tests;
|
||||||
|
|
||||||
|
public class GridTests
|
||||||
|
{
|
||||||
|
private readonly string[] _exampleInput = [
|
||||||
|
"MMMSXXMASM",
|
||||||
|
"MSAMXMSMSA",
|
||||||
|
"AMXSXMAAMM",
|
||||||
|
"MSAMASMSMX",
|
||||||
|
"XMASAMXAMM",
|
||||||
|
"XXAMMXXAMA",
|
||||||
|
"SMSMSASXSS",
|
||||||
|
"SAXAMASAAA",
|
||||||
|
"MAMMMXMMMM",
|
||||||
|
"MXMXAXMASX",
|
||||||
|
];
|
||||||
|
|
||||||
|
private async Task<string[]> GetPuzzleInput()
|
||||||
|
{
|
||||||
|
return await File.ReadAllLinesAsync(Path.Combine(AppContext.BaseDirectory, "INPUT.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task CountOccurrences_WhenCalledWithExampleInput_ItShouldReturnExpectedCount()
|
||||||
|
{
|
||||||
|
var result = new Grid(_exampleInput).CountOccurrences("XMAS");
|
||||||
|
|
||||||
|
await Assert.That(result).IsEqualTo(18);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task CountOccurrences_WhenCalledWithPuzzleInput_ItShouldReturnExpectedCount()
|
||||||
|
{
|
||||||
|
var input = await GetPuzzleInput();
|
||||||
|
var result = new Grid(input).CountOccurrences("XMAS");
|
||||||
|
|
||||||
|
await Assert.That(result).IsEqualTo(2644);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task CountXmases_WhenCalledWithExampleInput_ItShouldReturnExpectedCount()
|
||||||
|
{
|
||||||
|
var result = new Grid(_exampleInput).CountXmases();
|
||||||
|
|
||||||
|
await Assert.That(result).IsEqualTo(9);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task CountXmases_WhenCalledWithPuzzleInput_ItShouldReturnExpectedCount()
|
||||||
|
{
|
||||||
|
var input = await GetPuzzleInput();
|
||||||
|
var result = new Grid(input).CountXmases();
|
||||||
|
|
||||||
|
await Assert.That(result).IsEqualTo(1952);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
using System.Xml;
|
||||||
|
|
||||||
|
namespace CeresSearch;
|
||||||
|
|
||||||
|
record Direction(int XOffset, int YOffset)
|
||||||
|
{
|
||||||
|
public static readonly Direction Up = new(0, -1);
|
||||||
|
public static readonly Direction Down = new(0, 1);
|
||||||
|
public static readonly Direction Left = new(-1, 0);
|
||||||
|
public static readonly Direction Right = new(1, 0);
|
||||||
|
public static readonly Direction DownToTheRight = new(1, 1);
|
||||||
|
public static readonly Direction DownToTheLeft = new(-1, 1);
|
||||||
|
public static readonly Direction UpToTheRight = new(1, -1);
|
||||||
|
public static readonly Direction UpToTheLeft = new(-1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Grid(string[] input)
|
||||||
|
{
|
||||||
|
private readonly Direction[] _directions = [
|
||||||
|
Direction.UpToTheLeft,
|
||||||
|
Direction.UpToTheRight,
|
||||||
|
Direction.DownToTheLeft,
|
||||||
|
Direction.DownToTheRight,
|
||||||
|
Direction.Up,
|
||||||
|
Direction.Down,
|
||||||
|
Direction.Left,
|
||||||
|
Direction.Right,
|
||||||
|
];
|
||||||
|
|
||||||
|
public int CountXmases()
|
||||||
|
{
|
||||||
|
var total = 0;
|
||||||
|
|
||||||
|
WalkGrid((rowIndex, columnIndex) =>
|
||||||
|
{
|
||||||
|
if (FoundXmas(rowIndex, columnIndex))
|
||||||
|
{
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CountOccurrences(string word)
|
||||||
|
{
|
||||||
|
var total = 0;
|
||||||
|
|
||||||
|
WalkGrid((rowIndex, columnIndex) =>
|
||||||
|
total += _directions.Count(direction => FoundWord(word, direction, rowIndex, columnIndex))
|
||||||
|
);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WalkGrid(Action<int, int> callback)
|
||||||
|
{
|
||||||
|
for (var rowIndex = 0; rowIndex < input.Length; rowIndex++)
|
||||||
|
{
|
||||||
|
var row = input[rowIndex];
|
||||||
|
|
||||||
|
for (var columnIndex = 0; columnIndex < row.Length; columnIndex++)
|
||||||
|
{
|
||||||
|
callback(rowIndex, columnIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool FoundXmas(int rowIndex, int colIndex)
|
||||||
|
{
|
||||||
|
var currentCharacter = input[rowIndex][colIndex];
|
||||||
|
|
||||||
|
if (currentCharacter is not 'A')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xmasMap = new Dictionary<Direction, char>();
|
||||||
|
|
||||||
|
foreach (var direction in _directions)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
direction == Direction.Up ||
|
||||||
|
direction == Direction.Down ||
|
||||||
|
direction == Direction.Left ||
|
||||||
|
direction == Direction.Right
|
||||||
|
)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rowIndexToCheck = rowIndex + direction.XOffset;
|
||||||
|
var colIndexToCheck = colIndex + direction.YOffset;
|
||||||
|
|
||||||
|
if (IsOffGrid(rowIndexToCheck, colIndexToCheck))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var characterToCheck = input[rowIndexToCheck][colIndexToCheck];
|
||||||
|
|
||||||
|
if (characterToCheck != 'S' && characterToCheck != 'M')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmasMap.Add(direction, characterToCheck);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IsValidXmas(xmasMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsValidXmas(Dictionary<Direction, char> map)
|
||||||
|
{
|
||||||
|
var upToTheRight = map[Direction.UpToTheRight];
|
||||||
|
var downToTheLeft = map[Direction.DownToTheLeft];
|
||||||
|
var upToTheLeft = map[Direction.UpToTheLeft];
|
||||||
|
var downToTheRight = map[Direction.DownToTheRight];
|
||||||
|
|
||||||
|
return upToTheRight != downToTheLeft && upToTheLeft != downToTheRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool FoundWord(string word, Direction direction, int rowIndex, int columnIndex)
|
||||||
|
{
|
||||||
|
for (var currentTargetCharacterIndex = 0; currentTargetCharacterIndex < word.Length; currentTargetCharacterIndex++)
|
||||||
|
{
|
||||||
|
var currentTargetCharacter = word[currentTargetCharacterIndex];
|
||||||
|
var currentCharacterRowIndex = rowIndex + (direction.XOffset * currentTargetCharacterIndex);
|
||||||
|
var currentCharacterColumnIndex = columnIndex + (direction.YOffset * currentTargetCharacterIndex);
|
||||||
|
|
||||||
|
if (IsOffGrid(currentCharacterRowIndex, currentCharacterColumnIndex))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentCharacter = input[currentCharacterRowIndex][currentCharacterColumnIndex];
|
||||||
|
|
||||||
|
if (currentCharacter != currentTargetCharacter)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsOffGrid(int rowIndex, int columnIndex)
|
||||||
|
{
|
||||||
|
return rowIndex < 0 ||
|
||||||
|
rowIndex > input.Length - 1 ||
|
||||||
|
columnIndex < 0 ||
|
||||||
|
columnIndex > input[0].Length - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,2 +1,30 @@
|
|||||||
// See https://aka.ms/new-console-template for more information
|
using System.Diagnostics;
|
||||||
Console.WriteLine("Hello, World!");
|
|
||||||
|
using CeresSearch;
|
||||||
|
|
||||||
|
if (args.Length is 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Please provide a path to the input file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(args[0]) is false)
|
||||||
|
{
|
||||||
|
Console.WriteLine("The provided file does not exist.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var isPart2 = args.Length is 2 && args[1] is "part2";
|
||||||
|
var input = await File.ReadAllLinesAsync(args[0]);
|
||||||
|
|
||||||
|
var stopwatch = new Stopwatch();
|
||||||
|
stopwatch.Start();
|
||||||
|
|
||||||
|
var grid = new Grid(input);
|
||||||
|
|
||||||
|
var results = isPart2
|
||||||
|
? grid.CountXmases()
|
||||||
|
: grid.CountOccurrences("XMAS");
|
||||||
|
|
||||||
|
stopwatch.Stop();
|
||||||
|
Console.WriteLine($"The number of occurrences is {results}. ({stopwatch.ElapsedMilliseconds}ms)");
|
||||||
Reference in New Issue
Block a user