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

导读:本篇文章讲解 C语言小项目——井字棋游戏(升级版),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

🌟 前言

Wassup guys😎

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

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



游戏说明

井字棋,又名三子棋,英文名叫Tic-Tac-Toe;
 
是一种在3×3格子上进行的连珠游戏,和五子棋类似,格线排成井字故得名。
 
游戏需要的工具仅为纸和笔,然后由分别代表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'
*/

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';
}

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;
}

游戏代码详解

🍑 游戏菜单构建

打印一个游戏菜单,有两种选择
 
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()函数,去实现三子棋的过程

🍅 构建棋盘数组

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

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;
	}

}

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

📝代码二

定义一个函数: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;
}

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

🍅 判断输赢

当玩家或者电脑每下一步棋的时候,我们就定义一个函数,判断一下谁赢了;
 
当棋盘已经落满棋子的时候,并且谁也没有赢,我们就认定为平局;
 
当棋盘还没有落满棋子的时候,并且谁也没有赢,游戏就继续;
 
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';
}

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

🍅 主函数判断输赢

玩家和电脑下棋的思路可以这样理解👇
 
当玩家每下一步棋时,就进行输赢判断;
 
当电脑每下一步棋时,也进行输赢判断;
 
但是玩家走一步,电脑走一步,必须要拿循环来实现;
 
那么跳出循环的条件是什么呢?
 
上面已经分析了判断输赢的四种情况;
 
如果当棋盘已经全部落子了,就表示游戏不能再继续了,所以就可以跳出循环;
 
跳出来以后,就把上面判断输赢函数返回的结果来进行比较;
 
如果是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");
	}
}

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

🍑 AI算法思路二

其实上面的AI算法虽然说可以让电脑进行攻击和截堵,但还是有点缺陷,所以再给大家介绍一种。
 
这个算法很精妙,可以让玩家永远赢不了电脑,最多也就只能打成平局
 
首先第一步始终让电脑先落子,并且电脑落子的地方永远在坐标为(1,1)的格子里面👇
 
(注:#表示电脑,*表示玩家)
在这里插入图片描述
此时玩家落子就有剩余的8个格子可以选择
 
那么我们就遍历每一个格子,并推演出让电脑赢的方法(这里给大家演示一种)
 
第一步:首先电脑在坐标(1,1)落子;
 
第二步:玩家在坐标(1,2)落子;
在这里插入图片描述
第三步:电脑在坐标(3,1)落子;
 
第四步:玩家在坐标(2,1)落子;
在这里插入图片描述
第五步:电脑在坐标(3,3)落子;
在这里插入图片描述
第六步:此时玩家不管在棋盘剩余空格的任意位置落子,都已经输了👇
在这里插入图片描述
是不是很妙?其实五子棋的AI算法也类似,到时候会出一篇结合EasyX的图形化五子棋😏

🌟 结语

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/80907.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!