/// <summary> /// Get the co-ordinates with respect to grid and return the Cell type enum /// </summary> /// <param name="grid"></param> /// <param name="coOrdinates"></param> /// <returns>returns CellTypeEnum</returns> public static CellTypeEnum GetCellType(Grid grid, CoOrdinates coOrdinates) { if ((coOrdinates.X < -1 || coOrdinates.X > grid.RowCount) || (coOrdinates.Y < -1 || coOrdinates.Y > grid.ColumnCount)) { throw new ArgumentOutOfRangeException("Invalid Index value: must be greater than or equal to minus one and less than or equal to Row count"); } CellTypeEnum enumCellType = CellTypeEnum.None; if (coOrdinates.X == 0 && coOrdinates.Y == 0) enumCellType = CellTypeEnum.TopLeftCorner; else if (coOrdinates.X == 0 && coOrdinates.Y == grid.ColumnCount - 1) enumCellType = CellTypeEnum.TopRightCorner; else if (coOrdinates.X == grid.RowCount - 1 && coOrdinates.Y == 0) enumCellType = CellTypeEnum.BottomLeftCorner; else if (coOrdinates.X == grid.RowCount - 1 && coOrdinates.Y == grid.ColumnCount - 1) enumCellType = CellTypeEnum.BottomRightCorner; else if (coOrdinates.X == 0 && (coOrdinates.Y > 0 && coOrdinates.Y < grid.ColumnCount - 1)) enumCellType = CellTypeEnum.TopSide; else if (coOrdinates.X == grid.RowCount - 1 && (coOrdinates.Y > 0 && coOrdinates.Y < grid.ColumnCount - 1)) enumCellType = CellTypeEnum.BottomSide; else if ((coOrdinates.X > 0 && coOrdinates.X < grid.RowCount - 1) && coOrdinates.Y == 0) enumCellType = CellTypeEnum.LeftSide; else if ((coOrdinates.X > 0 && coOrdinates.X < grid.RowCount - 1) && coOrdinates.Y == grid.ColumnCount - 1) enumCellType = CellTypeEnum.RightSide; else if ((coOrdinates.X > 0 && coOrdinates.X < grid.RowCount - 1) && (coOrdinates.Y > 0 && coOrdinates.Y < grid.ColumnCount - 1)) enumCellType = CellTypeEnum.Center; else if (coOrdinates.X == -1 && (coOrdinates.Y > 0 && coOrdinates.Y < grid.ColumnCount - 1)) enumCellType = CellTypeEnum.OuterTopSide; else if ((coOrdinates.X > 0 && coOrdinates.X < grid.RowCount - 1) && coOrdinates.Y == grid.ColumnCount) enumCellType = CellTypeEnum.OuterRightSide; else if (coOrdinates.X == grid.RowCount && (coOrdinates.Y > 0 && coOrdinates.Y < grid.ColumnCount - 1)) enumCellType = CellTypeEnum.OuterBottomSide; else if ((coOrdinates.X > 0 && coOrdinates.X < grid.RowCount - 1) && coOrdinates.Y == -1) enumCellType = CellTypeEnum.OuterLeftSide; return enumCellType; }
/// <summary> /// Change state of grid if required to grow on any side /// </summary> /// <param name="inputGrid"></param> /// <param name="outputGrid"></param> public static void ChangeGridState(Grid inputGrid, Grid outputGrid) { CheckRowGrowth(inputGrid, outputGrid, -1); CheckRowGrowth(inputGrid, outputGrid, inputGrid.RowCount); CheckColumnGrowth(inputGrid, outputGrid, -1); CheckColumnGrowth(inputGrid, outputGrid, inputGrid.ColumnCount); }
/// <summary> /// Assign Source grid cell values to target grid /// </summary> /// <param name="sourceGrid"></param> /// <param name="targetGrid"></param> //private static void AssignCellValues(Grid sourceGrid, Grid targetGrid) //{ // for (int i = 0; i < sourceGrid.RowCount; i++) // { // for (int j = 0; j < sourceGrid.ColumnCount; j++) // { // targetGrid[i, j].IsAlive = sourceGrid[i, j].IsAlive; // } // } //} private static void AssignCellValues(Grid sourceGrid, Grid targetGrid) { for (int i = 0; i < sourceGrid.RowCount; i++) { for (int j = 0; j < sourceGrid.ColumnCount; j++) { targetGrid[i, j].IsAlive = sourceGrid[i, j].IsAlive; } } }
/// <summary> /// Display the grid /// </summary> public static void Display(Grid grid) { foreach (Row row in grid.GridObj) { foreach (Cell cell in row.Cells) { Console.Write(cell.ToString()); } Console.WriteLine(); } }
/// <summary> /// Change Cell state of specified co-ordinate using Rules /// </summary> /// <param name="inputGrid"></param> /// <param name="outputGrid"></param> /// <param name="coOrdinates"></param> public static void ChangeCellsState(Grid inputGrid, Grid outputGrid, CoOrdinates coOrdinates) { int liveNeighbourCount = CountAliveNeighbours(inputGrid, coOrdinates); // int l = CountLivingNeighbours(inputGrid, coOrdinates); lock (outputGrid) { if (IsAliveInNextState(inputGrid[coOrdinates.X, coOrdinates.Y], liveNeighbourCount)) { //set output grid's cell to live only if it is in alive status in next generation outputGrid[coOrdinates.X, coOrdinates.Y].IsAlive = true; } } }
/// <summary> /// Set target grid schema similar to source grid schema /// </summary> /// <param name="sourceGrid"></param> /// <param name="targetGrid"></param> private static void MatchSchema(Grid sourceGrid, Grid targetGrid) { while (targetGrid.RowCount < sourceGrid.RowCount) { Row newRow = new Row(); for (int k = 0; k < targetGrid.ColumnCount; k++) { Cell newCell = new Cell(false); newRow.AddCell(newCell); } targetGrid.AddRow(newRow); } while (targetGrid.ColumnCount < sourceGrid.ColumnCount) { Cell cell = new Cell(false); for (int k = 0; k < targetGrid.RowCount; k++) { targetGrid[k].AddCell(cell); } targetGrid.ColumnCount += 1; } }
/// <summary> /// Check if rule satisfies to expand column /// </summary> /// <param name="inputGrid"></param> /// <param name="outputGrid"></param> /// <param name="colId"></param> private static void CheckColumnGrowth(Grid inputGrid, Grid outputGrid, int colId) { //Create a whole new column in the beginning or end if rule is satified for any of the cell Boolean columnCreatedFlag = false; //Boolean IsPreviousCellsFilled = false; // start with the index 1 until 1 less than last index as index 0 and last index cannot have 3 live adjacent cell in any case // This index 0 and last index must be included if rule is changed in future; dead can alive with 2 live adjacent cells for (int i = 1; i < inputGrid.RowCount - 1; i++) { if (Rule.CountAliveNeighbours(inputGrid, new CoOrdinates(i, colId)) == 3) { if (columnCreatedFlag == false) { //if (IsPreviousCellsFilled == false) //{ for (int k = 0; k < outputGrid.RowCount; k++) { // Fill all cells with false Cell newDeadCell = new Cell(false); if (colId == -1) { outputGrid[k].InsertCell(0, newDeadCell, outputGrid.ColumnCount); } else { outputGrid[k].AddCell(newDeadCell); } } // IsPreviousCellsFilled = true; //} // increment column count to 1 outputGrid.ColumnCount += 1; columnCreatedFlag = true; } int yAxis = (colId == -1) ? 0 : outputGrid.ColumnCount - 1; outputGrid[i, yAxis].IsAlive = true; } } }
/// <summary> /// Deep copy Copy Source grid to target grid /// </summary> /// <param name="sourceGrid"></param> /// <param name="targetGrid"></param> public static void Copy(Grid sourceGrid, Grid targetGrid) { MatchSchema(sourceGrid, targetGrid); targetGrid.ReInitialize(); AssignCellValues(sourceGrid, targetGrid); }
/// <summary> /// Check if the adjacent cell is alive or not /// </summary> /// <param name="grid"></param> /// <param name="baseCoOrdinates"></param> /// <param name="offSetCoOrdinates"></param> /// <returns>returns 1 if live otherwise 0</returns> private static int IsAliveNeighbour(Grid grid, CoOrdinates baseCoOrdinates, CoOrdinates offSetCoOrdinates) { int live = 0; // set default as 0 int x = baseCoOrdinates.X + offSetCoOrdinates.X; // get x axis of neighbour int y = baseCoOrdinates.Y + offSetCoOrdinates.Y; // get y axis of neighbour // check the computed bound is within range of grid, if it is not within bounds live is 0 as default if ((x >= 0 && x < grid.RowCount) && y >= 0 && y < grid.ColumnCount) { // if reachable neighbour cell is alive then set live to 1 otherwise 0 live = grid[x, y].IsAlive ? 1 : 0; } return live; }
private static int CountLivingNeighbours(Grid grid, CoOrdinates cellXY) { var count = 0; if (cellXY.X > 0 & cellXY.Y > 0) { CoOrdinates[,] neighbours = new CoOrdinates[,] { {new CoOrdinates(cellXY.X - 1, cellXY.Y - 1)}, {new CoOrdinates(cellXY.X , cellXY.Y - 1)}, {new CoOrdinates(cellXY.X + 1, cellXY.Y-1)}, {new CoOrdinates(cellXY.X + 1, cellXY.Y )}, {new CoOrdinates(cellXY.X - 1, cellXY.Y + 1)}, {new CoOrdinates(cellXY.X - 1, cellXY.Y)}, {new CoOrdinates(cellXY.X , cellXY.Y +1)}, {new CoOrdinates(cellXY.X + 1, cellXY.Y+1)} }; foreach (CoOrdinates c in neighbours) { count = grid.GridObj[c.X].Cells[c.Y].IsAlive ? count += 1 : count; } } return count; }
/// <summary> /// Count live adjacent cells for specified cell co-ordinates /// </summary> /// <param name="grid"></param> /// <param name="coOrdinates"></param> /// <returns>returns number of live neighbours</returns> private static int CountAliveNeighbours(Grid grid, CoOrdinates coOrdinates) { int liveNeighbours = 0; // Get the Cell type of current cell CellTypeEnum enumInnerCell = ReachableCell.GetCellType(grid, coOrdinates); List<CoOrdinates> reachableCells = new List<CoOrdinates>(); // populate reachable cells from current cell for easier traversing ReachableCell.ReachableCells.TryGetValue(enumInnerCell, out reachableCells); if (reachableCells.Count == 0) throw new ArgumentNullException("Cannot find reachable co-ordinates"); foreach (CoOrdinates coOrds in reachableCells) { liveNeighbours += IsAliveNeighbour(grid, coOrdinates, coOrds); } return liveNeighbours; }
/// <summary> /// Check if rule satisfies to expand row /// </summary> /// <param name="inputGrid"></param> /// <param name="outputGrid"></param> /// <param name="rowId"></param> private static void CheckRowGrowth(Grid inputGrid, Grid outputGrid, int rowId) { //Create a whole new row in the beginning or end if rule is satified for any of the cell Boolean rowCreatedFlag = false; //Boolean IsPreviousCellsFilled = false; // start with the index 1 until 1 less than last index as index 0 and last index cannot have 3 live adjacent cell in any case // This index 0 and last index must be included if rule is changed in future; dead can alive with 2 live adjacent cells for (int j = 1; j < inputGrid.ColumnCount - 1; j++) { if (Rule.CountAliveNeighbours(inputGrid, new CoOrdinates(rowId, j)) == 3) { if (rowCreatedFlag == false) { Row newRow = new Row(); //if (IsPreviousCellsFilled == false) //{ for (int k = 0; k < outputGrid.ColumnCount; k++) { // Fill all cells with false Cell newDeadCell = new Cell(false); newRow.AddCell(newDeadCell); } //IsPreviousCellsFilled = true; //} if (rowId == -1) { outputGrid.InsertRow(0, newRow); } else { outputGrid.AddRow(newRow); } //outputGrid.RowCount += 1; rowCreatedFlag = true; } int XAxis = (rowId == -1) ? 0 : outputGrid.RowCount - 1; outputGrid[XAxis, j].IsAlive = true; } } //for (int j = 1; j < inputGrid.ColumnCount - 1; j++) //{ // if (Rule.CountAliveNeighbours(inputGrid, new CoOrdinates(rowId, j)) == 3) // { // if (rowCreatedFlag == false) // { // Row newRow = new Row(); // //if (IsPreviousCellsFilled == false) // //{ // for (int k = 0; k < outputGrid.ColumnCount; k++) // { // // Fill all cells with false // Cell newDeadCell = new Cell(false); // newRow.AddCell(newDeadCell); // } // //IsPreviousCellsFilled = true; // //} // if (rowId == -1) // { // outputGrid.InsertRow(0, newRow); // } // else // { // outputGrid.AddRow(newRow); // } // rowCreatedFlag = true; // } // int XAxis = (rowId == -1) ? 0 : outputGrid.RowCount - 1; // outputGrid[XAxis, j].IsAlive = true; // } //} }