Gomoku Game (Main Flow)
Learn to create a generalized tic-tac-toe game by dividing it into subparts in the form of the main flow of the game.
We’ve all played tic-tac-toe at least once in our lives. Our typical tic-tac-toe game has a 3x3 grid. There are two players, and each player selects a symbol. Whichever player gets their symbols placed consecutively in a row, either vertically, horizontally, or diagonally, wins the game.
What if we change the rules? Let’s say, instead of a 3x3 grid, we have larger grid dimensions, and change the winning condition to whoever occupies five consecutive cells (either vertically, horizontally, or diagonally) wins.
“Click to Connect” and play the game in the terminal given below. Here, the win count is five. The grid dimension is 12x12.
But before you begin, understand the game flow:
-
We’ll enter the players’ names, and choose symbols.
Sample inputs:
Enter player 1's name: John Enter player 2's name: Doe Enter player 1's symbol: x Enter player 2's symbol: o
-
After entering the names and choosing the symbols, we’ll see a grid. We’ll then choose the row and column (ri, ci) numbers to place our respective symbols. To place your symbol on first row (ri), second column (ci), simply enter 1 2.
Sample input:
John's turn to place 'x' at (row col): 1 2
Where 1 is the row number, and 2 is the column number to place the symbol.
Players need to have their symbols placed five times in a row vertically, horizontally, or diagonally to win the game.
Play it at least once to get an idea about the game, and then start with the implementation.
Did you know the above game is called Gomoku?
In this lesson, and the upcoming few, we’ll discover the entire journey of making a full-fledged Gomoku. We’ll discuss and guide you through every step of making this game. In the end, we will also make a computer vs. human version of Gomoku (in which our program will play against the user and will try its best to not only stop the opponent from winning the game, but also maximize its chances of winning it).
Main structure of the game
We’ll start with the human vs. human game. Irrespective of the version of the game, our game can be divided into two main stages:
-
The first stage includes all steps required to start the game. This includes the following:
- Initializing the game
- Taking inputs from the users
- Printing and updating the board
-
The second stage includes all the steps required to end the game. This includes keeping track of when either of the players wins the game or when the game gets drawn.
Regardless of what game we’re implementing, our first step is to think of what we’re going to need in terms of memory.
The memory, in terms of the variables or arrays that we will need in our code, is an essential part of the program because the rest of the program completely depends upon this factor. Our code should be completely generic, i.e., if the user enters 3
, then a 3x3 board should be formed, and if the user enters 4
, then a 4x4 board should be formed, and so on.
In tic-tac-toe, the following memory might be needed to build the game.
Deciding on the memory for the game
Apart from the local memory that we need within functions, let’s evaluate what major memory we will need to get started.
-
Board dimension: We need an integer variable to store the dimension of the board, which we’ll take from the user. Let’s call it
dim
. So, we haveint dim;
-
Tic-tac-toe board: We need a 2-D array for the board where we’ll write players’ symbols. We need a character array
Board
ofdim * dim
size. For example, if the user enters3
, then a 3x3 board should be created. So, we havechar Board[dim * dim];
-
Number of players: We need an integer variable,
NOP
, to store the number of players. Hence, we haveint NOP;
-
Turn: We need a variable to store which player’s turn it is. Hence, we have
int turn = 0;
Note that
turn
will be having0
for player 1 and1
for player 2. -
Player name: To store the players’ names, we need a 2-D character array called
PName[][]
. As we have two players, we havechar PName[2][30];
In case of more than two players, it can be
char PName[NOP][30]
.PName[turn]
will be the name of the player whose turn it is.- Note that one row will represent one name (ending with
NULL
or the\0
character).
-
Player symbols: We need another character array called
PSym[]
to store the symbols of the players. So, for two players, the array would be as follows:char PSym[2] = {‘X’, ‘O’};
Generally, it should be
char PSym[NOP]={symbol of every player}
.PSym[turn]
will be the symbol of the player whose turn it is.
-
Coordinates to place the symbol: We need two integer variables to store the x and y coordinates entered by the user where the user wants to print the symbol on the board. Let us call them
ri
andci
:int ri, ci;
Main flow of the game
Below is a step-by-step flow of the game:
Step 0: dim, Board[][], NOP, ri, ci , NOP, winner = -1, turn, winCount
PName[NOP][CAPACITY], pSym[ NOP ] = {‘X’, ‘O’}
Step 1: init(Board, dim, pName, pSym, NOP, turn, winCount)
// Initialize the empty board and turn whichever player wants to play first.
Step 2: do
{
printBoard(Board, dim)
// Print the board.
Step 3: do
{
askForMove(ri, ci, pName[turn], pSym)
// Ask from user to enter coordinates.
Step 4: }
while(!isValidMove(ri, ci, Board, dim) );
// Check if the coordinates are not valid, then move to step 3 again otherwise, move to the next step.
Step 5: updateBoard(Board,dim,ri,ci,pSym[turn])
// Here, the control will only come if the user has already given correct and valid coordinates. Update the board (Update does not mean displaying the updated board on the console).
Step 6: if( isWin( Board, dim,winCount, pSym[turn] ) )
winner = turn , break ;
// Check if symbol pSym[turn] won stop the game move to step 9.
Step 7: changeTurn (turn)
// Turn change. If the Turn is 1, change it to 2 or vice versa.
}
Step 8: while (isDraw(Board, dim) == false);
// If the game is not drawn, Goto step 2.
Step 9: showWinnerOrDraw(winner)
// If the game was won, whichever player’s turn ended the game should be shown as the winner, or the game should be declared drawn.
Things to learn from the main flow
Every game follows a sequence of steps and is typically structured in a game loop, as demonstrated in the example of Gomoku shown above from steps 2–8. The specific steps of each game may vary, but they will all have a loop. In addition, the game state is saved in the game’s memory, which is continually updated as the game loop iterates. It’s worth noting that the initialization step is always the first step of the game (after the declaration of the memory in step 0) and it is always outside the game loop.
Let’s move forward to the next lesson and complete our game in stages.