Ooui-tws-port/Samples/BugSweeper/Board.cs

236 lines
7.1 KiB
C#
Executable File

using System;
using Xamarin.Forms;
namespace BugSweeper
{
class Board : AbsoluteLayout
{
// Alternative sizes make the tiles a tad small.
const int COLS = 9; // 16
const int ROWS = 9; // 16
const int BUGS = 10; // 40
Tile[,] tiles = new Tile[ROWS, COLS];
int flaggedTileCount;
bool isGameInProgress; // on first tap
bool isGameInitialized; // on first double-tap
bool isGameEnded;
// Events to notify page.
public event EventHandler GameStarted;
public event EventHandler<bool> GameEnded;
public Board()
{
for (int row = 0; row < ROWS; row++)
for (int col = 0; col < COLS; col++)
{
Tile tile = new Tile(row, col);
tile.TileStatusChanged += OnTileStatusChanged;
this.Children.Add(tile);
tiles[row, col] = tile;
}
SizeChanged += (sender, args) =>
{
double tileWidth = this.Width / COLS;
double tileHeight = this.Height / ROWS;
foreach (Tile tile in tiles)
{
Rectangle bounds = new Rectangle(tile.Col * tileWidth,
tile.Row * tileHeight,
tileWidth, tileHeight);
AbsoluteLayout.SetLayoutBounds(tile, bounds);
}
};
NewGameInitialize();
}
public void NewGameInitialize()
{
// Clear all the tiles.
foreach (Tile tile in tiles)
tile.Initialize();
isGameInProgress = false;
isGameInitialized = false;
isGameEnded = false;
this.FlaggedTileCount = 0;
}
public int FlaggedTileCount
{
set
{
if (flaggedTileCount != value)
{
flaggedTileCount = value;
OnPropertyChanged();
}
}
get
{
return flaggedTileCount;
}
}
public int BugCount
{
get
{
return BUGS;
}
}
// Not called until the first tile is double-tapped.
void DefineNewBoard(int tappedRow, int tappedCol)
{
// Begin the assignment of bugs.
Random random = new Random();
int bugCount = 0;
while (bugCount < BUGS)
{
// Get random row and column.
int row = random.Next(ROWS);
int col = random.Next(COLS);
// Skip it if it's already a bug.
if (tiles[row, col].IsBug)
{
continue;
}
// Avoid the tappedRow & Col & surrounding ones.
if (row >= tappedRow - 1 &&
row <= tappedRow + 1 &&
col >= tappedCol - 1 &&
col <= tappedCol + 1)
{
continue;
}
// It's a bug!
tiles[row, col].IsBug = true;
// Calculate the surrounding bug count.
CycleThroughNeighbors(row, col,
(neighborRow, neighborCol) =>
{
++tiles[neighborRow, neighborCol].SurroundingBugCount;
});
bugCount++;
}
}
void CycleThroughNeighbors(int row, int col, Action<int, int> callback)
{
int minRow = Math.Max(0, row - 1);
int maxRow = Math.Min(ROWS - 1, row + 1);
int minCol = Math.Max(0, col - 1);
int maxCol = Math.Min(COLS - 1, col + 1);
for (int neighborRow = minRow; neighborRow <= maxRow; neighborRow++)
for (int neighborCol = minCol; neighborCol <= maxCol; neighborCol++)
{
if (neighborRow != row || neighborCol != col)
callback(neighborRow, neighborCol);
}
}
void OnTileStatusChanged(object sender, TileStatus tileStatus)
{
if (isGameEnded)
return;
// With a first tile tapped, the game is now in progress.
if (!isGameInProgress)
{
isGameInProgress = true;
// Fire the GameStarted event.
if (GameStarted != null)
{
GameStarted(this, EventArgs.Empty);
}
}
// Update the "flagged" bug count before checking for a loss.
int flaggedCount = 0;
foreach (Tile tile in tiles)
if (tile.Status == TileStatus.Flagged)
flaggedCount++;
this.FlaggedTileCount = flaggedCount;
// Get the tile whose status has changed.
Tile changedTile = (Tile)sender;
// If it's exposed, some actions are required.
if (tileStatus == TileStatus.Exposed)
{
if (!isGameInitialized)
{
DefineNewBoard(changedTile.Row, changedTile.Col);
isGameInitialized = true;
}
if (changedTile.IsBug)
{
isGameInProgress = false;
isGameEnded = true;
// Fire the GameEnded event!
if (GameEnded != null)
{
GameEnded(this, false);
}
return;
}
// Auto expose for zero surrounding bugs.
if (changedTile.SurroundingBugCount == 0)
{
CycleThroughNeighbors(changedTile.Row, changedTile.Col,
(neighborRow, neighborCol) =>
{
// Expose all the neighbors.
tiles[neighborRow, neighborCol].Status = TileStatus.Exposed;
});
}
}
// Check for a win.
bool hasWon = true;
foreach (Tile til in tiles)
{
if (til.IsBug && til.Status != TileStatus.Flagged)
hasWon = false;
if (!til.IsBug && til.Status != TileStatus.Exposed)
hasWon = false;
}
// If there's a win, celebrate!
if (hasWon)
{
isGameInProgress = false;
isGameEnded = true;
// Fire the GameEnded event!
if (GameEnded != null)
{
GameEnded(this, true);
}
return;
}
}
}
}