Gobang Game

This code can play a game according to the number of lines you specify, not limited to 3 rows and 3 columns

Design Ideas

  • Since this code is more than usual, I use multi-file management to reduce maintenance costs
    • Function declaration placed in game.h header file
    • Place game-related function definitions in the game.c source file
    • The main function is placed in main.c alone
  • When designing code, write out the body logic first, then test the correctness of the logic while implementing the code.

The following:

Start with the main function and write the general logic
int main(void)
{
	int input = 0;
	do
	{
		menu();

		printf("Please enter your choice:");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("Exit the game!");
			break;
		default:
			printf("Input error, please re-enter!");
			break;
		}

	} while (input);
	

	return 0;
}

Menu Functions
void menu()
{
	printf("**********************************\n");
	printf("*****     1.play   0.exit    *****\n");
	printf("**********************************\n");
}

Write out the logic of the game function

1. ** You want to play chess on the board, so create a two-dimensional array to act as the board** 1. ** Now you need a function to initialize the board, write it out first ** 1. ** Print the board for players to play, so you need a function to print the board ** 1. ** Now the player can start playing, and you need a function to play the board ** 1. ** Print the board ** 1. ** When the player has finished playing, the computer plays chess, Need a function for computer chess** 1. ** And after the player or computer has finished playing, it needs to be judged 1. Who wins 2. Whether or not the draw (the board is full) continues if none of the above happens, so this is a player's game and computer chess is a cyclic process**
void game()
{
	char board[ROW][COL];
	char ret = 0;
	srand((unsigned)time(NULL));

	InitBoard(board, ROW, COL);

	PrintBoard(board, ROW, COL);
	while (1)
	{
		
		PlayerMove(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
        
		board, ROW, COL);
		PrintBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		
	}
}

Initialize the board
  • Initialize the board to a space, which takes up space
void InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;

	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}

Print board
  • Printing a board prints out a frame

Looking closely at the board, you can see that for each line of the board, it consists of two lines, but the last line is not printed.

  • First line: Three spaces plus |.....
  • Line 2: Three underscores plus |....

So you can write the following code

void PrintBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
    int j = 0;
    for(i=0; i<row; i++)
    {	
        printf("  %c |  %c | %c | %c | %c \n", board[i][0],board[i][1],.. board[i][4]);
        if(i<row-1)
            printf("---|---|---|---|---\n");
    }
	
}

But the problem with the above code is that the number of columns is fixed, so we have to find out the rules of the columns based on the rules of the rows to write the code.

As we can see from our observations, each column of the board consists of two parts: only the second part of the last column of the board is not printed.

  • Part One: Three Spaces
  • Part Two: One |
  • Similar to split parts

The code is as follows:

void PrintBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;

	for (i = 0; i < row; i++)
	{
        //Part One of the Board Line | |   
		int j = 0;
		for (j = 0; j < col; j++)
		{
            //Part One of the Board Column
			printf(" %c ", board[i][j]);
            //Part Two of the Board Column
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
        //Second part of the board line---|---|---
		if (i < row - 1)
		{
			int j = 0;
			for (j = 0; j < col; j++)
			{
                //Part One of the Board Column
				printf("---");
                //Part Two of the Board Column
				if (j < col - 1)
				{
					printf("|");
				}
			}
			
		}
		printf("\n");
	}
}

Player Walks

The logic is simple, that is, to determine whether or not to override and whether or not to go beyond the boundaries. Note: Player's coordinates and programmer's coordinates are different

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	while (1)
	{
		printf("Player Walks:");
		scanf("%d %d", &x, &y);

		if (x >= 0 && x <= row && y >= 0 && y <= col)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("This location is occupied!");
			}
		}
		else
		{
			printf("Please re-enter!");
		}
	}

}

Computer walk

Just think about coverage when the computer goes

void ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0; 
	printf("Computer walk:\n");
	while (1)
	{
		x = rand() % row;
		y = rand() % col;

		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}		
}

Judge the board

There are four cases:

  1. Player wins and returns'*'
  2. Computer wins, return to'#

There are four things to consider when deciding who wins: Return directly to the same character, win if you return * and win if you return #

  • Lines are the same:
  • Columns are the same:
  • The main diagonals are the same:
  • The secondary diagonals are the same:
  1. Draw (is the board full), return to'Q'
  2. Continue the game and return to -'C'

Perfect game Function Logic
void game()
{
	char board[ROW][COL];
	char ret = 0;
	srand((unsigned)time(NULL));

	InitBoard(board, ROW, COL);

	PrintBoard(board, ROW, COL);
	while (1)
	{
		
		PlayerMove(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if ('C' != ret)
			break;
		ComputerMove(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if ('C' != ret)
			break;
	}
	if ('#' == ret)
		printf("Computer wins!\n");
	if ('*' == ret)
		printf("Player wins!\n");
	if ('Q' == ret)
		printf("It ends in a draw!\n");
}

Functions for Judging Board Conditions
char IsWin(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	char flag[ROW]; //Save the data to determine if it's the same
	int temp = 0;
	//Identify Lines Same
	for (i = 0; i < row; i++)
	{
        //Pass characters from each line to the flag array
		for (j = 0; j < col; j++)
		{
			flag[j] = board[i][j];
		}
        //Determine if all flag arrays are identical
		for (j = 0; j < col - 1; j++)
		{
			
			if (flag[j] != flag[j + 1]) 
			{
				break;
			}
		}
		if (col-1 == j && flag[0] != ' ')  //If j=col-1 when jumping out, it means that the comparison is complete and the same
		{
			return flag[0];
		}
	}
	//Identify Columns as Same
	while (temp < col)
	{
        //Pass each class individually to the flag array
		for (i = 0; i < row; i++)
		{
			for (j = 0; j < col; j++)   //Win or not for column
			{
				if (temp == j)
				{
					flag[i] = board[i][j];
					break;
				}
			}
		}
        //Determine if flag is the same
		for (j = 0; j < col - 1; j++)
		{
			if (flag[j] != flag[j + 1])
				break;
		}
		if (j == col - 1 && flag[0] != ' ')
			return flag[0];
		temp++;
	}
	//Judging that the principal diagonals are the same
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (i == j)
			{
				flag[i] = board[i][j];
			}
		}
	}
	for (j = 0; j < col-1; j++)
	{
		if (flag[j] != flag[j + 1])
			break;
	}
	if (j == col - 1 && flag[0] != ' ')
		return flag[0];

	//Judging that the secondary diagonals are the same, since the two coordinates together are exactly equal to the number of columns (rows) -1, you can set them as follows
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (i + j == (col - 1))
			{
				flag[i] = board[i][j];
			}
		}
	}
	for (j = 0; j < col - 1; j++)
	{
		if (flag[j] != flag[j + 1])
			break;
	}
	if (j == col - 1 && flag[0] != ' ')
		return flag[0];

	//Draw or not, encapsulates a function to determine if the board is full
	int ret = IsFull(board, row, col);
	if (1 == ret)
		return 'Q';
	return 'C';
}

Determine if the board is full
int IsFull(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
				return 0;
		}
	}
	return 1;
}

The complete code is as follows:
#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define ROW 5
#define COL 5
//Initialize the board
void InitBoard(char board[ROW][COL], int row, int col);

//Print board
void PrintBoard(char board[ROW][COL], int row, int col);

//Player Walks
void PlayerMove(char board[ROW][COL], int row, int col);

//Computer walk
void ComputerMove(char board[ROW][COL], int row, int col);

//Judge the board
char IsWin(char board[ROW][COL], int row, int col);
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"

void InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;

	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}

void PrintBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;

	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");

		if (i < row - 1)
		{
			int j = 0;
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			
		}
		printf("\n");
	}
}
void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	while (1)
	{
		printf("Player Walks:");
		scanf("%d %d", &x, &y);

		if (x >= 0 && x <= row && y >= 0 && y <= col)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("This location is occupied!");
			}
		}
		else
		{
			printf("Please re-enter!");
		}
	}

}
void ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0; 
	printf("Computer walk:\n");
	while (1)
	{
		x = rand() % row;
		y = rand() % col;

		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
	
	
}
char IsWin(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	char flag[ROW];
	int temp = 0;
	//Judgement line
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			flag[j] = board[i][j];
		}
		for (j = 0; j < col; j++)
		{
			if (j == col - 1)
				break;
			if (flag[j] != flag[j + 1])
			{
				break;
			}
		}
		if (col-1 == j && flag[0] != ' ')
		{
			return flag[0];
		}
	}
	//Judgement Column
	while (temp < col)
	{
		for (i = 0; i < row; i++)
		{
			for (j = 0; j < col; j++)   //Win or not for column
			{
				if (temp == j)
				{
					flag[i] = board[i][j];
					break;
				}
			}
		}
		for (j = 0; j < col - 1; j++)
		{
			if (flag[j] != flag[j + 1])
				break;
		}
		if (j == col - 1 && flag[0] != ' ')
			return flag[0];
		temp++;
	}
	//Principal Diagonal
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (i == j)
			{
				flag[i] = board[i][j];
			}
		}
	}
	for (j = 0; j < col-1; j++)
	{
		if (flag[j] != flag[j + 1])
			break;
	}
	if (j == col - 1 && flag[0] != ' ')
		return flag[0];

	//Paradiagonal
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (i + j == (col - 1))
			{
				flag[i] = board[i][j];
			}
		}
	}
	for (j = 0; j < col - 1; j++)
	{
		if (flag[j] != flag[j + 1])
			break;
	}
	if (j == col - 1 && flag[0] != ' ')
		return flag[0];

	//Is it a draw
	int ret = IsFull(board, row, col);
	if (1 == ret)
		return 'Q';
	return 'C';
}
//Determine if the board is full
int IsFull(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
				return 0;
		}
	}
	return 1;
}
#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"


void menu()
{
	printf("**********************************\n");
	printf("*****     1.play   0.exit    *****\n");
	printf("**********************************\n");
}

void game()
{
	char board[ROW][COL];
	char ret = 0;
	srand((unsigned)time(NULL));

	InitBoard(board, ROW, COL);

	PrintBoard(board, ROW, COL);
	while (1)
	{
		
		PlayerMove(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if ('C' != ret)
			break;
		ComputerMove(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if ('C' != ret)
			break;
	}
	if ('#' == ret)
		printf("Computer wins!\n");
	if ('*' == ret)
		printf("Player wins!\n");
	if ('Q' == ret)
		printf("It ends in a draw!\n");
}
int main(void)
{
	int input = 0;
	do
	{
		menu();

		printf("Please enter your choice:");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("Exit the game!");
			break;
		default:
			printf("Input error, please re-enter!");
			break;
		}

	} while (input);
	

	return 0;
}

Tags: C Game Development

Posted by Brian W on Tue, 02 Aug 2022 01:49:44 +0930