详解三子棋(九宫格)游戏

在这里插入图片描述

三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉棋、一条龙、井字棋等。游戏分为双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子走成一条线就视为胜利,而对方就算输了,但是三子棋在很多时候会出现和棋的局面。

请添加图片描述

一、三子棋的大体思路

(一)创建一个菜单,供玩家选择游玩或者退出。
(二)开始游戏后,我们需要将棋盘打印出来。
(三)就到了玩家落子。
(四)电脑落子。
(五)判断输赢与否。
(六)选择是否继续游玩。

二、三子棋的实现

为了使代码更加简洁美观,我们需要将代码模块化
😊

test.c (逻辑测试)
game.h(函数声明)
game.c(函数定义)

1.菜单的创建

详情请见代码:

void menu()
{
	printf("\n");
	printf("     三子棋     \n");      //游戏菜单,提示玩家输入对应数字选择是否开始游戏
	printf("\n");
	printf("请选择是否开始游戏\n");
	printf("1.开始\n");
	printf("0.退出\n");
}
void test()
{
	int input = 0;
	do  //这里让游戏重复进行
	{
		scanf("%d", &input);
		if (input == 1) //如果输入1则开始游戏
		{
			printf("游戏开始\n");
			game();  //这里进入到游戏代码
			menu();  //一局游戏结束提示是否继续游戏
		}
		else if (input == 0) //输入0则结束游戏
		{
			printf("感谢游玩\n");
		}
		else                //输入非0非1则提示重新输入
			printf("请重新输入\n");
	} while (input);// 输入非0则游戏,0则退出游戏,结束循环
}

int main()
{
	menu();
	test();
	return 0;
}

2.棋盘打印

如果要打印棋盘,则先要将棋盘初始化,那么不难想到,要用到二维数组,打印3*3的棋盘。

//我们在这里可以用define定义,来修改整个程序的行数和列数
#define ROW 3   //行数
#define COL 3   //列数
void game()
{
	char arr[ROW][COL];
	//初始化棋盘
	init_arr(arr, ROW, COL); //传参时将ROW,COL传过去,方便以后修改
	//打印棋盘
	print_arr(arr, ROW, COL);
}

初始化棋盘,要定义一个函数,声明并使用它。则我们再game.c中来定义这个初始化函数,在test.c中进行使用,当然使用时要对声明一下,否则用不了,这个就交给我们的game.h。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

.首先将棋盘初始化,二维数组 arr[ROW][COL] 初始化为 ’ '

void init_arr(char arr[ROW][COL],int row,int col)
{
	int i = 0;
	for(i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			arr[i][j] = ' ';
		}
	}
}

1.
初始化完成后,我们就要打印棋盘。
在这里插入图片描述
2.
要想完成这样的打印,我们就将棋盘分分组,分组来打印,组合到一起。
在这里插入图片描述
3.
我们首先想到的就是为一组,然后打印三次就可以,最后将第三组打印的删除就行。
但是这样就有个问题,限制了列数,只能打印 N行3列 的棋盘,所以我们将棋盘分组如下:

在这里插入图片描述
这样我们就可以完成 N行N列 的棋盘打印,最后将多余的‘|’以及‘—’删除就行。

代码实现如下:

void print_arr(char arr[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 ", arr[i][j]);
			if (j < col - 1)  //判断最右边是否多余'|',并不打印
			{
				printf("|");   
			}
		}
		printf("\n");
		int a = 0;
		if (i < row - 1)  //判断最下边是否多余'---',并不打印
		{
			for (a = 0; a < col; a++)
			{
				printf("---");
				if (a <col - 1)  //判断最右边是否多余'|',并不打印
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

这样打印出来的棋盘就很好看了。
😍

在这里插入图片描述

棋盘成功打印后,就该我们的真正下棋了。

大体逻辑为玩家落子,打印棋盘,电脑落子,打印棋盘,循环往复,最后判断输赢。

代码实现如下:

void game()
{
	char arr[ROW][COL];
	//初始化棋盘
	init_arr(arr, ROW, COL);
	//打印棋盘
	print_arr(arr, ROW, COL);
	char ret = 0;
	while (1)
	{
		
		//玩家落子
		player_move(arr, ROW, COL);
		print_arr(arr, ROW, COL);
		/*system("cls");*/
		ret = is_win(arr, ROW, COL);
		if (ret != 'c')
		{
			break;
		}
		//电脑落子
		computer_move(arr, ROW, COL);
		print_arr(arr, ROW, COL);
		ret = is_win(arr, ROW, COL);
		if (ret != 'c')
		{
			break;
		}
	}
	//判断输赢
	if (ret == 'o')
	{
		printf("恭喜你获胜!!\n");
	}
	else if (ret == 'x')
	{
		printf("电脑赢\n");
	}
	else if (ret == 'p')
	{
		printf("平局\n");
	}
}

3.玩家落子

首先是我们的玩家落子,这里我们提示玩家输入要下棋的坐标,玩家为’o’。

在这里插入图片描述

代码实现如下:

void player_move(char arr[ROW][COL], int row, int col)
{
	printf("请输入落子坐标:");
	int x = 0;
	int y = 0;
	while (1)
	{
		scanf("%d %d", &x, &y);
		if ((x > row || y > col)&&(x<=0||y<=0)) //判断玩家输入坐标是否合法,不合法则提示重新输入
		{
			printf("请重新输入坐标:");
		}
		else if (arr[x - 1][y - 1] != ' ')//若该坐标已经落过子,则提示重新输入
		{
			printf("该坐标已被占用,请重新输入:");
		}
		else
		{
			arr[x - 1][y - 1] = 'o';       //合法则打印'o'
			break;
		}
	}
}

4.电脑落子

玩家落子结束,轮到电脑落子,我们电脑落子用‘x’。

在这里插入图片描述

电脑落子,不难想到要用到随机值,将随机值代入到数组中,故代码如下:

void computer_move(char arr[ROW][COL], int row, int col)
{
	printf("电脑下\n");
	while (1)
	{
		int x = rand() % row;//因为棋盘为3*3,所以模上row则得到值的范围为0-2,没有越界
		int y = rand() % col;
		if (arr[x][y] == ' ')
		{
			arr[x][y] = 'x';
			break;
		}
	}
}

不要忘了main函数里的srand函数

srand((unsigned int)time(NULL));

5.判断胜负

玩家落子结束,电脑落子也结束,就该判断这回合落子是否产生了胜负,所以我们这么设计。

如果判断没有产生胜负,则继续循环,返回’c’
如果判断玩家胜,则返回’o’
如果判断电脑胜,则返回‘x’
如果棋盘满了,则为平局,返回’p’

加入到逻辑中,代码如下:

void game()
{
	char arr[ROW][COL];
	//初始化棋盘
	init_arr(arr, ROW, COL);
	//打印棋盘
	print_arr(arr, ROW, COL);
	char ret = 0;
	while (1)
	{
		
		//玩家落子
		player_move(arr, ROW, COL);
		print_arr(arr, ROW, COL);
		ret = is_win(arr, ROW, COL);
		//判断是否继续,如果为c则继续循环,不为c则跳出循环,判断胜负
		if (ret != 'c')
		{
			break;
		}
		//电脑落子
		computer_move(arr, ROW, COL);
		print_arr(arr, ROW, COL);
		ret = is_win(arr, ROW, COL);
		if (ret != 'c')
		{
			break;
		}
	}
	//判断胜负
	if (ret == 'o')
	{
		printf("恭喜你获胜!!\n");
	}
	else if (ret == 'x')
	{
		printf("电脑赢\n");
	}
	else if (ret == 'p')
	{
		printf("平局\n");
	}
}

那么该如何判断胜负?

三子棋,顾名思义,三子连在一起则胜,可以一行也可以一列,当然也可以对角线,除此之外,也有棋满未分出胜负的结果,故共有5中情况,接下来我们一一分析。

首先,行成三:

   //判断行是否成三
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int p = 0;
		for (j = 0; j < col; j++)
		{
			if (arr[i][j] == 'o')//这里我们判断如果有一个o,则给上一个标记
			{
				p++;//改行如果有一个'o',则p+1
			}
		}
		if (p == col)//若p的值等于列数,则说明改行全是'o',故玩家赢,返回'o'
		{
			return 'o';
		}
	}
	//同理电脑也是如此
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int p = 0;
		for (j = 0; j < col; j++)
		{
			if (arr[i][j] == 'x')
			{
				p++;
			}
		}
		if (p == col)
		{
			return 'x';
		}
	}

列成三:

    //判断列是否成三,和行的判断方式一样
	int j = 0;
	for (j = 0; j < col; j++)
	{
		int i = 0;
		int p = 0;
		for (i = 0; i < row; i++)
		{
			if (arr[i][j] == 'o')
			{
				p++;
			}
		}
		if (p == row)
		{
			return 'o';
		}
	}
	
	for (j = 0; j < col; j++)
	{
		int i = 0;
		int p = 0;
		for (i = 0; i < row; i++)
		{
			if (arr[i][j] == 'x')
			{
				p++;
			}
		}
		if (p == row)
		{
			return 'x';
		}
	}

对角线分为两种
首先是 \ 对角线:

    //  判断 \ 对角线是否成三
	int p1= 0;//让p1只标记'o'在对角线上的数量
	for (i = 0; i < row; i++)
	{
		if (arr[i][i] == 'o')
		{
			p1++;
		}
		if (p1== row)
		{
			return 'o';
		}
	}
	int p2 = 0;//让p2只标记'x'在对角线上的数量
	for (i = 0; i < row; i++)
	{
		if (arr[i][i] == 'x')
		{
			p2++;
		}
		if (p2 == row)
		{
			return 'x';
		}
	}

接下来是 / 对角线:

    //   判断 / 对角线是否成三
	int p3 = 0;//让p3只标记'o'在对角线上的数量
	for (i = row-1; i >=0; i--)
	{
		if (arr[i][row - 1 - i] == 'o')
		{
			p3++;
		}
		if (p3 == row)
		{
			return 'o';
		}
	}
	int p4 = 0;//让p4只标记'x'在对角线上的数量
	for (i = row - 1; i >= 0; i--)
	{
		if (arr[i][row - 1 - i] == 'x')
		{
			p4++;
		}
		if (p4== row)
		{
			return 'x';
		}
	}

最后则是棋满平局:

//判断棋盘是否满了
static int is_full(char arr[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 (arr[i][j] == ' ')//如果还有空格,则说明没有满,返回0
			{
				return 0;
			}
		}
	}
	return 1;//扫过所有坐标,没有空格,则说明棋满,返回1
}
    //棋盘满了则为平局
	if (is_full(arr,row,col)==1)//当返回值为1时说明棋满,返回'p'
	{
		return 'p';
	}

到此为止,如果以上判断都未成立,说明没有结束,继续落子

//直接返回'c'即可,继续落子
return 'c';

🌹PS:
如果落子结束想清空屏幕,则可以这样:

在这里插入图片描述
只需在玩家落子后加入system(“cls”)命令即可,当然别忘了头文件。

三、整体代码

test.c

#include "game.h"

void game()
{
	char arr[ROW][COL];
	//初始化棋盘
	init_arr(arr, ROW, COL);
	//打印棋盘
	print_arr(arr, ROW, COL);
	char ret = 0;
	while (1)
	{
		
		//玩家落子
		player_move(arr, ROW, COL);
		print_arr(arr, ROW, COL);
		system("cls");
		ret = is_win(arr, ROW, COL);
		if (ret != 'c')
		{
			break;
		}
		//电脑落子
		computer_move(arr, ROW, COL);
		print_arr(arr, ROW, COL);
		ret = is_win(arr, ROW, COL);
		if (ret != 'c')
		{
			break;
		}
	}
	//判断输赢
	if (ret == 'o')
	{
		printf("恭喜你获胜!!\n");
	}
	else if (ret == 'x')
	{
		printf("电脑赢\n");
	}
	else if (ret == 'p')
	{
		printf("平局\n");
	}
}
void menu()
{
	printf("\n");
	printf("     三子棋\n");
	printf("\n");
	printf("请选择是否开始游戏\n");
	printf("1.开始\n");
	printf("0.退出\n");
}
void test()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		scanf("%d", &input);
		if (input == 1)
		{
			printf("\n");
			game();
			menu();
		}
		else if (input == 0)
		{
			printf("感谢游玩\n");
		}
		else
			printf("请重新输入\n");
	} while (input);
}

int main()
{
	
	menu();
	test();
	return 0;
}

game.h

#define ROW 3
#define COL 3

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


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

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

//玩家落子
void player_move(char arr[ROW][COL], int row, int col);

//电脑落子
void computer_move(char arr[ROW][COL], int row, int col);

//判断输赢
char is_win(char arr[ROW][COL], int row, int col);

game.c

#include "game.h"

//初始化棋盘
void init_arr(char arr[ROW][COL],int row,int col)
{
	int i = 0;
	for(i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			arr[i][j] = ' ';
		}
	}
}

//打印棋盘
void print_arr(char arr[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 ", arr[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		int a = 0;
		if (i < row - 1)
		{
			for (a = 0; a < col; a++)
			{
				printf("---");
				if (a <col - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

//玩家落子
void player_move(char arr[ROW][COL], int row, int col)
{
	printf("请输入落子坐标:");
	int x = 0;
	int y = 0;
	while (1)
	{
		scanf("%d %d", &x, &y);
		if ((x > row || y > col)&&(x<=0||y<=0))
		{
			printf("请重新输入坐标:");
		}
		else if (arr[x - 1][y - 1] != ' ')
		{
			printf("该坐标已被占用,请重新输入:");
		}
		else
		{
			arr[x - 1][y - 1] = 'o';
			break;
		}
	}
}

//电脑落子
void computer_move(char arr[ROW][COL], int row, int col)
{
	printf("电脑下\n");
	while (1)
	{
		int x = rand() % row;
		int y = rand() % col;
		if (arr[x][y] == ' ')
		{
			arr[x][y] = 'x';
			break;
		}
	}
}

//判断棋盘是否满了
static int is_full(char arr[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 (arr[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 1;
}

//判断输赢
char is_win(char arr[ROW][COL], int row, int col)
{
	//判断行列是否成三
	
	int i = 0;
	
	//行
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int p = 0;
		for (j = 0; j < col; j++)
		{
			if (arr[i][j] == 'o')
			{
				p++;
			}
		}
		if (p == col)
		{
			return 'o';
		}
	}
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int p = 0;
		for (j = 0; j < col; j++)
		{
			if (arr[i][j] == 'x')
			{
				p++;
			}
		}
		if (p == col)
		{
			return 'x';
		}
	}
	
	//列
	int j = 0;
	for (j = 0; j < col; j++)
	{
		int i = 0;
		int p = 0;
		for (i = 0; i < row; i++)
		{
			if (arr[i][j] == 'o')
			{
				p++;
			}
		}
		if (p == row)
		{
			return 'o';
		}
	}
	
	for (j = 0; j < col; j++)
	{
		int i = 0;
		int p = 0;
		for (i = 0; i < row; i++)
		{
			if (arr[i][j] == 'x')
			{
				p++;
			}
		}
		if (p == row)
		{
			return 'x';
		}
	}

	//对角线
	
	//  \
	
	int p1= 0;
	for (i = 0; i < row; i++)
	{
		
		if (arr[i][i] == 'o')
		{
			p1++;
		}
		if (p1== row)
		{
			return 'o';
		}
	}
	
	int p2 = 0;
	for (i = 0; i < row; i++)
	{
		
		if (arr[i][i] == 'x')
		{
			p2++;
		}
		if (p2 == row)
		{
			return 'x';
		}
	}
	
	//   /
	int p3 = 0;
	for (i = row-1; i >=0; i--)
	{
		
		if (arr[i][row - 1 - i] == 'o')
		{
			p3++;
		}
		if (p3 == row)
		{
			return 'o';
		}
	}
	
	int p4 = 0;
	for (i = row - 1; i >= 0; i--)
	{
		
		if (arr[i][row - 1 - i] == 'x')
		{
			p4++;
		}
		if (p4== row)
		{
			return 'x';
		}
	}
	//棋盘满了则为平局
	if (is_full(arr,row,col)==1)
	{
		return 'p';
	}

	return 'c';
}

总结

至此,分析完毕,接下里就可以运行游戏,和电脑对局了。💕
ps:电脑很白痴,完全随机落子,输赢全看自己
🤣
在这里插入图片描述
感谢大家支持,如有不足之处,请各位大佬批评指正,希望有机会能和大佬多多交流,共同进步。
我会继续努力,做出真正的人工智能,而不是人工智障。

🌹🌹🌹💕💕💕

  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值