/// <summary> /// Detects pyramid or hole (if any) at the given coordinates in the <see cref="Grid" />, and randomly switch /// between pyramid and hole, based on <see cref="_probabilityP" /> and <see cref="_probabilityQ" /> parameters. /// </summary> /// <param name="p"> /// contains the coordinates where the function looks if there is a pyramid or hole in the <see cref="Grid" />. /// </param> private void RandomlySwitchFourCells(KpzNode[,] grid, KpzCoords p) { var neighbours = GetNeighbours(grid, p); var currentPoint = grid[p.x, p.y]; bool changedGrid = false; // We check our own {dx,dy} values, and the right neighbour's dx, and bottom neighbour's dx. if ( // If we get the pattern {01, 01} we have a pyramid: ((currentPoint.dx && !neighbours.nx.dx) && (currentPoint.dy && !neighbours.ny.dy) && (_random.NextDouble() < _probabilityP)) || // If we get the pattern {10, 10} we have a hole: ((!currentPoint.dx && neighbours.nx.dx) && (!currentPoint.dy && neighbours.ny.dy) && (_random.NextDouble() < _probabilityQ)) ) { // We make a hole into a pyramid, and a pyramid into a hole. currentPoint.dx = !currentPoint.dx; currentPoint.dy = !currentPoint.dy; neighbours.nx.dx = !neighbours.nx.dx; neighbours.ny.dy = !neighbours.ny.dy; changedGrid = true; } if (_enableStateLogger) { StateLogger.AddKpzAction("RandomlySwitchFourCells", grid, p, neighbours, changedGrid); } }
/// <summary> /// Runs an iteration of the KPZ algorithm (with <see cref="GridWidth"/> × <see cref="GridHeight"/> steps). /// </summary> public void DoIteration() { var numberOfStepsInIteration = GridWidth * GridHeight; if (_enableStateLogger) { StateLogger.NewKpzIteration(); } for (int i = 0; i < numberOfStepsInIteration; i++) { // We randomly choose a point on the grid. // If there is a pyramid or hole, we randomly switch them. var randomPoint = new KpzCoords { x = _random.Next(0, GridWidth), y = _random.Next(0, GridHeight) }; RandomlySwitchFourCells(Grid, randomPoint); } }
/// <summary> /// Gets the right and bottom neighbours of the point given with the coordinates <see cref="p" /> /// in the <see cref="Grid" />. /// </summary> private KpzNeighbours GetNeighbours(KpzNode[,] grid, KpzCoords p) { KpzNeighbours toReturn; toReturn.nxCoords = new KpzCoords { x = (p.x < GridWidth - 1) ? p.x + 1 : 0, y = p.y }; toReturn.nyCoords = new KpzCoords { x = p.x, y = (p.y < GridHeight - 1) ? p.y + 1 : 0 }; toReturn.nx = grid[toReturn.nxCoords.x, toReturn.nxCoords.y]; toReturn.ny = grid[toReturn.nyCoords.x, toReturn.nyCoords.y]; return(toReturn); }
/// <summary> /// Adds a deep copy of the grid into the current <see cref="KpzStateLogger" /> iteration, with cells /// to highlight (<see cref="Center" /> and <see cref="Neighbours" />). If the values in the grid were updated, /// they are highlighted with a green color, else they are highlighted with a red color, based on the parameter /// value of <see cref="ChangedGrid" />. /// </summary> public void AddKpzAction(string Description, KpzNode[,] Grid, KpzCoords Center, KpzNeighbours Neighbours, bool ChangedGrid) { var highlightedCoords = new List <KpzCoords>(); highlightedCoords.Add(new KpzCoords { x = Center.x, y = Center.y }); highlightedCoords.Add(new KpzCoords { x = Neighbours.nxCoords.x, y = Neighbours.nxCoords.y }); highlightedCoords.Add(new KpzCoords { x = Neighbours.nyCoords.x, y = Neighbours.nyCoords.y }); Iterations[Iterations.Count - 1].Actions.Add(new KpzAction { Description = Description, Grid = CopyOfGrid(Grid), HeightMap = new int[0, 0], HightlightColor = (ChangedGrid) ? Color.LightGreen : Color.Salmon, // green or red HighlightedCoords = highlightedCoords }); }