Creating Tic-Tac-Toe in C# and Blazor WebAssembly
Tags: csharp, dotnet, tutorial, blazor
Published: 2020-06-25 17:37:03

Blazor WebAssembly was [released a little while ago](https://devblogs.microsoft.com/aspnet/blazor-webassembly-3-2-0-now-available/), and since I'm a fan of all things Blazor, I decided it might be a good time for another game post! 

In this post, we're going to build a working C# and Blazor WebAssembly application that can play the children's game [tic-tac-toe](https://en.wikipedia.org/wiki/Tic-tac-toe). Let's get going!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vbg6vbv5qvzgzmw6erfz.jpg)<figcaption>Watch your fingers!  Photo by [Viktor Talashuk](https://unsplash.com/@viktortalashuk?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit) / [Unsplash](https://unsplash.com/?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit)</figcaption>

##The Sample Project
As always, there's [a sample project on GitHub](https://github.com/exceptionnotfound/BlazorWasmTicTacToe) to go along with this post. Check it out, and pull requests are welcome!

##Requirements
To develop in Blazor WebAssembly, we need to download the .NET Core SDK from [this page](https://dotnet.microsoft.com/download).

You can also use Visual Studio 16.6, Visual Studio Code with the C# extension, or Visual Studio Mac to develop using Blazor WebAssembly. For this project, I used the full Visual Studio.

##Creating the Project
*The screenshots below are from Visual Studio 2019 v16.6; your process to set up a new Blazor WebAssembly project may be different.*

Let's create a new project! In Visual Studio, navigate to File -> New -> Project and select Blazor App: 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/um70vjxljb95n8bh8kr1.png)

On the next screen, name your project and solution and specify the directory you want to use, then press Create:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/owcrup3xu4ugg81wfaw7.png)

Finally, select "Blazor WebAssembly App":

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/srsili67wlct5xcivh1j.png)

The resulting project's file directory will look something like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3xnukmkp6lqo3y2dwago.png)

If we run the app, we see that we have a fully-functional Blazor application:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mtfnrsfzb5u6ff4zrj0w.png)

Ta-da! We're on our way! Now let's start the hard part: modeling a tic-tac-toe game.

##Tic, Tac, Toe, Won!
We're going to take a lot of cues from [one of my earlier posts about modeling Connect Four in Blazor](https://exceptionnotfound.net/learning-blazor-by-building-connect-four-in-asp-net-core/).

Before we can write our code, let's first think about the kinds of things (or "models") a game of tic-tac-toe has.

It has a game board, which might look like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/yqleb6adwmdd0o9t831k.png)

Such a board has nine spaces on which a player can draw an X or an O. 

We also consider the X's and O's themselves. For this demo, we'll call them "Game Pieces" and think of them like tokens you place on the board. So, we'll need a class to model them.

Finally, we need trackers for when the game is won, or if the game is a draw. 

Let's get modeling!

##Board to Pieces

Let's start with the game pieces, i.e. the X's and O's. The only distinguishing characteristic of these pieces is that each has a letter associated. Let's create an enumeration for those letters, and a class for the pieces.

```csharp
public enum PieceStyle
{
    X,
    O,
    Blank
}

public class GamePiece
{
    public PieceStyle Style;

    public GamePiece()
    {
        Style = PieceStyle.Blank;
    }
}
```

Let's also start modeling a class for the game board:

```csharp
public class GameBoard
{
    //A 2D array of game pieces, 
    //expected to blank at the beginning of the game.
    public GamePiece[,] Board { get; set; }

    public PieceStyle CurrentTurn = PieceStyle.X;

    public GameBoard()
    {
        Reset();
    }
}
```

Note the constructor method, and the *Reset()* method called by it. All this method does is reset every space to blank:

```csharp
public void Reset()
{
    Board = new GamePiece[3, 3];

    //Populate the Board with blank pieces
    for (int i = 0; i <= 2; i++)
    {
        for (int j = 0; j <= 2; j++)
        {
            Board[i, j] = new GamePiece();
        }
    }
}
```

But now we start the real work: how do we model a game being played?

##Children, Take Turns!

Let's consider the kinds of steps we need to take to model a game of tic-tac-toe in progress. 

We need to track whose turn it is. In our *GameBoard* class, we can do this by using a property *CurrentTurn*, and a method *SwitchTurns()*:

```csharp
public class GameBoard
{
    //...Other Properties

    public PieceStyle CurrentTurn = PieceStyle.X;
    
    private void SwitchTurns()
    {
        //This is equivalent to: if currently X's turn, 
        // make it O's turn, and vice-versa
        CurrentTurn = 
            CurrentTurn == PieceStyle.X ? PieceStyle.O : PieceStyle.X;
    }
}
```

We also need a method to represent a turn being taken. On a player's turn, they will click an empty space and place their marker (X or O) on that space. However, they shouldn't be able to click any spaces in two conditions:

1. The space is already occupied OR
2. The game is complete.

Let's deal with the second condition first. We can use a new property to check if the game is complete:

```csharp
public class GameBoard 
{
    //...Other Properties
    
    public bool GameComplete => GetWinner() != null || IsADraw();
    
    //...Other Methods
}
```

We will implement the methods *GetWinner()* and *IsADraw()* later. The main thing to take away from this is that the game is complete when either a winner is declared or a draw occurs.

Now we can write a method to allow players to "claim" spaces, which also includes a check to make sure that they aren't already claimed:

```csharp
public class GameBoard 
{
    //...Other Properties and Methods

    //Given the coordinates of the space that was clicked...
    public void PieceClicked(int x, int y)
    { 
        //If the game is complete, do nothing
        if (GameComplete) { return; }

        //If the space is not already claimed...
        GamePiece clickedSpace = Board[x, y];
        if (clickedSpace.Style == PieceStyle.Blank)
        {
            //Set the marker to the current turn marker (X or O)
            clickedSpace.Style = CurrentTurn;
            
            //Make it the other player's turn
            SwitchTurns();
        }
    }
}
```

That's all the code we need for our tic-tac-toe players to take turns! Now let's deal with some other scenarios.

##3, 2, 1... Draw!

*NOTE: The code in this section and the next was originally submitted by [John Tomlinson](https://github.com/johnt84) and modified by me.*

It's possible (and if the players are older than five, likely) that a tic-tac-toe game will end in a draw. A "draw" occurs when all spaces are occupied and no winner can be found. So, let's create a method to watch for this situation. 

```csharp
public class GameBoard 
{
    public bool IsADraw()
    {
        int pieceBlankCount = 0;

        //Count all the blank spaces. 
        //If the count is 0, this is a draw.
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                pieceBlankCount = this.Board[i, j].Style == PieceStyle.Blank
                                    ? pieceBlankCount + 1
                                    : pieceBlankCount;
            }
        }

        return pieceBlankCount == 0;
    }
}
```

##The Only Winning Move is Not to Play
Now we come to the most complex of the scenarios we're going to be dealing with: how do we determine if a game has been won?

The method to check this is going to be brute-force: for each space on the board, check each possible direction for matching pieces, and if you find three in a row, stop checking.

First, let's implement an enumeration to show the directions from which we will look for tic-tac-toes:

```csharp
public enum EvaluationDirection
{
    Up,
    UpRight,
    Right,
    DownRight
}
```

The method to do this for a single given space looks like this:

```csharp
public class GameBoard
{
    //...Other Properties and Methods
 
    private WinningPlay EvaluatePieceForWinner(int i, int j, 
                                               EvaluationDirection dir)
    {
        GamePiece currentPiece = Board[i, j];
        if (currentPiece.Style == PieceStyle.Blank)
        {
            return null;
        }

        int inARow = 1;
        int iNext = i;
        int jNext = j;

        var winningMoves = new List<string>();

        while (inARow < 3)
        {
            //For each direction, increment the pointers 
            //to the next space to be evaluated
            switch (dir)
            {
                case EvaluationDirection.Up:
                    jNext -= 1;
                    break;
                case EvaluationDirection.UpRight:
                    iNext += 1;
                    jNext -= 1;
                    break;
                case EvaluationDirection.Right:
                    iNext += 1;
                    break;
                case EvaluationDirection.DownRight:
                    iNext += 1;
                    jNext += 1;
                    break;
            }
            
            //If the next "space" is off the board, 
            //don't check it.
            if (iNext < 0 || iNext >= 3 
                || jNext < 0 || jNext >= 3) { break; }
            
            //If the next space has a matching letter...
            if (Board[iNext, jNext].Style == currentPiece.Style)
            {
                //Add this space to the collection 
                //of winning spaces.
                winningMoves.Add($"{iNext},{jNext}");
                inARow++;
            }
            else //Otherwise, no tic-tac-toe is found 
                 //for this space/direction
            {
                return null;
            }
        }

        //If we found three in a row
        if (inARow >= 3)
        {
            //Return this set of spaces as the winning set
            winningMoves.Add($"{i},{j}");

            return new WinningPlay()
            {
                WinningMoves = winningMoves,
                WinningStyle = currentPiece.Style,
                WinningDirection = dir,
            };
        }

        //If we got here, we didn't find any tic-tac-toes 
        //for the given space.
        return null;
    }
}
```

But that method only evaluates for a single space; now we need a method to do that for *all* spaces.

```csharp
public class GameBoard
{
    public WinningPlay GetWinner()
    {
        WinningPlay winningPlay = null;

        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                foreach (EvaluationDirection evalDirection in (EvaluationDirection[])Enum.GetValues(typeof(EvaluationDirection)))
                {
                    winningPlay = EvaluatePieceForWinner(i, j, evalDirection);
                    if (winningPlay != null) { return winningPlay; }
                }
            }
        }

        return winningPlay;
    }
}
```

*The above code is the "brute force" I mentioned earlier: a triple-nested loop!*

##A Couple of Extras
Finally, let's implement two more methods: one which gets a message to display the user when the game is won or drawn, and one to check for those situations so we can display the message.

```csharp
public class GameBoard
{
    public string GetGameCompleteMessage()
    {
        var winningPlay = GetWinner();
        return winningPlay != null 
               ? $"{winningPlay.WinningStyle} Wins!" : "Draw!";
    }

    public bool IsGamePieceAWinningPiece(int i, int j)
    {
        var winningPlay = GetWinner();
        return winningPlay?.WinningMoves?
                           .Contains($"{i},{j}") ?? false;
    }
}
```

With that, our GameBoard class is complete! Now we just need to use it on a razor component.

##The Component of Your Doom
Here's a basic razor component (which is what Blazor calls the .razor files) that we will modify to host our tic-tac-toe game.

```html
@page "/tictactoe"
@using BlazorWasmTicTacToe.Models;

<h1>Tic-Tac-Toe</h1>

@code {
    GameBoard board = new GameBoard();
}
```

First, let's write the markup for the board itself.

```html
<div class="board">
    @for (int i = 0; i < 3; i++)
    {
        <div class="column">
            @for (int j = 0; j < 3; j++)
            {
                int x = i;
                int y = j;
                <div class="gamepiece
                         @board.Board[i,j].Style.ToString().ToLower()" 
                         @onclick="@(() => board.PieceClicked(x,y))"
                         style="@(board.IsGamePieceAWinningPiece(i, j)
                                  ? "opacity: 0.6" : "")"></div>
            }
        </div>
    }
</div>
```

Note that the div with class "gamepiece" has styles dynamically applied to it when it is occupied by a letter and when it is part of the winning tic-tac-toe.

The last little piece is to output a message for wins and draws.

```html
@if (!board.GameComplete)
{
    <h2>@board.CurrentTurn's Turn!</h2>
}
else
{
    <h2>@board.GetGameCompleteMessage() 
        <button class="btn btn-success" 
                @onclick="@(() => board.Reset())">
            Reset
        </button>
    </h2>
}
```

And with that, we have a working tic-tac-toe game written in C# and Blazor WebAssembly!

##GIF Time!

Here's how our tic-tac-toe game looks:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/w3nbt4eim7xxrpelaxis.gif)

Turned out pretty well, if I do say so myself! But you don't have to believe me, because you can [check out the sample project over on GitHub](https://github.com/exceptionnotfound/BlazorWasmTicTacToe).

##Summary
Building a sample Blazor WebAssembly project with C# isn't too hard at all! Just remember that you need very up-to-date IDEs (VS 2019 or VS Code) and to [download the SDK from Microsoft's site](https://dotnet.microsoft.com/download/dotnet-core/3.1). 

I love the fact that I can write C# and it can be turned into a fully client-side application! So much that I am proud to say:

> "Cheers to the coming death of JavaScript!"

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mxqg8676c3pqonpfb7nq.jpg)<figcaption>Photo by [Kelsey Knight](https://unsplash.com/@kelsoknight?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit) / [Unsplash](https://unsplash.com/?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit)</figcaption>

Well, actually, that might be a bit too much. It's probably more like:

> "Here's to the mild annoyance of JavaScript developers!"

Yeah, that sounds right.

Thanks for reading, and Happy Coding!