0

C语言小项目——井字棋游戏(升级版)

 2 years ago
source link: https://blog.csdn.net/m0_63325890/article/details/122639733
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Wassup guys😎

今天是我们的C语言小项目「井字棋升级版」

Let’s get it!
在这里插入图片描述





井字棋,又名三子棋,英文名叫Tic-Tac-Toe;

是一种在3x3格子上进行的连珠游戏,和五子棋类似,格线排成井字故得名。

游戏需要的工具仅为纸和笔,然后由分别代表O和X的两个游戏者轮流在格子里留下标记(一般来说先手者为X),任意三个标记形成一条直线,则为获胜。

其游戏过程就像下面这样👇
在这里插入图片描述

游戏效果展示

游戏运行结果如下👇

在这里插入图片描述

我在函数这一篇总结中,讲过函数的声明和定义,所有这里我用三个文件来实现这个三子棋游戏

友友们可以将以下代码复制到自己的编译器当中运行:

game.h

游戏函数的声明

#pragma once
//游戏函数的声明
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//棋盘的行数
#define ROW 3 

//棋盘的列数
#define COL 3


//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);

//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col);

//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);

//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);

//电脑检查自己是否会赢
int CheckComputer(char board[ROW][COL], int row, int col);

//电脑检查玩家是否会赢
int CheckPlayer(char board[ROW][COL], int row, int col, int k);

//判断输赢函数
char Is_Win(char board[ROW][COL], int row, int col);
/*
1.玩家赢 ---> 返回'*'
2.电脑赢 ---> 返回'#'
3. 平局  ---> 返回'P'
4. 继续  ---> 返回'C'
*/
newCodeMoreWhite.png

game.c

游戏函数的实现

#define _CRT_SECURE_NO_WARNINGS 1
//游戏函数的实现

#include "game.h"

void InitBoard(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++)
		{
			board[i][j] = ' ';
		}
	}
}

void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	//row = 3行
	//col = 3列
	for (i = 0; i < row; i++)
	{
		if (i == 0)
		{
			printf("┌----┬----┬----┐\n");
		}
		if ((i == 1) || (i == 2))
		{
			printf("├----┼----┼----┤\n");
		}
		for (int j = 0; j < col; j++)
		{
			printf("│  %c ", board[i][j]);
		}
		printf("│\n");
	}
	printf("└----┴----┴----┘\n");
}


void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("玩家下棋,请输入坐标:> ");
		scanf("%d %d", &x, &y);
		printf("你下棋的位置↓\n");
		if ((x >= 1 && x <= row) && (y >= 1 && y <= col))
		{
			if (board[x-1][y-1] == ' ')
			{
				board[x-1][y-1] = 'x';
				break;
			}
			else
			{
				printf("该坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,超出范围\n");
		}
	}
}


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

	//z是判断变量
	int z = 0;

	z = CheckComputer(board, row, col);

	printf("电脑下棋的位置↓\n");
	while (0 == z)
	{
		x = rand() % row;
		y = rand() % col;

		if (board[x][y] == ' ')
		{
			board[x][y] = 'o';
			break;
		}
	}
}
//电脑检查自己能不能赢
int CheckComputer(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;

	//k用于返回值
	int k = 0;
	while (0 == k)
	{
		//电脑判断自己在三行上是否会赢
		for (i = 0; i < row; i++)
		{
			//如果第一个格子和第二个格子都是电脑的棋子,并且第三个格子是空的
			//那么电脑直接落子
			if (board[i][0] == board[i][1] && (board[i][0] == 'o' || board[i][1] == 'o') && board[i][2] == ' ')
			{
				board[i][2] = 'o';
				k = 1;
				break;
			}
			if (board[i][0] == board[i][2] && (board[i][0] == 'o' || board[i][2] == 'o') && board[i][1] == ' ')
			{
				board[i][1] = 'o';
				k = 1;
				break;
			}

			if (board[i][1] == board[i][2] && (board[i][1] == 'o' || board[i][2] == 'o') && board[i][0] == ' ')
			{
				board[i][0] = 'o';
				k = 1;
				break;
			}
		}
		if (k != 0)
			break;

		//电脑判断自己在三列上是否会赢
		for (j = 0; j < col; j++)
		{
			if (board[0][j] == board[1][j] && (board[0][j] == 'o' || board[1][j] == 'o') && board[2][j] == ' ')
			{
				board[2][j] = 'o';
				k = 1;
				break;
			}

			if (board[0][j] == board[2][j] && (board[0][j] == 'o' || board[2][j] == 'o') && board[1][j] == ' ')
			{
				board[1][j] = 'o';
				k = 1;
				break;
			}
			if (board[1][j] == board[2][j] && (board[1][j] == 'o' || board[2][j] == 'o') && board[0][j] == ' ')
			{
				board[0][j] = 'o';
				k = 1;
				break;
			}
		}
		if (k != 0)
			break;

		//使用while循环判断对角线是否会赢
		while (0 == k)
		{
			//左边对角线
			if (board[0][0] == board[1][1] && (board[0][0] == 'o' || board[1][1] == 'o') && board[2][2] == ' ')
			{
				board[2][2] = 'o';
				k = 1;
				break;
			}

			if (board[0][0] == board[2][2] && (board[0][0] == 'o' || board[2][2] == 'o') && board[1][1] == ' ')
			{
				board[1][1] = 'o';
				k = 1;
				break;
			}

			if (board[1][1] == board[2][2] && (board[1][1] == 'o' || board[2][2] == 'o') && board[0][0] == ' ')
			{
				board[0][0] = 'o';
				k = 1;
				break;
			}

			//右边对角线
			if (board[0][2] == board[1][1] && (board[0][2] == 'o' || board[1][1] == 'o') && board[2][0] == ' ')
			{
				board[2][0] = 'o';
				k = 1;
				break;
			}

			if (board[0][2] == board[2][0] && (board[0][2] == 'o' || board[2][0] == 'o') && board[1][1] == ' ')
			{
				board[1][1] = 'o';
				k = 1;
				break;
			}
			if (board[1][1] == board[2][0] && (board[1][1] == 'o' || board[2][0] == 'o') && board[0][2] == ' ')
			{
				board[0][2] = 'o';
				k = 1;
				break;
			}
			break;
		}

		k = CheckPlayer(board, row, col, k);

		return k;
	}

}
//检查玩家是否会赢
int CheckPlayer(char board[ROW][COL], int row, int col, int k)
{
	int i = 0;
	int j = 0;
	while (0 == k)
	{
		//判断玩家在三行上是否会赢
		for (i = 0; i < row; i++)
		{
			if (board[i][0] == board[i][1] && (board[i][0] == 'x' || board[i][1] == 'x') && board[i][2] == ' ')
			{
				board[i][2] = 'o';
				k = 1;
				break;
			}
			if (board[i][0] == board[i][2] && (board[i][0] == 'x' || board[i][2] == 'x') && board[i][1] == ' ')
			{
				board[i][1] = 'o';
				k = 1;
				break;
			}
			if (board[i][2] == board[i][1] && (board[i][2] == 'x' || board[i][1] == 'x') && board[i][0] == ' ')
			{
				board[i][0] = 'o';
				k = 1;
				break;
			}
		}
		if (k != 0)
			break;

		//判断玩家在三列上是否会赢
		for (j = 0; j < col; j++)
		{
			if (board[0][j] == board[1][j] && (board[1][j] == 'x' || board[0][j] == 'x') && board[2][j] == ' ')
			{
				board[2][j] = 'o';
				k = 1;
				break;
			}

			if (board[0][j] == board[2][j] && (board[2][j] == 'x' || board[0][j] == 'x') && board[1][j] == ' ')
			{
				board[1][j] = 'o';
				k = 1;
				break;
			}

			if (board[1][j] == board[2][j] && (board[2][j] == 'x' || board[1][j] == 'x') && board[0][j] == ' ')
			{
				board[0][j] = 'o';
				k = 1;
				break;
			}
		}
		break;
	}

	//判断玩家在对角线上是否会赢
	while (0 == k)
	{
		//左边对角线
		if (board[0][0] == board[1][1] && (board[1][1] == 'x' || board[0][0] == 'x') && board[2][2] == ' ')
		{
			board[2][2] = 'o';
			k = 1;
			break;
		}
		if (board[0][0] == board[2][2] && (board[2][2] == 'x' || board[0][0] == 'x') && board[1][1] == ' ')
		{
			board[1][1] = 'o';
			k = 1;
			break;
		}
		if (board[1][1] == board[2][2] && (board[1][1] == 'x' || board[2][2] == 'x') && board[0][0] == ' ')
		{
			board[0][0] = 'o';
			k = 1;
			break;
		}

		//右边对角线
		if (board[0][2] == board[1][1] && (board[0][2] == 'x' || board[1][1] == 'x') && board[2][0] == ' ')
		{
			board[2][0] = 'o';
			k = 1;
			break;
		}

		if (board[0][2] == board[2][0] && (board[2][0] == 'x' || board[0][2] == 'x') && board[1][1] == ' ')
		{
			board[1][1] = 'o';
			k = 1;
			break;
		}

		if (board[1][1] == board[2][0] && (board[2][0] == 'x' || board[1][1] == 'x') && board[0][2] == ' ')
		{
			board[0][2] = 'o';
			k = 1;
			break;
		}
		break;
	}
	return k;
}

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)
{
	//1.判断输赢
	int i = 0;

	//三行判断
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
		{
			return board[i][1];
		}
	}

	//三列判断
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[2][i] != ' ')
		{
			return board[1][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[2][0] != ' ')
	{
		return board[1][1];
	}

	//2.判断平局
	if (1 == is_full(board, row, col))
	{
		return 'P';
	}

	//3.游戏继续
	return 'C';
}
newCodeMoreWhite.png

test.c

#define _CRT_SECURE_NO_WARNINGS 1
//测试游戏
#include "game.h"

void menu()
{
	printf("\n");
	printf("********三子棋小游戏********\n");
	printf("****************************\n");
	printf("*********  1.Play  *********\n");
	printf("*********  0.Exit  *********\n");
	printf("****************************\n");
}

void game()
{
	//定义一个棋盘数组
	char board[ROW][COL];

	//初始化棋盘
	InitBoard(board, ROW, COL);

	//打印棋盘
	DisplayBoard(board, ROW, COL);

	char ret = 0;
	while (1)
	{
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		ret = Is_Win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}

		ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		ret = Is_Win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}

	if (ret == 'x')
	{
		printf("恭喜你,赢得了游戏胜利\n");
	}
	else if (ret == 'o')
	{
		printf("不是吧,你连电脑都赢不了\n");
	}
	else
	{
		printf("居然和电脑打成了平手,你不行啊!\n");
	}
}

int main()
{
	srand((unsigned int)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);
	return 0;
}
newCodeMoreWhite.png

游戏代码详解

🍑 游戏菜单构建

打印一个游戏菜单,有两种选择

1、玩游戏

0、退出游戏

代码实现📝

void menu()
{
	printf("\n");
	printf("********三子棋小游戏********\n");
	printf("****************************\n");
	printf("*********  1.Play  *********\n");
	printf("*********  0.Exit  *********\n");
	printf("****************************\n");
}

在这里插入图片描述

🍑 主函数构建

当运行这个游戏的时候,会首先生成一个菜单,让我们选择;

但是当我玩完一局过后,还想再玩,所以会用到循环

代码实现📝

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);
	return 0;
}

在这里插入图片描述

🍑 三子棋的过程

game()函数,去实现三子棋的过程

🍅 构建棋盘数组

三子棋,顾名思义,我们要定义一个3x3的二维数组棋盘

void game()
{
	//定义一个棋盘数组
	char board[ROW][COL];
}

🍅 初始化棋盘数组

当棋盘数组定义好以后,我们就要初始化棋盘

可以看到,这个棋盘里面最开始都是空的,所以我们把棋盘定义成空的字符
在这里插入图片描述

首先我们要在 game.h头文件 里面去声明这个初始化函数

//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);

然后再去 game.c游戏函数 里面实现

void InitBoard(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++)
		{
			board[i][j] = ' ';
		}
	}
}

在这里插入图片描述

注意:后面的函数也是一样,要先去头文件里面声明,再到游戏函数里面去实现

🍅 打印棋盘

我们初始化好棋盘以后,要在屏幕上打印一下

在这里插入图片描述
聪明的朋友能猜到这个棋盘是怎么想出来的吗🤣

代码实现📝

void DisplayBoard(char board[ROW][COL], int row, int col)
{

	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		if (i == 0)
		{
			printf("┌----┬----┬----┐\n");
		}
		if ((i == 1) || (i == 2))
		{
			printf("├----┼----┼----┤\n");
		}
		for (int j = 0; j < col; j++)
		{
			printf("│  %c ", board[i][j]);
		}
		printf("│\n");
	}
	printf("└----┴----┴----┘\n");
}

在这里插入图片描述

🍅 玩家下棋

接下来就是玩家开始下棋;

由于是个二维数组,并且数组下标是从0开始的,但是玩家可能不是程序员,所以不知道数组的下标;

所以这里把下标定义从1开始;

并且当玩家在棋盘落子以后,我们把棋盘打印出来。

代码实现📝

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("玩家下棋,请输入坐标:> ");
		scanf("%d %d", &x, &y);
		printf("你下棋的位置↓\n");
		if ((x >= 1 && x <= row) && (y >= 1 && y <= col))
		{
			if (board[x-1][y-1] == ' ')
			{
				board[x-1][y-1] = 'x';//玩家落子用'*'表示
				break;
			}
			else
			{
				printf("该坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,超出范围\n");
		}
	}
}

在这里插入图片描述

🍅 电脑下棋

电脑下棋的方法我们选择用时间戳来生成一个随机数,并把随机数的范围控制在0~3以内;

关于随机数的生成,这里简单说一下
在这里插入图片描述

代码实现📝

void ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋的位置↓\n");
	
	while (1)
	{
		x = rand() % row;
		y = rand() % col;

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

}

注意,我们这里调用rand函数,必须在主函数里面设置一下srand函数
在这里插入图片描述
在这里插入图片描述

🍅 AI电脑算法升级

如果你运行了这个程序以后,会发现电脑的走法貌似不太聪明的样子;

因为我们用随机数生成,会造成玩家赢的很轻松;

那如果电脑有了AI的思想呢?它就知道如何进攻、防守。

那么来思考一下,你是怎么下三子棋的?

1、如果我们在三行、三列、对角线上,下了两个棋子后,我们会继续下第三个;

2、如果对方在三行、三列、对角线上有了相同两个棋子后,我们会堵截,不让它下第三个;

此时我们就有了思路👇

电脑需要的就是在:出现两个相同的棋子的地方下自己的棋子就好了

📝代码一

ComputerMove函数进行修改;

电脑下棋需要加一步,获取返回值,如果返回值为0,那么电脑只有乖乖的按照伪随机数来走啦

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

	//z返回值
	int z = 0;

	z = CheckComputer(board, row, col);

	printf("电脑下棋的位置↓\n");
	while (0 == z)
	{
		x = rand() % row;
		y = rand() % col;

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

📝代码二

定义一个函数:CheckComputer,作用是电脑检查自己是否会赢;

1、电脑在坐标(1,1)和坐标(1,2)的格子进行判断,如果(1,1)或者(1,2)的格子都为自己的棋子,那么直接在(1,3)的格子落子👇
在这里插入图片描述
2、电脑在坐标(1,1)和坐标(1,3)的格子进行判断,如果(1,1)或者(1,3)的格子都为自己的棋子,那么直接在坐标(1,2)的格子落子👇
在这里插入图片描述
3、电脑在坐标(1,2)和坐标(1,3)的格子进行判断,如果(1,2)或者(1,3)的格子都为自己的棋子,那么直接在坐标(1,1)的格子落子👇
在这里插入图片描述
此时我们只需要定义一个循环,三行都进行判断即可,同理,三列和对角线也是一样

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

	//k用于返回值
	int k = 0;
	while (0 == k)
	{
		//电脑判断自己在三行上是否会赢
		for (i = 0; i < row; i++)
		{
			//如果第一个格子和第二个格子都是电脑的棋子,并且第三个格子是空的
			//那么电脑直接落子
			if (board[i][0] == board[i][1] && (board[i][0] == 'o' || board[i][1] == 'o') && board[i][2] == ' ')
			{
				board[i][2] = 'o';
				k = 1;
				break;
			}
			if (board[i][0] == board[i][2] && (board[i][0] == 'o' || board[i][2] == 'o') && board[i][1] == ' ')
			{
				board[i][1] = 'o';
				k = 1;
				break;
			}

			if (board[i][1] == board[i][2] && (board[i][1] == 'o' || board[i][2] == 'o') && board[i][0] == ' ')
			{
				board[i][0] = 'o';
				k = 1;
				break;
			}
		}
		if (k != 0)
			break;

		//电脑判断自己在三列上是否会赢
		for (j = 0; j < col; j++)
		{
			if (board[0][j] == board[1][j] && (board[0][j] == 'o' || board[1][j] == 'o') && board[2][j] == ' ')
			{
				board[2][j] = 'o';
				k = 1;
				break;
			}

			if (board[0][j] == board[2][j] && (board[0][j] == 'o' || board[2][j] == 'o') && board[1][j] == ' ')
			{
				board[1][j] = 'o';
				k = 1;
				break;
			}
			if (board[1][j] == board[2][j] && (board[1][j] == 'o' || board[2][j] == 'o') && board[0][j] == ' ')
			{
				board[0][j] = 'o';
				k = 1;
				break;
			}
		}
		if (k != 0)
			break;

		//使用while循环判断对角线是否会赢
		while (0 == k)
		{
			//左边对角线
			if (board[0][0] == board[1][1] && (board[0][0] == 'o' || board[1][1] == 'o') && board[2][2] == ' ')
			{
				board[2][2] = 'o';
				k = 1;
				break;
			}

			if (board[0][0] == board[2][2] && (board[0][0] == 'o' || board[2][2] == 'o') && board[1][1] == ' ')
			{
				board[1][1] = 'o';
				k = 1;
				break;
			}

			if (board[1][1] == board[2][2] && (board[1][1] == 'o' || board[2][2] == 'o') && board[0][0] == ' ')
			{
				board[0][0] = 'o';
				k = 1;
				break;
			}

			//右边对角线
			if (board[0][2] == board[1][1] && (board[0][2] == 'o' || board[1][1] == 'o') && board[2][0] == ' ')
			{
				board[2][0] = 'o';
				k = 1;
				break;
			}

			if (board[0][2] == board[2][0] && (board[0][2] == 'o' || board[2][0] == 'o') && board[1][1] == ' ')
			{
				board[1][1] = 'o';
				k = 1;
				break;
			}
			if (board[1][1] == board[2][0] && (board[1][1] == 'o' || board[2][0] == 'o') && board[0][2] == ' ')
			{
				board[0][2] = 'o';
				k = 1;
				break;
			}
			break;
		}

		k = CheckPlayer(board, row, col, k);

		return k;
	}

}
newCodeMoreWhite.png

三行
在这里插入图片描述
三列
在这里插入图片描述
左对角线
在这里插入图片描述
右对角线
在这里插入图片描述
完整代码
在这里插入图片描述

📝代码二

定义一个函数:CheckPlayer,作用是电脑检查玩家是否会赢;

如果玩家在三行、三列、对角线上有了相同两个棋子后,电脑会堵截,不让玩家下第三个

1、电脑在坐标(1,1)和坐标(1,2)的格子进行判断,如果(1,1)或者(1,2)的格子都为玩家的棋子,那么直接在(1,3)的格子落子堵截👇
在这里插入图片描述
2、电脑在坐标(1,1)和坐标(1,3)的格子进行判断,如果(1,1)或者(1,3)的格子都为玩家的棋子,那么直接在(1,2)的格子落子堵截👇
在这里插入图片描述
3、电脑在坐标(1,2)和坐标(1,3)的格子进行判断,如果(1,2)或者(1,3)的格子都为玩家的棋子,那么直接在(1,1)的格子落子堵截👇
在这里插入图片描述
此时我们只需要定义一个循环,三行都进行判断即可,同理,三列和对角线也是一样

int CheckPlayer(char board[ROW][COL], int row, int col, int k)
{
	int i = 0;
	int j = 0;
	while (0 == k)
	{
		//判断玩家在三行上是否会赢
		for (i = 0; i < row; i++)
		{
			if (board[i][0] == board[i][1] && (board[i][0] == 'x' || board[i][1] == 'x') && board[i][2] == ' ')
			{
				board[i][2] = 'o';
				k = 1;
				break;
			}
			if (board[i][0] == board[i][2] && (board[i][0] == 'x' || board[i][2] == 'x') && board[i][1] == ' ')
			{
				board[i][1] = 'o';
				k = 1;
				break;
			}
			if (board[i][2] == board[i][1] && (board[i][2] == 'x' || board[i][1] == 'x') && board[i][0] == ' ')
			{
				board[i][0] = 'o';
				k = 1;
				break;
			}
		}
		if (k != 0)
			break;

		//判断玩家在三列上是否会赢
		for (j = 0; j < col; j++)
		{
			if (board[0][j] == board[1][j] && (board[1][j] == 'x' || board[0][j] == 'x') && board[2][j] == ' ')
			{
				board[2][j] = 'o';
				k = 1;
				break;
			}

			if (board[0][j] == board[2][j] && (board[2][j] == 'x' || board[0][j] == 'x') && board[1][j] == ' ')
			{
				board[1][j] = 'o';
				k = 1;
				break;
			}

			if (board[1][j] == board[2][j] && (board[2][j] == 'x' || board[1][j] == 'x') && board[0][j] == ' ')
			{
				board[0][j] = 'o';
				k = 1;
				break;
			}
		}
		break;
	}

	//判断玩家在对角线上是否会赢
	while (0 == k)
	{
		//左边对角线
		if (board[0][0] == board[1][1] && (board[1][1] == 'x' || board[0][0] == 'x') && board[2][2] == ' ')
		{
			board[2][2] = 'o';
			k = 1;
			break;
		}
		if (board[0][0] == board[2][2] && (board[2][2] == 'x' || board[0][0] == 'x') && board[1][1] == ' ')
		{
			board[1][1] = 'o';
			k = 1;
			break;
		}
		if (board[1][1] == board[2][2] && (board[1][1] == 'x' || board[2][2] == 'x') && board[0][0] == ' ')
		{
			board[0][0] = 'o';
			k = 1;
			break;
		}

		//右边对角线
		if (board[0][2] == board[1][1] && (board[0][2] == 'x' || board[1][1] == 'x') && board[2][0] == ' ')
		{
			board[2][0] = 'o';
			k = 1;
			break;
		}

		if (board[0][2] == board[2][0] && (board[2][0] == 'x' || board[0][2] == 'x') && board[1][1] == ' ')
		{
			board[1][1] = 'o';
			k = 1;
			break;
		}

		if (board[1][1] == board[2][0] && (board[2][0] == 'x' || board[1][1] == 'x') && board[0][2] == ' ')
		{
			board[0][2] = 'o';
			k = 1;
			break;
		}
		break;
	}
	return k;
}
newCodeMoreWhite.png

三行
在这里插入图片描述
三列
在这里插入图片描述
左对角线
在这里插入图片描述
右对角线
在这里插入图片描述
完整代码
在这里插入图片描述

🍅 判断输赢

当玩家或者电脑每下一步棋的时候,我们就定义一个函数,判断一下谁赢了;

当棋盘已经落满棋子的时候,并且谁也没有赢,我们就认定为平局;

当棋盘还没有落满棋子的时候,并且谁也没有赢,游戏就继续;

1、玩家赢 —> 返回x

2、电脑赢 —> 返回o

3、平局 —> 返回P

4、继续 —> 返回C

那么怎么来判断输赢呢?

其实很简单,你看这个棋盘👇
在这里插入图片描述
当三行或者三列,以及两条对角线都落满相同的棋子时,那就就赢了;

举个例子👇

如图,当第一行全部落满相同的棋子
在这里插入图片描述

那么我们就返回中间红色这个位置的棋盘,并拿去判断;
在这里插入图片描述
如果是x号,那么就是玩家胜利;

如果是o号,那么就是电脑胜利

代码示例📝

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)
{
	//1.判断输赢
	int i = 0;

	//三行判断
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
		{
			return board[i][1];
		}
	}

	//三列判断
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[2][i] != ' ')
		{
			return board[1][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[2][0] != ' ')
	{
		return board[1][1];
	}

	//2.判断平局
	if (1 == is_full(board, row, col))
	{
		return 'P';
	}

	//3.游戏继续
	return 'C';
}
newCodeMoreWhite.png

三行判断
在这里插入图片描述
三列判断
在这里插入图片描述
对角线判断
在这里插入图片描述
判断平局
在这里插入图片描述
游戏继续
在这里插入图片描述

🍅 主函数判断输赢

玩家和电脑下棋的思路可以这样理解👇

当玩家每下一步棋时,就进行输赢判断;

当电脑每下一步棋时,也进行输赢判断;

但是玩家走一步,电脑走一步,必须要拿循环来实现;

那么跳出循环的条件是什么呢?

上面已经分析了判断输赢的四种情况;

如果当棋盘已经全部落子了,就表示游戏不能再继续了,所以就可以跳出循环;

跳出来以后,就把上面判断输赢函数返回的结果来进行比较;

如果是x,表示玩家赢了;

如果是o,表示电脑赢了;

如果是P,表示平局了。

void game()
{
	char ret = 0;
	while (1)
	{
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		ret = Is_Win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}

		ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		ret = Is_Win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}

	if (ret == 'x')
	{
		printf("恭喜你,赢得了游戏胜利\n");
	}
	else if (ret == 'o')
	{
		printf("不是吧,你连电脑都赢不了\n");
	}
	else
	{
		printf("居然和电脑打成了平手,你不行啊!\n");
	}
}

newCodeMoreWhite.png

循环走棋
在这里插入图片描述
判断
在这里插入图片描述

🍑 AI算法思路二

其实上面的AI算法虽然说可以让电脑进行攻击和截堵,但还是有点缺陷,所以再给大家介绍一种。

这个算法很精妙,可以让玩家永远赢不了电脑,最多也就只能打成平局

首先第一步始终让电脑先落子,并且电脑落子的地方永远在坐标为(1,1)的格子里面👇

(注:#表示电脑,*表示玩家)
在这里插入图片描述
此时玩家落子就有剩余的8个格子可以选择

那么我们就遍历每一个格子,并推演出让电脑赢的方法(这里给大家演示一种)

第一步:首先电脑在坐标(1,1)落子;

第二步:玩家在坐标(1,2)落子;
在这里插入图片描述
第三步:电脑在坐标(3,1)落子;

第四步:玩家在坐标(2,1)落子;
在这里插入图片描述
第五步:电脑在坐标(3,3)落子;
在这里插入图片描述
第六步:此时玩家不管在棋盘剩余空格的任意位置落子,都已经输了👇
在这里插入图片描述
是不是很妙?其实五子棋的AI算法也类似,到时候会出一篇结合EasyX的图形化五子棋😏

🌟 结语

编程这件事情,你如果不练习,你只是学了语法而已,那是绝对不会写代码的🌝

🌟我是Edison,你知道的越多,你不知道越多,我们下期见!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK