/// <summary> /// Reveals all unrevealed, non-flagged cells and returns the cells that were revealed. /// </summary> /// <returns></returns> private List <Cell> RevealAllNonFlaggedCells() { var revealedCells = new List <Cell>(Minefield.CellCount); for (var fy = 0; fy < Settings.Height; fy++) { for (var fx = 0; fx < Settings.Width; fx++) { var cell = Minefield.Get(fx, fy); if (!cell.IsFlagged && !cell.IsRevealed) { cell.IsRevealed = true; revealedCells.Add(cell); } } } return(revealedCells); }
/// <summary> /// Reveals a cell at the specified location. If cell is a mine, the game ends with a failed result. /// If the cell is a blank (no adjacent mines), all adjacent unrevealed non-mine cells are also revealed. /// If only mines are left, regardless of flag status, the game ends with a success result. /// </summary> /// <param name="x">X co-ordinate of cell.</param> /// <param name="y">Y co-ordinate of cell.</param> /// <param name="confident">If true, will reveal all non-flagged non-revealed neighbour cells if the number /// of flagged cells equals at least the number of mines in the neighbourhood, regardless if the flags are /// set on the correct cells. Traditionally this occurred when both left and right mouse buttons were pressed. /// </param> /// <returns>An array of cells that were revealed. First element is always the specified cell, the rest /// in the order they were revealed in.</returns> public Cell[] Reveal(int x, int y, bool confident = false) { if (State != GameState.Running) { throw new InvalidOperationException("Game is not running"); } if (x < 0 || x > Settings.Width - 1) { throw new ArgumentOutOfRangeException("x"); } if (y < 0 || y > Settings.Height - 1) { throw new ArgumentOutOfRangeException("y"); } // reveal cell var cell = Minefield.Get(x, y); if (cell.IsRevealed) { throw new InvalidOperationException("Cell is already revealed"); } if (cell.IsFlagged) { throw new InvalidOperationException("Cell is flagged as a mine"); } cell.IsRevealed = true; _numRevealed++; var revealedCells = new List <Cell>(Minefield.CellCount) { cell }; // is the game over? if so, reveal all unrevealed cells if (cell.IsMine || Minefield.CellCount - Settings.MineCount == _numRevealed) { State = GameState.Stopped; Result = cell.IsMine ? GameResult.Failure : GameResult.Success; revealedCells.AddRange(RevealAllNonFlaggedCells()); return(revealedCells.ToArray()); } // reveal any unrevealed non-mine neighbours if cell is blank var neighbours = Field.GetAdjacentPoints(cell.Location, Settings.Width, Settings.Height); if (cell.Neighbours == 0) { neighbours.ToList().ForEach(p => { // recursively reveal adjacent cell var adjacent = Minefield.Get(p.X, p.Y); if (!adjacent.IsFlagged && !adjacent.IsMine && !adjacent.IsRevealed) { revealedCells.AddRange(Reveal(adjacent.Location, confident)); } }); } // confident reveal? if (confident) { // get neighbours and count mines and flags var flagCount = neighbours.Where(p => Minefield.Get(p).IsFlagged).Count(); var mineCount = neighbours.Where(p => Minefield.Get(p).IsMine).Count(); if (flagCount >= mineCount) { neighbours.ToList().ForEach(p => { // recursively reveal even if it is a mine var adjacent = Minefield.Get(p.X, p.Y); if (!adjacent.IsFlagged && !adjacent.IsRevealed) { revealedCells.AddRange(Reveal(adjacent.Location, confident)); } }); } } return(revealedCells.ToArray()); }