/// <summary> /// "Draw" an ellipse structure type /// </summary> /// <param name="status">Structure status</param> /// <param name="coords">Structure coordinates</param> /// <param name="lineNum">Seed line number</param> /// <exception cref="SeedLineException">Incorrect number of coordinates</exception> private void DrawEllipse(DeadOrAlive status, int[] coords, int lineNum) { int expectedCoords = 4; if (coords.Length != expectedCoords) { throw new SeedLineException(lineNum, expectedCoords); } int bottomRow = coords[0]; int bottomCol = coords[1]; int topRow = coords[2]; int topCol = coords[3]; double rowLen = (topRow - bottomRow) + 1.0; double colLen = (topCol - bottomCol) + 1.0; double colCen = ((topCol - bottomCol) / 2.0) + bottomCol; double rowCen = ((topRow - bottomRow) / 2.0) + bottomRow; for (int r = bottomRow; r <= topRow; r++) { for (int c = bottomCol; c <= topCol; c++) { // Only record that cell as part of the ellipse if its centre falls within the range of the // ellipse if (CheckCellCentre((double)r, (double)c, rowCen, colCen, rowLen, colLen) && !CheckOutOfBounds(r, c)) { cellsArray[r, c] = status; } } } }
/// <summary> /// "Draw" a rectangle structure type /// </summary> /// <param name="status">Structure status</param> /// <param name="coords">Structure coordinates</param> /// <param name="lineNum">Seed line number</param> /// <exception cref="SeedLineException">Incorrect number of coordinates</exception> private void DrawRectangle(DeadOrAlive status, int[] coords, int lineNum) { int expectedCoords = 4; if (coords.Length != expectedCoords) { throw new SeedLineException(lineNum, expectedCoords); } int bottomRow = coords[0]; int bottomCol = coords[1]; int topRow = coords[2]; int topCol = coords[3]; for (int r = bottomRow; r <= topRow; r++) { for (int c = bottomCol; c <= topCol; c++) { if (!CheckOutOfBounds(r, c)) { cellsArray[r, c] = status; } } } }
/// <summary> /// Validates the components of a version 2 seed line /// </summary> /// <param name="components">An array of the components</param> /// <param name="lineNum">The line number</param> /// <param name="status">Output the status (dead or alive)</param> /// <param name="structure">Output the structure (cell, rectangle or ellipse)</param> /// <param name="coords">Output the coordinates</param> /// <exception cref="SeedLineException">Errors in the composition of the seed file</exception> private void CheckComponents(string[] components, int lineNum, out DeadOrAlive status, out string structure, out int[] coords) { int numExpectedComponents = 3; // Check there is the correct number of components first if (components.Length != numExpectedComponents) { throw new SeedLineException("Incorrect formatting.", lineNum); } string structureStatus = components[0].ToLower(); string structureType = components[1].ToLower(); string structureCoords = components[2]; // Get status & structure if (!(statusTypes.Contains(structureStatus) && structureTypes.Contains(structureType))) { throw new SeedLineException("Unknown status or structure.", lineNum); } else { status = structureStatus == "o" ? DeadOrAlive.alive : DeadOrAlive.dead; structure = structureType; coords = GetCoordinates(structureCoords, lineNum); } }
/// <summary> /// "Draw" a cell structure type /// </summary> /// <param name="status">Structure status</param> /// <param name="coords">Structure coordinates</param> /// <param name="lineNum">Seed line number</param> /// <exception cref="SeedLineException">Incorrect number of coordinates</exception> private void DrawCell(DeadOrAlive status, int[] coords, int lineNum) { int expectedCoords = 2; if (coords.Length != expectedCoords) { throw new SeedLineException(lineNum, expectedCoords); } int row = coords[0]; int col = coords[1]; if (!CheckOutOfBounds(row, col)) { cellsArray[row, col] = status; } }
/// <summary> /// Checks each cell against the rules of the Game of Life to determine their status next generation /// </summary> /// <returns>A 2D array of what the board will look like next generation</returns> private DeadOrAlive[,] CreateNextGeneration() { DeadOrAlive[,] nextGenStatusArray = new DeadOrAlive[settings.Rows, settings.Columns]; Neighbourhood neighbourhood = new Neighbourhood(settings.Neighbourhood, settings.Order, settings.Centre, settings.Periodic, statusArray); for (int r = 0; r < settings.Rows; r++) { for (int c = 0; c < settings.Columns; c++) { int livingNeighbours = neighbourhood.CheckNeighbours(r, c); if (statusArray[r, c] != DeadOrAlive.alive) { // Living neighbours of the dead cell must be equal to a value in the --birth rules for it // to be alive if (settings.Birth.Contains(livingNeighbours)) { nextGenStatusArray[r, c] = DeadOrAlive.alive; } // Otherwise it stays dead else { // If ghost mode is enabled, need to determine the correct next-gen shading nextGenStatusArray[r, c] = settings.Ghost ? ChooseShading(statusArray[r, c]) : DeadOrAlive.dead; } } else if (statusArray[r, c] == DeadOrAlive.alive) { // Living neighbours of living cells must be equal to a value in the --survival rules for it // to stay alive if (settings.Survival.Contains(livingNeighbours)) { nextGenStatusArray[r, c] = DeadOrAlive.alive; } // Otherwise it will die else { nextGenStatusArray[r, c] = settings.Ghost ? DeadOrAlive.dark : DeadOrAlive.dead; } } } } return(nextGenStatusArray); }
/// <summary> /// Chooses the correct next-gen status of a cell, important for ghost-mode /// </summary> /// <param name="status">The cell's current status</param> /// <returns>The cell's next-gen status</returns> private DeadOrAlive ChooseShading(DeadOrAlive status) { switch (status) { case DeadOrAlive.alive: return(DeadOrAlive.dark); case DeadOrAlive.dark: return(DeadOrAlive.medium); case DeadOrAlive.medium: return(DeadOrAlive.light); case DeadOrAlive.light: return(DeadOrAlive.dead); default: break; } return(DeadOrAlive.dead); }
public Cell(int x, int y, DeadOrAlive state) { this.X = x; this.Y = y; State = state; }