123 lines
3 KiB
C#
123 lines
3 KiB
C#
|
var boards = new List<Board>();
|
||
|
using var sr = new StreamReader("../inputs/day04.txt");
|
||
|
var lines = sr.ReadToEnd().Split("\n").Select(x => x.Trim()).ToList();
|
||
|
var numbers = lines.First().Split(",").Select(x => Convert.ToByte(x)).ToList();
|
||
|
lines.RemoveAt(0); //Drop numbers
|
||
|
lines.RemoveAt(0); //Drop whitespace
|
||
|
|
||
|
var currentBoard = new List<string>();
|
||
|
foreach (var line in lines)
|
||
|
{
|
||
|
if (!string.IsNullOrEmpty(line))
|
||
|
{
|
||
|
currentBoard.Add(line);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
boards.Add(new Board(currentBoard));
|
||
|
currentBoard = new List<string>();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var part1Done = false;
|
||
|
foreach (var number in numbers)
|
||
|
{
|
||
|
foreach (var board in boards)
|
||
|
board.Mark(number);
|
||
|
|
||
|
var winningBoards =
|
||
|
boards.Where(board => board.Win).ToArray(); // Need to enumerate this before the loop or it will break
|
||
|
foreach (var board in winningBoards)
|
||
|
{
|
||
|
if (!part1Done)
|
||
|
{
|
||
|
Console.WriteLine($"2021 Day 04 Part 1 result: {board.Score * number}");
|
||
|
part1Done = true;
|
||
|
}
|
||
|
|
||
|
if (boards.Count == 1)
|
||
|
Console.WriteLine($"2021 Day 04 Part 2 result: {board.Score * number}");
|
||
|
|
||
|
boards.Remove(board);
|
||
|
}
|
||
|
|
||
|
if (!boards.Any())
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
private class Board
|
||
|
{
|
||
|
private readonly byte?[,] _rows;
|
||
|
internal int Score => _rows.Cast<byte?>().Aggregate(0, (score, number) => score + (number ?? 0));
|
||
|
private bool HorizontalWin => DidRowWin(_rows);
|
||
|
private bool VerticalWin => DidRowWin(Transpose());
|
||
|
internal bool Win => HorizontalWin || VerticalWin;
|
||
|
|
||
|
internal Board(IEnumerable<string> inputRows)
|
||
|
{
|
||
|
_rows = new byte?[5, 5];
|
||
|
|
||
|
for (var r = 0; r < inputRows.Count(); r++)
|
||
|
{
|
||
|
var nums = inputRows
|
||
|
.ElementAt(r)
|
||
|
.Split(" ")
|
||
|
.Where(x => !string.IsNullOrEmpty(x))
|
||
|
.Select(x => Convert.ToByte(x));
|
||
|
|
||
|
for (var c = 0; c < nums.Count(); c++)
|
||
|
{
|
||
|
_rows[c, r] = nums.ElementAt(c);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void Mark(byte number)
|
||
|
{
|
||
|
for (var r = 0; r < _rows.GetLength(0); r++)
|
||
|
{
|
||
|
for (var c = 0; c < _rows.GetLength(1); c++)
|
||
|
{
|
||
|
if (_rows[c, r].HasValue && _rows[c, r].Value == number)
|
||
|
_rows[c, r] = null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private byte?[,] Transpose()
|
||
|
{
|
||
|
var cols = new byte?[5, 5];
|
||
|
|
||
|
for (var c = 0; c < 5; c++)
|
||
|
{
|
||
|
for (var r = 0; r < 5; r++)
|
||
|
{
|
||
|
cols[c, r] = _rows[r, c];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return cols;
|
||
|
}
|
||
|
|
||
|
private static bool DidRowWin(byte?[,] rows)
|
||
|
{
|
||
|
var win = true;
|
||
|
|
||
|
for (var r = 0; r < rows.GetLength(0); r++)
|
||
|
{
|
||
|
win = true;
|
||
|
|
||
|
for (var c = 0; c < rows.GetLength(1); c++)
|
||
|
{
|
||
|
if (rows[c, r].HasValue)
|
||
|
win = false;
|
||
|
}
|
||
|
|
||
|
if (win)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return win;
|
||
|
}
|
||
|
}
|