• C语言 - 你一定能看懂的三子棋详解(万字长文,傻瓜式解析)


    三子棋详解

    一.写在前面

    ☀️1.制作目的
    三子棋是一个有趣的小游戏,我们在学习编程中尝试制作这样有趣的小游戏更能激发我们学习编程的兴趣以及和信心。

    ☁️2.代码虽长但易理解
    为了使得读者更易看懂,我在游戏代码中加入了大量的注释,这使得文章中的代码量可能有点长,但更易理解。
    此外,文章中可能文字描述较少,我将各种解释放在了代码的注释中

    ⚡️3.采用宏定义
    在工程中,我使用了宏定义,将ROW(行)和 COL(列)定义为3使得代码的可读性和扩展性更高,不仅方便理解,且易于修改。

    ❄️4.清屏函数
    为了令界面看起来更加清爽,我在棋盘打印的函数中加入了清屏函数。

    📢5.文章或代码中某些名词解释如下

    • ROW 和 COL 表示行和列
    • menu 表示游戏菜单
    • InitBoard 表示棋盘数组的初始化
    • DisplayBoard 表示棋盘的展示
    • PlayerMove 表示玩家下棋
    • ComputerMove 表示电脑下棋
    • IsWin 表示输赢的判断

    二.效果预览

    🔆运行程序
    在这里插入图片描述

    🔆输入数字 1 ,进入游戏
    在这里插入图片描述

    🔆输入下棋坐标,进行下棋,玩家下的棋为 X ,电脑下的棋为 O
    比如我输入坐标 2 2,电脑随机下棋得到下图
    在这里插入图片描述

    🔆继续下棋,直到游戏胜利
    在这里插入图片描述

    三.整体思路

    🚀 1. 打印游戏菜单
    🚀 2. 玩家作出选择,进入游戏
    🚀 3. 定义棋盘,并初始化为空格
    🚀 4. 打印棋盘
    🚀 5. 进入对战,玩家和电脑下棋
    🚀6. 判断胜负

    四.开始制作

    1. 打印游戏菜单

    用一个函数打印游戏菜单,玩家输入 1 表示进入游戏,玩家输入 0 表示离开游戏。

    void menu()
    {
    	printf("*************************\n");
    	printf("*****    1. play    *****\n");
    	printf("*****    0. exit    *****\n");
    	printf("*************************\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    菜单效果如下:
    在这里插入图片描述

    2.用 do while 语句实现玩家作出选择

    玩家若选择 1 ,进入游戏。
    玩家若选择 0 ,退出游戏。
    玩家若输入其他数字,重新作出选择。

    主函数如下:

    int main()
    {
    	// 定义一个用来做选择的数
    	int input = 0;
    	
    	// 利用do while语句来作出选择
    	do
    	{
    		// 打印菜单
    		menu();
    		// 输入0或1来作出选择,1表示开始游戏,0表示离开游戏
    		scanf("%d", &input);
    		// 进入你所作出的选择中
    		switch (input)
    		{
    		case 1:
    			// 进入游戏
    			game();
    			break;
    		case 0:
    			// 离开游戏
    			break;
    		default:
    			// 如果玩家输入了其他数字,提醒玩家输入错误,要求玩家重新输入
    			printf("输入错误,请重新输入\n");
    			break;
    		}
    	} while (input != 1 && input != 0);
    
    	return 0;
    }
    
    • 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

    3.进入游戏

    注:将 ROW 和 COL 定义为 3

    // 用 ROW 表示棋盘的行,用 COL 表示棋盘的列
    #define ROW 3
    #define COL 3
    
    • 1
    • 2
    • 3

    进入游戏后,先定义一个二维数组,作为棋盘。

    	// 进入游戏后,第一件要做的事就是定义棋盘
    	char Board[ROW][COL];
    
    • 1
    • 2

    然后用一个初始化函数将这个二维数组的所有元素初始化为空格

    	// 定义棋盘后,因为还未开始下棋,所以需用一个函数将棋盘的每个元素初始化为空格
    	InitBoard(Board, ROW, COL);
    
    • 1
    • 2
    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] = ' ';
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4.打印一个 3*3 的棋盘

    在打印之前使用 system函数(引用头文件stdlib,h) 清空屏幕
    由于棋盘具有行和列,那么也就需要利用两个循环来打印每行每列的元素
    为了美观,当然不能只打印一些空格出来,利用各种符号来模拟出棋盘的边界也是很重要的。

    void DisplayBoard(char Board[ROW][COL], int row, int col)
    {
    	// 为了使每次打印棋盘更加清爽一点,我们在打印之前清空屏幕
    	system("cls");
    
    	// 定义 i 与 j 进行打印棋盘
    	int i = 0;
    	int j = 0;
    	for (i = 0; i < row; i++)
    	{
    		// 以此来打印每行的分隔行
    		printf("*---*---*---*\n"); 
    		// 打印每一行
    		printf("|");
    		for (j = 0; j < col; j++)
    		{
    			printf(" %c ", Board[i][j]);
    			printf("|");
    		}
    		// 每一行打印完后进行换行
    		printf("\n");
    	}
    	// 待循环走完后再打印一行来使棋盘美观
    	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

    效果如下:
    在这里插入图片描述

    5.对战开始

    打印棋盘后玩家与电脑开始对战
    利用 while 循环,胜负未分时循环继续,胜负已分时结束循环
    同时,在 while 循环中,我们用一个 iswin 函数和 if 语句来判断游戏的输赢

    对战过程如下:

    	char ret = 0;
    	while (1)
    	{
    		// 我们利用一个函数让玩家先手下棋
    		PlayerMove(Board, ROW, COL);
    		// 在玩家下棋成功后,打印棋盘。
    		DisplayBoard(Board, ROW, COL);
    		// 用ret函数接受函数的返回值,根据返回值来判断对战情况
    		ret = IsWin(Board, ROW, COL);
    		// 此处用if语句,除了ret为'C'时,其他情况都是游戏结束,跳出循环
    		if (ret != 'C')
    		{
    			break;
    		}
    		
    		// 在玩家下棋后让电脑下棋
    		ComputerMove(Board, ROW, COL);
    		// 在电脑下棋成功后,打印棋盘。
    		DisplayBoard(Board, ROW, COL);
    		// 用ret接受函数的返回值,根据返回值来判断对战情况
    		ret = IsWin(Board, ROW, COL);
    		// 此处用if语句,除了ret为'C'时,其他情况都是游戏结束,跳出循环
    		if (ret != 'C')
    		{
    			break;
    		}
    	}
    
    • 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

    玩家下棋

    规定玩家下的棋为 X 。
    玩家下棋时需让玩家输入要落子的坐标,输入完成成后程序判断玩家输入的坐标是否合法以及是否被占用,若合法且未被占用,下棋成功;若不合法或者坐标已被占用,提醒玩家重新输入。
    这里可以用到 while 循环,当下棋成功时跳出循环,当下棋失败时循环结束
    代码如下:

    void PlayerMove(char Board[ROW][COL], int row, int col)
    {
    	// 因为玩家下的棋可能不合法,所以我们此时应使用while循坏
    	// 在玩家下棋合法时跳出循环,不合法时在循环内让玩家继续输入坐标下棋
    	while (1)
    	{
    		// 玩家应输入坐标来下棋(如输入 2 1 表示下棋在第二行第一列)
    		int x = 0;
    		int y = 0;
    		scanf("%d %d", &x, &y);
    		// 在玩家下棋后判断玩家下棋是否合法。如果合法,下棋成功;如果不合法,重新输入。
    		// 判断合法的步骤如下(两个步骤,所以最好用两个if):
    		// 1.判断玩家输入的坐标是否在规定范围内
    		// 2.判断玩家输入的那个坐标是否被占用:
    		//		因为定义棋盘的数组是从0开始,玩家输入的坐标应从1开始
    		//		所以判断玩家输入的坐标是否合法时应将玩家输入的x坐标和y坐标都减1
    		if (x >= 1 && x <= 3 && y >= 1 && y <= 3)
    		{
    			if (Board[x - 1][y - 1] == ' ')
    			{
    				// 如果合法,改变数组的元素
    				// 我们规定,玩家下的棋为'X'
    				Board[x - 1][y - 1] = 'X';
    
    				// 改变元素后跳出while循环
    				break;
    			}
    			else
    			{
    				// 如果该位置被占用,提醒玩家重新输入
    				printf("你输入的坐标被占用,请重新输入一个坐标\n");
    			}
    		}
    		else
    		{
    			// 如果玩家输入的坐标不在棋盘内,提醒玩家重新输入
    			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
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    电脑下棋

    电脑下棋时需在程序中生成两个随机数来模拟电脑下棋,我们可以使用时间戳来完成这一任务
    首先需引用两个头文件

    // 时间戳的头文件
    #include 
    #include 
    
    • 1
    • 2
    • 3

    我们将生成的随机数模 2 ,就可以转化为0~2的随机数。这样,便不用判断坐标是否合法。
    但仍需判断坐标是否被占用。
    将电脑下的棋规定为 O
    和玩家下棋一样,这里也要用到 while 循环,当下棋成功时跳出循环,当下棋失败时循环结束。
    代码如下:

    void ComputerMove(char Board[ROW][COL], int row, int col)
    {
    	// 用时间戳生成随机数来模拟电脑随机下棋
    	srand((unsigned int)time(NULL));
    
    	// 由于电脑下棋的坐标可能被占用,所以此时需用一个循环
    	// 当下棋成功跳出循坏,当下棋失败循环继续
    	while (1)
    	{
    		// 将时间戳余3即可得到0~2的随机数
    		int x = rand() % 3;
    		int y = rand() % 3;
    
    		// 判断随机生成的坐标是否被占用,若被占用,重新生成;若未占用,改变棋盘的数组并跳出循环。
    		// 由于生成的数一定是0~2,所以只用判断是否被占用即可。
    		if (Board[x][y] == ' ')
    		{
    			Board[x][y] = 'O';
    			break;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    6.判断输赢

    在每次玩家下棋和电脑下棋之后,都要用一个 IsWin 函数来查看对战情况。
    我们用 ret 来接受该函数的返回值。用 X 表示玩家胜利,用 O 表示电脑胜利,用 C 表示游戏继续,用 D 表示平局。
    首先看是否有三个连着的相同的元素(元素不为空格)
    (1)判断每行
    (2)判断每列
    (3)判断对角线

    	int i = 0;
    
    	// 首先判断一整行是否有连着的相同的'X'或者'O',如果有则返回'X'或者'O'
    	for (i = 0; i < row; i++)
    	{
    		// 判断是否存在三个元素中两两相同且不为空格
    		if (Board[i][0] == Board[i][1] && Board[i][0] == Board[i][2] && Board[i][0] != ' ')
    		{
    			return Board[i][0];
    		}
    	}
    
    	// 再判断一竖行是否有连着的相同的'X'或者'O',如果有则返回'X'或者'O'
    	for (i = 0; i < col; i++)
    	{
    		// 判断是否存在三个元素中两两相同且不为空格
    		if (Board[0][i] == Board[1][i] && Board[0][i] == Board[2][i] && Board[0][i] != ' ')
    		{
    			return Board[0][i];
    		}
    	}
    
    	// 最后判断两个对角线的元素是否有连着的相同的'X'或者'O',如果有则返回'X'或者'O'
    	if (Board[0][0] == Board[1][1] && Board[0][0] == Board[2][2] && Board[0][0] != ' ')
    	{
    		return Board[0][0];
    	}
    	if (Board[0][2] == Board[1][1] && Board[0][2] == Board[2][0] && Board[0][2] != ' ')
    	{
    		return Board[0][2];
    	}
    
    • 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

    如果在判断完之后函数还未结束,说明胜负未分,此时要么是游戏还未结束,要么是游戏平局(所有的格子都没占满)。
    所以可以遍历这个二维数组,如果遇到空格说明游戏还未结束,返回 C
    在遍历完成后若函数还未结束,说明所有的空格已被占满。此时游戏结束,返回 D
    代码实现如下:

    	// 此处遍历棋盘,如果棋盘中还有空格则令游戏继续
    	for (i = 0; i < row; i++)
    	{	
    		int j = 0;
    		for (j = 0; j < col; j++)
    		{
    			if (Board[i][j] == ' ')
    			{
    				// 此处返回 C 表示英语单词continue,即游戏继续
    				return 'C';
    			}
    		}
    	}
    
    	// 如果游戏未分胜负,棋盘中又没有空位,则返回 D 表示英语单词draw,即游戏平局
    	return 'D';
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    该函数整体代码如下

    char IsWin(char Board[ROW][COL], int row, int col)
    {
    	int i = 0;
    
    	// 首先判断一整行是否有连着的相同的'X'或者'O',如果有则返回'X'或者'O'
    	for (i = 0; i < row; i++)
    	{
    		// 判断是否存在三个元素中两两相同且不为空格
    		if (Board[i][0] == Board[i][1] && Board[i][0] == Board[i][2] && Board[i][0] != ' ')
    		{
    			return Board[i][0];
    		}
    	}
    
    	// 再判断一竖行是否有连着的相同的'X'或者'O',如果有则返回'X'或者'O'
    	for (i = 0; i < col; i++)
    	{
    		// 判断是否存在三个元素中两两相同且不为空格
    		if (Board[0][i] == Board[1][i] && Board[0][i] == Board[2][i] && Board[0][i] != ' ')
    		{
    			return Board[0][i];
    		}
    	}
    
    	// 最后判断两个对角线的元素是否有连着的相同的'X'或者'O',如果有则返回'X'或者'O'
    	if (Board[0][0] == Board[1][1] && Board[0][0] == Board[2][2] && Board[0][0] != ' ')
    	{
    		return Board[0][0];
    	}
    	if (Board[0][2] == Board[1][1] && Board[0][2] == Board[2][0] && Board[0][2] != ' ')
    	{
    		return Board[0][2];
    	}
    
    	// 如果函数还能运行到这里,说明胜负还未分
    	// 胜负未分有两种情况,一种是棋盘还没占满,下棋进行;一种是棋盘已占满(即平局)。
    
    	// 此处遍历棋盘,如果棋盘中还有空格则令游戏继续
    	for (i = 0; i < row; i++)
    	{	
    		int j = 0;
    		for (j = 0; j < col; j++)
    		{
    			if (Board[i][j] == ' ')
    			{
    				// 此处返回 C 表示英语单词continue,即游戏继续
    				return 'C';
    			}
    		}
    	}
    
    	// 如果游戏未分胜负,棋盘中又没有空位,则返回 D 表示英语单词draw,即游戏平局
    	return 'D';
    }
    
    • 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

    在玩家与电脑下棋结束后,就需要判断是玩家赢了还是电脑赢了,这里使用 switch case 语句输出相应的内容:

    	// 在while循环结束后,即对战结束后,判断玩家赢还是电脑赢,又或是平局
    	switch (ret)
    	{
    	case 'X':
    		printf("恭喜你,你赢了!\n");
    		break;
    	case 'O':
    		printf("游戏结束,你输了。\n");
    		break;
    	case 'D':
    		printf("平局\n");
    		break;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    游戏到此结束!

    工程整体代码如下

    #pragma warning (disable:6031)
    #define _CRT_SECURE_NO_WARNINGS 1
    
    #include 
    
    // 时间戳的头文件
    #include 
    #include 
    
    // 用 ROW 表示棋盘的行,用 COL 表示棋盘的列
    #define ROW 3
    #define COL 3
    
    void menu()
    {
    	printf("*************************\n");
    	printf("*****    1. play    *****\n");
    	printf("*****    0. exit    *****\n");
    	printf("*************************\n");
    }
    
    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 DisplayBoard(char Board[ROW][COL], int row, int col)
    {
    	// 为了使每次打印棋盘更加清爽一点,我们在打印之前清空屏幕
    	system("cls");
    
    	// 定义 i 与 j 进行打印棋盘
    	int i = 0;
    	int j = 0;
    	for (i = 0; i < row; i++)
    	{
    		// 以此来打印每行的分隔行
    		printf("*---*---*---*\n"); 
    		// 打印每一行
    		printf("|");
    		for (j = 0; j < col; j++)
    		{
    			printf(" %c ", Board[i][j]);
    			printf("|");
    		}
    		// 每一行打印完后进行换行
    		printf("\n");
    	}
    	// 待循环走完后再打印一行来使棋盘美观
    	printf("*---*---*---*\n");
    
    }
    
    void PlayerMove(char Board[ROW][COL], int row, int col)
    {
    	// 因为玩家下的棋可能不合法,所以我们此时应使用while循坏
    	// 在玩家下棋合法时跳出循环,不合法时在循环内让玩家继续输入坐标下棋
    	while (1)
    	{
    		// 玩家应输入坐标来下棋(如输入 2 1 表示下棋在第二行第一列)
    		int x = 0;
    		int y = 0;
    		scanf("%d %d", &x, &y);
    		// 在玩家下棋后判断玩家下棋是否合法。如果合法,下棋成功;如果不合法,重新输入。
    		// 判断合法的步骤如下(两个步骤,所以最好用两个if):
    		// 1.判断玩家输入的坐标是否在规定范围内
    		// 2.判断玩家输入的那个坐标是否被占用:
    		//		因为定义棋盘的数组是从0开始,玩家输入的坐标应从1开始
    		//		所以判断玩家输入的坐标是否合法时应将玩家输入的x坐标和y坐标都减1
    		if (x >= 1 && x <= 3 && y >= 1 && y <= 3)
    		{
    			if (Board[x - 1][y - 1] == ' ')
    			{
    				// 如果合法,改变数组的元素
    				// 我们规定,玩家下的棋为'X'
    				Board[x - 1][y - 1] = 'X';
    
    				// 改变元素后跳出while循环
    				break;
    			}
    			else
    			{
    				// 如果该位置被占用,提醒玩家重新输入
    				printf("你输入的坐标被占用,请重新输入一个坐标\n");
    			}
    		}
    		else
    		{
    			// 如果玩家输入的坐标不在棋盘内,提醒玩家重新输入
    			printf("你输入的坐标不在棋盘内,请重新输入\n");
    		}
    	}
    }
    
    void ComputerMove(char Board[ROW][COL], int row, int col)
    {
    	// 用时间戳生成随机数来模拟电脑随机下棋
    	srand((unsigned int)time(NULL));
    
    	// 由于电脑下棋的坐标可能被占用,所以此时需用一个循环
    	// 当下棋成功跳出循坏,当下棋失败循环继续
    	while (1)
    	{
    		// 将时间戳余3即可得到0~2的随机数
    		int x = rand() % 3;
    		int y = rand() % 3;
    
    		// 判断随机生成的坐标是否被占用,若被占用,重新生成;若未占用,改变棋盘的数组并跳出循环。
    		// 由于生成的数一定是0~2,所以只用判断是否被占用即可。
    		if (Board[x][y] == ' ')
    		{
    			Board[x][y] = 'O';
    			break;
    		}
    	}
    }
    
    char IsWin(char Board[ROW][COL], int row, int col)
    {
    	int i = 0;
    
    	// 首先判断一整行是否有连着的相同的'X'或者'O',如果有则返回'X'或者'O'
    	for (i = 0; i < row; i++)
    	{
    		// 判断是否存在三个元素中两两相同且不为空格
    		if (Board[i][0] == Board[i][1] && Board[i][0] == Board[i][2] && Board[i][0] != ' ')
    		{
    			return Board[i][0];
    		}
    	}
    
    	// 再判断一竖行是否有连着的相同的'X'或者'O',如果有则返回'X'或者'O'
    	for (i = 0; i < col; i++)
    	{
    		// 判断是否存在三个元素中两两相同且不为空格
    		if (Board[0][i] == Board[1][i] && Board[0][i] == Board[2][i] && Board[0][i] != ' ')
    		{
    			return Board[0][i];
    		}
    	}
    
    	// 最后判断两个对角线的元素是否有连着的相同的'X'或者'O',如果有则返回'X'或者'O'
    	if (Board[0][0] == Board[1][1] && Board[0][0] == Board[2][2] && Board[0][0] != ' ')
    	{
    		return Board[0][0];
    	}
    	if (Board[0][2] == Board[1][1] && Board[0][2] == Board[2][0] && Board[0][2] != ' ')
    	{
    		return Board[0][2];
    	}
    
    	// 如果函数还能运行到这里,说明胜负还未分
    	// 胜负未分有两种情况,一种是棋盘还没占满,下棋进行;一种是棋盘已占满(即平局)。
    
    	// 此处遍历棋盘,如果棋盘中还有空格则令游戏继续
    	for (i = 0; i < row; i++)
    	{	
    		int j = 0;
    		for (j = 0; j < col; j++)
    		{
    			if (Board[i][j] == ' ')
    			{
    				// 此处返回 C 表示英语单词continue,即游戏继续
    				return 'C';
    			}
    		}
    	}
    
    	// 如果游戏未分胜负,棋盘中又没有空位,则返回 D 表示英语单词draw,即游戏平局
    	return 'D';
    }
    
    void game()
    {
    	// 进入游戏后,第一件要做的事就是定义棋盘
    	char Board[ROW][COL];
    	
    	// 定义棋盘后,因为还未开始下棋,所以需用一个函数将棋盘的每个元素初始化为空格
    	InitBoard(Board, ROW, COL);
    	
    	// 接着定义一个函数来打印棋盘
    	DisplayBoard(Board, ROW, COL);
    
    	// 玩家与电脑开始对战
    	// 利用while循环,胜负未分时循环继续,胜负已分时结束循环
    	// 同时,在while循环中,我们用一个iswin函数和if语句来判断游戏的输赢
    	
    	char ret = 0;
    	while (1)
    	{
    		// 我们利用一个函数让玩家先手下棋
    		PlayerMove(Board, ROW, COL);
    		// 在玩家下棋成功后,打印棋盘。
    		DisplayBoard(Board, ROW, COL);
    		// 用ret函数接受函数的返回值,根据返回值来判断对战情况
    		ret = IsWin(Board, ROW, COL);
    		// 此处用if语句,除了ret为'C'时,其他情况都是游戏结束,跳出循环
    		if (ret != 'C')
    		{
    			break;
    		}
    		
    		// 在玩家下棋后让电脑下棋
    		ComputerMove(Board, ROW, COL);
    		// 在电脑下棋成功后,打印棋盘。
    		DisplayBoard(Board, ROW, COL);
    		// 用ret接受函数的返回值,根据返回值来判断对战情况
    		ret = IsWin(Board, ROW, COL);
    		// 此处用if语句,除了ret为'C'时,其他情况都是游戏结束,跳出循环
    		if (ret != 'C')
    		{
    			break;
    		}
    	}
    
    	// 在while循环结束后,即对战结束后,判断玩家赢还是电脑赢,又或是平局
    	switch (ret)
    	{
    	case 'X':
    		printf("恭喜你,你赢了!\n");
    		break;
    	case 'O':
    		printf("游戏结束,你输了。\n");
    		break;
    	case 'D':
    		printf("平局\n");
    		break;
    	}
    }
    
    int main()
    {
    	// 定义一个用来做选择的数
    	int input = 0;
    	
    	// 利用do while语句来作出选择
    	do
    	{
    		// 打印菜单
    		menu();
    		// 输入0或1来作出选择,1表示开始游戏,0表示离开游戏
    		scanf("%d", &input);
    		// 进入你所作出的选择中
    		switch (input)
    		{
    		case 1:
    			// 进入游戏
    			game();
    			break;
    		case 0:
    			// 离开游戏
    			break;
    		default:
    			// 如果玩家输入了其他数字,提醒玩家输入错误,要求玩家重新输入
    			printf("输入错误,请重新输入\n");
    			break;
    		}
    	} while (input != 1 && input != 0);
    
    	return 0;
    }
    
    • 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
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
  • 相关阅读:
    Web自动化测试入门 : 前端页面的组成分析详解
    你必须要知道Mybatis中的OGNL表达式
    Visual Studio C++工程——包含目录、库目录、附加依赖项、附加包含目录、附加库目录配置与静态库、动态库的调用
    知识图谱之Cypher语言的使用
    第二章:C语言基础之数据类型+常量+变量+转义字符
    Clickhouse 用户自定义外部函数
    ESP32-C3入门教程 基础篇⑥——SPI通信点亮LCD显示屏
    java-php-python-ssm随心淘网管理系统计算机毕业设计
    Swin Transformer目标检测—训练自己数据集
    PostgreSQL常用命令使用
  • 原文地址:https://blog.csdn.net/m0_72940975/article/details/127448207