Detailed explanation of 5 simple and easy-to-understand games in C language

foreword

We use 5 easy-to-understand mini-games to strengthen our understanding of the C language. These five mini-games not only include single-player games, but also man-to-machine and everyone-to-player games. Let's play an exciting game after studying!

1. Preparation

We are going to make 5 small games, and we need to create a header file and a source file for each of the 5 small games . They are game1.h/game1.c, game2.h/game2.c, game3.h/game3.c, game4.h/game4.c, game5.h/game5.c. The purpose of this is to build each game separately to facilitate operations such as reconstruction of our mini-game in the future. We also need a main.c to include the header files of these 5 small games. The main function is only responsible for calling. We implement all the mini-game code functions in other files and decorate them with static, so that users can use the game function to indirectly call the code of our mini-game.

2. Game menu

Let's build main.c first:
1. It needs to include the header files of five small games
2. Build our main function

#include"game1.h"//包含小游戏1的头文件
#include"game2.h"//包含小游戏2的头文件
#include"game3.h"//包含小游戏3的头文件
#include"game4.h"//包含小游戏4的头文件
#include"game5.h"//包含小游戏5的头文件
#include<time.h>
int main()
{
    
    
	srand((unsigned int)time(NULL));//用来生成随机数
	do
	{
    
    
		int optional = 0;//创建一个接收选择的变量
		menu();
		printf("请输入你的选项:\n");
		scanf("%d", &optional);
		switch (optional)
		{
    
    
		case 1:
			game1();
			break;
		case 2:
			game2();
			break;
		case 3:
			game3();
			break;
		case 4:
			game4();
			break;
		case 5:
			game5();
			break;
		case 0:
			printf("感谢你的游玩,欢迎下次使用。\n");
			exit(0);
		default:
			printf("你的选项输入有误,请重新输入:\n");
			break;
		}
	} while (1);
}

We use a do-while loop in the main function, the purpose is to allow the user to make a choice, and the user will not exit until the user chooses to exit or messes up.
The scanf function is risky. When the user messes up the input letters, it will cause buffer exceptions. So we put the selection variable we want to receive in the loop and give it an initial value of 0 to cause the program to exit when the user enters a letter.
The srand function is used to generate random numbers. When we only use the rand function, the generated random numbers will remain unchanged, which will make our repeated playing experience worse.
We are creating a menu for the collection of these games, allowing users to choose which game to play.

void menu()
{
    
    
	printf("*****************************\n");
	printf("*****1.猜数字   2.三子棋*****\n");
	printf("*****3.扫  雷   4.五子棋*****\n");
	printf("*****5.飞行棋   0.退  出*****\n");
	printf("*****************************\n");
}

The basic menu is ready, we enter the menu of each mini-game.
Let's first create the header file of the mini game:

#pragma once
#include<stdio.h>
#include<stdlib.h>
void game1();

The mini-games we correspond to the game in the header files of the mini-games. I take mini-game 1 as an example, and the other four mini-games are similar to this.
We then create source files for each:

#include"game1.h"
static void menu1()
{
    
    
	printf("*****************************\n");
	printf("*****      猜数字       *****\n");
	printf("***** 1.Start the game ******\n");
	printf("***** 0.Exit the game  ******\n");
	printf("*****************************\n");
}
void game1()
{
    
    
	int optional = 0;//创建一个接收选择的变量
	do
	{
    
    
		optional = 0;
		menu1();
		printf("请输入你的选项:\n");
		scanf("%d", &optional);
		switch (optional)
		{
    
    
		case 1:
			//game();
			break;
		case 0:
			printf("猜数字小游戏以退出。\n");
			break;
		default:
			printf("你的选项输入有误,请重新输入:\n");
			break;
		}
	} while (optional);
}

Still take game1 as an example, the options in other mini-games are the same as game1, only change the name of the mini-game in the menu function. The game function in the loop is used to call the composition function in this small game.
Let's run it now to test whether the code is what we expected. The
insert image description here
test can be carried out normally according to our ideas. Now let us formally write each small game.

3. Game content

1. Guess the number

Idea: The system randomly generates a random number. By comparing the number we input with the generated number, it will give us a prompt to guess whether it is too big or too small.

static void game()
{
    
    
	int num = rand() % 100 + 1;//创建一个变量,用来存放随机数。
	int guess = 0;//创建一个变量,用来存放所猜的数字。	
	//rand函数是用来生成随机数的,我们用rand函数生成的随机数对100取模并加1,可以产生1~100的随机数
	while(1)
	{
    
    
		printf("请输入你猜测的数字:");
		scanf("%d", &guess);
		if (guess == num)
		{
    
    
			printf("恭喜你,猜对了!\n");
			break;
		}
		else if (guess > num)
		{
    
    
			printf("你猜的数字过大,请重新猜测吧!\n");
		}
		else if (guess < num)
		{
    
    
			printf("你猜的数字过小,请重新猜测吧!\n");
		}
	}
	return;
}

Let's simply run it!
insert image description here
It works fine, and we can play it repeatedly.

2. Backgammon

Idea: Use an array to store our chess pieces and judge whether we win.
1. Print the chessboard
2. The player plays chess
3. Determine whether the player wins
4. The computer plays chess
5. Determine whether the computer wins
We first define two macros: used to determine the size of the chessboard we can set.

#define ROW 3  //行
#define COL 3  //列

We start to build the game function to see what modules are needed to support the game idea:

static void game()
{
    
    
	char win;//创建一个变量,存放判段获胜条件的字符。
	//我们把C代表继续,D代表平局,*代表玩家获胜,#代表电脑获胜
	char checkerboard[ROW][COL] = {
    
     0 };//创建一个数组,用来存放棋盘信息
	initialization(checkerboard,ROW,COL);//初始化数组,把数组中的每个元素初始化为空格
	ptintinitialization(checkerboard, ROW, COL);//打印棋盘
	while(1)
	{
    
    
		Player(checkerboard, ROW, COL, '*');//玩家下棋,玩家的标志为 *
		win = Iswin(checkerboard, ROW, COL);//判断是否获胜
		if (win != 'C')
		{
    
    
			break;
		}
		ptintinitialization(checkerboard, ROW, COL);//打印棋盘
		Computer(checkerboard, ROW, COL, '#');//电脑下棋,电脑的标志为 #
		win = Iswin(checkerboard, ROW, COL);
		if (win != 'C')
		{
    
    
			break;
		}
		ptintinitialization(checkerboard, ROW, COL);//打印棋盘
	}
	if (win == 'D')
	{
    
    
		printf("平局\n");
		ptintinitialization(checkerboard, ROW, COL);
	}
	else if (win == '*')
	{
    
    
		printf("恭喜你获得胜利\n");
		ptintinitialization(checkerboard, ROW, COL);
	}
	else
	{
    
    
		printf("很遗憾,你输掉了比赛\n");
		ptintinitialization(checkerboard, ROW, COL);
	}
}

We first create the array we use and a variable that can judge whether we win or lose. We initialize the array and print it to let the player know the position where they can play chess. The man-machine battle is realized through the player's chess function and the computer's chess function. .
Initialize array function:

static void initialization(char arr[ROW][COL],int row,int col)//初始化数组
{
    
    
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
    
    
		for (j = 0; j < col; j++)
		{
    
    
			arr[i][j] = ' ';//把数组中的每个元素赋值为空格
		}
	}
}

Print checkerboard function:

static void ptintinitialization(char arr[ROW][COL], int row, int col)//打印棋盘
{
    
    
	int i = 0;
	for (i = 0; i < row; i++)
	{
    
    
		int j = 0;
		for (j = 0; j < col; j++)
		{
    
    
			if (j < col - 1)
			{
    
    
				printf(" %c |", arr[i][j]);//打印棋盘,如果为列中的最后一个元素,则不打印|
			}
			else
			{
    
    
				printf(" %c ", arr[i][j]);
			}
		}
		printf("\n");
		if(i < row-1)//打印棋盘,如果为行中的最后一个元素,则不打印---
		{
    
    
			for (j = 0; j < col; j++)
			{
    
    
				if (j < col)
				{
    
    
					printf("--- ");
				}
			}
		}
		printf("\n");
	}
}

insert image description here
The printing effect is shown in the figure.
When we change the macro to:

#define ROW 9  //行
#define COL 9  //列

insert image description here
We can see that the printed chessboard expands. This is the benefit of macros that don't require us to modify the value in each function. Just change the value defined by the macro to change the size of our chessboard.

Player chess function:

static void Player(char arr[ROW][COL], int row, int col, char ch)//玩家下棋函数
{
    
    
	int x = 0;
	int y = 0;
	while(1)
	{
    
    
		printf("请输入你要下棋的坐标:");
		scanf("%d %d", &x, &y);
		if (x<1 || x>row || y<1 || y>col)//判断坐标是否合法
		{
    
    
			printf("你输入的坐标不合法,请重新输入。\n");
		}
		else if (arr[x - 1][y - 1] != ' ')//判断输入坐标是否被占用
		{
    
    
			printf("你输入的坐标已被占用,请重新输入。\n");
		}
		else
		{
    
    
			arr[x - 1][y - 1] = ch;//数组下标从0开始,所以玩家的真实坐标要进行减1
			break;
		}
	}
}

Computer chess function:

static void Computer(char arr[ROW][COL], int row, int col, char ch)
{
    
    
	while (1)
	{
    
    
		int x = rand() % 3;//产生0~2的数字
		int y = rand() % 3;
		if (arr[x][y] == ' ')//如果坐标未被占用,则电脑下棋,否则产生新的坐标进行判断
		{
    
    
			arr[x][y] = ch;//电脑的坐标的下标和数组下标对应,不需要进行减1操作
			break;
		}
	}
}

Judging whether to win the function:

static char Iswin(char arr[ROW][COL], int row, int col)//判断是否获胜
{
    
    
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)//判断每一排中是否有人获胜
	{
    
    
		if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][1] != ' ')
		{
    
    
			return arr[i][1];
		}
	}
	for (i = 0; i < col; i++)//判断每一列中是否有人获胜
	{
    
    
		if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[1][i] != ' ')
		{
    
    
			return arr[1][i];
		}
	}
	if ((arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[1][1] != ' ') || 
		(arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[1][1] != ' '))//判断对角线上是否有人获胜
	{
    
    
		return arr[1][1];
	}
	for (i = 0; i < row; i++)
	{
    
    
		for (j = 0; i < col; i++)
		{
    
    
			if (arr[i][j] == ' ');//判断是否还有空位
			{
    
    
				return 'C';
			}
		}
	}
	return 'D';
}

Let's run it and see the result!
insert image description here
Note:
1. The scanf we use is not safe. You can find the corresponding solution to understand why it is not safe.
2. When initializing the array used, pay attention to the interval. When passing an array parameter, pay attention to whether the types of the formal parameter and the actual parameter are consistent. We use an array of char type. What will happen if the formal parameter is accepted by int? Everyone can go down and have a try.
3. You can refactor this code, and everyone can play against each other. Only the man-machine battle is shown here, let's refactor it and join the human-machine battle.
If the formal parameter is accepted by int, it will cause the array to go out of bounds and cause a stack error.

3. Minesweeper

Idea: Use an array to store the information of mines, and find the place without mines through investigation.
1. Print the map
2. The player conducts minesweeping
3. Determine whether the player steps on mines
4. Update the map
Analysis:
Insert the picture description here The insert image description here
above picture is a 9*9 minesweeping map. When we want to judge the red place, we need to judge the surrounding area It is bound to cause out-of-bounds access. How to solve this problem?
We expand the array by one line up, down, left, and right, so that the judgment will not cause the array to go out of bounds. Let's analyze the problem of printing arrays through code.
We set up two arrays, one is used to store map information, and the other is used to display to the player. The array displayed to the player needs to judge the safe place on the map by storing the array of map information.
We first define five macros: respectively determine the size of the map we can set and the size of our printed map, and the last macro is used to store the number of our mines, which is also convenient for us to test later.

#define ROW 9  //显示的行
#define COL 9  //显示的列
#define ROWS ROW+2  //真实数组的行
#define COLS COL+2  //真实数组的列
#define MINENUM 10  //地雷的个数

Then add our game function to see the specific ideas:

static void game()
{
    
    
	int winnum = ROW * COL - MINENUM;//设置一个变量,用来存放还有多少个安全的地方
	char minemap[ROWS][COLS] = {
    
     0 };//雷分布的地图
	char showmap[ROWS][COLS] = {
    
     0 };//向玩家展示的地图
	Initialization(minemap, showmap, ROWS, COLS);//初始化数组,把雷分布随机分布在地图中,并且把向玩家展示的地图全部替换为 * 
	//Ptintinitialization(minemap, ROW, COL);//测试代码,用来打印地图
	while (winnum)
	{
    
    
		int x = 0;
		int y = 0;
		Ptintinitialization(showmap, ROW, COL);//打印展示地图
		printf("请输入排雷坐标:");
		scanf("%d %d", &x, &y);
		if (x<1 || x>ROW || y<1 || y>COL)//判断坐标是否合法
		{
    
    
			printf("你输入的坐标不合法,请重新输入。\n");
		}
		else if (showmap[x][y] != '*')//判断坐标是否已被排查过
		{
    
    
			printf("你输入的坐标已被排过雷了,请重新输入。\n");
		}
		else 
		{
    
    
			if (!Determine(minemap, x, y))//!Determine(minemap, x, y)用来判断是否踩到雷
			{
    
    
				Ptintinitialization(minemap, ROW, COL);//打印地雷地图,让玩家知道地雷在哪里。
				break;
			}
			Renewmap(minemap, showmap, x, y);//用来更新向玩家展示的地图
			winnum--;//对安全的地方进行减1
		}
	}
	if(winnum == 0)//当安全地方为0时,证明排雷成功
	{
    
    
		printf("恭喜你排雷成功!\n");
		Ptintinitialization(showmap, ROW, COL);//打印展示地图,让玩家知道自己获胜地图
	}
}

Initialize array function:

static void Initialization(char minemap[ROWS][COLS], char showmap[ROWS][COLS], int rows, int cols)
{
    
    
	int count = MINENUM;//创建一个变量,用来计算放置的雷的数量
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)//把地雷地图全部赋值为字符0
	{
    
    
		for (j = 0; j < cols; j++)
		{
    
    
			minemap[i][j] = '0';
		}
	}
	while (count)//把雷分布随机分布在地雷地图中
	//我们把0代表安全,1代表雷区
	{
    
    
		int x = rand() % ROW + 1;//创建随机变量范围在1~9
		int y = rand() % COL + 1;//创建随机变量范围在1~9
		if (minemap[x][y] == '0')//判断该位置是否已有雷
		{
    
    
			minemap[x][y] = '1';//放置地雷
			count--;
		}
	}
	for (i = 0; i < rows; i++)//把展示地图全部赋值为字符*
	{
    
    
		for (j = 0; j < cols; j++)
		{
    
    
			showmap[i][j] = '*';
		}
	}
}

insert image description here
The map row we show is 1 ~ ROW, and the column is 1 ~ COL, so the coordinates of the generated mines are controlled within this range.
Print map function:

static void Ptintinitialization(char showmap[ROWS][COLS], int row, int col)//打印地图
{
    
    
	int i = 1;
	int j = 1;
	for (i = 1; i <= row; i++)
	{
    
    
		if (i == 1)//当i为1时,需要多一个空格,目的为了和地图对齐
		{
    
    
			printf(" ");
		}
		printf(" %d", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)//打印我们所需要的地图
	{
    
    
		printf("%d", i);
		for (j = 1; j <= col; j++)
		{
    
    
			printf(" %c", showmap[i][j]);
		}
		printf("\n");
	}
}

We start printing from 1, print to ROW, and only print where we need.
To judge whether to step on mine:

static bool Determine(char minemap[ROWS][COLS],int x,int y)
{
    
    
	if (minemap[x][y] == '1')
	{
    
    
		printf("排雷失败,你已死亡!\n");
		return false;
	}
	else
	{
    
    
		return true;
	}
}

Update the displayed map:

static void Renewmap(char minemap[ROWS][COLS], char showmap[ROWS][COLS], int x, int y)
{
    
    
	showmap[x][y] = (minemap[x - 1][y - 1] + minemap[x - 1][y] + minemap[x - 1][y + 1]
				  + minemap[x][y - 1] + minemap[x][y + 1]
				  + minemap[x + 1][y - 1] + minemap[x + 1][y] + minemap[x + 1][y + 1]) - 8*'0' + '0';
}

insert image description here
Update the map shown to the player to add up the number of surrounding mines and replace them with the corresponding number. We are using a character array, which stores character 1 and character 0, so we need to subtract the ASCLL code value of 0 to get an integer number, add them to represent the number of mines in 8 places around this square, and finally add The ASCLL code value of 0 gets the corresponding character number.
Let's test it: we uncomment the test code, and set the number of mines defined by our macro to be larger. I set it to 79 first. You can change it according to the difficulty you want to play when you actually play. Let's take a look at mine
insert image description here
clearance Whether the failure will be displayed normally:
insert image description here
the failure of mine clearance will also be displayed normally.
Note:
1. scanf is not safe.
2. Pay attention to the interval when initializing the array used, and pay attention to whether it is out of bounds when accessing the array.
3. Reconstruction ideas: You can add an expanded map (you can expand it when there are no mines in the surrounding 8 places, until you know that there is a mine around a grid), add a small flag (replace the place that is considered to be a mine with a small flag, and only cancel the small flag to change it) Minesweeper can only be carried out at the position), adding time (when the time expires, if all mines are not cleared, the game ends), etc.

4. Backgammon

Ideas: Determine which player has played five consecutive pieces in a row (a row or a column or a diagonal line with 5 consecutive pieces of the same piece) 1. Print the
board
2. Player 1 plays chess
3. Determine whether player 1 wins
4. Player 2 plays Play chess
5. Determine whether player 2 wins
or not We still use macros to define the size of the board first:

#define ROW 9  //棋盘的行
#define COL 9  //棋盘的列

Look at the game idea again:

static void game()
{
    
    
	char win;//创建一个变量,存放判段获胜条件的字符。
	//我们把C代表继续,D代表平局,白棋(@)代表玩家1获胜,黑棋(O)代表玩家2获胜
	char checkerboard[ROW][COL] = {
    
     0 };//棋盘数组
	Initialization(checkerboard, ROW, COL);//初始化数组,把棋盘的所有位置都赋值为 *
	Ptintinitialization(checkerboard, ROW, COL);//打印棋盘
	while (1)
	{
    
    
		Player(checkerboard, ROW, COL, '@');//玩家1下棋,玩家1的标志为 @
		win = Iswin(checkerboard, ROW, COL);//判断是否获胜
		if (win != 'C')
		{
    
    
			break;
		}
		Ptintinitialization(checkerboard, ROW, COL);//打印棋盘
		Player(checkerboard, ROW, COL, 'O');//玩家2下棋,玩家2的标志为 O
		win = Iswin(checkerboard, ROW, COL);//判断是否获胜
		if (win != 'C')
		{
    
    
			break;
		}
		Ptintinitialization(checkerboard, ROW, COL);//打印棋盘
	}
	if (win == 'D')
	{
    
    
		printf("平局\n");
		Ptintinitialization(checkerboard, ROW, COL);
	}
	else if (win == '@')
	{
    
    
		printf("玩家1获胜\n");
		Ptintinitialization(checkerboard, ROW, COL);
	}
	else
	{
    
    
		printf("玩家2获胜\n");
		Ptintinitialization(checkerboard, ROW, COL);
	}
}

The idea of ​​backgammon is exactly the same as that of backgammon, except that the computer is replaced by another player. So the game function code has basically not changed much. The players have the same thinking in playing chess, so we only need one function to solve the thinking of two players playing chess.
Initialize array function:

static void Initialization(char arr[ROW][COL], int row, int col)//初始化数组,把棋盘的所有位置都赋值为 *
{
    
    
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)//把展示地图全部赋值为字符*
	{
    
    
		for (j = 0; j < col; j++)
		{
    
    
			arr[i][j] = '*';
		}
	}
}

The idea of ​​initializing the array is exactly the same as the map shown to the player in minesweeper.
Print map function:

static void Ptintinitialization(char arr[ROW][COL], int row, int col)//打印棋盘
{
    
    
	int i = 0;
	int j = 0;
	for (i = 1; i <= row; i++)
	{
    
    
		if (i == 1)//当i为1时,需要多两个空格,目的为了和地图对齐
		{
    
    
			printf("  ");
		}
		if (i < 9)//当i小于9时,需要多一个个空格,目的为了和地图对齐
		{
    
    
			printf(" %d ", i);
		}
		else//当i大于于9时,不需要多一个个空格
		{
    
    
			printf(" %d", i);
		}
	}
	printf("\n");
	for (i = 0; i < row; i++)//打印我们所需要的地图
	{
    
    
		printf("%2d", i + 1);
		for (j = 0; j < col; j++)
		{
    
    
			printf(" %c ", arr[i][j]);//需要多一个个空格,目的为了和地图对齐
		}
		printf("\n");
	}
}

The backgammon map can be zoomed in and out at will, and you must pay attention to whether the map is aligned with the rows and columns above.
Player chess function:

int x = 0;//用来接收玩家下棋的坐标
int y = 0;//用来接收玩家下棋的坐标
static void  Player(char arr[ROW][COL], int row, int col, char ch)//玩家下棋函数,通过ch来判断是玩家1还是玩家2
{
    
    
	int player = 0;//创建一个变量来确定是玩家几
	if (ch == '@')//如果ch为白棋(@),则代表玩家1
	{
    
    
		player = 1;
	}
	else//反之则为玩家2
	{
    
    
		player = 2;
	}
	while (1)
	{
    
    
		printf("请玩家 %d 输入要下棋的坐标:",player);
		scanf("%d %d", &x, &y);
		if (x<1 || x>row || y<1 || y>col)//判断坐标是否合法
		{
    
    
			printf("你输入的坐标不合法,请重新输入。\n");
		}
		else if (arr[x - 1][y - 1] != '*')//判断输入坐标是否被占用
		{
    
    
			printf("你输入的坐标已被占用,请重新输入。\n");
		}
		else
		{
    
    
			arr[x - 1][y - 1] = ch;//数组下标从0开始,所以玩家的真实坐标要进行减1
			break;
		}
	}
}

We set the coordinates of the player's chess as a global variable, so that we can judge whether it is the case of five sons in a row.
Judging whether to win the function:
insert image description here

enum Direction
{
    
    
	LEFT,
	RIGHT,
	UP,
	DOWN,
	LEFTUP,
	RIGHTDOWN,
	RIGHTUP,
	LEFTDOWN
};
static char Iswin(char arr[ROW][COL], int row, int col)//判断是否获胜
{
    
    
	static chessnum = 0;//创建一个静态变量,用来存放棋盘中使用的格数
	chessnum++;//每进行一次判断调用就对棋盘使用格数进行+1
	int winnum1 = 1 + Wincount(arr, ROW, COL, LEFT) + Wincount(arr, ROW, COL, RIGHT);
	//确定左和右共计多少相同个棋子,需要加上自身的棋子
	int winnum2 = 1 + Wincount(arr, ROW, COL, UP) + Wincount(arr, ROW, COL, DOWN);
	//确定上和下共计多少相同个棋子,需要加上自身的棋子
	int winnum3 = 1 + Wincount(arr, ROW, COL, LEFTUP) + Wincount(arr, ROW, COL, RIGHTDOWN);
	//确定左上和右下共计多少相同个棋子,需要加上自身的棋子
	int winnum4 = 1 + Wincount(arr, ROW, COL, RIGHTUP) + Wincount(arr, ROW, COL, LEFTDOWN);
	//确定右上和左下共计多少相同个棋子,需要加上自身的棋子
	if (winnum1 >= 5 || winnum2 >= 5 || winnum3 >= 5 || winnum4 >= 5)//判断是否获胜
	{
    
    
		return arr[x - 1][y - 1];//返回获胜棋子的字符
	}
	else
	{
    
    
		if (chessnum == ROW * COL)//如果棋盘使用格数等于棋盘的格数,证明平局
		{
    
    
			return 'D';
		}
		else//如果棋盘使用格数不等于棋盘的格数,证明还有空位,继续进行比赛
		{
    
    
			return 'C';
		}
	}
}

We need to count the same number of chess pieces in these 8 directions. There will be no 5 consecutive * situations, and the address we save will always be the address of the last player. We represent the 8 directions with the menu type.

static int Wincount(char arr[ROW][COL], int row, int col, enum Direction dir)
{
    
    
	int count = 0;//记录相同棋子个数
	int _x = x - 1;//要对坐标进行减1,因为我们的棋盘从1开始,数组下标从0开始
	int _y = y - 1;//要对坐标进行减1,因为我们的棋盘从1开始,数组下标从0开始
	//用局部变量保存,避免在这里修改全局变量的值
	while (1)
	{
    
    
		switch (dir)
		{
    
    
		case LEFT:
			_y--;//对中心坐标的列坐标进行减1
			break;
		case RIGHT:
			_y++;//对中心坐标的列坐标进行加1
			break;
		case UP:
			_x++;
			break;
		case DOWN:
			_x--;
			break;
		case LEFTUP:
			_y--;
			_x++;
			break;
		case RIGHTDOWN:
			_y++;
			_x--;
			break;
		case RIGHTUP:
			_y++;
			_x++;
			break;
		case LEFTDOWN:
			_y--;
			_x--;
			break;
		default:
			break;
		}
		if (_x < 0 || _x > ROW || _y < 0 || _y>COL)//判断位置是否合法
		{
    
    
			return count;
		}
		else if(arr[_x][_y] != arr[x-1][y-1])//判断是否和上一个玩家的棋子相同
		{
    
    
			return count;
		}
		else
		{
    
    
			count++;
		}
	}
}

We set it as an infinite loop to judge the specific number of chess pieces in the same direction. The menu type is different from the parameters we pass, so we take different routes in the switch branch.
Note:
Array out of bounds. Reconstructing ideas
for judging Wuzilianzhu : you can join the network, realize online battles, you can add the function of regretting chess, etc.

5. Ludo

How to play: 1. Except that the starting position is the same, the rest of the time when a player's position is the same as another player's position, a stampede occurs.
2. When the player steps on the props, perform the corresponding prop operation
3. The player who reaches the end first is the winning
idea:
1. Use an array to store map information
2. Use a structure to construct player information
3. Use a structure Arrays to store player information
4. Use random functions to simulate sieve operations
Let's first construct the game idea:

int map[100];//创建一个地图大小为100的地图。并且把地图元素全部初始化为0
//为了对数组进行方便的操作,我们把数组设置为全局变量,使每个函数可以直接访问数组
static void game()
{
    
    
	struct Player play[2];//创建一个玩家数组,里面存放玩家信息
	Initializationmap();//初始化地图数组,把地图相应位置填上道具元素,
	//我们把地图数组设置为了全局函数,所以不要需要传参
	Initializationplay(play);//初始化玩家数组,加入玩家信息,并把玩家位置置于地图开始位置
	Ptintinitialization(play);//打印棋盘,地图数组为全局函数,所以不要对地图传参。
	//需要玩家信息来判断地图要填的字符,所以要对玩家进行传参
	while (1)//使玩家交替进行游玩,直到产生胜利者
	{
    
    
		if (play[0].flags == false)//判断玩家1是否处于暂停回合。
		{
    
    
			Play(&play[0], &play[1],play);//玩家1进行游戏
			Ptintinitialization(play);//打印棋盘
		}
		else//处于暂停回合,把暂停回合改为继续
		{
    
    
			play[0].flags = false;
		}
		if (play[0].position >= 99)//判断玩家1是否获胜
		{
    
    
			printf("%s侥幸赢了%s\n", play[0].name, play[1].name);
			break;
		}
		if (play[1].flags == false)//判断玩家2是否处于暂停回合。
		{
    
    
			Play(&play[1], &play[0],play);//玩家2进行游戏
			Ptintinitialization(play);//打印棋盘
		}
		else
		{
    
    
			play[1].flags = false;//更改暂停选项
		}
		if (play[1].position >= 99)//判断玩家2是否获胜
		{
    
    
			printf("%s侥幸赢了%s\n", play[1].name, play[0].name);
			break;
		}
	}
}

For convenience, we set the map array as a global array, which reduces parameter passing. And the array does not need to be changed after initialization. We also set up a structure array to store player information (position, whether it is in a pause position).
Initialize the map function:

static void Initializationmap()//初始化地图数组
//地图数组中
//0代表什么都没有
//1代表道具1(幸运轮盘),2代表道具2(地雷),3代表道具3(暂停),4代表道具4(时空隧道)
{
    
    
	int luckyturn[] = {
    
    1, 20, 45, 60, 75, 90};//在相应的位置放入 幸运轮盘
	for (int i = 0; i < sizeof(luckyturn) / sizeof(luckyturn[0]); i++)
	//sizeof(luckyturn) / sizeof(luckyturn[0])用来求出数组元素的个数
	{
    
    
		map[luckyturn[i]] = 1;
	}
	int Landmine[] = {
    
     3, 6, 19, 25, 36, 49, 69, 70, 80 };//在相应的位置放入 地雷
	for (int i = 0; i < sizeof(Landmine) / sizeof(Landmine[0]); i++)
	{
    
    
		map[Landmine[i]] = 2;
	}
	int puse[] = {
    
     2, 11, 26, 35, 44, 59, 71, 88 };//在相应的位置放入 暂停
	for (int i = 0; i < sizeof(puse) / sizeof(puse[0]); i++)
	{
    
    
		map[puse[i]] = 3;
	}
	int timetunnel[] = {
    
     5, 15, 30, 50, 77 };//在相应的位置放入 时空隧道
	for (int i = 0; i < sizeof(timetunnel) / sizeof(timetunnel[0]); i++)
	{
    
    
		map[timetunnel[i]] = 4;
	}
}

The initial map operation allows us to place the appropriate props in the desired position, and the position of the props can be changed according to our preferences.
Initialize player function:

static void Initializationplay(struct Player *play)
{
    
    
	printf("请输入玩家A的姓名\n");
	scanf("%s", &(play[0].name));
	while (!strcmp(play[0].name,""))//判断玩家A的姓名是否为空
	{
    
    
		printf("玩家姓名不能为空,请重新输入玩家A的姓名\n");
		scanf("%s", &(play[0].name));
	}
	printf("请输入玩家B的姓名\n");
	scanf("%s", &(play[1].name));
	while (1)
	{
    
    
		if (!strcmp(play[1].name, ""))//判断玩家B的姓名是否为空
		{
    
    
			printf("玩家姓名不能为空,请重新输入玩家B的姓名\n");
			scanf("%s", &(play[1].name));
		}
		else if(!strcmp(play[1].name, play[0].name))//判断玩家B的姓名和玩家A是否相同
		{
    
    
			printf("玩家姓名不能一致,请重新输入玩家B的姓名\n");
			scanf("%s", &(play[1].name));
		}
		else
		{
    
    
			break;
		}
	}
	play[0].position = 0;//把玩家A的位置置于0位置(地图开始位置)
	play[0].flags = false;//把玩家A的暂停条件置为假。
	play[1].position = 0;//把玩家B的位置置于0位置(地图开始位置)
	play[1].flags = false;//把玩家B的暂停条件置为假。
}

In this function, we have performed a string comparison. You cannot directly use == for string comparison. You must use the strcmp function
to display the map function:

extern char Drawstrmap(const struct Player* play, int i);//对Drawstrmap函数进行声明
static void Ptintinitialization(const struct Player* play) //打印棋盘
//由于不会对玩家信息进行更改,我们把参数设置为const,防止在函数中误改
{
    
    
		printf("图例:幸运轮盘:#    地雷:@    暂停:I     时空隧道:>     \n");//向玩家展示道具信息
		//第一段
		for (int i = 0; i < 30; i++)
		{
    
    
			printf("%c ", Drawstrmap(play, i));
		}
		printf("\n");
		//第一竖列
		for (int i = 30; i < 35; i++)
		{
    
    
			for (int j = 0; j <= 28; j++)
			{
    
    
				printf("  ");
			}
			printf("%c ", Drawstrmap(play, i));
			printf("\n");
		}
		//第二段
		for (int i = 64; i >= 35; i--)//地图为从前向后打打印
		{
    
    
			printf("%c ", Drawstrmap(play, i));
		}
		printf("\n");
		//第二数列
		for (int i = 65; i <= 69; i++)
		{
    
    
			printf("%c ", Drawstrmap(play, i));
			printf("\n");
		}
	    //第三行竖列
		for (int i = 70; i <= 99; i++)
		{
    
    
			printf("%c ", Drawstrmap(play, i));
		}
		printf("\n");//画完地图换行
}

static char Drawstrmap(const struct Player* play, int i)//打印地图元素
{
    
    
	char ch;
	if (play[0].position == play[1].position && play[0].position == i)
	//当玩家1和玩家2的位置处于起始位置时
	{
    
    
		ch = 'M';
	}
	else if (play[0].position == i)//当玩家1位于当前位置时
	{
    
    
		ch = 'A';
	}
	else if (play[1].position == i)//当玩家2位于当前位置时
	{
    
    
		ch = 'B';
	}
	else
	{
    
    
		switch (map[i])
		{
    
    
		case 0://地图数组元素为0时
			ch = 'O';
			break;
		case 1:
			ch = '#';
			break;
		case 2:
			ch = '@';
			break;
		case 3:
			ch = 'I';
			break;
		case 4:
			ch = '>';
			break;
		}
	}
	return ch;
}

insert image description here
Here we construct a Drawstrmap function, the purpose is to construct the integer elements in the map array into the character elements we need, we pass in the position of the map to determine what characters to print, and do not change our map array.
Play function:

static void Play(struct Player *play1, struct Player* play2, struct Player* play)
//play1为当前玩家,play2为另一名玩家,play为玩家数组,传玩家数组方便进行位置判断
{
    
    
	int points = rand() % 6 + 1;//设置随机变量,范围为1~6
	printf("%s请按任意键开始致筛子\n", play1->name);
	system("pause");//暂停屏幕
	printf("%s筛到了%d,前进%d格,", play1->name, points, points);
	system("pause");
	play1->position += points;//对玩家位置进行更新
	Weizhi(play);//判断玩家位置是否在合法的范围内
	if (play1->position == play2->position)//现在玩家的位置和另一名玩家位置相同时
	{
    
    
		printf("%s踩到了%s,%s退6格,", play1->name, play2->name, play2->name);
		system("pause");
		play2->position -= 6;//对另一名玩家位置进行更新
		Weizhi(play);//判断玩家位置是否在合法的范围内
		printf("%s已退6格,", play2->name);
		system("pause");
	}
	else
	{
    
    
		switch (map[play1->position])//检查本位玩家是否进行到道具位置
		{
    
    
		case 0:
			printf("%s踩到了方块,安全,", play1->name);
			system("pause");
			break;
		case 1:
		{
    
    
			printf("%s踩到了幸运转盘,1————交换位置,2————轰炸对方,请选择按键\n", play1->name);
			int a = 0;//用来接收用户的选择
			scanf("%d", &a);
			while (1)
			{
    
    
				if (a == 1)
				{
    
    
					printf("%s选择了交换位置,", play1->name);
					system("pause");
					int b = play1->position;
					play1->position = play2->position;
					play2->position = b;
					Weizhi(play);//判断玩家位置是否在合法的范围内
					printf("交换完成,");
					system("pause");
					break;
				}
				else if (a == 2)
				{
    
    
					printf("%s选择了轰炸对方,%s向后退6格,", play1->name, play2->name);
					system("pause");
					play2->position -= 6;
					Weizhi(play);
					printf("执行成功,\n");
					system("pause");
					break;
				}
				else
				{
    
    
					printf("输入不正确,请重新输入");
					int ch;
					while ((ch = fgetc(stdin)) != EOF && ch != '\n');
					//清除缓冲区,防止缓冲区问题使程序不能正常进行
					scanf("%d", &a);
				}
			}
		}
			break;
		case 2:
			printf("%s踩到了地雷,退6格,", play1->name);
			system("pause");
			play1->position -= 6;
			Weizhi(play);
			break;
		case 3:
			printf("%s踩到了暂停,下一回合禁止行动", play1->name);
			system("pause");
			play1->flags = true;
			break;
		case 4:
			printf("%s踩到了时空隧道,前进十格", play1->name);
			system("pause");
			play1->position += 10;
			Weizhi(play);
			break;
		}
	}
	Weizhi(play);
	system("cls");//清除屏幕
}

We simulate the sieve and use props in the play function. We set the clear buffer to solve the scanf function buffer problem and avoid an infinite loop.
Note:
Array out of bounds. We want to make sure that each player's position is within the map.
Ideas for string comparison
reconstruction: 1. It can join the network to realize online battles. 2. Separately encapsulate the lucky roulette into a function. 3. Add more props. 4. Join other players. 5 points can be added, and points can be exchanged for props.

Summarize

Our five mini-games are all done. The following are points to pay attention to when making small games:
The scanf function is not safe. We can find a safe function to replace it, or solve the security problem of scanf
. Type arrays, as well as integer arrays, beware of arrays out of bounds, and pay attention to array parameters.
Construct frequently used codes as functions to reduce code redundancy.

Guess you like

Origin blog.csdn.net/2301_76986069/article/details/130986103