using System; using System.IO; using System.Threading; using System.Threading.Tasks; namespace _2020 { class Q11 { static SeatState[,] list = null; static int numRows = 0; static int numCols = 0; enum SeatState { Floor, Empty, Occupied, } public static void Go() { var start = DateTime.Now; MakeList(); Util.Log($"Q11 MakeList took {(DateTime.Now - start).TotalMilliseconds}ms"); var p1start = DateTime.Now; Part1(); Util.Log($"Q11 part1 took {(DateTime.Now - p1start).TotalMilliseconds}ms"); var p2start = DateTime.Now; Part2(); Util.Log($"Q11 part2 took {(DateTime.Now - p2start).TotalMilliseconds}ms"); Util.Log($"Q11 took {(DateTime.Now - start).TotalMilliseconds}ms"); } static void MakeList() { var lines = File.ReadAllLines("11input.txt"); numRows = lines.Length; numCols = lines[0].Length; list = new SeatState[numRows, numCols]; for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { list[i, j] = lines[i][j] == '.' ? SeatState.Floor : SeatState.Empty; } } } static int GetNumOccupiedAdjacent(SeatState[,] seatList, int row, int col) { int numOccupied = 0; if (row - 1 >= 0) { if (col - 1 >= 0 && seatList[row - 1, col - 1] == SeatState.Occupied) { numOccupied++; } if (seatList[row - 1, col] == SeatState.Occupied) { numOccupied++; } if (col + 1 < numCols && seatList[row - 1, col + 1] == SeatState.Occupied) { numOccupied++; } } if (col - 1 >= 0 && seatList[row, col - 1] == SeatState.Occupied) { numOccupied++; } if (col + 1 < numCols && seatList[row, col + 1] == SeatState.Occupied) { numOccupied++; } if (row + 1 < numRows) { if (col - 1 >= 0 && seatList[row + 1, col - 1] == SeatState.Occupied) { numOccupied++; } if (seatList[row + 1, col] == SeatState.Occupied) { numOccupied++; } if (col + 1 < numCols && seatList[row + 1, col + 1] == SeatState.Occupied) { numOccupied++; } } return numOccupied; } static int GetNumOccupiedLOS(SeatState[,] seatList, int row, int col) { int numOccupied = 0; bool checkSeat(int checkRow, int checkCol) { if (seatList[checkRow, checkCol] == SeatState.Occupied) { numOccupied++; return true; } if (seatList[checkRow, checkCol] == SeatState.Empty) { return true; } return false; } // ul for (int checkRow = row - 1, checkCol = col - 1; checkRow >= 0 && checkCol >= 0; checkRow--, checkCol--) { if (checkSeat(checkRow, checkCol)) { break; } } // u for (int checkRow = row - 1, checkCol = col; checkRow >= 0; checkRow--) { if (checkSeat(checkRow, checkCol)) { break; } } // ur for (int checkRow = row - 1, checkCol = col + 1; checkRow >= 0 && checkCol < numCols; checkRow--, checkCol++) { if (checkSeat(checkRow, checkCol)) { break; } } // l for (int checkRow = row, checkCol = col - 1; checkCol >= 0; checkCol--) { if (checkSeat(checkRow, checkCol)) { break; } } // r for (int checkRow = row, checkCol = col + 1; checkCol < numCols; checkCol++) { if (checkSeat(checkRow, checkCol)) { break; } } // dl for (int checkRow = row + 1, checkCol = col - 1; checkRow < numRows && checkCol >= 0; checkRow++, checkCol--) { if (checkSeat(checkRow, checkCol)) { break; } } // d for (int checkRow = row + 1, checkCol = col; checkRow < numRows; checkRow++) { if (checkSeat(checkRow, checkCol)) { break; } } // dr for (int checkRow = row + 1, checkCol = col + 1; checkRow < numRows && checkCol < numCols; checkRow++, checkCol++) { if (checkSeat(checkRow, checkCol)) { break; } } return numOccupied; } static int GetNumOccupied(SeatState[,] currState) { int totalNumOccupied = 0; for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { if (currState[i, j] == SeatState.Occupied) { totalNumOccupied++; } } } return totalNumOccupied; } static void Part1() { SeatState[,] currState = new SeatState[numRows, numCols]; SeatState[,] nextState = new SeatState[numRows, numCols]; Array.Copy(list, currState, numRows * numCols); int rounds = 0; for (int numChanges = 0; rounds == 0 || numChanges != 0; rounds++) { Array.Copy(currState, nextState, numRows * numCols); numChanges = 0; Parallel.For(0, numRows, (i) => { for (int j = 0; j < numCols; j++) { var numOccupied = GetNumOccupiedAdjacent(currState, i, j); if (currState[i, j] == SeatState.Empty && numOccupied == 0) { nextState[i, j] = SeatState.Occupied; Interlocked.Increment(ref numChanges); } else if (currState[i, j] == SeatState.Occupied && numOccupied >= 4) { nextState[i, j] = SeatState.Empty; Interlocked.Increment(ref numChanges); } } }); Array.Copy(nextState, currState, numRows * numCols); } Util.Log($"Q11Part1: stabilized after {rounds - 1} rounds, total occupied={GetNumOccupied(currState)}"); } static void Part2() { SeatState[,] currState = new SeatState[numRows, numCols]; SeatState[,] nextState = new SeatState[numRows, numCols]; Array.Copy(list, currState, numRows * numCols); int rounds = 0; for (int numChanges = 0; rounds == 0 || numChanges != 0; rounds++) { Array.Copy(currState, nextState, numRows * numCols); numChanges = 0; Parallel.For(0, numRows, (i) => { for (int j = 0; j < numCols; j++) { var numOccupied = GetNumOccupiedLOS(currState, i, j); if (currState[i, j] == SeatState.Empty && numOccupied == 0) { nextState[i, j] = SeatState.Occupied; Interlocked.Increment(ref numChanges); } else if (currState[i, j] == SeatState.Occupied && numOccupied >= 5) { nextState[i, j] = SeatState.Empty; Interlocked.Increment(ref numChanges); } } }); Array.Copy(nextState, currState, numRows * numCols); } Util.Log($"Q11Part2: stabilized after {rounds - 1} rounds, total occupied={GetNumOccupied(currState)}"); } } }