A Gomoku AI that uses various AI algorithm and evaluates the game under rules and give optimized result.
DEMO LINK! => Gomoku AI
This project is built in .NET 8, with two API endpoints that receives 2D Board, Depth/Iteration, and Rule. The project implements a Gomoku (also known as Five in a Row) game with following AI algorithms for move evaluation and selection:
- Monte Carlo Tree Search and Priority
- Minimax, Alpha-beta puring, and Heuristic Scoring
It also utilizes at least one of the following rules:
- Free Style Rule
- Renju Rule
[https://en.wikipedia.org/wiki/Gomoku#Variants] <= Learn More about rules!
Followings are the core components:
-
AIModels
- HMA-B/: Includes logics and behaviours of Minimax Algorithm along with Alpha-beta puring with Heuristic scoring.
- MCTS/: Includes logics and behaviours of Monte carlo tree search based on prioritized moves.
-
RuleModels/ (Game Logic and AI)
- Provides all the logic for Free Style Rule as well as Renju Rule (e.g., forbidden moves such as overlines, double threes, double fours, etc.)
- Checks for a winner, counts consecutive stones, and so on.
-
Models
- Defines the shape of the incoming request body (
List<List<int>> Boardfor overall board,Depthfor Minimax search depth and number of Monte Carlo Tree Search iteration).
- Defines the shape of the incoming request body (
-
The client (or another application) sends a POST request to either:
/api/gomoku/minimax-moveendpoint for Minimax./api/gomoku/minimax-moveendpoint for Monte Carlo Tree Search.
-
The request must include a JSON body matching InputModel, which contains:
- A 2D list (
List<List<int>>) representing the board:- 0 indicates an empty cell.
- 1 indicates a Black stone.
- -1 indicates a White stone.
- An integer
Depthused to potentially set:- The search depth for Minimax.
- The iteration for Monte Carlo Tree Search
- A 2D list (
-
Based on the counts of Black (
1) and White (-1) stones from the board, it automatically determines whose turn it is:- For any invalid or complete game, it returns (
x: -1, y: -1) with message and other params indicating it. - If there are more Black stones than White stones, it’s White’s turn (
-1). - Otherwise, it’s Black’s turn (
1).
- For any invalid or complete game, it returns (
The endpoint will return BadRequest under following conditions:
- If the board is null or empty
- If the board dimensions are smaller than 7×7
- If the board isn't rectangular
- If the board contains invalid values (anything other than
0,1, or-1) - If the difference between the number of Black and White stones exceeds
1 - If Black has made a forbidden move according to Renju rules
- If the code detects multiple winners simultaneously
- Check for a winner
- Uses
HasWinnerto see if there is exactly one winner. If a winner is found, returns an Ok with winner's number (1for Black,-1for White) with"Black Wins 🎉"or"White Wins 🎉".
- Uses
- Check for draw
- If every cell is occupied and no winner is found, returns an Ok with
"It's a Draw 🤝".
- If every cell is occupied and no winner is found, returns an Ok with
- Run AI
- If the game is valid and ongoing, based on the API endpoint, the code runs either Minimax or Monte Carlo Tree Search logic with the appropriate player assignments (AI vs Human).
- Then it performs followings:
- Minimax: It runs
GetBestMoveto run Minimax move - Monte Carlo Tree Search: It runs
Searchto run MCTS move
- Minimax: It runs
- Both returns
Movefor the best cell to place the next stone.
Description:
For both endpoints, given a Board, Depth, and RuleType, returns either:
- An error describing why the request is invalid, or
- The best move for the next player (or a game over/draw response).
- Board: A 2D array of integers.
- 0 = Empty cell
- 1 = Black stone
- -1 = White stone
- Depth: An integer controlling either the Minimax depth or a number of iterations for MCTS
On success (and the game still in progress):
{
Status: "Playing",
X: 5,
Y: 3,
Color: "Black", // or "White"
Message: "Playing"
}If the game is already won:
{
Status: "Win",
X: 2,
Y: 6,
Color: "White", // always AI's color
Message: "White Wins 🎉"
}If the game is a draw:
{
Status:"'Draw",
X: -1,
Y: -1,
Color: "White", // always AI's color
Message: "It's a Draw 🤝"
}On invalid board:
{
Status: "Error",
X: -1,
Y: -1,
Color: "White", // always AI's color
Message: "Invalid board values. Only 0 (empty), 1 (black), and -1 (white) are allowed."
}(Or another relevant message explaining the specific issue.)
Run from Visual Studio
Double-click the .sln file to open it in Visual Studio. In Solution Explorer, right-click on the project that you want to run (the one containing your Program.cs) and choose Set as Startup Project. Press F5 (or click the green "Start Without Debugging" button) to build and run the project.
- Black plays first, then white plays. Both players take turn until either one of the player connects more than 5 lines or the board is full, which is draw.
- There is no restriction for both Black and White players.
-
Forbidden Moves for Black:
- Overline (more than 5 in a row, e.g., 6, 7, ...).
- Double-Three (a move that simultaneously creates two (or more) open three patterns).
- Double-Four (a move that simultaneously creates two (or more) four-in-a-row patterns).
-
White has no forbidden moves.
-
When Black violates any forbidden move condition, the game state is considered invalid in this API’s context, and a BadRequest is returned.
{ "Board": [ [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, -1, 0, 0, 0], [0, 0, 0, 1, -1, 0, 0, 0], [0, 0, 0, 1, -1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0] ], "Depth": 3, "RuleType": "freestyle" // or "renju" }