IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 关于三子棋游戏的简易实现与N子棋胜利判断方法 -> 正文阅读

[C++知识库]关于三子棋游戏的简易实现与N子棋胜利判断方法

关于三子棋游戏的简易实现与N子棋胜利判断方法

要实现三子棋游戏,主要需要实现以下几个要求:>

  • 需要一个棋盘,既然需要一个棋盘,棋盘是在一个平面上的,所以我们需要创建一个二维数组
  • 棋盘的打印
  • 玩家下棋与电脑下棋
  • 判断胜利

因为在写三子棋游戏中,我分了两个文件,一个是game.c,一个是test.c。game.c主要是游戏的实现部分,而test.c是主函数测试部分,

并且相对应的给了一个game.h文件,用来实现函数各个声明与标识符常量的定义

这里先给出game.h以便更好了解各个标识符所代表的意义.


#include <stdio.h>


#include <stdlib.h>

#include <time.h>

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

char IsWin(char board[ROW][COL], int row, int col);

以下是test.c文件代码内容:

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"



void menu()
{
	printf("**************************\n");
	printf("******    1.play   *******\n");
	printf("******    0.exit   *******\n");
	printf("**************************\n");
}


void game()
{
	char ret = 0;
	char board[ROW][COL];//? NO,we can't do it, because we are so hard to change relveant value;
	//首先初始化棋盘
	InitBoard(board, ROW, COL);
	//接下来是打印棋盘
	Displayboard(board, ROW, COL);
	//接下来玩家下其
	while (1)
	{
		PlayerMove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		ComputerMove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
}


void test()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择数字:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);

}

int main()
{
	srand((unsigned int)time(NULL));
	test();
	return 0;
}

接着为game.c文件代码内容:

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

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)
{
	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 PlayerMove(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("该坐标已被占用,请重新输入\n");
			}
		}
		else
		{
			printf("该坐标非法,请重新输入\n");
		}
	}
}


void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑下:>\n");
	while (1)
	{
		int x = rand() % row;
		int y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}


int IsFull(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 1;
		}
	}
	return 0;
}



char IsWin(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][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];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[1][3] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	int ret = IsFull(board, row, col);
	if (1 == ret)
	{
		return 'C';
	}
	else
	{
		return 'E';
	}
}

首先是test.c中的内容:
在这里插入图片描述

? 这里的test函数是为了存放我们想要实现的让玩家输入数字来判断是否进入游戏的一个函数,这里的srand函数是为了后面中电脑下棋的一个前提条件:

? 于是现在来到了我们的test函数中

在这里插入图片描述

首先还是常例的打印菜单函数,提示以下玩家应该选什么:
在这里插入图片描述

运行结果是这样

在这里插入图片描述

既然已经提示了,接下来总得输入点什么吧?因此上图的scanf与do…while循环便是为了来适配我们的选择,因为游戏至少执行一次,当你输入1的时候,进入游戏,结束游戏后,while判断input为真,可以重新输入数字。当输入为0时,do…while循环判定为假,直接退出循环,退出程序,当input输入其他值时,重新输入.现在我们输入几个数字之后来看一下效果:(下图的game函数暂时使用printf(“三子棋游戏”)来代替。

在这里插入图片描述

接下来轮到game函数部分,也是今天最重要的一部分,这其内部,我们将通过各类函数来实现三子棋游戏功能,先看代码:

刚开始想法是,先创建一个二维数组对吧,类似于这样:

在这里插入图片描述

但是行和列里面直接放置数字三是否不太合适呢,万一某天我们要玩五子棋,甚至是十字棋,我们要一个一个去改动与其相关的变量,因此,这里是不太合适的,因此,我们在game.h中定义两个标识符常量ROW,与COL,分别为行和列,这样每次只用更改ROW与COL的值就可以了(别忘记包含头文件噢)

在这里插入图片描述

数组定义好之后,接下来我们需要将其初始化,我们写一个Initboard函数来实现,先给大家看一看构建好的三子棋棋盘是什么样的。
在这里插入图片描述

旁边的横线与竖线是我们所起的装饰,可以很明显的看到,我们为数组每一个值都初始化为空格,这样也是以便后文的下棋。

在这里插入图片描述

写了一个Initboard函数过后,我们在game.h中进行声明并在game.c中进行定义
在这里插入图片描述

初始化过后,我们就可以来打印棋盘了,打印棋盘前,我们将棋盘分为两部分,分别打印,如下所示

在这里插入图片描述

将 %c |分为一组,—|分为另一组来进行打印,并且—|只用打印两组,也即为row-1组

因此,我们这样编写Displayboard函数
在这里插入图片描述

里层第一个for循环中为什么要加if(j<col-1)的条件?,因为我们在打印|时,每一行只要col-1条,在这里也每一行即为2条|,不信你可以去看下方上方三子棋的图喔,下方的if(j<col-1)同理,里层第二个for循环也一样,只需要在row-1行前打印—|就够了,请看下图

在这里插入图片描述(之前分析时候的图)**

**这样处理之后,程序运行的结果为:在这里插入图片描述

我们便成功的将其打印出来了。

棋盘有了,接下来总得下棋吧?我们编写一个PlayerMove函数来实现,既然是下棋,也不能只下一次,因此我们也要编写一个循环

如下图所示

在这里插入图片描述

接下来时PlayerMove函数的具体实现

在这里插入图片描述

此处我们将玩家下棋的字符弄为若玩家成功下棋,直接跳出循环,不用再继续了,若玩家输错,则可以重新输入。这里为什么我们会将board[x-1]y-1] 赋值为 呢,正是因为数组的下标从0开始,但玩家一般会觉得第一行就是第一行,因此,实际的坐标是比输入的坐标-1得到的。现在我们看一下效果**

在这里插入图片描述

此然玩家下完了,也应该轮到电脑下了吧?这里我们编写一个ComputerMove函数来实现电脑下棋,如下所示
在这里插入图片描述

此处的x与y我们让其生成0~2随机值,这样可以对应到数组每个元素的下标,并且当数组该下表所对应的值为空格时,赋值为’#;直接跳出循环。

当玩家下完与电脑下完之后,我们需要判断其是否胜利,因此我们编写IsWin函数来判断是否胜利,若胜利,我们返回此时下棋的那个字符,若平局,我们返回字符‘E’,若未平局也未胜利,则返回 ‘C’,代表游戏继续。下面是IsWin函数的具体实现方法。

在这里插入图片描述

此处在判断每一行与每一列,对角线元素是否相同后,若都不相同,则有可能是平局,因此我们写了一个IsFull函数,来判断是否还有棋盘中是否还有空格,如果有空格,则证明还未平局。那我们就return ‘C’,否则,return‘E’,代表平局。IsFull函数的实现方法:

在这里插入图片描述

运行出来的结果为:

在这里插入图片描述

下面是程序的改进方法:

在判断胜利方面,我们其实把程序写死了,也即为只能判断三子棋的胜利,现在我要改动数值玩五子棋,那么其实这个程序已经无法再使用了,因此,我对胜利的判断有以下思考:即计算所下的那个位置的字符所在的行其总个数,列的总个数,对角线的总个数

下面我将画一张图来表示

在这里插入图片描述

下面对代码进行改动

因为我们每次下棋后都要进行判断,因此干脆在下棋中直接进行判断即可,对程序改动如下:
在这里插入图片描述

对PlayerMove与ComputerMove改为有返回值类型的函数

在这里插入图片描述

在ComputerMove与PlayerMove后面增加了IsWin函数

IsWin函数便实现我们刚才的通过加和来判断输赢,我们重点来看一下其怎么实现:

char IsWin(char board[ROW][COL], int x, int y)
{
	int total = 1;
	int i = 0;
	int j = 0;
	//判断一行中元素个数是否为3
	for (i = y+1; i <= COL - 1; i++)
	{
		if (board[x][i] == board[x][y])
		{
			total++;
		}
	}
	for (i = y - 1; i >= 0; i--)
	{
		if (board[x][i] == board[x][y])
		{
			total++;
		}
	}
	if (total == ROW)
	{
		return board[x][y];
	}
	//判断一列
	total = 1;
	for (i = x + 1; i <= ROW - 1; i++)
	{
		if (board[i][y] == board[x][y])
			total++;
	}
	for (i = x - 1; i >= 0; i--)
	{
		if (board[i][y] == board[x][y])
			total++;
	}
	if (total == COL)
	{
		return board[x][y];
	}
	total = 1;
	//判断对角线
	for (i = x - 1, j = y + 1; i >= 0 && j <= COL - 1; i--, j++)
	{
		if (board[i][j] == board[x][y])
			total++;
	}
	for (i = x +1, j = y -1; i<=ROW-1&&j>=0; i++,j--)
	{
		if (board[i][j] == board[x][y])
			total++;
	}
	if (total == COL)
	{
		return board[x][y];
	}
	total = 1;
	for (i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--)
	{
		if (board[i][j] == board[x][y])
			total++;
	}
	for (i = x + 1, j = x + 1; i <= ROW - 1 && j <= COL - 1; i++, j++)
	{
		if (board[i][j] == board[x][y])
			total++;
	}
	if (total == COL)
	{
		return board[x][y];
	}
	int rec = IsFull(board,ROW,COL);
	if (rec == 1)
	{
		return 'E';
	}
	else
	{
		return 'C';
	}
}

在这里插入图片描述

此处便是判断一行,我们将我们下棋的那个点的坐标作为参数传值进去,同时判断其左边与右边与其相同的元素个数,定义一个变量total,为了计算相同元素个数,我们已经下的那一次棋也算为相同元素个数之1,因此其赋值为1,

在这里插入图片描述

判断列数则与其上面相同,如下所示

在这里插入图片描述

判断对角线时,对角线有两种情况,我们需要分别来考虑,第一种情况是这样的

在这里插入图片描述

还有一种情况:

在这里插入图片描述

因此,我们也就可以写出对角线的相同元素和的代码,但别忘了还有判断平局与继续的IsFull函数,把他直接跟着后面就可以了

在这里插入图片描述

这样的话就顺利写出来了现在来看一下五子棋的效果

在这里插入图片描述

本文完。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-10 12:12:56  更:2021-11-10 12:13:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:02:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码