C语言实现三子棋plus版本(困难人机电脑不会输,支持双人对战)

目录

  • 一、功能描述
  • 二、游戏部分功能介绍
  • 三、代码实现
    • 1. main()代码
    • 2.游戏菜单代码
    • 3.playgame()代码
    • 3.模式菜单和难度菜单
    • 4.初始化棋盘
    • 5.打印棋盘
    • 6.玩家下棋
    • 7.简单人机下棋
    • 8.困难人机下棋
      • 8.1 电脑检测自己这次落棋后是否能赢
      • 8.2 电脑检测是否要堵玩家的棋
      • 8.3 困难人机主函数
    • 9.判断输赢
      • 9.1 判断是否棋盘满
      • 9.2 判断输、赢、平局
    • 10.双人游戏
  • 四、游戏页面以及结果演示
    • 1.人机模式
      • 1.1 简单人机
      • 1.2 困难人机
    • 2.双人模式
  • 五、全部代码

一、功能描述

该版本可以选择双人游戏和人机对战,并且人机对战分为两个等级(简单人机随机下棋;困难人机是优化后的算法具有堵棋、三连功能)。

二、游戏部分功能介绍

1.打印游戏菜单
2.初始化棋盘
3.打印棋盘
4.打印模式菜单
5.打印难度菜单
6.双人游戏
7.简单人机
8.困难人机
9.判断棋盘是否下满
10.判断输赢

三、代码实现

1. main()代码

用户输入

int main() {
	srand((unsigned int)time(NULL));//随机数
	int input = 0;
	do
	{
		menu();
		printf("请输入 >");
		scanf("%d", &input);
		switch (input) {
		case 1:
			playgame();
			break;
		case 0:
			printf("游戏退出...\n");
			break;
		default:
			printf("请输入正确的格式\n");
		}

	} while (input);

	return 0;
}

2.游戏菜单代码

void menu() {
	printf("****************************\n");
	printf("*****   0 退出游戏    ******\n");
	printf("*****   1 进入游戏    ******\n");
	printf("****************************\n");
}

3.playgame()代码

void playgame() {
	char model;//接收用户选择的模式
	char difficulty;//接收难度系数
	char ch;//接收数据 用于清空缓存区
	model_menu();
	printf("请你选择模式 >");
	while ((ch = getchar()) != '\n' && ch != EOF);//清空缓存区  
	scanf("%c", &model);

	if (model == 'a') {
		difficulty_menu();
		printf("请选择难度等级:");
		while ((ch = getchar()) != '\n' && ch != EOF);//清空缓存区 

		scanf("%c", &difficulty);
		if (difficulty == 'd') {
			printf("困难模式开始...\n");
			playgame_pvc(&difficulty);
		}
		else if (difficulty == 'e') {
			printf("简单模式开始...\n");
			playgame_pvc(&difficulty);
		}
	}
	else if (model == 'b') {
		printf("人人对战\n");
		play_game_pvp();
	}
}

3.模式菜单和难度菜单

//模式菜单
void model_menu() {
	printf("***************************\n");
	printf("** a 人机模式 b 双人模式 **\n");
	printf("***************************\n");

}
//难度菜单
void difficulty_menu() {
	printf("***************************\n");
	printf("** e 简单模式 d 困难模式 **\n");
	printf("***************************\n");
}

4.初始化棋盘

void init_board(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] = ' ';
		}
	}
}

5.打印棋盘

void print_board(char board[ROW][COL], int row, int col) {
	int i = 0;
	for (i = 0; i < row; i++) {
		//打印数据
		for (int j = 0; j < col; j++) {
			if (j < col - 1)
				printf(" %c |", board[i][j]);
			else
				printf(" %c\n", board[i][j]);
		}
		//打印分隔符
		if (i < row - 1) {
			for (int j = 0; j < row; j++) {
				if (j < row - 1)
					printf("---|");
				else
					printf("---\n");
			}
		}
	}
}

6.玩家下棋

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

	while (1) {
		scanf("%d %d", &i, &j);
		if (board[i - 1][j - 1] == ' ') {
		//注意坐标与二维数组对应关系
			board[i - 1][j - 1] = '*';
			break;
		}
		else {
			printf("此位置已被下过,请重新落棋:");
		}
	}
}

7.简单人机下棋

void computer_move_easy(char board[ROW][COL], int row, int col) {
	int i = 0, j = 0;
	printf("电脑走:\n");
	while (1) {
		i = rand() % row;
		j = rand() % col;
		if (board[i][j] == ' ') {
			board[i][j] = '#';
			break;
		}
	}
}

8.困难人机下棋

8.1 电脑检测自己这次落棋后是否能赢

  • 电脑检测棋盘在横向、纵向以及主副对角线是否有两个’#‘,如果有就代表电脑可以直接下上第三个’#‘;如果没有则需要继续判断是否需要堵玩家的棋子。
  • 代码:
//检查电脑是否一线两子 如果有直接赢
int computer_will_win(char board[ROW][COL], int row, int col) {
	int i = 0;
	int j = 0;
	int p_win = 0;//标志是否直接赢
	if(0 == p_win)
	{
		//判断电脑横行上是否会赢
		for (i = 0; i < row; i++)
		{
			if (board[i][0] == board[i][1] && board[i][1] == '#' && board[i][2] == ' ')
			{
				board[i][2] = '#';
				p_win = 1;
				break;
			}
			if (board[i][0] == board[i][2] && board[i][0] == '#' && board[i][1] == ' ')
			{
				board[i][1] = '#';
				p_win = 1;
				break;
			}

			if (board[i][1] == board[i][2] && board[i][1] == '#' && board[i][0] == ' ')
			{
				board[i][0] = '#';
				p_win = 1;
				break;
			}
		}
		if (p_win != 0)
			return p_win;
		//判断电脑列上是否有机会赢
		for (j = 0; j < col; j++)
		{
			if (board[0][j] == board[1][j] && board[1][j] == '#' && board[2][j] == ' ')
			{
				board[2][j] = '#';
				p_win = 1;
				break;
			}

			if (board[0][j] == board[2][j] && board[2][j] == '#' && board[1][j] == ' ')
			{
				board[1][j] = '#';
				p_win = 1;
				break;
			}
			if (board[1][j] == board[2][j] && board[2][j] == '#' && board[0][j] == ' ')
			{
				board[0][j] = '#';
				p_win = 1;
				break;
			}
		}
		if (p_win != 0)
			return p_win;
	}
	//判断电脑在对角线上是否会赢
	if (0 == p_win)
	{
		if (board[0][0] == board[1][1] && board[1][1] == '#' && board[2][2] == ' ')
		{
			board[2][2] = '#';
			p_win = 1;
			return p_win;

		}

		if (board[0][0] == board[2][2] && board[2][2] == '#' && board[1][1] == ' ')
		{
			board[1][1] = '#';
			p_win = 1;
			return p_win;

		}

		if (board[1][1] == board[2][2] && board[1][1] == '#' && board[0][0] == ' ')
		{
			board[0][0] = '#';
			p_win = 1;
			return p_win;

		}

		if (board[0][2] == board[1][1] && board[0][2] == '#' && board[2][0] == ' ')
		{
			board[2][0] = '#';
			p_win = 1;
			return p_win;

		}

		if (board[0][2] == board[2][0] && board[2][0] == '#' && board[1][1] == ' ')
		{
			board[1][1] = '#';
			p_win = 1;
			return p_win;

		}
		if (board[1][1] == board[2][0] && board[2][0] == '#' && board[0][2] == ' ')
		{
			board[0][2] = '#';
			p_win = 1;
			return p_win;

		}

	}
	
	return p_win;//p_win==0 说明没有直接赢 需继续判断是否要堵棋
}

8.2 电脑检测是否要堵玩家的棋

  • 如果程序执行到此说明电脑不能直接赢,而是要判断玩家的棋子有没有一条线上出现二连’ * '的情况。如果有就“堵棋”;如果也不需要“堵棋”,那么电脑就随机下棋了(执行简单人机的核心下棋代码)。
  • 代码:
//检测玩家是否能一线两子  如果有就堵
int people_will_win(char board[ROW][COL], int row, int col) {
	int i = 0;
	int j = 0;
	int k = 0;
	while (0 == k)
	{
		//判断玩家在横行上是否会赢
		for (i = 0; i < row; i++)
		{
			if (board[i][0] == board[i][1] && board[i][1] == '*' && board[i][2] == ' ')
			{
				board[i][2] = '#';
				k = 1;
				break;
			}

			if (board[i][0] == board[i][2] && board[i][0] == '*' && board[i][1] == ' ')
			{
				board[i][1] = '#';
				k = 1;
				break;
			}

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

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

			if (board[0][j] == board[2][j] && board[2][j] == '*' && board[1][j] == ' ')
			{
				board[1][j] = '#';
				k = 1;
				break;
			}

			if (board[1][j] == board[2][j] && board[2][j] == '*' && board[0][j] == ' ')
			{
				board[0][j] = '#';
				k = 1;
				break;
			}
		}
		break;
	}

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

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

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

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

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

		if (board[1][1] == board[2][0] && board[2][0] == '*' && board[0][2] == ' ')
		{
			board[0][2] = '#';
			k = 1;
			break;
		}
		break;
	}
	return k;//返回值如果是1那么已经对玩家进行了堵棋,如果是0则无需堵。
}

8.3 困难人机主函数

//电脑下棋优化版
void computer_move_diff(char board[ROW][COL], int row, int col) {
	int i = 0, j = 0;
	int p;
	printf("电脑走:\n");

	//电脑先检测自己这一次落棋后自己是否能赢
	p = computer_will_win( board, row, col);
	if (p == 1) {//电脑已经下过棋
		return;
	}
	//检查玩家是否会赢 会赢直接堵截
	p = people_will_win(board, row, col);
	if (p == 1) {//电脑对玩家进行了堵截不需要再下
		return;
	}
	//运行到这说明也没有赢 也没有堵截 随机下棋
	while (1) {
		i = rand() % row;
		j = rand() % col;
		if (board[i][j] == ' ') {
			board[i][j] = '#';
			break;
		}
	}

}

9.判断输赢

9.1 判断是否棋盘满

  • 代码:
//判断棋盘是否下满
int is_full(char board[ROW][COL], int row, int col)
{
	int i, j;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
				//只要有位置为空就说明还没满
				return 0;
		}
	}
	//遍历全部都下满,则棋盘满了
	return 1;
}

9.2 判断输、赢、平局

  • 如果在任一方向出现三连一样的字符(排除三连空格情况),那么久说明有一方赢了,直接返回这个字符(#:代表电脑赢(或者玩家2)、* :代表玩家赢)。如果没有人赢就判断是否出现平局的情况(棋盘满了)。如果以上情况均未发生那就游戏继续。
  • 代码:
//检查是否有一方获胜
char check_win(char board[ROW][COL], int row, int col)
{
	int i;
	//判断横向是否有一样的
	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[1][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];
	else if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
		return board[1][1];
	//如果没人赢 检查棋盘是否满 也就是平局
	else if (is_full(board, row, col))
		return '$';
	//以上情况都没有则分不出输赢
	return 0;
}

10.双人游戏

  • 有了以上各种函数基础双人游戏代码就很简单了,只需要让一方先下棋,打印出棋盘然后判断是否分出胜负;另一方下棋,打印出棋盘然后判断胜负。如此循环知道分出胜负。
  • 代码:
//双人对战游戏
void play_game_pvp() {
	char key;//接收输赢结果
	//定义棋盘
	char  board[ROW][COL];
	//初始化棋盘
	init_board(board, ROW, COL);
	//打印棋盘
	print_board(board, ROW, COL);

	while (1)
	{
		printf("请p1下棋:(输入坐标)>");
		person_move(board, ROW, COL);//玩家1下棋
		print_board(board, ROW, COL);//打印棋盘				
		key = check_win(board, ROW, COL);//判输赢平局
		//打印输赢结果
		if (key == '*')
		{
			printf("恭喜p1赢啦\n");
			break;
		}
		if (key == '#')
		{
			printf("恭喜p2赢了\n");
			break;
		}
		if (key == '$')
		{
			printf("平局了!\n");
			break;
		}
		printf("请p2下棋:(输入坐标)>");
		person2_move(board, ROW, COL);//玩家2下棋
		print_board(board, ROW, COL);//打印棋盘
		key = check_win(board, ROW, COL);//判输赢平局
		//打印输赢结果
		if (key == '*')
		{
			printf("恭喜你获得胜利啦\n");
			break;
		}
		if (key == '#')
		{
			printf("p2赢了\n");
			break;
		}
		if (key == '$')
		{
			printf("你们打平局了!\n");
			break;
		}

	}
}

四、游戏页面以及结果演示

1.人机模式

C语言实现三子棋plus版本(困难人机电脑不会输,支持双人对战)_第1张图片

1.1 简单人机

C语言实现三子棋plus版本(困难人机电脑不会输,支持双人对战)_第2张图片

  • 这时的人机还很呆 不会堵棋,玩家轻易获胜!

1.2 困难人机

  • 困难人机一旦二连就可以直接赢。
    C语言实现三子棋plus版本(困难人机电脑不会输,支持双人对战)_第3张图片
  • 困难人机可以在三个方向赌棋
    C语言实现三子棋plus版本(困难人机电脑不会输,支持双人对战)_第4张图片

2.双人模式

C语言实现三子棋plus版本(困难人机电脑不会输,支持双人对战)_第5张图片

五、全部代码

  • 全部代码内容较多 以上也展示的差不多了,避免页面太长,想要直接全部拷贝来自己玩一玩的小伙伴可以码云复制。

  • 点击这里获取全部代码

  • 写的思想比较简单 可能存在错误如有发现欢迎指正 咱再继续改进。

你可能感兴趣的:(小游戏,c语言)