• 综合练习——三子棋小游戏


    前言

    相信大家在小时候都与自己的同桌在上课时一起摸过鱼,三子棋小游戏可以说是最方便的摸鱼小游戏了,那时的我们是在纸上玩,现在我们想在电脑上玩,我们可以不可以自己设计一下呢?下面我就与大家分享一下三子棋小游戏的设计思路,以及代码实现。

    思路分析

    首先我们想要下棋,是不是必须有个棋盘供我们落子,小时候我们用方格信纸画一个3x3的区域当棋盘,我们可以把这个区域看作一个二维数组,再设计上一些边界装饰,我们的棋盘就有了。那这个小游戏都需要什么功能呢?首先游戏需要有一个开始菜单,进入游戏会显示主菜单。其次我们在电脑上下棋肯定是与电脑对弈,所以我们还需要有玩家下棋,电脑下棋两个功能,我们需要知道玩家和电脑在哪里下棋了,我们是不是需要打印棋盘,最后还要判断是玩家获胜还是电脑获胜还是平局,是不是还需要一个判断胜负的功能。好了有了以上的功能我们就可以实现三子棋小游戏的全部需求。那这些功能具体如何实现,下面我带领大家一起来在编译器中写一写。

    代码实现

    游戏框架和主界面功能

    void menu()
    {
    	printf("************************\n");
    	printf("************************\n");
    	printf("*******1.开始游戏*******\n");
    	printf("*******0.结束游戏*******\n");
    	printf("************************\n");
    	printf("************************\n");
    }
    
    void game()
    {
    	//二维数组当作棋盘
    	char board[ROW][COL] = { 0 };
    
    }
    
    int main()
    {
    	int input = 0;
    
    	do
    	{
    		menu();
    	
    		printf("请选择是否开始游戏:");
    		scanf("%d", &input);
    
    		switch (input)
    		{
    		case 1:
    		   {
    			game();
    			break;
    		   }
    		case 0:
    		  {
    			printf("游戏结束\n");
    			break;
    		  }
    
    		default :
    		  {
    			printf("您的选择有误,请重新选择\n");
    		  }
    		}
    	} while (input);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    在这里插入图片描述

    因为我们想让游戏游戏可以反复游玩,所以我们使用循环来实现,进入循环首先打印游戏主菜单,我们对游戏菜单使用了函数封装,调用函数就可以实现打印主菜单,之后由玩家进行选择是否开始游戏,通过分支进行选择开始游戏或者结束游戏,玩家选择开始游戏后进入游戏的主体游玩,游戏主体我们同样使用函数封装起来。游戏的框架结构就是这样,之后我们就需要对游戏主体进行设计。

    游戏主体

    打印棋盘

    我们想要打印棋盘的样子如下图

    在这里插入图片描述
    我们想打印这样一个三子棋的棋盘,首先我们对棋盘进行分析,可以将棋盘拆分,我们将第一行看作 数据 | 数据 | 数据这样子,第二行我们看作---|---|---,我们可以将这两行的输出看成一组,作为一行进行打印,这样就可以对应我们的二维数组的行数,我们就可以把打印的这些东西放入一个循环当中for (i = 0; i < row; i++)根据数组的行数进行打印。

    void dispaly_board(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++)
    		{
    			printf(" %c ", board[i][j]);
    		    printf("|");
    		}
    
    		printf("\n");
    
    		for (j = 0; j < col; j++)
    			{
    				printf("---");
    				printf("|");
    			}
    
    		printf("\n");
    
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述
    好像这样还是与我们预期的样子不一样,我们继续分析,将我们需要的三子棋棋盘与这个棋盘对比,我们发现我们需要的棋盘,最后一个数据右边不打印|,最下面一组数据不打印---|---|---所以我们需要对打印进行一定约束,加上一定的限制条件,让他实现我们想要的需求。

    void dispaly_board(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++)
    		{
    			printf(" %c ", board[i][j]);
    			if (j < col - 1)
    			{
    				printf("|");
    			}
    		}
    
    		printf("\n");
    
    		if (i < row - 1)
    		{
    			for (j = 0; j < col; j++)
    			{
    				printf("---");
    				if (j < col - 1)
    				{
    					printf("|");
    				}
    			}
    		}
    
    		printf("\n");
    
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    我们让---|---|---少打印一次,同时数组元素后边的|也少打印一次,我们加上这些限制条件这样就可以实现我们的需求了。当我们执行代码
    在这里插入图片描述
    我们发现好像还是与我们的需求不一样啊,这怎么对不齐呢?原因是我们的二维数组进行初始化时,元素都为\0,我们需要对二维数组进行初始化,将数组元素都初始为' '

    初始化二维数组

    我们对二维数组进行初始化,编写一个初始化函数

    void init_board(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] = ' ';
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这样我们个二维数组当中每一个元素都赋值了,赋值为' ' 。我们再次打印我们的棋盘
    在这里插入图片描述
    我们的棋盘就打印完成了,接下来就到了下棋模块的编写了。

    玩家下棋

    玩家下棋的思路是,玩家输入坐标,首先我们进行判断,玩家输入的坐标是否合理,不合理重新输入,合理继续判断是否该位置已有棋子,已有旗子重新输入,没有旗子就落子。我们来看看这个函数的编写。

    void player_move(char board[ROW][COL], int row, int col)
    {
    	int x = 0;
    	int y = 0;
    
    	while (1)
    	{
    		printf("玩家请下棋:");
    		scanf("%d%d", &x, &y);
    
    		if (x >= 1 && x <= row && y >= 1 && y <= col)
    		{
    			if (board[x - 1][y - 1] == ' ')
    			{
    				board[x - 1][y - 1] = '*';
    				break;
    			}
    			else
    			{
    				printf("您选择的位置已有旗子,请重新选择:");
    			}
    		}
    
    		else
    		{
    			printf("您输入的坐标不合理,请重新选择:");
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    如上图,玩家进行输入,之后进行判断,如果在棋盘范围之内,再次判断,如果为空那么就落子,我们设计玩家的棋子为*,落子后跳出循环,如果已有旗子那么给出提示,再次让玩家输入,如果玩家输入旗子坐标超出棋盘,也给出相应提示,再次让玩家输入。
    在这里插入图片描述
    效果如上图,这里解释一下为什么board[x-1][y-1]这里的坐标要减一,因为玩家不懂编程,所以他们不知道数组的元素下标是从0开始的,所以他们输入的坐标值会比数组元素下标大1,所以这里进行了减一处理。

    电脑下棋

    电脑下棋思路同玩家下棋,只是电脑不需要提示,如果判断错误直接继续循环就可以了。那电脑如何获得坐标呢?我们可以使用随机数来获取,具体代码如下

    void computer_move(char board[ROW][COL], int row, int col)
    {
    
    	while (1)
    	{
    		int x = rand() % row;
    		int y = rand() % col;
    		if (board[x][y] == ' ')
    		{
    			board[x][y] = '#';
    			break;
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    因为我们使用了随机值,所以在主函数中要设置随机值的生成器srand((unsigned)time(NULL));还需要引入头文件#include #include,我们将生成的随机值跟他对应的行和列取余数,这样就控制了随机的大小,使生成的数就在棋盘的坐标范围内,之后进入循环,进行判断如果为' '就落子,我们设计的电脑玩家的棋子为#

    在这里插入图片描述

    判断输赢

    既然使游戏必然有输赢,所以我们需要设计一个函数来判断输赢

    int is_full(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;
    }
    
    char is_win(char board[ROW][COL], int row, int col)
    {
    	int i = 0;
    	for (i = 0; i < row; i++)
    	{
    		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
    		{
    			return board[i][0];
    		}
    	}
    
    	for (i = 0; i < col; i++)
    	{
    		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
    		{
    			return board[0][i];
    		}
    	}
    
    	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
    	{
    		return board[1][1];
    	}
    
    	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
    	{
    		return board[1][1];
    	}
    
    	if (1 == is_full(board,ROW,COL))
    	{
    		return 'Q';
    	}
    	else
    	{
    		return 'C';
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    当我们的同一行或者同一列再或者对角线上的数组元素相等且不等于' '时,我们返回对应的符号

    if (ret == '*')
    	{
    		printf("恭喜你,你赢了!!\n");
    	}
    	else if (ret == '#')
    	{
    		printf("对不起,电脑赢了!!\n");
    	}
    	else if (ret == 'Q')
    	{
    		printf("平局,在来一局吧!!\n");
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    通过判断给出相应的信息,最后可以打印一下棋盘最后的结果。

    最终游戏代码展示

    test.c

    #define  _CRT_SECURE_NO_WARNINGS 1
    
    #include"game1.h"
    
    void menu()
    {
    	printf("************************\n");
    	printf("************************\n");
    	printf("*******1.开始游戏*******\n");
    	printf("*******0.结束游戏*******\n");
    	printf("************************\n");
    	printf("************************\n");
    }
    
    void game()
    {
    	//二维数组当作棋盘
    	char board[ROW][COL] = {0};
    	char ret = 0;
    	初始化
    	init_board(board,ROW,COL);
    	//打印棋盘
    	dispaly_board(board, ROW, COL);
    
    	while (1)
    	{
    		//玩家下棋
    		player_move(board, ROW, COL);
    		//查看是否落子
    		dispaly_board(board, ROW, COL);
    		//判断输赢
    		ret = is_win(board, ROW, COL);
    		if (ret != 'C')
    			break;
    		//电脑下棋
    		computer_move(board, ROW, COL);
    		//查看是否落子
    		dispaly_board(board, ROW, COL);
    		//判断输赢
    		ret = is_win(board, ROW, COL);
    		if (ret != 'C')
    			break;
    	}
    	if (ret == '*')
    	{
    		printf("恭喜你,你赢了!!\n");
    	}
    	else if (ret == '#')
    	{
    		printf("对不起,电脑赢了!!\n");
    	}
    	else if (ret == 'Q')
    	{
    		printf("平局,在来一局吧!!\n");
    	}
    
    	dispaly_board(board, ROW, COL);
    }
    
    int main()
    {
    	srand((unsigned)time(NULL));
    	int input = 0;
    
    	do
    	{
    		menu();
    	
    		printf("请选择是否开始游戏:");
    		scanf("%d", &input);
    
    		switch (input)
    		{
    		case 1:
    		   {
    			game();
    			break;
    		   }
    		case 0:
    		  {
    			printf("游戏结束\n");
    			break;
    		  }
    
    		default :
    		  {
    			printf("您的选择有误,请重新选择\n");
    		  }
    		}
    	} while (input);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    game.c

    #define  _CRT_SECURE_NO_WARNINGS 1
    
    #include"game1.h"
    
    //初始化棋盘
    void init_board(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 dispaly_board(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++)
    		{
    			printf(" %c ", board[i][j]);
    			if (j < col - 1)
    			{
    				printf("|");
    			}
    		}
    
    		printf("\n");
    
    		if (i < row - 1)
    		{
    			for (j = 0; j < col; j++)
    			{
    				printf("---");
    				if (j < col - 1)
    				{
    					printf("|");
    				}
    			}
    		}
    
    		printf("\n");
    
    	}
    }
    
    //玩家下棋
    void player_move(char board[ROW][COL], int row, int col)
    {
    	int x = 0;
    	int y = 0;
    
    	while (1)
    	{
    		printf("玩家请下棋:");
    		scanf("%d%d", &x, &y);
    
    		if (x >= 1 && x <= row && y >= 1 && y <= col)
    		{
    			if (board[x - 1][y - 1] == ' ')
    			{
    				board[x - 1][y - 1] = '*';
    				break;
    			}
    			else
    			{
    				printf("您选择的位置已有旗子,请重新选择:");
    			}
    		}
    
    		else
    		{
    			printf("您输入的坐标不合理,请重新选择:");
    		}
    	}
    }
    
    void computer_move(char board[ROW][COL], int row, int col)
    {
    
    	while (1)
    	{
    		int x = rand() % row;
    		int y = rand() % col;
    		if (board[x][y] == ' ')
    		{
    			board[x][y] = '#';
    			break;
    		}
    	}
    }
    
    int is_full(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;
    }
    
    char is_win(char board[ROW][COL], int row, int col)
    {
    	int i = 0;
    	for (i = 0; i < row; i++)
    	{
    		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
    		{
    			return board[i][0];
    		}
    	}
    
    	for (i = 0; i < col; i++)
    	{
    		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
    		{
    			return board[0][i];
    		}
    	}
    
    	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
    	{
    		return board[1][1];
    	}
    
    	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
    	{
    		return board[1][1];
    	}
    
    	if (1 == is_full(board,ROW,COL))
    	{
    		return 'Q';
    	}
    	else
    	{
    		return 'C';
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153

    game.h

    #pragma once
    
    #include
    #include
    #include
    
    #define ROW 3
    #define COL 3
    
    //初始化数组
    void init_board(char board[ROW][COL], int row, int col);
    
    //打印数组
    void dispaly_board(char board[ROW][COL], int row, int col);
    
    //玩家下棋
    void player_move(char board[ROW][COL], int row, int col);
    
    //电脑下棋
    void computer_move(char board[ROW][COL], int row, int col);
    
    //判断输赢
    char is_win(char board[ROW][COL], int row, int col);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
  • 相关阅读:
    [C++]多态(下)
    22-09-20 西安 谷粒商城(04)Redisson、布隆过滤器、AOP赋能自定义注解@GmallCache
    Docker 基本管理
    mysql MVC jsp实现表分页
    JVM之【GC-垃圾清除算法】
    python安装selenium(Firefox和Chrome)+元素定位
    如何设置代理ip服务器地址
    解析Linux top 系统信息并生成动态图表
    Unity webgl 关于适配网页 ,并且用到js中的SetTimeOut和SetInterval()
    Linux 线程控制 —— 线程清理 pthread_cleanup_push
  • 原文地址:https://blog.csdn.net/weixin_64182409/article/details/126047702