Alexander Sigler ee9ecad64a
All checks were successful
continuous-integration/drone/push Build is passing
Started 2023 Year and completed days 1-4
2023-12-05 17:11:12 -08:00

197 lines
6.6 KiB
C#

using AdventOfCode.Common;
using AdventOfCode.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AdventOfCode._2023
{
public class Day3 : AOCDay
{
protected override AOCResponse ExecutePartA()
{
var board = new SchematicBoard(this.GetSplitInput().ToList());
var validSchematicNumbers = board.GetValidSchematicNumbers();
this.Answer = validSchematicNumbers.Sum(x => x.Number);
return this._response;
}
protected override AOCResponse ExecutePartB()
{
var board = new SchematicBoard(this.GetSplitInput().ToList());
var gearLookup = board.GetGearLookup();
if (!this._request.IgnoreLogMessages)
{
foreach (var gl in gearLookup)
{
Log($"Gear at {gl.Key} has numbers: {string.Join(",", gl.Value)}");
}
}
//Select valid gears, those with two numbers at a location
var validGears = gearLookup.Where(x => x.Value.Count == 2);
//Calculate the gear ration (num1 * num2)
var gearRatios = validGears.Select(x => x.Value.First() * x.Value.Last());
//Sum up all the gear ratio for an answer
this.Answer = gearRatios.Sum(x => x);
return this._response;
}
}
class SchematicBoard
{
private List<SchematicNumber> _schematicNumbers;
private char[,] _board;
public SchematicBoard(List<string> input)
{
_schematicNumbers = new List<SchematicNumber>();
var rows = input.Count;
var columns = input.First().Length;
_board = new char[rows, columns];
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < columns; x++)
{
_board[x,y] = input[x][y];
}
}
_board.PrintSquareArray();
//Pull out our schematic numbers from our board
for (int x = 0; x < _board.GetLength(0); x++)
{
for (int y = 0; y < _board.GetLength(1); y++)
{
if (char.IsDigit(_board[x, y]))
{
var number = "";
var yPoses = new List<int>();
for (int l = y; l < _board.GetLength(1); l++)
{
if (char.IsDigit(_board[x, l]))
{
yPoses.Add(l);
number += _board[x, l].ToString();
}
else
{
y = l;
break;
}
}
_schematicNumbers.Add(new SchematicNumber()
{
Number = int.Parse(number),
Coords = yPoses.Select(yPos => Tuple.Create(x, yPos)).ToList()
});
}
}
}
}
public IEnumerable<SchematicNumber> GetValidSchematicNumbers()
{
return _schematicNumbers.Where(x => x.IsValidNumber(_board));
}
public Dictionary<string, HashSet<int>> GetGearLookup()
{
var lookup = new Dictionary<string, HashSet<int>>();
foreach (var schematicNumber in _schematicNumbers)
{
var gears = schematicNumber.GetGearCoordinates(_board);
foreach (var gear in gears)
{
if (lookup.ContainsKey(gear))
{
lookup[gear].Add(schematicNumber.Number);
}
else
{
lookup[gear] = new HashSet<int>() { schematicNumber.Number };
}
}
}
return lookup;
}
}
class SchematicNumber
{
public int Number { get; set; }
public List<Tuple<int, int>> Coords { get; set; }
public bool IsValidNumber(char[,] board)
{
foreach (var coord in Coords)
{
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
var checkedPosX = coord.Item1 + x;
var checkedPosY = coord.Item2 + y;
//Check if the points are within the valid size of our board
if (checkedPosX < 0 || checkedPosY < 0) continue;
if (checkedPosX >= board.GetLength(0) || checkedPosY >= board.GetLength(1)) continue;
//Get our char at the given index
var charAtPoint = board[checkedPosX, checkedPosY];
//Check if the char is NOT a digit, and NOT a period, then return true its adjacent
if (!char.IsDigit(charAtPoint) && charAtPoint != '.')
{
return true;
}
}
}
}
return false;
}
public List<string> GetGearCoordinates(char[,] board)
{
var gearCoords = new List<string>();
foreach (var coord in Coords)
{
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
var checkedPosX = coord.Item1 + x;
var checkedPosY = coord.Item2 + y;
//Check if the points are within the valid size of our board
if (checkedPosX < 0 || checkedPosY < 0) continue;
if (checkedPosX >= board.GetLength(0) || checkedPosY >= board.GetLength(1)) continue;
//Get our char at the given index
var charAtPoint = board[checkedPosX, checkedPosY];
//Check if it is a gear point
if (charAtPoint == '*')
{
gearCoords.Add($"{checkedPosX},{checkedPosY}");
}
}
}
}
return gearCoords;
}
}
}