C语言三子棋小游戏开发详细解析

Posted Clover三叶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言三子棋小游戏开发详细解析相关的知识,希望对你有一定的参考价值。

三子棋游戏

游戏介绍:

 

游戏规则:

 

 

项目要求:

创建一个显目,在显目中添加三个源代码,一个用来执行主函数、一个用来定义函数和常量、一个用来完成函数功能

执行主函数:Chess.c

用来定义函数和常量:sanziqi.h  (就类似库函数那样,到时候我们需要引用它,所以后缀是 .h )

用来完成函数功能:hanshu.c

 

打印菜单函数:

这一块没什么可以说的,主要就是输出函数的使用,比较简单

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

 

菜单写出来了,是不是还需要用户来选择,既然用户有选择,那就需要东西来接收用户输入的数据,并进行判断,这里我们就可以使用 switch 分支语句来接收并执行用户的要求

void choic()                                     //游戏入口
{
	int input = 0;
	
	srand((unsigned int)time(NULL));             //生成随机数种子
	
	do
	{
		printf("请选择:>");
		scanf("%d",&input);
		switch(input)
		{
			case 1:
				printf("游戏开始\\n");
				game();
				break;
			case 0:
				printf("游戏结束\\n");
				break;
			default:
				printf("输入错误\\n");
				break; 
		}
	}while(input);
}

分析:那个 srand((unsigned int)time(NULL)); 现在先不用去理他,看其他部分代码,那一句下面会分析他的作用;switch 里面的 game()是游戏执行的主体函数,后面也会讲到;有人可能不理解为什么要用循环,循环的条件为什么用 input ,很简单,我们平时玩游戏的时候,是不是每完玩一局,都会出现再来一把或者退出这样的界面让你选择,这就是用了循环,如果没有这个循环,你玩完一把之后程序就自动结束了,那又要重开;至于 input ,while( ) 的条件为真(非零数)则执行,为假(0)则不执行,input 又是接收用户数据的变量,而在菜单中退出我们给的对应值是 0,开始游戏给的对应值是非零值 1 只要用户不退出那么 while 的条件就为真,循环执行;退出的话,那 input = 0,条件为假,循环不执行,程序结束。

 

前面的代码写完后,基本的界面要求就完成了,接下来就要写游戏的主体部分了

 

执行游戏主体部分的函数:game( )

  • 绘制棋盘,三子棋一共有九个格子,横三行,竖三列,所以这里要用到数组来保存棋盘的数据

第一步:

创建棋盘,让计算机知道有这么块位置

char board[ROW][COL] = {0};

ROW:表示行
COL :表示列

这两个定义成了常量

#define ROW 3   //棋盘行数 
#define COL 3   //棋盘列数 

 

第二步:

初始化棋盘

clean(board,ROW,COL);

 

定义函数:

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

row、col 同样也是代表行和列

 

函数功能实现:

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

前面我们定义数组的时候给的是 0 ,但是真正要初始化的时候我们要使每个格子里面放的是空格

 

第三步:

绘制出棋盘的边格

draw(board,ROW,COL);

 

函数定义:

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

 

函数功能实现:

void draw(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 ++)
		{
			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);

 

函数功能实现:

void playermove(char board[ROW][COL],int row,int col)  //下棋部分 
{
	int x = 0;
	int y = 0;
	
	printf("玩家走:>\\n");
	while(1)
	{
		printf("请输入落子位置:>\\n");
		scanf("%d%d",&x,&y);
	
		if(x >= 1 && x <= row && y >= 1 && y <= col)      // x y 可以取 1 是从用户的角度来看,1 实际是 0 
		{
			if(board[x-1][y-1] == \' \')
			{
				board[x-1][y-1] = \'*\';
				break;                      //落子完成后跳出循环打印 *  
			}
			else
			{
				printf("该坐标已被占用\\n"); 
			}
		}
		else
		{
			printf("不在棋盘内请重新输入\\n");
		}
	}
}

分析:board[x-1][y-1] 减一这里有人会不明白,在编程语言中数组下标是从零开始的,那么正常的每学过编程的人他不知道,他们就认为是从一开始,那我们就要满足用户的需求了,在它输入了落子的坐标后,程序自动帮他们减一找到对应的坐标;

* 号代表用户的落子标志

 

第五步:

电脑落子

函数定义:

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

 

函数功能实现:

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] = \'#\';
			break;
		}
	}
	
}

分析:我们完成的是简单的三子棋游戏,不是向那些比较牛的棋类游戏还有棋谱,电脑知道如何判断你的位置做出相应对策的那种,所以我们只需要电脑随机落子就行,当然要满足落子的位置是空位置,随机落子,当然需要产生随机数,还要随机种子,前面写菜单那里就有涉及到,这个位置来详细讲解:srand((unsigned int)time(NULL));

 

我们在使用rand()的时候生成一个随机数,但是在用rand的时候本身又需要一个随机数(有的套娃的感觉),那怎么办?

我们知道,电脑的时间是不是在每分每秒都在变动,这里我们就提到一个 “时间戳” 的概念,时间戳当前计算机的时间减去计算机的起始时间(1970.1.1.0:0:0)

这样我们就可以用时间戳来设置随机数的生成起点,C语言又是如何获取时间戳的

time函数:

  • time的参数是个指针,我们不需要所以把参数写成(NULL)空指针(头文件:time.h)
  • 将得到的时间戳强制转换为整型(unsigned int)(其实 time 本身是个长整型,是对其他函数进行的重命名,这里不多讲,了解一下)

 

完整的下棋代码(写在game()函数里)

while(1)
{
	playermove(board,ROW,COL);
	draw(board,ROW,COL);                    //打印棋盘显示 * 
		
	ret = win(board,ROW,COL);               //判断玩家是否赢
	if(ret != \'C\')
	{
		break;
	}
		
	computermove(board,ROW,COL);
	draw(board,ROW,COL);
		
	ret = win(board,ROW,COL);               //判断电脑是否赢
	if(ret != \'C\')
	{
		break;
	}
}

//win 函数会返回四种状态
//1.玩家赢  ‘* ’ 
//2.电脑赢  ‘# ’ 
//3.平局  ‘Q ’ 
//4.继续  ‘C ’ 

下面会讲到 win 函数,他的作用是判断输赢

 

最后一步:

1.检查棋盘是否满了

int pingju(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;//满了 
}

分析:这里草率了一点,函数名就叫做 “平局” 因为棋盘要是满了还没分出胜负那就是平局了,没毛病哈哈,用户和电脑每下一步都要执行一次这个函数判断棋盘是否满了,还要判断一下是否有哪一方获胜。

 

2.判断输赢

一共有八中情况可能赢

 

char win(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][0] != \' \')
		{
			return board[i][0];
		}
	}
	
	for(i = 0;i < row;i ++)  //竖三列
	{
		if(board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != \' \')
		{
			return board[0][i];
		}
	}
	
	//对角线
	if(board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != \' \')
	{
		return board[0][0];
	}
	if(board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != \' \')
	{
		return board[0][2];
	}
	
	//判断平局 
	if(1 == pingju(board,ROW,COL))
	{
		return \'Q\';
	}
	return \'C\';  //这里 else 可写可不写 
}

分析:return board[i][0] ; return board[0][i] ; return board[0][0] ; return board[0][2] ,因为如果条件成立就代表赢了,且字符都一样,我就取了第一个判断的字符作为返回值

 

接收 win 的返回值并判断获胜方

if(ret == \'*\')
{
	printf("玩家获胜\\n");
}
else if(ret == \'#\')
{
	printf("电脑获胜\\n");
}
else
{
	printf("平局\\n"); 
}

 

程序的完整代码

Chess.c

#include <stdlib.h>
#include "sanziqi.h"

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

void game()                                     //游戏主体
{
	int ret = 0;                               //接收 win 的返回值 
	
	char board[ROW][COL] = {0};                 //保存棋盘上的数据
	clean(board,ROW,COL);	                    //初始化棋盘数据
	draw(board,ROW,COL);                        //绘制棋盘
	
	//玩家落子 
	while(1)
	{
		playermove(board,ROW,COL);
		draw(board,ROW,COL);                    //打印棋盘显示 * 
		
		ret = win(board,ROW,COL);               //判断玩家是否赢
		if(ret != \'C\')
		{
			break;
		}
		
		computermove(board,ROW,COL);
		draw(board,ROW,COL);
		
		ret = win(board,ROW,COL);               //判断电脑是否赢
		if(ret != \'C\')
		{
			break;
		}
	}
	
	if(ret == \'*\')
	{
		printf("玩家获胜\\n");
	}
	else if(ret == \'#\')
	{
		printf("电脑获胜\\n");
	}
	else
	{
		printf("平局\\n"); 
	}
	
}

void choic()                                     //游戏入口
{
	int input = 0;
	
	srand((unsigned int)time(NULL));             //生成随机数 
	
	do
	{
		printf("请选择:>");
		scanf("%d",&input);
		switch(input)
		{
			case 1:
				printf("游戏开始\\n");
				game();
				break;
			case 0:
				printf("游戏结束\\n");
				break;
			default:
				printf("输入错误\\n");
				break; 
		}
	}while(input);
}

int main(int argc, char** argv)
{
	choic();
	
	return 0;
}

 

sanziqi.h

#define ROW 3   //棋盘行数 
#define COL 3   //棋盘列数 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void clean(char board[ROW][COL],int row,int col);
void draw(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 win(char board[ROW][COL],int row,int col);
//这个函数会返回四种状态
//1.玩家赢  ‘* ’ 
//2.电脑赢  ‘# ’ 
//3.平局  ‘Q ’ 
//4.继续  ‘C ’ 


hanshu.c

#include "sanziqi.h"

void clean(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 draw(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 ++)
		{
			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;
	
	printf("玩家走:>\\n");
	while(1)
	{
		printf("请输入落子位置:>\\n");
		scanf("%d%d",&x,&y);
	
		if(x >= 1 && x <= row && y >= 1 && y <= col) // x y 可以取 1 是从用户的角度来看,1 实际是 0 
		{
			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)
{
	int x = 0;
	int y = 0;
	
	printf("电脑走:>\\n");
	
	while(1)
	{
		x = rand() % row;  //生成随机下标 
		y = rand() % col;
		
		if(board[x][y] == \' \')
		{
			board[x][y] = \'#\';
			break;
		}
	}
	
}

//返回 1 表示棋盘满了,返回 0 表示棋盘未满 
int pingju(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 win(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][0] != \' \')
		{
			return board[i][0];
		}
	}
	
	for(i = 0;i < row;i ++)  //竖三列
	{
		if(board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != \' \')
		{
			return board[0][i];
		}
	}
	
	//对角线
	if(board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != \' \')
	{
		return board[0][0];
	}
	if(board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != \' \')
	{
		return board[0][2];
	}
	
	//判断平局 
	if(1 == pingju(board,ROW,COL))
	{
		return \'Q\';
	}
	return \'C\';  //这里 else 可写可不写 
}


还有不明白的地方评论区留言

以上是关于C语言三子棋小游戏开发详细解析的主要内容,如果未能解决你的问题,请参考以下文章

手把手带你搞定C语言实现三子棋游戏,让你的代码有趣起来(超详细教程,从思路到代码,快码起来!)

C语言小游戏-三子棋(详细实现+源码)

C语言小游戏-三子棋(详细实现+源码)

C语言小游戏-三子棋(详细实现+源码)

多文件实现三子棋

C语言游戏跟电脑battle三子棋