Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Advent of Code 2020 Day 11 Parts 1 and 2 solution by Mike LeSauvage
- public class SeatAnalysis : MonoBehaviour
- {
- public delegate int GetOccupiedSeatsDelegate(char[,] seatMap, int row, int col);
- [SerializeField] TextAsset seatMapTextfile = null; //Hooked up in the input text in the Unity editor.
- static char FLOOR_CHAR = '.';
- static char EMPTY_CHAR = 'L';
- static char OCCUPIED_CHAR = '#';
- static int PART_ONE_OCCUPIED_SEAT_THRESHOLD = 4;
- static int PART_TWO_OCCUPIED_SEAT_THRESHOLD = 5;
- static int PART_ONE_ID = 0;
- static int PART_TWO_ID = 1;
- void Start()
- {
- string[] seatMapStrings = seatMapTextfile.text.Split('\n');
- char[,] startingSeatMap = new char[seatMapStrings.Length, seatMapStrings[0].Length-1];
- //Solve part one.
- FillMapFromStrings(seatMapStrings, startingSeatMap);
- SolveDay10(startingSeatMap, PART_ONE_ID);
- //Reset map and solve part two.
- FillMapFromStrings(seatMapStrings, startingSeatMap);
- SolveDay10(startingSeatMap, PART_TWO_ID);
- }
- // Takes the provided initial map as a string and loads it into the two-dimensional character map.
- void FillMapFromStrings(string[] mapAsStrings, char[,] map)
- {
- int numRows = map.GetLength(0);
- int numCols = map.GetLength(1);
- for (int row = 0; row < numRows; row++)
- {
- for (int seat = 0; seat < numCols; seat++)
- {
- map[row, seat] = mapAsStrings[row][seat];
- }
- }
- }
- // Repeatedly calls PlayMusicalChairs() to change seating configuration until it stabilizes.
- // Uses different rules for part one or two based on partID.
- // When the seating map is no longer changing, outputs how many people are in seats.
- void SolveDay10(char[,] currentSeatMap, int partID)
- {
- char[,] nextSeatMap = new char[currentSeatMap.GetLength(0), currentSeatMap.GetLength(1)];
- char[,] tempSeatMap;
- while (true)
- {
- bool didSeatsChange = false;
- if(partID == PART_ONE_ID)
- {
- didSeatsChange = PlayMusicalChairs(currentSeatMap, nextSeatMap, GetNumOccupiedAdjacentSeatsPartOneRules, PART_ONE_OCCUPIED_SEAT_THRESHOLD);
- }
- else if(partID == PART_TWO_ID)
- {
- didSeatsChange = PlayMusicalChairs(currentSeatMap, nextSeatMap, GetNumOccupiedAdjacentSeatsPartTwoRules, PART_TWO_OCCUPIED_SEAT_THRESHOLD);
- }
- tempSeatMap = currentSeatMap;
- currentSeatMap = nextSeatMap;
- nextSeatMap = tempSeatMap;
- if (!didSeatsChange)
- break;
- }
- Debug.Log($"Final occupied count: {GetOccupiedSeatCount(currentSeatMap)}");
- }
- // Counts occupied seats in a seat map.
- int GetOccupiedSeatCount(char[,] seatMap)
- {
- int numRows = seatMap.GetLength(0);
- int numCols = seatMap.GetLength(1);
- int occupiedCount = 0;
- for (int row = 0; row < numRows; row++)
- {
- for (int col = 0; col < numCols; col++)
- {
- if (seatMap[row, col] == OCCUPIED_CHAR)
- {
- occupiedCount++;
- }
- }
- }
- return occupiedCount;
- }
- // Takes a starting seat map and generates the new map.
- // Irrespective of part one or two:
- // - people sit in seats when there are no adjacent seats occupied.
- // - people leave seats when there are too many adjacent seats occupied.
- //
- // The rules for part one and two are different, so:
- // - the delegate GetNumOccupiedAdjacentSeats is used to determine how many seats are adjacent.
- // - occupiedSeatThreshold specifies how many adjacent seats are acceptable.
- //
- // Returns true if map changed, false otherwise.
- bool PlayMusicalChairs(char[,] startingSeats, char[,] endingSeats, GetOccupiedSeatsDelegate GetNumOccupiedAdjacentSeats, int occupiedSeatThreshold)
- {
- int numRows = startingSeats.GetLength(0);
- int numCols = startingSeats.GetLength(1);
- bool changed = false;
- for (int row = 0; row < numRows; row++)
- {
- for (int col = 0; col < numCols; col++)
- {
- char startSeat = startingSeats[row, col];
- //Floor. Floor never changes.
- if (startSeat == FLOOR_CHAR)
- {
- endingSeats[row, col] = FLOOR_CHAR;
- continue;
- }
- int numAdjacentOccupied = GetNumOccupiedAdjacentSeats(startingSeats, row, col);
- //Handle seats
- if(startSeat == EMPTY_CHAR && numAdjacentOccupied == 0)
- {
- endingSeats[row, col] = OCCUPIED_CHAR;
- changed = true;
- }
- else if(startSeat == OCCUPIED_CHAR && numAdjacentOccupied >= occupiedSeatThreshold)
- {
- endingSeats[row, col] = EMPTY_CHAR;
- changed = true;
- }
- else
- {
- endingSeats[row, col] = startingSeats[row, col];
- }
- }
- }
- return changed;
- }
- // Implements counting rules for Day 11 Part 2.
- // Counts how many occupied seats can be seen from the target [row, col] seat.
- // Looks out at each of the 8 main compass directions (N S W E NW NE SW SE)
- // - Stops looking when a seat is encountered, occupied or not, or edge of map reached.
- // - Increments count if occupied.
- //
- // Returns the number of people found in adjacent seats.
- int GetNumOccupiedAdjacentSeatsPartTwoRules(char[,] seatMap, int row, int col)
- {
- int numOccupied = 0;
- //Look directions are the 8 compass directions.
- //NOTE: this is NOT (x,y) - (y,x) as we've been working in (row, col)
- (int, int)[] lookDirections = new (int, int)[] { (-1, -1), (-1, 0), (-1, 1),
- ( 0, -1), ( 0, 1),
- ( 1, -1), ( 1, 0), ( 1, 1)
- };
- //Handle looking in each of the 8 directions from the target seat.
- foreach( (int rowDelta, int colDelta)dir in lookDirections)
- {
- int curRow = row;
- int curCol = col;
- while (true)
- {
- //Move current row/col
- //Check if valid spot in map.
- //Check for seat
- //If occupied, add to count.
- //If occupied or empty, break loop
- curRow += dir.rowDelta;
- curCol += dir.colDelta;
- if(!IsSeatInMap(curRow, curCol, seatMap.GetLength(0), seatMap.GetLength(1)))
- {
- break;
- }
- if(seatMap[curRow, curCol] == OCCUPIED_CHAR)
- {
- numOccupied++;
- break;
- }
- if(seatMap[curRow, curCol] == EMPTY_CHAR)
- {
- break;
- }
- }
- }
- return numOccupied;
- }
- // Implements counting rules for Day 11 Part 1
- // Counts how many seats are immediately adjacent to the seat at [row, col] in the given seat map.
- // Adjacent seats are the 8 main compass directions (N S W E NW NE SW SE)
- //
- // Returns the number of people found in adjacent seats.
- int GetNumOccupiedAdjacentSeatsPartOneRules(char[,] seatMap, int row, int col)
- {
- int numOccupied = 0;
- //Loop across the three rows and within them the three columns surrounding the target seat.
- for(int testRow = row-1; testRow < row+2; testRow++)
- {
- for(int testCol = col-1; testCol < col+2; testCol++)
- {
- //Don't test the seat at the center of the test!
- if(testRow == row && testCol == col)
- {
- continue;
- }
- //Count seat if it's occupied.
- if(IsSeatInMap(testRow, testCol, seatMap.GetLength(0), seatMap.GetLength(1)))
- {
- if(seatMap[testRow, testCol] == '#')
- {
- numOccupied++;
- }
- }
- }
- }
- return numOccupied;
- }
- //Checks if the seat is in the range bounded by the map.
- bool IsSeatInMap(int row, int col, int numRows, int numCols)
- {
- if(row >= 0 && row < numRows && col >= 0 && col < numCols)
- {
- return true;
- }
- return false;
- }
- //Print out the current seat map. Included here for debugging.
- void PrintSeatMap(char[,] seatMap)
- {
- char[] rowChars = new char[seatMap.GetLength(1)];
- for(int row=0; row < seatMap.GetLength(0); row++)
- {
- for (int seat = 0; seat < seatMap.GetLength(1); seat++)
- {
- rowChars[seat] = seatMap[row, seat];
- }
- string rowString = new string(rowChars);
- Debug.Log(rowString);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement