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. If you wish to contribute to this project by adding new styles/ validations, you can head over to my github repository.


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 name to the app? How about "Blazing Tic Tac Toe''? Very thoughtful, I know!

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.
 


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.


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 file where it says @code {, click the bulb icon or simply click (Ctrl + '.') then select "Extract block to code behind", refer figure 3.


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 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, lets call it "board".
  • string variable: to represent 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 winningCombos

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 winningCombos to check if our board[] has met the winning combination. if yes we are going to show 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 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 how we call javascript methods using JSRuntime. 

There are 2 scenarios when we are calling JS, 

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

First and foremost, go to wwwroot, and create a new folder named "js", inside the folder add 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 parameter, so JsRuntime looks for the same method that we specify as parameter.
  • ShowTie, representing the tie, in code snippet 2 at line number 41, we are specifying this method name as 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 actually 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, here you have to give the same name as your razor file. For our example we will name Index.razor.css, refer image below.


Figure 4: Adding component specific CSS

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


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 few snaps in action.

Alright! that's all you had to do. Use this project to understand some basic 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 Blazor app, 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: Source code is attached for your reference, download from here. or jump to the github repository to add new changes if you want to collaborate with me on this. 

Cheers,

Rikam.

Similar Articles