/// <summary> /// The StartFireAtPoint method is called to start a fire at a specific point in the forest. /// </summary> /// <param name="point"></param> /// <param name="forestWidthPixels"></param> /// <param name="forestHeightPixels"></param> public void StartFireAtPoint(Point point, double forestWidthPixels, double forestHeightPixels) { try { if (point != null && forestWidthPixels > 0 && forestHeightPixels > 0) { // Retrieve the x/y coordinates in pixels. double xPositionPixels = point.X; double yPositionPixels = point.Y; // Convert the x/y coordinates from pixels to cells. int xPosition = (int)((xPositionPixels / forestWidthPixels) * Constants.ForestWidth); int yPosition = (int)((yPositionPixels / forestHeightPixels) * Constants.ForestHeight); // Determine the cell index from the x/y coordinates. int cellIndex = xPosition + (yPosition * Constants.ForestWidth); // Retrieve the forest cell and set it to burning. if (IsCellIndexValid(cellIndex)) { ForestCell forestCell = _forestCells.ElementAt(cellIndex); if (forestCell.CellState == CellState.Tree) { forestCell.CellState = CellState.Burning; } } } } catch (Exception ex) { throw new Exception("Forest.StartFireAtPoint(Point point, double forestWidthPixels, double forestHeightPixels): " + ex.ToString()); } }
/// <summary> /// Create a forest cell from an existing forest cell. /// </summary> /// <param name="forestCell"></param> public ForestCell(ForestCell forestCell) { try { if (forestCell == null) { throw new Exception("forestCell can not be null"); } _cellState = forestCell.CellState; } catch (Exception ex) { throw new Exception("ForestCell(ForestCell forestCell): " + ex.ToString()); } }
/// <summary> /// The UpdateForest method is called to update the forest. /// An empty cell may become a tree cell, as per the regrowth probability. /// A burning cell becomes an empty cell. /// A tree cell becomes a burning cell, if any of its neighbours are burning. /// A tree cell may become a burning cell, even with no burning neighbours, as per the lightning probability. /// </summary> private async Task UpdateForest() { try { await Task.Run(() => { lock (_updateLock) { ObservableCollection <ForestCell> updatedForest = new ObservableCollection <ForestCell>(); // The updated forest. // Update the forest cells, one cell at a time. foreach (ForestCell forestCell in _forestCells) { ForestCell updatedForestCell = new ForestCell(forestCell); // Make a copy of the current forest cell. // Update the forest cell. if (forestCell.CellState == CellState.Empty) { // If the cell is empty, apply regrowth. updatedForestCell.CellState = ApplyRegrowth() ? CellState.Tree : updatedForestCell.CellState; } else if (forestCell.CellState == CellState.Tree) { // If the cell is a tree, check for any burning neighbours. int cellIndex = _forestCells.IndexOf(forestCell); // Retrieve the index of the tree cell. // Determine the indexes for all of the neighbours. int topNeighbourIndex = cellIndex - Constants.ForestWidth; int topRightNeighbourIndex = cellIndex - Constants.ForestWidth + 1; int rightNeighbourIndex = cellIndex + 1; int bottomRightNeighbourIndex = cellIndex + Constants.ForestWidth + 1; int bottomNeighbourIndex = cellIndex + Constants.ForestWidth; int bottomLeftNeighbourIndex = cellIndex + Constants.ForestWidth - 1; int leftNeighbourIndex = cellIndex - 1; int topLeftNeighbourIndex = cellIndex - Constants.ForestWidth - 1; // Determine if the cell is on the top/right/bottom/left edge of the forest - certain neighbours must be ignored if a cell is on an edge. bool topEdge = cellIndex < Constants.ForestWidth ? true : false; bool rightEdge = ((cellIndex + 1) % Constants.ForestWidth) == 0 ? true : false; bool leftEdge = (cellIndex % Constants.ForestWidth) == 0 ? true : false; bool bottomEdge = (cellIndex + Constants.ForestWidth) >= (Constants.ForestWidth *Constants.ForestHeight) ? true : false; // Check each neighbour. if (!topEdge && updatedForestCell.CellState != CellState.Burning && IsCellBurning(topNeighbourIndex)) { updatedForestCell.CellState = CellState.Burning; } if (!rightEdge && updatedForestCell.CellState != CellState.Burning && IsCellBurning(topRightNeighbourIndex)) { updatedForestCell.CellState = CellState.Burning; } if (!rightEdge && updatedForestCell.CellState != CellState.Burning && IsCellBurning(rightNeighbourIndex)) { updatedForestCell.CellState = CellState.Burning; } if (!rightEdge && updatedForestCell.CellState != CellState.Burning && IsCellBurning(bottomRightNeighbourIndex)) { updatedForestCell.CellState = CellState.Burning; } if (!bottomEdge && updatedForestCell.CellState != CellState.Burning && IsCellBurning(bottomNeighbourIndex)) { updatedForestCell.CellState = CellState.Burning; } if (!leftEdge && updatedForestCell.CellState != CellState.Burning && IsCellBurning(bottomLeftNeighbourIndex)) { updatedForestCell.CellState = CellState.Burning; } if (!leftEdge && updatedForestCell.CellState != CellState.Burning && IsCellBurning(leftNeighbourIndex)) { updatedForestCell.CellState = CellState.Burning; } if (!leftEdge && updatedForestCell.CellState != CellState.Burning && IsCellBurning(topLeftNeighbourIndex)) { updatedForestCell.CellState = CellState.Burning; } // If the cell is still a tree, apply a lighting strike. if (updatedForestCell.CellState == CellState.Tree) { updatedForestCell.CellState = ApplyLightningStrike() ? CellState.Burning : updatedForestCell.CellState; } } else if (forestCell.CellState == CellState.Burning) { // If the cell is burning, it becomes an empty cell. updatedForestCell.CellState = CellState.Empty; } updatedForest.Add(updatedForestCell); // Add the updated forest cell to the updated forest. } // Update the forest. if (updatedForest.Count == _forestCells.Count) { foreach (ForestCell forestCell in _forestCells) { CellState updatedCellState = updatedForest.ElementAt(_forestCells.IndexOf(forestCell)).CellState; if (updatedCellState != forestCell.CellState) { forestCell.CellState = updatedCellState; } } } } }); } catch (Exception ex) { throw new Exception("Forest.UpdateForest(): " + ex.ToString()); } }