[C language] implementation of N-sub chess game

Today, I will play a small game of N-sub chess, which can be realized from 3x3,4x4 to NxN

Requirements: be able to play chess according to the input coordinates and judge whether to win or lose

First write out the general framework of the main function:

int main()
{
	int input = 0;
	srand((unsigned)time(NULL));
	do
	{
		menu();
		printf("Please select:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
		{
			game();
			break;
		}
		case 0:
		{
			printf("Exit the game\n");
			break;
		}
		default:
		{
			printf("Selection error, please re select\n");
			break;
		}
		}
	} while (input);
	return 0;
}

srand is set up so that the computer can play chess randomly on the chessboard according to random numbers

1. Menu creation

void menu()
{
	printf("**********************************\n");
	printf("*********** 1.The game begins ***********\n");
	printf("*********** 0.game over ***********\n");
	printf("**********************************\n");
}

2. Preparation of game function

void game()
{
	char out;
	//Store game internal data
	char board[ROW][COL];
	//Initialize checkerboard (space)
	InBoard(board, ROW, COL);
	//Print chessboard
	PrintBoard(board, ROW, COL);
	while (1)
	{
		//Player action
		Player(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		//Determine whether the game is over
		out = Win(board, ROW, COL);
		if (out != 'G')
		{
			break;
		}
		//Computer action
		PC(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		//Determine whether the game is over
		out = Win(board, ROW, COL);
		if (out != 'G')
		{
			break;
		}
	}
	//Judge the outcome at the end of the game
	if (out == '*')
	{
		printf("Player victory\n");
	}
	else if (out == '#')
	{
		printf("Computer victory\n");
	}
	else
	{
		printf("it ends in a draw\n");
	}
}

Here, the data of the binary array I created to store the internal data of the game uses two constants. I define two global constants to change the size of the N-sub chess I want to play at any time

What I think here is that the chess played by players is "*" and the chess played by computers is "#"

Here, all functions are thought out in advance, and then the function contents of the implementation are written step by step

The overall process of the game:

1. Print an empty chessboard to the player first

2. Players can play chess on an empty chessboard by inputting coordinates, and then judge whether the game has the result of victory or defeat or draw after the player plays this move. The game should not continue, and then print out the chessboard after playing this sub again

3. Let the computer play chess randomly on an empty chessboard (I don't know how to write a more intelligent computer). At the same time, judge the game result after the computer plays this chess. Do you need to continue the game, and then print out the chessboard after playing this chess again

4. Finally, if the game is terminated, judge whether it is the result of player victory, computer victory or draw

1. First, you need to print an empty chessboard for players to see:

void InBoard(char board[ROW][COL], int row, int col)
{
	int a = 0;
	int b = 0;
	for (a = 0; a < row; a++)
	{
		for (b = 0; b < col; b++)
		{
			board[a][b] = ' ';
		}
	}
}

This function is used to initialize the chessboard first, and turn all the data stored in the game into spaces for players to see. If it is not initialized, the chessboard will be printed with random codes

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

The chessboard printed here can be printed every time the numbers in the two-dimensional array are changed

Here, the chessboard format is printed according to the required chessboard size. If you want a 3x3 chessboard, you can print a tic tac toe chessboard. If you want a 4x4 chessboard, you can also print a larger one. You only need to change the value of the constant in the global constant (this function will be often used later)

2. Then the player can start entering coordinates to play chess on the chessboard

void Player(char board[ROW][COL], int row, int col)
{
	int a = 0;
	int b = 0;
	printf("Player action\n");
	while (1)
	{
		printf("Please enter coordinates:>");
		scanf("%d %d", &a, &b);
		//Judge whether the entered coordinates are legal
		if (a >= 1 && a <= col && b >= 1 && b <= row)
		{
			if (board[a - 1][b - 1] == ' ')
			{
				board[a - 1][b - 1] = '*';
				break;
			}
			else
			{
				printf("There are chess pieces in the entered coordinates, please re-enter\n");
			}
		}
		else
		{
			printf("Coordinate input error, please re-enter\n");
		}

	}
}

When allowing players to input, it is necessary to judge the legitimacy of the coordinates entered by players:

1. Does it exceed the size of the chessboard

2. Is the position where the player wants to play chess empty and can play chess

Because the coordinates of the first grid in the player's chess game are "1 1", but the coordinates of the first grid in the two-dimensional array are "0 0", the coordinates of the stored grid should be - 1 for each number entered by the player to ensure the correctness of the input

If the coordinates entered by the player are legal, store "*" in the two-dimensional array at the corresponding position of the chessboard

(judge the progress of the game and write it after playing chess on the computer)

3. Computer chess

void PC(char board[ROW][COL], int row, int col)
{
	printf("Computer action\n");
	while (1)
	{
		int a = rand() % row;
		int b = rand() % col;
		if (board[a][b] == ' ')
		{
			board[a][b] = '#';
			break;
		}
	}
}

I use the coordinates of two random numbers for the computer. The random number adopts the random method of time stamp. Because the coordinates input by the computer are controllable, we don't need to judge the legitimacy of the coordinates input by the computer, but only whether there are elements in the coordinates input by the computer. And there is no need to prompt the computer, just keep cycling, find the empty coordinate and fill "#" into the two-dimensional array

4. Judge whether the game continues or not. If it does not continue, the outcome will be peace

Here, I judge the result of the game as follows:
Return * to win for the player
Return # to computer victory
Return N to draw
Return to G to continue the game

First, you need to judge whether a line is the same

char Win(char board[ROW][COL], int row, int col)
{
	int a = 0;
	int b = 0;
	char c;
	//Judge a line
	for (a = 0; a < row; a++)
	{
		for (b = 0; b < col - 1; b++)
		{
			if ((board[a][b] == board[a][b + 1] && board[a][b + 1] == ' ') || board[a][b] != board[a][b + 1])
			{
				break;
			}
			if (b == row - 2)
			{
				return board[a][b];
			}
		}
	}

The character type c created earlier can be ignored first, and it should be used for later judgment

Here, I judge line by line. If the elements of a line are all the same, b in the nested for loop will reach the maximum value and return the elements in the last grid of that line (in this way, both players and computers can use this judgment function)

Then judge the same in one line

//Judge a column
	for (b = 0; b < col; b++)
	{
		//if (board[0][a] == board[1][a] && board[1][a] == board[2][a] && board[1][a] != ' ')
		//{
		//	return board[1][a];
		//}
		for (a = 0; a < row - 1; a++)
		{
			if (board[a][b] == board[a + 1][b] && board[a + 1][b] == ' ' || board[a][b] != board[a + 1][b])
			{
				break;
			}
			if (a == row - 2)
			{
				return board[a][b];
			}
		}
	}

It is basically the same as the function logic of the above judgment line. The knowledge changes the changes of a and b

Then judge that the bevel angle is the same

//Judge the upper left to lower right diagonal
	while (1)
	{
		for (a = 0; a < row-1; a++)
		{
			for (b = 0; b < col-1; b++)
			{
				if (a == b && board[a][b] != ' ')
				{
					c = board[a][b];
					if (c != board[a + 1][b + 1])
					{
						goto right;
					}
				}
				if (a == b && board[a][b] == ' ')
				{
					goto right;
				}
			}
		}
		return board[a][b];
	}
	right:

The judgment method I use is to judge whether the elements from the upper left corner to the lower right corner are different. First store the first element in 'c' and then compare it with the next Yuan Shu. If it is different or there are spaces in it, jump out of this judgment and go directly to the next judgment. The same is true from the upper right corner to the lower left corner below

//Judge the diagonal from top right to bottom left
	while (1)
	{
		for (a = 0; a < row-1; a++)
		{
			for (b = col-1; b > 0; b--)
			{
				if ((a + b) == (row - 1) && board[a][b] != ' ')
				{
					c = board[a][b];
					if (c != board[a + 1][b - 1])
					{
						goto third;
					}
				}
				if ((a + b) == (row - 1) && board[a][b] == ' ')
				{
					goto third;
				}
			}
		}
		return board[a][b];
	}
	third:

The logic is the same, just change the direction of retrieval

After all these judgments are correct, they are the elements in the last grid of the returned search

Finally, judge the draw

	int tmp = FULL(board, row, col);
	if (tmp == 1)
	{
		return 'N';
	}
	return 'G';
}

Judge the draw here, I wrote another function. If the return value of the function is 1, it is the draw result. If it returns other games, it will continue

int FULL(char board[ROW][COL], int row, int col)
{
	int a = 0;
	int b = 0;
	for (a = 0; a < row; a++)
	{
		for (b = 0; b < col; b++)
		{
			if (board[a][b] == ' ')
			{
				return 0;//The chessboard is not full
			}
		}
	}
	return 1;
}

Because the above has judged all the ways that can win

So to judge a draw here, we only need to judge whether the chessboard is filled, and no one wins

If all the cells are not spaces after retrieval, it returns 1, and as long as there is another space, it returns 0

Finally, this judgment function is placed behind player actions and computer actions

while (1)
	{

		//Player action
		Player(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		//Determine whether the game is over
		out = Win(board, ROW, COL);
		if (out != 'G')
		{
			break;
		}
		//Computer action
		PC(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		//Determine whether the game is over
		out = Win(board, ROW, COL);
		if (out != 'G')
		{
			break;
		}
	}

If no one wins and the chessboard is not full, the function should return 'G', so that the game continues to cycle

If someone wins or draws, the function may return any one of '*', '#', and 'G', which will jump out of the while loop and come to the following to judge the result of the game

5. Final result judgment

//Judge the outcome at the end of the game
	if (out == '*')
	{
		printf("Player victory\n");
	}
	else if (out == '#')
	{
		printf("Computer victory\n");
	}
	else
	{
		printf("it ends in a draw\n");
	}

At this time, you can distinguish what elements are stored in the out returned by the previous judgment

Then give feedback on the final results

Then the whole program will jump back to the main function at the beginning and judge again whether you want to play the game again

I think I'm still complicated in judging the winning or losing part of the game. The computer I wrote is not intelligent enough. I don't know how to optimize the winning or losing part. Can someone help me optimize it (accept guidance with an open mind)

Keywords: C Back-end

Added by davidjmorin on Thu, 09 Dec 2021 14:02:08 +0200