From d0734ae79591ff2624296d9feca27aef5f82673f Mon Sep 17 00:00:00 2001 From: "Frank A. Krueger" Date: Sat, 9 Dec 2017 19:18:34 -0800 Subject: [PATCH] Add BugSweeper sample --- Ooui/Client.js | 2 +- Samples/BugSweeper/App.cs | 13 ++ Samples/BugSweeper/Board.cs | 235 ++++++++++++++++++++++ Samples/BugSweeper/BugSweeperPage.xaml | 78 +++++++ Samples/BugSweeper/BugSweeperPage.xaml.cs | 174 ++++++++++++++++ Samples/BugSweeper/Images/RedBug.png | Bin 0 -> 12103 bytes Samples/BugSweeper/Images/Xamarin120.png | Bin 0 -> 7181 bytes Samples/BugSweeper/Tile.cs | 191 ++++++++++++++++++ Samples/BugSweeperSample.cs | 16 ++ Samples/Samples.csproj | 6 + 10 files changed, 714 insertions(+), 1 deletion(-) create mode 100755 Samples/BugSweeper/App.cs create mode 100755 Samples/BugSweeper/Board.cs create mode 100644 Samples/BugSweeper/BugSweeperPage.xaml create mode 100755 Samples/BugSweeper/BugSweeperPage.xaml.cs create mode 100755 Samples/BugSweeper/Images/RedBug.png create mode 100755 Samples/BugSweeper/Images/Xamarin120.png create mode 100755 Samples/BugSweeper/Tile.cs create mode 100644 Samples/BugSweeperSample.cs diff --git a/Ooui/Client.js b/Ooui/Client.js index 4709ced..e796069 100644 --- a/Ooui/Client.js +++ b/Ooui/Client.js @@ -1,5 +1,5 @@ -var debug = true; +var debug = false; const nodes = {}; diff --git a/Samples/BugSweeper/App.cs b/Samples/BugSweeper/App.cs new file mode 100755 index 0000000..bc51379 --- /dev/null +++ b/Samples/BugSweeper/App.cs @@ -0,0 +1,13 @@ +using System; +using Xamarin.Forms; + +namespace BugSweeper +{ + public class App : Application + { + public App () + { + MainPage = new BugSweeperPage(); + } + } +} diff --git a/Samples/BugSweeper/Board.cs b/Samples/BugSweeper/Board.cs new file mode 100755 index 0000000..33b3950 --- /dev/null +++ b/Samples/BugSweeper/Board.cs @@ -0,0 +1,235 @@ +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 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 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; + } + } + } +} diff --git a/Samples/BugSweeper/BugSweeperPage.xaml b/Samples/BugSweeper/BugSweeperPage.xaml new file mode 100644 index 0000000..64b74c6 --- /dev/null +++ b/Samples/BugSweeper/BugSweeperPage.xaml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +