Create A Tic-Tac-Toe Game In Blazor

Let me begin this article with good news! Mahesh & I have recently released a book on WPF & C#, It has everything that you need to build an industry-level application in WPF. 

You can get your copy here => WPF SIMPLIFIED

Now back to our game: Here is the demo of the game that we are going to build in this article.

Animation of Blazing Tic Tac Toe
Blazing Tic Tac Toe

There are 2 ways to achieve this we can go full-fledged on CSS or we can write logic in C#. Well, I prefer C#. The reason is I want to demonstrate how JavaScript can be integrated with Blazor.

Before we jump into the topic let's give some cool names to the app. How about "Blazing Tic Tac Toe''? Very thoughtful, I know!

Watch Detailed Video

What do we need to build a Tic Tac Toe?

Let me give you a 50,000 feet overview. We need a razor component, CSS, C# code behind, and one JS file to deal with you know JavaScript stuff. That's all.

Note: JavaScript files go into wwwroot folder.
 

File structure for 'Blazing Tic Tac Toe
Figure 1: File structure for "Blazing Tic Tac Toe"

Step 1: Crack open Visual Studio and select Blazor WebAssembly App, as shown in Figure 2.

Creation of 'Blazor WebAssembly App
Figure 2: Create "Blazor WebAssembly App"

Index.razor

First, let's push all code behind in a separate file AKA into Index.razor.cs. Here is a simple trick to achieve that.

  • You will find there is a section of the file where it says @code {, click the bulb icon or simply click (Ctrl + '.') then select "Extract block to code behind", refer to figure 3.

Extract block to code behind
Figure 3: Extract block to code behind

Now Index.razor will only have a UI component and all the game logic will be written in code-behind file Index.razor.cs.

  • On line number 2, we are injecting IJSRuntime, we are gonna use that later in our logic to call JavaScript methods.
  • We need to add 9 boxes on the screen. We can simply do this with a for loop. create one div loop through 9 times.
    • Note: On line number 7, we are looping through the array named as "board". The board is a string array which going to hold either "X" or "O". It will be clear once we jump into the actual code.
  • There is an OnClick event on line number 11, this tells us which box has been selected. We need this index to keep a track of winning combinations. 
@page "/"
@inject IJSRuntime JS

<div>
    <h1>Blazing Tic Tac Toe</h1>
    <div class="board">
        @for(int i=0; i< board.Length; i++)
        {
            int idx = i;
            <div class="square"
                 @onclick="()=> SquareCliked(idx)">
                 <h5 class="char">@board[i]</h5>
             </div>
        }
    </div>
</div>

Code snippet 1: Index.razor

Now the actual bread and butter of the game. The logic

Index.razor.cs

Ingredients

  • string[] array: to hold values of 9 boxes, let's call it "board".
  • string variable: to represent a symbol that either could be "X" or "O", let's call it player
  • Jagged Array[][] to store winning combinations: there are only 8 combinations to win the game, we can simply hardcode these values. let's call it winning combos

The Logic

Now that we have our material, we need to create a method named SquareCliked, which is the OnClick event's handler. From code snippet 1, line number 11.

All we have to do is loop through winning combos to check if our board[] has met the winning combination. if yes we are going to show a nice alert using javascript.

We also need to reset the game once the game is finished. simply reset the board[] array.

Before we jump to the javascript, let me give you the logic for the game.

using Microsoft.JSInterop;
namespace BlazingTicTacToe.Pages
{
    public partial class Index
    {
        string[] board = { "", "", "", "", "", "", "", "", "" };
        string player = "X";
        int[][] winningCombos =
        {
            new int[3] {0,1,2},
            new int[3] {3,4,5},
            new int[3] {6,7,8},
            new int[3] {0,3,6},
            new int[3] {1,4,7},
            new int[3] {2,5,8},
            new int[3] {0,4,8},
            new int[3] {2,4,6}
        };

        private async Task SquareCliked(int idx)
        {
            board[idx] = player;
            player = player == "X" ? "O" : "X";

            foreach (int[] combo in winningCombos)
            {
                int p1 = combo[0];
                int p2 = combo[1];
                int p3 = combo[2];
                if (board[p1] == String.Empty || board[p2] == String.Empty || board[p3] == String.Empty) continue;
                if (board[p1] == board[p2] && board[p2] == board[p3] && board[p1] == board[p3])
                {
                    string winner = player == "X" ? "Player TWO" : "Player ONE";
                    await JS.InvokeVoidAsync("ShowSwal", winner);
                    ResetGame();
                }
            }

            if (board.All(x => x != ""))
            {
                await JS.InvokeVoidAsync("ShowTie");
                ResetGame();
            }
        }

        private void ResetGame()
        {
            for (int i = 0; i < board.Length; i++)
            {
                board[i] = "";
            }
        }
    }
}

Code snippet 2: Index.razor.cs

The JavaScript

You must be wondering what are those things on line number 34 and 41. well, that's what we call javascript methods using JSRuntime. 

There are 2 scenarios when we are calling JS, 

  • When either Player 1 or 2 wins.
  • If the game is tied.

First and foremost, go to wwwroot, and create a new folder named "js", inside the folder add a new javascript file, name it common.js

There are 2 methods,

  • ShowSwal, means, show sweet alert, in code snippet 2 at line number 34, we are mentioning this method name as a parameter, so JsRuntime looks for the same method that we specify as a parameter.
  • ShowTie, representing the tie, in code snippet 2 at line number 41, we are specifying this method name as a parameter.
window.ShowSwal = (player) => {
    Swal.fire({
        title: player + ' won!!',
        width: 350,
        padding: '3em',
        color: '#716add',
        backdrop: `
                        rgba(0,0,123,0.4)
                        url("/images/nyan-cat-nyan.gif")
                        left top
                        no-repeat
                      `
    })
}
window.ShowTie = () => {
    Swal.fire({
        title: 'Go home, nobody won!',
        width: 350,
        padding: '3em',
        color: '#716add',
        backdrop: `
                        rgba(0,0,123,0.4)
                        url("/images/crying-tear.gif")
                        left top
                        no-repeat
                      `
    })
}

Code snippet 3: common.js

Now let's integrate JavaScript with Blazor app.

Open Index.html under wwwroot folder. and inside a head tag add these 3 script tags.

<script src="js/common.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="sweetalert2.min.js"></script>

Code snippet 4: Adding Sweet alert CDN to project.

To show you the right placement here is the entire index.html, this is how it is supposed to look after you've done the modification. follow line number 13,14 and 15 in below snippet.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>BlazingTicTacToe</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
    <link href="BlazingTicTacToe.styles.css" rel="stylesheet" />
    <link rel="stylesheet" href="sweetalert2.min.css">
    <script src="js/common.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
    <script src="sweetalert2.min.js"></script>
</head>

<body>
    <div id="app">Loading...</div>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
</body>

</html>

Code snippet 5: Index.html

The CSS

we are almost done, but it's not done unless we have some CSS right? if you remember for code snippet 1, we have added a bunch of classes to our divs. let's code those classes in a separate CSS file. 

Here is the trick to create a razor-specific css file. simply click on the folder named "pages" and say "Add new item" then select Style Sheet, you have to give the same name as your razor file. For our example, we will name Index.razor.css, refer image below.

Adding component specific CSS
Figure 4: Adding component-specific CSS

now you will see how newly added CSS is automatically assigned right below the razor component. 

Component specific CSS
Figure 5: Component-specific CSS

Here is the css with basic properties with flex and hover.

* {
    padding: 0;
    margin: 0;
    font-family: 'Itim', cursive;
}

h1 {
    text-align: center;
    margin-bottom: 10px;
}

.board {
    width: 33rem;
    height: 31rem;
    margin: auto;
    border: 1px solid white;
    display: flex;
    flex-wrap: wrap;
}

.square {
    width: 10rem;
    height: 10rem;
    border: 1px solid white;
    margin-right: 4px;
    border-radius: 30px;
    background: #78bec5;
    opacity: 80;
}

    .square:hover {
        background: #ecaf4f;
        cursor: pointer;
    }

.char {
    font-size: 5rem;
    text-align: center;
    font-weight: 800;
    margin-top: 15%;
    color: #dc685a;
}

Code snippet 6: Index.razor.css

Let's see a few snaps in action.

Alright! That's all you had to do. Use this project to understand some fundamentals of Blazor's working model.

Conclusion

Now we know how to develop a small game such as this, we learned how to integrate JavaScript into the Blazor app, and now we know how to add code behind and CSS into separate files rather than messing it all up in a single razor file. I hope you enjoyed the show.

Note: The source code is attached for your reference, download it from the top of this article.

Cheers,


Similar Articles