/// <summary> /// This method updates the status of each cell in the Game of Life board /// </summary> /// <param name="matrix">Matrix containing the cells of the Game of Life board</param> /// <returns>The updated board matrix (The next day)</returns> public static Cell[,] MakeMove(Cell[,] matrix) { // Copy all elements in matrix to _bufferMatrix CopyCells(matrix); // Update each cell in _bufferMatrix for (int i = 0; i < matrix.GetLength(0); i++) { for (int j = 0; j < matrix.GetLength(1); j++) { int? cellStatus = matrix[i, j].Status; UpdateCell(matrix, i, j, cellStatus); } } return _bufferMatrix; }
/// <summary> /// Use to copy all elements in matrix to _bufferMatrix /// </summary> /// <param name="matrix">Matrix containing all cells of the Game of Life board</param> /// <remarks>If elements in the parameter are not value types, the following modification is needed: replace contents in first nested loop with outcommented code</remarks> private static void CopyCells(Cell[,] matrix) { int dimensionI = matrix.GetLength(0); int dimensionJ = matrix.GetLength(1); _bufferMatrix = new Cell[dimensionI, dimensionJ]; for (int i = 0; i < dimensionI; i++) { for (int j = 0; j < dimensionJ; j++) { _bufferMatrix[i, j] = matrix[i, j]; //// The following commented lines should replace the line above if Cell becomes a reference type instead of a value type. //_bufferMatrix[i, j] = new Cell(); //_bufferMatrix[i,j].Status = matrix[i,j].Status; } } }
/// <summary> /// The constructor which will create a new game board /// </summary> /// <param name="size">The width of the board (the board is a square)</param> public Game(uint size) { //Preconditions if (size < 1) throw new ArgumentException("Size must be above 0"); if (size > MAX_BOARD_SIZE) throw new ArgumentException("Size must not rise above " + MAX_BOARD_SIZE); _boardSize = size; Board = new Cell[_boardSize, _boardSize]; //Will set the cells at the board to a random state (10% chance for zombie, 60% for living cells and 30% for dead cells Random rng = new Random(); for (int a = 0; a < _boardSize; a++) { for (int b = 0; b < _boardSize; b++) { Board[a, b] = new Cell(); int smth = rng.Next(100); if (smth < 10) { Board[a, b].Status = null; } else if (smth < 60) { Board[a, b].Status = 1; } else { Board[a, b].Status = 0; } } } }
public void CellStatusChangeTest() { //Test the creation of a cell Cell testCell1 = new Cell(); Assert.AreEqual(testCell1.Status, null); //Test setting a cell's status to null again Cell testCell2 = new Cell(); testCell2.Status = null; Assert.AreEqual(testCell2.Status, null); //Test setting a cell's status to 0 Cell testCell3 = new Cell(); testCell3.Status = 0; Assert.AreEqual(testCell3.Status, 0); //Test setting a cell's status to 1 Cell testCell4 = new Cell(); testCell4.Status = 1; Assert.AreEqual(testCell4.Status, 1); //Test setting a cell's status to 2 Cell testCell5 = new Cell(); testCell5.Status = 2; Assert.AreEqual(testCell5.Status, null); //Test setting a cell's status to -1 Cell testCell6 = new Cell(); testCell6.Status = -1; Assert.AreEqual(testCell6.Status, null); //Test resetting a cell's status to something new Cell testCell7 = new Cell(); testCell7.Status = 1; testCell7.Status = 0; Assert.AreEqual(testCell7.Status, 0); }
/// <summary> /// Updates a single cell from the Game of Life matrix /// </summary> /// <param name="matrix">The matrix representing the Game of Life board</param> /// <param name="row">Used to identify cell row</param> /// <param name="col">Used to identify cell column</param> /// <param name="cellStatus">The status of the matrix[i,j]'th cell. It is a parameter instead of having to figure it out inside the method to avoid excessive/unnecessary extra code</param> /// <remarks>Updates to the cell is stored in a private field. && While checking the neighbours of every cell, there will inevitably be thrown multiple IndexOutOfRangeException, these are all caught but are not handled (as it is part of the method design).</remarks> private static void UpdateCell(Cell[,] matrix, int row, int col, int? cellStatus) { if (cellStatus == null) { // If the cell is a zombie there's no hope for it. return; } int neighbours = 0; bool zombieNear = false; for (int i = row - 1; i <= row + 1; i++) { for (int j = col - 1; j <= col + 1; j++) { if (i == row && j == col) { // The cell is not a neighbour of itself... continue; } try { if (matrix[i, j].Status == 1) { neighbours++; } else if (zombieNear == false && cellStatus == 1 && matrix[i, j].Status == null) { // If there's an adjacent zombie and the cell is alive zombieNear = true; } } catch (IndexOutOfRangeException) { // This will happen for every cell on the edge of the board } } } // Time to figure out what happens with the cell! if (cellStatus == 1) { if (neighbours <= 1 || neighbours >= 4) { _bufferMatrix[row, col].Status = 0; } else if (zombieNear == true && InfectedByZombie(row, col)) { // Yet another casualty of the zombie apocalypse return; } } else if (cellStatus == 0 && neighbours == 3) { // One neighbour calls 911, one does cpr, and one keeps the zombies away _bufferMatrix[row, col].Status = 1; } }
public void ModifyCellTest() { // Will check state mofications for every single cell uint sizeOfBoard = 10; int? zombieCell = null; int? deadCell = 0; int? livingCell = 1; Game gameTest = new Game(sizeOfBoard); //Create new cells to insert into the board Cell[] cells = new Cell[sizeOfBoard * sizeOfBoard]; for (uint row = 0; row < sizeOfBoard; row++) { for (uint column = 0; column < sizeOfBoard; column++) { uint index = row * sizeOfBoard + column; cells[index].Column = column; cells[index].Row = row; cells[index].Status = livingCell; } } //Insert the cells try { gameTest.ModifyCell(cells); } catch (InvalidOperationException ie) { Assert.Fail(); } //Check the board to only contain living cells for (uint a = 0; a < sizeOfBoard; a++) { for (uint b = 0; b < sizeOfBoard; b++) { Assert.AreEqual(gameTest[a,b], livingCell); } } //Modify to a board of pure dead cells for (uint row = 0; row < sizeOfBoard; row++) { for (uint column = 0; column < sizeOfBoard; column++) { uint index = row * sizeOfBoard + column; cells[index].Column = column; cells[index].Row = row; cells[index].Status = 0; } } //Insert the new cells try { gameTest.ModifyCell(cells); } catch (InvalidOperationException ie) { Assert.Fail(); } ///Check the board to be of dead cells for (uint a = 0; a < sizeOfBoard; a++) { for (uint b = 0; b < sizeOfBoard; b++) { Assert.AreEqual(gameTest[a, b], deadCell); } } //Modify to a board of pure zombie cells - Arrrrrg.... for (uint row = 0; row < sizeOfBoard; row++) { for (uint column = 0; column < sizeOfBoard; column++) { uint index = row * sizeOfBoard + column; cells[index].Column = column; cells[index].Row = row; cells[index].Status = zombieCell; } } //Insert the new cells try { gameTest.ModifyCell(cells); } catch (InvalidOperationException ie) { Assert.Fail(); } //Check the board to be of zombie cells only for (uint a = 0; a < sizeOfBoard; a++) { for (uint b = 0; b < sizeOfBoard; b++) { Assert.AreEqual(gameTest[a, b], zombieCell); } } //Modify back to be a board of pure living cells (The happy ending!) for (uint row = 0; row < sizeOfBoard; row++) { for (uint column = 0; column < sizeOfBoard; column++) { uint index = row * sizeOfBoard + column; cells[index].Column = column; cells[index].Row = row; cells[index].Status = livingCell; } } //Insert the cells try { gameTest.ModifyCell(cells); } catch (InvalidOperationException ie) { Assert.Fail(); } //Check the board for living cells only for (uint a = 0; a < sizeOfBoard; a++) { for (uint b = 0; b < sizeOfBoard; b++) { Assert.AreEqual(gameTest[a, b], livingCell); } } }
public void NextDayTest2() { uint gameSize = 10; Game gameTest = new Game(gameSize); Cell[] cells = new Cell[gameSize * gameSize]; //Set all the cells to be alive and happy for (uint column = 0; column < gameSize; column++) { for (uint row = 0; row < gameSize; row++) { uint index = column * gameSize + row; cells[index].Column = column; cells[index].Row = row; cells[index].Status = 1; } } gameTest.ModifyCell(cells); gameTest.NextDay(); //Now all cells (except those in the 4 corners) will be dead. The last 4 will still be alive for (uint column = 0; column < gameSize; column++) { for (uint row = 0; row < gameSize; row++) { if ((column == 0 && row == 0) || (column == gameSize - 1 && row == 0) || (column == 0 && row == gameSize - 1) || (column == gameSize - 1 && row == gameSize - 1)) { Assert.AreEqual(gameTest[column, row], 1); } else { Assert.AreEqual(gameTest[column, row], 0); } } } }
public void NextDayTest1() { uint gameSize = 10; Game gameTest = new Game(gameSize); Cell[] cells = new Cell[gameSize * gameSize]; //Make all cells zombies for (uint column = 0; column < gameSize; column++) { for (uint row = 0; row < gameSize; row++) { uint index = column * gameSize + row; cells[index].Column = column; cells[index].Row = row; cells[index].Status = null; } } gameTest.ModifyCell(cells); gameTest.NextDay(); //All cells are zombies, so the next day will be with just as many zombies... for (uint column = 0; column < gameSize; column++) { for (uint row = 0; row < gameSize; row++) { Assert.AreEqual(gameTest[column,row], null); } } }
public void MakeMoveTest() { int size = 5; Cell[,] board = new Cell[size, size]; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { board[i, j] = new Cell(); board[i, j].Status = 1; } } board = Processing.MakeMove(board); // Only the corner cells should survive the first move Assert.AreEqual(1, board[0, 0].Status); Assert.AreEqual(1, board[0, size - 1].Status); Assert.AreEqual(1, board[size - 1, 0].Status); Assert.AreEqual(1, board[size - 1, size - 1].Status); // All other cells should be dead for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (i == 0 && j == 0 || i == 0 && j == size - 1 || i == size - 1 && j == 0 || i == size - 1 && j == size - 1) { // Skip the corner cells continue; } Assert.AreEqual(0, board[i, j].Status); } } board = Processing.MakeMove(board); // Now all cells should be dead for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { Assert.AreEqual(0, board[i, j].Status); } } // Now placing 4 live cells with a zombie in the middle board[0, 1].Status = 1; board[1, 0].Status = 1; board[1, 2].Status = 1; board[2, 1].Status = 1; board[1, 1].Status = null; board = Processing.MakeMove(board); // After first day, board[0,1] and board[2,1] has become zombies (due to the seed used in Processing) Assert.AreEqual(null, board[0, 1].Status); Assert.AreEqual(null, board[2, 1].Status); // The zombie is still a zombie Assert.AreEqual(null, board[1, 1].Status); // board[1,0] and board[1,2] are still alive Assert.AreEqual(1, board[1, 0].Status); Assert.AreEqual(1, board[1, 2].Status); board = Processing.MakeMove(board); // Now board[1,0] and board[1,2] have died of loneliness :'( // The zombie is still a zombie Assert.AreEqual(null, board[0, 1].Status); Assert.AreEqual(null, board[2, 1].Status); Assert.AreEqual(null, board[1, 1].Status); // board[1,0] and board[1,2] are dead Assert.AreEqual(0, board[1, 0].Status); Assert.AreEqual(0, board[1, 2].Status); // Zombies should stay zombies for (int i = 0; i < 50; i++) { board = Processing.MakeMove(board); } Assert.AreEqual(null, board[0, 1].Status); Assert.AreEqual(null, board[2, 1].Status); Assert.AreEqual(null, board[1, 1].Status); }
/// <summary> /// Will ask the user if he wants to modify any cells to a specific state. /// If the user wants to modify any cells it will be from within here. /// </summary> /// <param name="max">The maximum amount of cells the user can modify</param> private void AskUserForModifyCell(uint max) { uint number = 0; bool validDefineCell = true; while (validDefineCell) { System.Console.Write("How many cells do you want to define(maximum is " + max + "): "); if (UInt32.TryParse(System.Console.ReadLine(), out number)) validDefineCell = !(number <= max); } if (number != 0) { System.Console.WriteLine("Define cells by writing [row] [column] [state] - state can be [a]live, [d]ead or [z]ombie."); System.Console.WriteLine("An example is: 3 5 d. "); Cell[] cells = new Cell[number]; bool invalidCellInfo; uint column = 0; uint row = 0; int? state = 0; for (int index = 0; index < cells.Length; index++) { invalidCellInfo = true; while (invalidCellInfo) { System.Console.Write("Define cell " + index + ": "); string[] splittedLine = System.Console.ReadLine().Split(' '); System.Console.WriteLine(); //Interpretates what the answer try { if (splittedLine.GetLength(0) != 3) throw new FormatException(); row = UInt32.Parse(splittedLine[0]); column = UInt32.Parse(splittedLine[1]); if (splittedLine[2] == "a") state = 1; else if (splittedLine[2] == "d") state = 0; else if (splittedLine[2] == "z") state = null; else throw new FormatException(); invalidCellInfo = false; } catch (FormatException e) { System.Console.WriteLine("Not a valid input - must be like: 1 1 a - Try again:"); } } cells[index].Column = column; cells[index].Row = row; cells[index].Status = state; } _game.ModifyCell(cells); System.Console.WriteLine("All wanted cells have been defined!"); } System.Console.WriteLine(); }