var boards = new List(); 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(); foreach (var line in lines) { if (!string.IsNullOrEmpty(line)) { currentBoard.Add(line); } else { boards.Add(new Board(currentBoard)); currentBoard = new List(); } } 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().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 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; } }