mirror of
https://github.com/parnic/advent-of-code-2024.git
synced 2025-06-16 12:30:13 -05:00
Day 4
This solution feels pretty bad. I think I shouldn't have used my ivec2 utilities and just checked the next spots for part 2. It would probably have been simpler given all the constraints. I'm also certain there's a smarter way to solve this than what I did, but...it works, so...?
This commit is contained in:
150
src/04.cs
Normal file
150
src/04.cs
Normal file
@ -0,0 +1,150 @@
|
||||
using aoc2024.Util;
|
||||
|
||||
namespace aoc2024;
|
||||
|
||||
internal class Day04 : Day
|
||||
{
|
||||
private char[][] puzzle = [];
|
||||
internal override void Parse()
|
||||
{
|
||||
var lines = Util.Parsing.ReadAllLines($"{GetDay()}").ToList();
|
||||
int numRows = lines.Count;
|
||||
puzzle = new char[numRows][];
|
||||
for (int i = 0; i < numRows; i++)
|
||||
{
|
||||
var row = lines[i].ToCharArray();
|
||||
puzzle[i] = row;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsValid(char[][] puzzle, long row, long col)
|
||||
{
|
||||
return row >= 0 && col >= 0 && row < puzzle.Length && col < puzzle[row].Length;
|
||||
}
|
||||
|
||||
private static int HasXmas(char[][] puzzle, long row, long col)
|
||||
{
|
||||
int numHas = 0;
|
||||
const string lookingFor = "XMAS";
|
||||
var dirs = ivec2.EIGHTWAY;
|
||||
foreach (var dir in dirs)
|
||||
{
|
||||
int onChar = 1;
|
||||
var nextPos = new ivec2(row, col) + dir;
|
||||
while (IsValid(puzzle, nextPos.x, nextPos.y) && puzzle[nextPos.x][nextPos.y] == lookingFor[onChar])
|
||||
{
|
||||
onChar++;
|
||||
nextPos += dir;
|
||||
|
||||
if (onChar == lookingFor.Length)
|
||||
{
|
||||
numHas++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return numHas;
|
||||
}
|
||||
|
||||
internal override string Part1()
|
||||
{
|
||||
int numFound = 0;
|
||||
for (int row = 0; row < puzzle.Length; row++)
|
||||
{
|
||||
for (int col = 0; col < puzzle[row].Length; col++)
|
||||
{
|
||||
if (puzzle[row][col] == 'X')
|
||||
{
|
||||
numFound += HasXmas(puzzle, row, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $"Num XMAS: <+white>{numFound}";
|
||||
}
|
||||
|
||||
private static bool HasMasInX(char[][] puzzle, long row, long col)
|
||||
{
|
||||
const int maxDist = 2;
|
||||
if (!IsValid(puzzle, row + maxDist, col) || !IsValid(puzzle, row, col + maxDist) || !IsValid(puzzle, row + maxDist, col + maxDist))
|
||||
{
|
||||
// not enough spots to search
|
||||
return false;
|
||||
}
|
||||
|
||||
List<ivec2> ms = [];
|
||||
for (int y = 0; y <= maxDist; y++)
|
||||
{
|
||||
if (y == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int x = 0; x <= maxDist; x++)
|
||||
{
|
||||
if (x == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (puzzle[row + y][col + x] == 'M')
|
||||
{
|
||||
ms.Add(new ivec2(col + x, row + y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ms.Count != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var m in ms)
|
||||
{
|
||||
var requiredDir = ivec2.ZERO;
|
||||
if (m.y == row && m.x == col)
|
||||
{
|
||||
requiredDir = ivec2.DOWN + ivec2.RIGHT;
|
||||
}
|
||||
else if (m.y == row && m.x == col + maxDist)
|
||||
{
|
||||
requiredDir = ivec2.DOWN + ivec2.LEFT;
|
||||
}
|
||||
else if (m.y == row + maxDist && m.x == col)
|
||||
{
|
||||
requiredDir = ivec2.UP + ivec2.RIGHT;
|
||||
}
|
||||
else if (m.y == row + maxDist && m.x == col + maxDist)
|
||||
{
|
||||
requiredDir = ivec2.UP + ivec2.LEFT;
|
||||
}
|
||||
|
||||
var next1 = m + requiredDir;
|
||||
var next2 = m + requiredDir + requiredDir;
|
||||
if (puzzle[next1.y][next1.x] != 'A' || puzzle[next2.y][next2.x] != 'S')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal override string Part2()
|
||||
{
|
||||
int numFound = 0;
|
||||
for (int row = 0; row < puzzle.Length; row++)
|
||||
{
|
||||
for (int col = 0; col < puzzle[row].Length; col++)
|
||||
{
|
||||
if (HasMasInX(puzzle, row, col))
|
||||
{
|
||||
numFound++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $"Num X-MAS: <+white>{numFound}";
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ public readonly struct ivec2 : IEquatable<ivec2>, IComparable<ivec2>, IComparabl
|
||||
public static readonly ivec2 DOWN = new ivec2(0, 1);
|
||||
public static readonly ivec2[] FOURWAY = {RIGHT, LEFT, UP, DOWN};
|
||||
public static readonly ivec2[] EIGHTWAY = {UP, UP + RIGHT, RIGHT, RIGHT + DOWN, DOWN, DOWN + LEFT, LEFT, LEFT + UP};
|
||||
public static readonly ivec2[] DIAGONALS = {UP + RIGHT, DOWN + RIGHT, UP + LEFT, DOWN + LEFT};
|
||||
|
||||
public ivec2(long xv, long yv)
|
||||
{
|
||||
@ -100,6 +101,28 @@ public readonly struct ivec2 : IEquatable<ivec2>, IComparable<ivec2>, IComparabl
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<ivec2> GetDiagonalNeighbors(ivec2 p)
|
||||
{
|
||||
foreach (var dir in DIAGONALS)
|
||||
{
|
||||
yield return this + dir;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<ivec2> GetBoundedDiagonalNeighbors(int minX, int minY, int maxX, int maxY)
|
||||
{
|
||||
foreach (var dir in DIAGONALS)
|
||||
{
|
||||
var pt = this + dir;
|
||||
if (!pt.IsWithinRange(minX, minY, maxX, maxY))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return pt;
|
||||
}
|
||||
}
|
||||
|
||||
public long this[long i] => (i == 0) ? x : y;
|
||||
|
||||
public static ivec2 operator +(ivec2 v) => v;
|
||||
|
Reference in New Issue
Block a user