三子棋游戏C实现

三子棋游戏

注:本篇三子棋实现使用C语言,在VS编译环境下实现。

  • 文件的创建
  • 三子棋代码框架
  • 初始化和打印函数
  • 玩家下棋
  • 电脑下棋
  • 胜负判断
  • 效果演示
  • 全部代码

三子棋详细步骤讲解

1.文件的创建

为了让代码更加整洁和分工明确,我们需要在VS上创建三个不同的文件,1.创建test.c的源文件,用于测试三子棋游戏。2.创建game.c的头文件,实现游戏函数的声明。3.创建game.c源文件,用于游戏函数的实现。创建好后如下图。
在这里插入图片描述

2.三子棋代码框架

我们编写任何一个复杂工程项目,都是先把框架写出来,然后一步一步去实现它。

如图,在test.c文件下设计框架:
在这里插入图片描述

框架设计好后,开始实现内容,menu作为菜单函数,可以这样设计:
void menu()
{
	printf("******************************\n");
	printf("*********   1.play   *********\n");
	printf("*********   0.exit   *********\n");
	printf("******************************\n");
}

按F5编译运行,我们输入0,结果如下图:

在这里插入图片描述

3.初始化和打印函数实现

如何设计三子棋游戏呢,我们先观察三子棋样貌,有三行三列,我们下棋一次棋,保存一下,然后电脑下棋…不难得出棋盘类似于一个二维数组,观察棋盘图,定义初始化数组,然后实现打印函数。在这里插入图片描述

我们在test.c中创建初始化和打印函数,在game.h中声明函数,在game.c中实现数组,之后实现函数同理,创建和声明将不再赘述。

1.在test文件中创建初始化函数和打印函数
在这里插入图片描述
2.在game.h文件中声明函数
在这里插入图片描述
3.初始化函数的实现
在这里插入图片描述
4.打印棋盘函数的实现
在这里插入图片描述
5.效果如图
在这里插入图片描述
注:改变define中的值可以改变棋盘大小

4.玩家下棋

步骤1.先在test.c中的game()函数中创建。2.在game.h中声明。3.在game.c中实现。前两部操作同上,不展开讲述,最后我会将全部代码放到最后,这里详细讲解game.c中玩家下棋的实现。

void player(char board[row][col], int r, int c)
{
	int i = 0;
	int j = 0;
	printf("玩家下棋:>\n");
	while (1)  //会出现下棋位置错误或重复下棋情况,需要循环
	{
		printf("请输入下棋位置:>");
		scanf("%d %d", &i, &j);
		//常人思维第一个位置是1 1,但实践在数组里是0 0
		//下棋位置不能越界
		if ((i >= 1 && i <= row) && (j >= 1 && j <= col))
		{
			//下棋位置不能是之前下过的
			if (board[i-1][j-1] == ' ')//i-1这样解决常人输入1 1情况
			{
				board[i-1][j-1] = '*';
				break;
			}
			else
			{
				printf("该位置已经下过,请重新下棋\n");
			}
		}
		else
		{
			printf("下棋位置错误,请重新下棋\n");
		}
	}
}

注:写完玩家下棋函数后,在其下在接上之前的打印函数,这样下一个子就可以立刻看到棋盘。

5.电脑下棋

基本步骤同上,rand(),srand(),time()函数可以去这个网站了解:https://legacy.cplusplus.com/

//game.c

void computer(char board[row][col], int r, int c)
{
	int i = 0;
	int j = 0;
	printf("电脑下棋:>\n");
	while (1)
	{
		//rand()随机值函数,任何数模上一个数,得到范围是0~这个数
		i = rand() % row;  //使用rand函数需要用srand()函数,头文件<stdlib.h>
		j = rand() % col;  //srand()函数需要调用time()函数,头文件<time.h>
		if (board[i][j] == ' ')
		{
			board[i][j] = '#';
			break;
		}
	}  //因为是电脑下棋,不需要提示错误,自己会循环
}

//test.c
因为srand()函数只调用一次,所以在main()中加如下代码

srand((unsigned int)time(NULL));
6.判断胜负

首先在game()函数中创建判断胜负函数is_win(),分别在玩家下棋和电脑下完一次棋后进行判断,根据判断值返回值来看是继续下棋还是谁赢了,或者是平局。

1.设计判断函数之前game()函数内容
在这里插入图片描述
2.设计后game()函数内容
在这里插入图片描述
3.判断函数is_win()的实现
注:因为函数是有返回值,字符,所以声明是设计为char返回类型,而不是void
在这里插入图片描述
判断满没满full()函数的实现。注:写在is_win()函数上面
在这里插入图片描述

7.效果演示

在这里插入图片描述

8.全部代码
  • test.c
#define _CRT_SECURE_NO_WARNINGS 1   //这是VS使用scanf函数报错bug应对方法

#include "game.h" //头文件声明函数,这里引用头文件,就不用在test上声明,省事

void game()
{
	char board[row][col] = { 0 }; //创建棋盘数组
	Inital(board,row,col);   //初始化棋盘
	display(board, row, col);//打印棋盘
	//玩游戏
	while (1)
	{
		player(board, row, col);
		display(board, row, col);
		//判断一下情况
		if ('c' != is_win(board, row, col))
		{
			break;
		}
		computer(board, row, col);
		//判断一下情况
		if ('c' != is_win(board, row, col))
		{
			break;
		}
		display(board, row, col);
	}
	//跳出循环,不在下棋,根据判断函数返回值确定结果
	if ('*' == is_win(board, row, col))
	{
		printf("玩家赢\n");
	}
	if ('#' == is_win(board, row, col))
	{
		printf("电脑赢\n");
	}
	if ('p' == is_win(board, row, col))
	{
		printf("平局\n");
	}
	//最后将结果在输出一遍
	display(board, row, col);
}
void menu()
{
	printf("******************************\n");
	printf("*********   1.play   *********\n");
	printf("*********   0.exit   *********\n");
	printf("******************************\n");

}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do			//用do....while循环来构建基本框架
	{
		menu();   //创建menu函数,来打印游戏菜单
		printf("请输入数字:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:		//输入1,进入game函数
			game();   //game函数就是之后的游戏实现
			break;
		case 0:
			printf("退出游戏\n");
			break;    //输入0,break退出switch函数
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input); //正好输入0退出,while(0)为假,退出游戏
	return 0;
}

  • game.h
#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>  //printf,scanf函数声明
#include <stdlib.h>
#include <time.h>

#define row 3  //宏定义棋盘长宽,以后修改方便
#define col 3

//初始化棋盘函数的声明,因为不反回值,所以用void
void Inital(char board[row][col], int r,int c); 
//打印棋盘的声明
void display(char board[row][col], int r, int c);
//玩家下棋
void player(char board[row][col],int r,int  c);
//电脑下棋
void computer(char board[row][col], int r, int c);
//判断输赢
char is_win(char board[row][col], int r, int c);
  • game.h
#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

void Inital(char board[row][col], int r, int c)
{
	int i = 0;
	for (i = 0; i < r; i++)    //二维数组初始化两个for循环
	{				 //第一个for循环代表行,第二个for代表列
		int j = 0;
		for (j = 0; j < c; j++)
		{
			board[i][j] = ' ';  //数组赋值为空格‘ ’
		}
	}
}

void display(char board[row][col], int r, int c)
{
	int i = 0;
	for (i = 0; i < r; i++)  //这个大for循环控制的是行,r=3,3行
	{
		int j = 0;
		for (j = 0; j < c; j++)  //这个for循环控制列,将'   |'作为一组打印
		{
			printf(" %c ", board[i][j]);
			if (j < c - 1)		//观察棋盘,最后一列的|不打印
			{
				printf("|");
			}
		}
		printf("\n");
		if (i < r - 1) //观察棋盘,最后一行的---和|不打印,但'   |'打印了
		{
			for (j = 0; j < c; j++)  //打印3列‘---’
			{

				printf("---");
				if (j < c - 1)   //只打印2列'|'
				{
					printf("|");
				}
			}
			printf("\n");
		}	
	}
}

void player(char board[row][col], int r, int c)
{
	int i = 0;
	int j = 0;
	printf("玩家下棋:>\n");
	while (1)  //会出现下棋位置错误或重复下棋情况,需要循环
	{
		printf("请输入下棋位置:>");
		scanf("%d %d", &i, &j);
		//常人思维第一个位置是1 1,但实践在数组里是0 0
		//下棋位置不能越界
		if ((i >= 1 && i <= row) && (j >= 1 && j <= col))
		{
			//下棋位置不能是之前下过的
			if (board[i-1][j-1] == ' ')//i-1这样解决常人输入1 1情况
			{
				board[i-1][j-1] = '*';
				break;
			}
			else
			{
				printf("该位置已经下过,请重新下棋\n");
			}
		}
		else
		{
			printf("下棋位置错误,请重新下棋\n");
		}
	}
}
void computer(char board[row][col], int r, int c)
{
	int i = 0;
	int j = 0;
	printf("电脑下棋:>\n");
	while (1)
	{
		//rand()随机值函数,任何数模上一个数,得到范围是0~这个数
		i = rand() % row;  //使用rand函数需要用srand()函数,头文件<stdlib.h>
		j = rand() % col;  //srand()函数需要调用time()函数,头文件<time.h>
		if (board[i][j] == ' ')
		{
			board[i][j] = '#';
			break;
		}
	}  //因为是电脑下棋,不需要提示错误,自己会循环
}
int full(char board[row][col], int r, int c)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < r; i++)
	{
		for (j = 0; j < c; j++)
		{
			if (' ' == board[i][j])
			{
				return 0;
			}
		}
	}
	return 1;
}
char is_win(char board[row][col], int r, int c)
{
	int i = 0;
	int j = 0;
	//判断行是否相等
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] != ' ')
		{
			return board[i][0];
		}
	}
	//判断列是否相等
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != ' ')
		{
			return board[i][0];
		}
	}
	//判断右对角是否相等
	if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][i] != ' ')
	{
		return board[0][0];
	}
	//判断左对角是否相等
	if (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] != ' ')
	{
		return board[0][0];
	}
	//判断棋盘是否满了
	if (1 == full(board,row,col))
	{
		return 'p'; //满了,平局
	}
	else
		return 'c';//没满,继续下棋
}

这里三子棋讲解就结束啦,当然还有很多不足之处,如:1.三子棋写死了,不能实现五子棋 2.打印屏幕没设计清除等等,好了,同志们赶紧冲,搞起来。

请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值