Introduction
Tic Tac Toe is a popular game that has been enjoyed for generations, on the other hand, our generation enjoys AI. It's about time we clash them together. In this article, we will be designing Tic Tac Toe in Blazor and developing AI-driven game logic with the Min Max algorithm, an artificial intelligence algorithm used for game decision-making.
![Step-by-Step Guide to develop Tic-Tac-Toe AI with Blazor]()
What is the Min Max Algorithm?
The Min Max algorithm is used to design digital board games like chess and checkers to help determine the best possible move for a player. The algorithm works by evaluating all possible moves a player can make and predicting the best outcome of each move.
To begin with, let me lay down the steps:
- Create a new Blazor application.
- Create a new component called "TicTacToe".
- Iterate div tags under 2 for loops to create a 3x3 matrix
- Create a char array of 3x3 to support matrix data, and create a list of winning combinations
- Add a method that will be called when the user clicks on a cell in the grid
- Design a MinMax algorithm to suggest the next possible best move
- Use the MinMax algorithm with the Blazor app to predict the next best move for AI
- Check if the cell is already occupied. If it is, return
- Call the MinMax algorithm to get the next best move
- Update the cell with the current player's mark (X or O).
- Check if the game has been won or if it is a tie.
- If the game is finished, show animation with JavaScript and reset the grid.
- Repeat the above steps until the game is won or a tie is reached.
Let's take a closer look at each of these steps.
Step 1. Create a new Blazor application
To create a new Blazor application, open Visual Studio and select "Create a new project". In the "Create a new project" dialog, select "Blazor WebAssembly App" or "Blazor Server App" and click "Next".
![Step-by-Step Guide to develop Tic-Tac-Toe AI with Blazor]()
Give your project a name and click "Create".
![Step-by-Step Guide to develop Tic-Tac-Toe AI with Blazor]()
Step 2. Add a new razor component called "TicTacToe"
To add a new component, right-click on the project, select "Add" then select "New item", which will bring the dialog below, then select "Razor component", give it a name, and click on the "Add" button.
![Step-by-Step Guide to develop Tic-Tac-Toe AI with Blazor]()
Step 3. Iterate div tags under 2 for loops to create a 3x3 matrix
In the "TicTacToe" component, add the following HTML to create a 3x3 grid:
Listing 1: TicTacToe.razor (HTML)
Step 4. Create a char array of 3x3 to support matrix data and create a list of winning combinations
Create an empty char array, "Board", and create a char to represent a "Player", There are 8 possible winning combos, create a list of "WinningCombos"
@code {
char[,] Board = { { ' ', ' ', ' ' }, { ' ', ' ', ' ' }, { ' ', ' ', ' ' } };
char Player = 'o';
List<List<int[]>> WinningCombos = new()
{
new List<int[]>() {new int[] { 0,0 }, new int[] { 0, 1 }, new int[] { 0, 2} },
new List<int[]>() {new int[] { 1,0 }, new int[] { 1, 1 }, new int[] { 1, 2} },
new List<int[]>() {new int[] { 2,0 }, new int[] { 2, 1 }, new int[] { 2, 2} },
new List<int[]>() {new int[] { 0,0 }, new int[] { 1, 0 }, new int[] { 2, 0} },
new List<int[]>() {new int[] { 0,1 }, new int[] { 1, 1 }, new int[] { 2, 1} },
new List<int[]>() {new int[] { 0,2 }, new int[] { 1, 2 }, new int[] { 2, 2} },
new List<int[]>() {new int[] { 0,0 }, new int[] { 1, 1 }, new int[] { 2, 2} },
new List<int[]>() {new int[] { 0,2 }, new int[] { 1, 1 }, new int[] { 2, 0} },
};
}
Listing 2: TicTacToe.razor (C#)
Step 5. Add a method that will be called when the user clicks on a cell in the grid
Listing 3: TicTacToe.razor (C#)
Step 6. Design a MinMax algorithm to suggest the next possible best move
Let's write the algorithm in a separate file. Right-click on project > add a folder, name "AI," then add a C# file inside the folder, name it "MinMaxAlgorithm.cs"
namespace BlazingTicTacToe.AI
{
public class MinMaxAlgorithm
{
public class Turn
{
public int row, col;
};
private static readonly char Player = 'x';
private static readonly char Opponent = 'o';
private static readonly char EmptyCell = ' ';
static bool AreMoveLeft(char[,] board)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (board[i, j] == EmptyCell)
{
return true;
}
}
}
return false;
}
static int GetCurrentScore(char[,] board)
{
for (int i = 0; i < 3; i++)
{
if (board[i, 0] == board[i, 1] && board[i, 1] == board[i, 2])
{
if (board[i, 0] == Player)
{
return +10;
}
else if (board[i, 0] == Opponent)
{
return -10;
}
}
}
for (int j = 0; j < 3; j++)
{
if (board[0, j] == board[1, j] && board[1, j] == board[2, j])
{
if (board[0, j] == Player)
{
return +10;
}
else if (board[0, j] == Opponent)
{
return -10;
}
}
}
if (board[0, 0] == board[1, 1] && board[1, 1] == board[2, 2])
{
if (board[0, 0] == Player)
{
return +10;
}
else if (board[0, 0] == Opponent)
{
return -10;
}
}
if (board[0, 2] == board[1, 1] && board[1, 1] == board[2, 0])
{
if (board[0, 2] == Player)
{
return +10;
}
else if (board[0, 2] == Opponent)
{
return -10;
}
}
return 0;
}
static int ComputeMinMax(char[,] board, int depth, bool isMax)
{
int score = GetCurrentScore(board);
if (score == 10) return score;
if (score == -10) return score;
if (AreMoveLeft(board) == false) return 0;
if (isMax)
{
int bestValue = -1000;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (board[i, j] == EmptyCell)
{
board[i, j] = Player;
bestValue = Math.Max(bestValue, ComputeMinMax(board, depth + 1, !isMax));
board[i, j] = EmptyCell;
}
}
}
return best;
}
else
{
int bestValue = 1000;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (board[i, j] == EmptyCell)
{
board[i, j] = Opponent;
bestValue = Math.Min(bestValue, ComputeMinMax(board, depth + 1, !isMax));
board[i, j] = EmptyCell;
}
}
}
return bestValue ;
}
}
public static Turn GetNextBestMove(char[,] board)
{
int bestValue = -1000;
Turn bestTurn = new()
{
row = -1,
col = -1
};
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (board[i, j] == EmptyCell)
{
board[i, j] = Player;
int currentTurnValue = ComputeMinMax(board, 0, false);
board[i, j] = EmptyCell;
if (currentTurnValue > bestValue)
{
bestTurn.row = i;
bestTurn.col = j;
bestValue = currentTurnValue;
}
}
}
}
return bestTurn;
}
}
}
Listing 4: MinMaxAlgorithm.cs
Step 7. Use the MinMax algorithm to predict the next best move for AI and Update the cell with the current player's mark (X or O)
Listing 5: TicTacToe.razor, SquareClick method (C#)
Add a few helper methods to reset the game.
Listing 5: TicTacToe.razor, helper methods (C#)
The JavaScript
You must wonder what those statements are in listing 5 > line numbers 19 and 27. 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 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 to show a sweet alert. In code snippet 2 at line 34, we mention this method name as a parameter, so JsRuntime looks for the same method 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.
Listing 6: 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.
Listing 7: 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. 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 TicTacToe.razor.css, refer image below.
![]()
Now you will see how newly added CSS is automatically assigned below the razor component.
![]()
Here is the CSS with basic properties with flex and hover.
Listing 8: TicTacToe.razor.css
Conclusion
I believe, Implementing the Tic Tac Toe game using the Min Max algorithm in Blazor was a great learning experience. This algorithm is widely used in game development and can help you create more intelligent and challenging games.
Blazor provides an excellent platform to implement this game as it uses C# language to write the code, making it easier for most developers. It also allows you to create interactive UI and responsive web applications using HTML, CSS, and JavaScript.