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:
2024-12-04 08:45:08 -06:00
parent dbee23c6a3
commit 66f0f805a8
2 changed files with 173 additions and 0 deletions

150
src/04.cs Normal file
View 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}";
}
}

View File

@ -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 DOWN = new ivec2(0, 1);
public static readonly ivec2[] FOURWAY = {RIGHT, LEFT, UP, DOWN}; 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[] 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) 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 long this[long i] => (i == 0) ? x : y;
public static ivec2 operator +(ivec2 v) => v; public static ivec2 operator +(ivec2 v) => v;