如何用c语言实现三子棋

目录

前言

一:三子棋的游戏规则

二:创建源文件和头文件

 三:代码基础逻辑和菜单的打印。

主函数:

 DisMenu函数():

四:初始化棋盘。

五:打印棋盘。

六:玩家下棋

七:电脑下棋。 

 八:game()函数中的设计

九:判断游戏是否结束。

十:完整代码

 game.h

game.c

text.c

实际效果图 


前言

本篇文章主要运用C语言中二维数组的知识来一步步实现三子棋小游戏,进而巩固对知识的理解,提升代码能力。


一:三子棋的游戏规则

开始游戏后玩家会看到一个3✖️3的网格,玩家输入坐标后电脑自动下棋 ,如果三个相同的棋成行,列,或者对角则一方胜利,如果棋盘下满未分胜负,则游戏结束,玩家现选择是否重新玩。


二:创建源文件和头文件

头文件:game.h
源文件:text.c      game.c
text.c包含主函数,用来判断游戏逻辑是否正确。
为了让代码更加简洁,更易于维护,我们把每一个功能的实现封装成函数,game.h用来定义这些函数。
其中头文件game.h用来包含需要用到的头文件,宏定义一些符号常量和声明game.c中的函数。

game.h中包含的头文件:

043e3ecdb8304fc48b5ff27a8324198c.png


 三:代码基础逻辑和菜单的打印。

基础逻辑:为了让玩家进行一次游戏后依然能够选择是否重新开始,我们需要在text.c中设计一个循环,并设计一个game()函数,我们将游戏的逻辑写入game函数()中,运行一次game()函数就代表进行了一次游戏。


菜单:在进行游戏以前我们需要知道玩家是否想玩,我们在game.h中声明一个函数DisMenu()并在game.c中进行函数定义(后续函数声明定义都是如此),通过scanf()函数获取到玩家输入的信息,如果为1就进行游戏,0就跳出循环,结束程序 其他就打印输出错误提示,进行新一次循环。

主函数:


 DisMenu函数():


四:初始化棋盘。

我们先在game.h中宏定义棋盘的规格,ROW代表行数,COL代表列数。


然后在game()函数中定义一个char类型的数组Board[ROW][COL]用来保存棋盘每一格的信息。

16497a9fa1f143d5be4c486323b9ee19.png

声明并定义函数initBoard(),函数传入的参数为数组和棋盘行列数,此时Board数组并没有初始化,为了方便后续判断网格状态,我们统一初始化为’ ’(即空格)。


五:打印棋盘。

声明并定义一个函数DisPlayBoard(),函数参数为Board数组和棋盘行列数。在主函数中调用DisPlayBoard()函数。注意棋盘打印到每一行最后时一定要进行换行,并且每一行元素打印要用下划线间隔开。


六:玩家下棋

声明并定义一个函数playerMove(),函数参数为Board数组和棋盘行列数。
下棋其实就是通过玩家输入的坐标来改变对应数组中的元素,我们规定玩家的棋为*。

注意:玩家输入的坐标应当是行标列标均从1开始,使用数组进行修改时要将下标改为x-1和y-1,避免数组越界访问。

67ab21f1e4e74771884b08210c3b03b0.png


七:电脑下棋。 

声明并定义一个函数computerMove(),函数参数为Board数组和棋盘行列数。
我们选择让电脑随机下棋 (我不会设计算法,大家可以自己尝试一下),调用srand()函数取当今时间为随机数生成的种子,rand()函数随机生成不为负数的整数,用rand()对任意整数x取余可以得到[0,x)范围内的整数。

b088f56400c84a9585b5f4b00789206d.png


 八:game()函数中的设计

我们想让一次game()函数的执行代表一次游戏结束,三子棋在两方下完棋后如果游戏未结束就继续下棋,使用我们将玩家和电脑的下棋设计成一个循环,如果游戏结束就跳出一次循环。

439da4cffdc0452ebf1b28fc9cbca0e6.png


九:判断游戏是否结束。

我们声明并定义一个函数IsWin(),函数参数为Board数组和棋盘行列数,并且返回可以判断游戏状态的字符。
平局:如果上述情况都不成立,我们考虑是否平局,如果棋盘全满就返回Q,我们声明并定义函数IsFull(),函数参数为Board数组和棋盘行列数,函数返回值为int类型,如果全满返回1,否则返回0。
每一次玩家电脑下完棋我们都进行判断,如果返回值不为C就分别打印结果,并跳出game()函数中的循环,否则玩家继续下棋。

b3721cece57e4dac9e61493eb63a8b45.png

bec64989c72d465a93c98bad3cb284fe.png

我们将判断游戏状态的函数IsWin()放入game函数的循环中,并依据返回值判断游戏是否继续

53a88e5bca4143a69e531eafc14097ae.png


十:完整代码


 game.h

#define ROW 3
#define COL 3
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
//菜单
void DisMenu();

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

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

//玩家下棋
void PlayMove(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);

//判断棋盘是否下满
int IsFull(char Board[ROW][COL], int row, int col);

game.c

#include "game.h"

//打印菜单
void DisMenu()
{
	printf("*********************\n");
	printf("*******/1.play*******\n");
	printf("*******/0.exit*******\n");
	printf("*********************\n");
	printf("选择是否玩游戏->");
}

//判断是否下满
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 0; //遍历数组,找到任意一个为空格的元素就返回0
		}
	}
	return 1;//数组中没有空格,返回1,游戏平局
}

//初始化棋盘
void initBoard(char Board[ROW][COL], int row, int col)
{   
	int i = 0, j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
			Board[i][j] = ' ';  //双重for循环遍历数组中元素,都初始化为空格
	}
}

//打印棋盘
void DisPlayBoard(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 PlayMove(char Board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;  //记录坐标
	while (1)
	{
		printf("玩家->");
		scanf_s("%d %d", &x, &y);  //玩家输入坐标
		if (x > 0 && x < 4 && y > 0 && y < 4)   //输入坐标在合法范围内
		{
			if (Board[x - 1][y - 1] == ' ')//数组元素为空格代表可以写入
			{
				Board[x - 1][y - 1] = '*';
				DisPlayBoard(Board, ROW, COL);
				break;//修改了一次元素,代表下了一次棋,应该换电脑下棋,跳出循环。
			}
			else   //如果数组元素不为空格代表已经被占用
			{
				printf("输入非法,重新输入\n");
			}	
		}
		//输入坐标超出范围
		else
			printf("输入非法,重新输入\n");
	}
}

//电脑下棋
void ComputerMove(char Board[ROW][COL], int row, int col)
{
	while (1)  //设计一个死循环来生成合法坐标
	{
		int x = rand() % ROW;
		int y = rand() % COL;  //记录坐标
		if (x < 3&& y < 3)   //合法
		{
			if (Board[x][y] == ' ')  //如果坐标未被占用,就修改数组元素(下棋)
			{
				Board[x][y] = '#';
				printf("电脑->\n");
				DisPlayBoard(Board, ROW, COL);
				break;  //下了一步棋,跳出循环
			}
		}
	}
}

//判断游戏输赢
char IsWin(char Board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	//判断3行
	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][1];
	}
	//判断三列
	for (j = 0; j < COL; j++)
	{
		if (Board[0][j] == Board[1][j] && Board[1][j] == Board[2][j] && Board[0][j] != ' ')
			return Board[0][j];
	}
	//判断对角线
	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[1][1] != ' ')
		return Board[1][1];
	//平局
	if (IsFull(Board, ROW, COL) == 1)
		return 'Q';
	else  //上述情况都不是,游戏继续
		return 'C';
}

text.c

#include "game.h"

void game()
{
	char Board[ROW][COL];
	initBoard(Board,ROW,COL);   //初始化棋盘

	//打印棋盘
	DisPlayBoard(Board, ROW, COL);

	while (1)
	{
		//玩家下棋
		PlayMove(Board, ROW, COL);
		
		//电脑下棋
		ComputerMove(Board, ROW, COL);
		//判断是否结束
		char end=IsWin(Board, ROW, COL);
		if (end == '*')
		{
			printf("玩家胜利\n");
			break;
		}
		else if (end == '#')
		{
			printf("电脑胜利\n");
			break;
		}
		else if (end == 'Q')
		{
			printf("平局\n");
			break;
		}
	}
}


int main()
{
	int n = 0;
	srand((unsigned int)time(NULL));   //以当前时间为随机数种子
	do
	{
		DisMenu();  //打印菜单
		scanf_s("%d", &n);
		//判断是否进行游戏
		if (n == 1)  //n为1,进行游戏
		{
			game();  //进行游戏
		}
		else if (n == 0)   //n为0,结束游戏
		{
			break;
		}
		else   //其它值,重新输入
		{
			printf("非法输入,请重新输入。\n");
		}
	} while (1);
	return 0;
}

实际效果图 

f16bafd475e649adbc42545362345f48.png3c5a9d017c0b425e8ebc9d56ffcc3062.png


评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

派小星233

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值