Introduction
This is a familiar game with a new twist. To win, you must find and flag all ten bugs. Ten bugs are hidden in a 9-by-9 grid of tiles.That first double tab is always safe. Thereafter, numbers indicate the number of surrounding tiles with bugs. Flag it with a single tab. Avoid double-tabbing a tile with bug!.
 
Let's start.
 
Step 1
You can create Xamarin.Forms app by going to File >> New >> Visual C# >> Cross-platform >> Cross-Platform App (Xamarin.Native or Xamarin.Forms), enter desired name for your project, and press OK.
(Project name- BugSweeper)
![]() 
  
 
Step 2
After the project creation, go to Solution Explorer >> BugSweeper(PCL) app >> click open MainPage.xaml and add the following code.
Used ToolBox items,
- StackLayout
- Label
- BoxView
- Grid
- <?xml version="1.0" encoding="utf-8" ?>  
- <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"  
-              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"  
-              xmlns:local="clr-namespace:BugSwapperApp"  
-              x:Class="BugSwapperApp.MainPage">  
-   
-     <ContentView SizeChanged="OnMainContentView_SizeChanged">  
-         <Grid x:Name="mainGrid" ColumnSpacing="0" RowSpacing="0">  
-             <Grid.RowDefinitions>  
-                 <RowDefinition Height="7*"/>  
-                 <RowDefinition Height="4*"/>  
-             </Grid.RowDefinitions>  
-             <Grid.ColumnDefinitions>  
-                 <ColumnDefinition Width="0"/>  
-                 <ColumnDefinition Width="*"/>  
-             </Grid.ColumnDefinitions>  
-             <StackLayout x:Name="textStack" Grid.Row="0" Grid.Column="1" Spacing="0">  
-                 <StackLayout HorizontalOptions="Center" Spacing="0">  
-                     <Label Text="BugSweeper" Font="Bold, Large" TextColor="Navy"/>  
-                     <BoxView Color="Orange" HeightRequest="3"/>  
-                 </StackLayout>  
-                 <Label Text="Tab to flag/unflag a potential bug" VerticalOptions="CenterAndExpand" HorizontalOptions="Center"/>  
-                 <Label Text="Double-tab if you're sure it's not a bug.  
-  The First Double tab be safe" VerticalOptions="CenterAndExpand" HorizontalOptions="Center"/>  
-                 <StackLayout Orientation="Horizontal" Spacing="0" VerticalOptions="CenterAndExpand" HorizontalOptions="Center">  
-                     <Label BindingContext="{x:Reference board}" Text="{Binding FlaggedTileCount,StringFormat='Flagged {0}'}"/>  
-                     <Label BindingContext="{x:Reference board}" Text="{Binding BugCount, StringFormat=' out of {0} bugs.'}"/>  
-                 </StackLayout>  
-   
-                 <Label x:Name="timeLabel" Text="0:00" VerticalOptions="CenterAndExpand" HorizontalOptions="Center"/>  
-             </StackLayout>  
-             <ContentView Grid.Row="1" Grid.Column="1" SizeChanged="OnBoardContentView_SizeChanged">  
-                 <Grid>  
-                     <Grid.RowDefinitions>  
-                         <RowDefinition Height="*"/>  
-                     </Grid.RowDefinitions>  
-                     <Grid.ColumnDefinitions>  
-                         <ColumnDefinition Width="*"/>  
-                     </Grid.ColumnDefinitions>  
-                     <local:Board x:Name="board"/>  
-                     <StackLayout x:Name="congratulationsText" Orientation="Horizontal" HorizontalOptions="Center" VerticalOptions="Center" Spacing="0">  
-                         <Label Text="C" TextColor="Black"/>  
-                         <Label Text="O" TextColor="Black"/>  
-                         <Label Text="N" TextColor="Black"/>  
-                         <Label Text="G" TextColor="Black"/>  
-                         <Label Text="R" TextColor="Black"/>  
-                         <Label Text="A" TextColor="Black"/>  
-                         <Label Text="T" TextColor="Black"/>  
-                         <Label Text="U" TextColor="Black"/>  
-                         <Label Text="L" TextColor="Black"/>  
-                         <Label Text="A" TextColor="Black"/>  
-                         <Label Text="T" TextColor="Black"/>  
-                         <Label Text="I" TextColor="Black"/>  
-                         <Label Text="O" TextColor="Black"/>  
-                         <Label Text="N" TextColor="Black"/>  
-                         <Label Text="S" TextColor="Black"/>  
-                         <Label Text="!" TextColor="Black"/>  
-                         <Label Text="!" TextColor="Black"/>  
-                      </StackLayout>  
-                     <StackLayout x:Name="consolationText" Orientation="Horizontal" Spacing="0" HorizontalOptions="Center" VerticalOptions="Center">  
-                         <Label Text="T" TextColor="Black"/>  
-                         <Label Text="O" TextColor="Black"/>  
-                         <Label Text="O" TextColor="Black"/>  
-                         <Label Text="L" TextColor="Black"/>  
-                         <Label Text="O" TextColor="Black"/>  
-                         <Label Text="S" TextColor="Black"/>  
-                         <Label Text="T" TextColor="Black"/>  
-                         <Label Text="!" TextColor="Black"/>  
-                         <Label Text=":" TextColor="Gray"/>  
-                         <Label Text=")" TextColor="Green"/>  
-                     </StackLayout>  
-                     <Button x:Name="playAgainButton" Text="Play Another Game?" VerticalOptions="Center" HorizontalOptions="Center" Clicked="onplayAgainButton_Clicked" BorderColor="Black" BorderWidth="2" BackgroundColor="White" TextColor="Blue"/>  
-                 </Grid>  
-             </ContentView>  
-               
-         </Grid>  
-                   
-     </ContentView>  
-   
- </ContentPage>  
 
 
![]()
Step 3
In this step, open Solution Explorer >> BugSweeper (PCL) >> MainPage.xaml.cs and double click to open MainPage.xaml.cs. Here is the code.
- using System;  
- using System.Collections.Generic;  
- using System.Linq;  
- using System.Text;  
- using System.Threading.Tasks;  
- using Xamarin.Forms;  
-   
- namespace BugSwapperApp  
- {  
-     public partial class MainPage : ContentPage  
-     {  
-         const string timeFormat = @"%m\:ss";  
-   
-         bool isGameInProgress;  
-         DateTime gameStartTime;  
-         public MainPage()  
-         {  
-             InitializeComponent();  
-   
-             board.GameStarted += (sender, args) =>  
-             {  
-                 isGameInProgress = true;  
-                 gameStartTime = DateTime.Now;  
-                 Device.StartTimer(TimeSpan.FromSeconds(1), () =>  
-                 {  
-                     timeLabel.Text = (DateTime.Now - gameStartTime).ToString(timeFormat);  
-                     return isGameInProgress;  
-                 });  
-             }; board.GameEnded += (sender, hasWon) =>  
-             {  
-                 isGameInProgress = false;  
-   
-                 if (hasWon)  
-                 {  
-                     DisplayWonAnimation();  
-                 }  
-                 else  
-                 {  
-                     DisplayLostAnimation();  
-                 }  
-             };  
-             PrepareForNewGame();  
-         }  
-         void PrepareForNewGame()  
-         {  
-             board.NewGameInitialize();  
-   
-             congratulationsText.IsVisible = false;  
-             consolationText.IsVisible = false;  
-             playAgainButton.IsVisible = false;  
-             playAgainButton.IsEnabled = false;  
-   
-             timeLabel.Text = new TimeSpan().ToString(timeFormat);  
-             isGameInProgress = false;  
-         }  
-   
-          void OnMainContentView_SizeChanged(object sender, EventArgs e)  
-         {  
-             ContentView contentView = (ContentView)sender;  
-             double width = contentView.Width;  
-             double height = contentView.Height;  
-   
-             bool isLandscape = width > height;  
-   
-             if (isLandscape)  
-             {  
-                 mainGrid.RowDefinitions[0].Height = 0;  
-                 mainGrid.RowDefinitions[1].Height = new GridLength(1, GridUnitType.Star);  
-   
-                 mainGrid.ColumnDefinitions[0].Width = new GridLength(1, GridUnitType.Star);  
-                 mainGrid.ColumnDefinitions[1].Width = new GridLength(1, GridUnitType.Star);  
-   
-                 Grid.SetRow(textStack, 1);  
-                 Grid.SetColumn(textStack, 0);  
-             }  
-             else   
-             {  
-                 mainGrid.RowDefinitions[0].Height = new GridLength(3, GridUnitType.Star);  
-                 mainGrid.RowDefinitions[1].Height = new GridLength(5, GridUnitType.Star);  
-   
-                 mainGrid.ColumnDefinitions[0].Width = 0;  
-                 mainGrid.ColumnDefinitions[1].Width = new GridLength(1, GridUnitType.Star);  
-   
-                 Grid.SetRow(textStack, 0);  
-                 Grid.SetColumn(textStack, 1);  
-             }  
-         }  
-   
-          void OnBoardContentView_SizeChanged(object sender, EventArgs e)  
-         {  
-             ContentView contentView = (ContentView)sender;  
-             double width = contentView.Width;  
-             double height = contentView.Height;  
-             double dimension = Math.Min(width, height);  
-             double horzPadding = (width - dimension) / 2;  
-             double vertPadding = (height - dimension) / 2;  
-             contentView.Padding = new Thickness(horzPadding, vertPadding);  
-         }  
-         async void DisplayWonAnimation()  
-         {  
-             congratulationsText.Scale = 0;  
-             congratulationsText.IsVisible = true;  
-   
-               
-               
-             double congratulationsTextWidth = congratulationsText.Measure(Double.PositiveInfinity, Double.PositiveInfinity).Request.Width;  
-   
-             congratulationsText.Rotation = 0;  
-             congratulationsText.RotateTo(3 * 360, 1000, Easing.CubicOut);  
-   
-             double maxScale = 0.9 * board.Width / congratulationsTextWidth;  
-             await congratulationsText.ScaleTo(maxScale, 1000);  
-   
-             foreach (View view in congratulationsText.Children)  
-             {  
-                 view.Rotation = 0;  
-                 view.RotateTo(180);  
-                 await view.ScaleTo(3, 100);  
-                 view.RotateTo(360);  
-                 await view.ScaleTo(1, 100);  
-             }  
-   
-             await DisplayPlayAgainButton();  
-         }  
-   
-         async void DisplayLostAnimation()  
-         {  
-             consolationText.Scale = 0;  
-             consolationText.IsVisible = true;  
-   
-               
-             double consolationTextWidth = consolationText.Measure(Double.PositiveInfinity, Double.PositiveInfinity).Request.Width;  
-   
-             double maxScale = 0.9 * board.Width / consolationTextWidth;  
-             await consolationText.ScaleTo(maxScale, 1000);  
-             await Task.Delay(1000);  
-             await DisplayPlayAgainButton();  
-         }  
-   
-         async Task DisplayPlayAgainButton()  
-         {  
-             playAgainButton.Scale = 0;  
-             playAgainButton.IsVisible = true;  
-             playAgainButton.IsEnabled = true;  
-   
-               
-             double playAgainButtonWidth = playAgainButton.Measure(Double.PositiveInfinity, Double.PositiveInfinity).Request.Width;  
-   
-             double maxScale = board.Width / playAgainButtonWidth;  
-             await playAgainButton.ScaleTo(maxScale, 1000, Easing.SpringOut);  
-         }  
-   
-   
-   
-          void onplayAgainButton_Clicked(object sender, EventArgs e)  
-         {  
-             PrepareForNewGame();  
-         }  
-     }  
- }  
 
 
![]() 
 Step 4
 
Open Solution Explorer >> BugSweeper(PCL) >> right click and select New Item. In this popup window, select Cross Platform >> Class.
This way, you can add a new class. Now, create a new class named Board.cs and double-click to get into its design view and insert the code given below.
- using System;  
- using System.Collections.Generic;  
- using System.Linq;  
- using System.Text;  
- using System.Threading.Tasks;  
- using Xamarin.Forms;  
-   
- namespace BugSwapperApp  
- {  
-     class Board : AbsoluteLayout  
-     {  
-         const int COLS = 9;           
-         const int ROWS = 9;          
-         const int BUGS = 10;  
-         Tile[,] tiles = new Tile[ROWS, COLS];  
-         int flaggedTileCount;  
-         bool isGameInProgress;                
-         bool isGameInitialized;               
-         bool isGameEnded;  
-   
-         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()  
-         {  
-               
-             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;  
-             }  
-         }  
-   
-   
-           
-         void DefineNewBoard(int tappedRow, int tappedCol)  
-         {  
-               
-             Random random = new Random();  
-             int bugCount = 0;  
-   
-             while (bugCount < BUGS)  
-             {  
-                   
-                 int row = random.Next(ROWS);  
-                 int col = random.Next(COLS);  
-   
-                   
-                 if (tiles[row, col].IsBug)  
-                 {  
-                     continue;  
-                 }  
-   
-                   
-                 if (row >= tappedRow - 1 &&  
-                     row <= tappedRow + 1 &&  
-                     col >= tappedCol - 1 &&  
-                     col <= tappedCol + 1)  
-                 {  
-                     continue;  
-                 }  
-   
-                   
-                 tiles[row, col].IsBug = true;  
-   
-                   
-                 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;  
-   
-               
-             if (!isGameInProgress)  
-             {  
-                 isGameInProgress = true;  
-   
-                   
-                 if (GameStarted != null)  
-                 {  
-                     GameStarted(this, EventArgs.Empty);  
-                 }  
-             }  
-   
-               
-             int flaggedCount = 0;  
-   
-             foreach (Tile tile in tiles)  
-                 if (tile.Status == TileStatus.Flagged)  
-                     flaggedCount++;  
-   
-             this.FlaggedTileCount = flaggedCount;  
-   
-               
-             Tile changedTile = (Tile)sender;  
-   
-               
-             if (tileStatus == TileStatus.Exposed)  
-             {  
-                 if (!isGameInitialized)  
-                 {  
-                     DefineNewBoard(changedTile.Row, changedTile.Col);  
-                     isGameInitialized = true;  
-                 }  
-   
-                 if (changedTile.IsBug)  
-                 {  
-                     isGameInProgress = false;  
-                     isGameEnded = true;  
-   
-                       
-                     if (GameEnded != null)  
-                     {  
-                         GameEnded(this, false);  
-                     }  
-                     return;  
-                 }  
-   
-                   
-                 if (changedTile.SurroundingBugCount == 0)  
-                 {  
-                     CycleThroughNeighbors(changedTile.Row, changedTile.Col,  
-                         (neighborRow, neighborCol) =>  
-                         {  
-                               
-                             tiles[neighborRow, neighborCol].Status = TileStatus.Exposed;  
-                         });  
-                 }  
-             }  
-   
-               
-             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 (hasWon)  
-             {  
-                 isGameInProgress = false;  
-                 isGameEnded = true;  
-   
-                   
-                 if (GameEnded != null)  
-                 {  
-                     GameEnded(this, true);  
-                 }  
-                 return;  
-             }  
-         }  
-     }  
- }  
 
 
![]() Step 5
 
Step 5
Now, we need to add images. For that, go to Solution Explorer >> BugSweeper(PCL) >> right-click on BugSweeper(PCL) project and select Add>> Existing Item. In this popup window, select images to insert and the images are used for tiles.
- BugSwapperApp.Microsoft.png  
- BugSwapperApp.Microsoft.png  
 
 
Step 6
In this step, similarly, create a new class named Tile.cs. Here is the code for this class.
- using System;  
- using System.Collections.Generic;  
- using System.Linq;  
- using System.Text;  
- using System.Threading.Tasks;  
- using Xamarin.Forms;  
-   
- namespace BugSwapperApp  
- {  
-     enum TileStatus  
-     {  
-         Hidden,  
-         Flagged,  
-         Exposed  
-     }  
-     class Tile : Frame  
-     {  
-         TileStatus tileStatus = TileStatus.Hidden;  
-         Label label;  
-         Image flagImage, bugImage;  
-         static ImageSource flagImageSource;  
-         static ImageSource bugImageSource;  
-         bool doNotFireEvent;  
-   
-         public event EventHandler<TileStatus> TileStatusChanged;  
-   
-         static Tile()  
-         {  
-             flagImageSource = ImageSource.FromResource("BugSwapperApp.Microsoft.png");  
-             bugImageSource = ImageSource.FromResource("BugSwapperApp.Xbox.png");  
-         }  
-   
-         public Tile(int row , int col)  
-         {  
-             this.Row = row;  
-             this.Col = col;  
-   
-             this.BackgroundColor = Color.Yellow;  
-             this.OutlineColor = Color.Blue;  
-             this.Padding = 2;  
-   
-             label = new Label  
-             {  
-                 Text = " ",  
-                 TextColor = Color.Yellow,  
-                 BackgroundColor = Color.Blue,  
-                 HorizontalTextAlignment = TextAlignment.Center,  
-                 VerticalTextAlignment = TextAlignment.Center,  
-             };  
-   
-             flagImage = new Image  
-             {  
-                 Source = flagImageSource,  
-   
-             };  
-   
-             bugImage = new Image  
-             {  
-                 Source = bugImageSource  
-             };  
-   
-             TapGestureRecognizer singleTap = new TapGestureRecognizer  
-             {  
-                 NumberOfTapsRequired = 1  
-             };  
-             singleTap.Tapped += OnSingleTap;  
-             this.GestureRecognizers.Add(singleTap);  
-             if (Device.OS != TargetPlatform.Windows && Device.OS != TargetPlatform.WinPhone)  
-             {  
-                 TapGestureRecognizer doubleTap = new TapGestureRecognizer  
-                 {  
-                     NumberOfTapsRequired = 2  
-                 };  
-                 doubleTap.Tapped += OnDoubleTap;  
-                 this.GestureRecognizers.Add(doubleTap);  
-   
-   
-             }  
-         }  
-   
-         public int Row { private set; get; }  
-   
-         public int Col { private set; get; }  
-   
-         public bool IsBug { set; get; }  
-   
-         public int SurroundingBugCount { set; get; }  
-   
-         public TileStatus Status  
-         {  
-             set  
-             {  
-                 if (tileStatus != value)  
-                 {  
-                     tileStatus = value;  
-   
-                     switch (tileStatus)  
-                     {  
-                         case TileStatus.Hidden:  
-                             this.Content = null;  
-  
- #if FIX_WINDOWS_PHONE_NULL_CONTENT  
-   
-                             if (Device.OS == TargetPlatform.WinPhone || Device.OS == TargetPlatform.Windows) {  
-                                 this.Content = new Label { Text = " " };  
-                             }  
-  
- #endif  
-                             break;  
-   
-                         case TileStatus.Flagged:  
-                             this.Content = flagImage;  
-                             break;  
-   
-                         case TileStatus.Exposed:  
-                             if (this.IsBug)  
-                             {  
-                                 this.Content = bugImage;  
-                             }  
-                             else  
-                             {  
-                                 this.Content = label;  
-                                 label.Text =  
-                                         (this.SurroundingBugCount > 0) ?  
-                                             this.SurroundingBugCount.ToString() : " ";  
-                             }  
-                             break;  
-                     }  
-   
-                     if (!doNotFireEvent && TileStatusChanged != null)  
-                     {  
-                         TileStatusChanged(this, tileStatus);  
-                     }  
-                 }  
-             }  
-             get  
-             {  
-                 return tileStatus;  
-             }  
-         }  
-   
-           
-         public void Initialize()  
-         {  
-             doNotFireEvent = true;  
-             this.Status = TileStatus.Hidden;  
-             this.IsBug = false;  
-             this.SurroundingBugCount = 0;  
-             doNotFireEvent = false;  
-         }  
-   
-   
-   
-         bool lastTapSingle;  
-         DateTime lastTapTime;  
-   
-   
-         void OnSingleTap(object sender, object args)  
-         {  
-   
-             switch (this.Status)  
-             {  
-                 case TileStatus.Hidden:  
-                     this.Status = TileStatus.Flagged;  
-                     break;  
-   
-                 case TileStatus.Flagged:  
-                     this.Status = TileStatus.Hidden;  
-                     break;  
-   
-                 case TileStatus.Exposed:  
-   
-                     break;  
-             }  
-         }  
-   
-         void OnDoubleTap(object sender, object args)  
-         {  
-             this.Status = TileStatus.Exposed;  
-         }  
-     }  
- }  
 
 
![]() 
  
Step 7
Click ' F5 ' or Build to run your projects. Running this project, you will have the result like below.
![]() 
  
 
Finally, we have successfully created a Xamarin.Forms BugSweeper Application.