c语言实现三子棋(N子棋)(逐行代码解析)(后附完整源代码)


在这里插入图片描述

《三子棋》是一款古老的民间传统游戏,又被称为黑白棋、圈圈叉叉棋、井字棋、一条龙、九宫棋等。游戏分为双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子连成一条线的一方则视为胜利者。

在这里插入图片描述

本次的三子棋为了更加简洁,将代码模块化,分为3个模块,test.c(测试的逻辑),game.c(游戏的实现),game.h(游戏的头文件,我将所有的声明都放在这里面)

在这里插入图片描述

废话不多说开始写游戏

一.游戏的前置步骤

这段代码在test.c模块中

void test()
{

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

为了使main函数更加简洁,我们将逻辑的实现都放在test函数中
这段代码在test.c模块中

void menu()
{
	printf("*********************************\n");
	printf("*******    1.开始游戏     *******\n");
	printf("*******    0.退出游戏     *******\n");
	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("请重新输入");
			break;
		}
	} while (input);//如果玩家输入0则不再循环,退出游戏
}

这里我们进入test函数内部
1.首先我们需要游戏能够重复进行,所以我们使用do while结构。
2.然后我们需要一个简易的菜单,所以我们用一个menu函数,打印一个菜单
3.接着我们需要让玩家输入,如果是1就进行游戏(游戏的实现我们在game函数里),如果是0就退出游戏,如果是其他数字则输入无效

在这里插入图片描述

二.游戏的实现

1.地图的打印

在这里插入图片描述

我们需要一个这样的地图用于存放我们的数据,像 ‘*’,‘#’ 之类的,而要存储数据那么我们就需要用到数组啦。其实在这里 ‘|’ ‘—’ 这些杠都是为了好看,数组才是主体。

1.初始化数组

在test.c中
在这里插入图片描述

在game.h中,如果对于这里不懂的,可以看看我的函数的声明这篇博客

博客链接

在这里插入图片描述

在game.c中,我们实现这个函数
在这里插入图片描述

2.打印棋盘

其实跟初始化棋盘是一个道理,先在test.c中调用,再在game.h里声明,最后在game.c中实现

在test.c中
在这里插入图片描述
在game.h中
在这里插入图片描述
在game.c中
在这里插入图片描述

在这里插入图片描述

2.游戏进行

1.玩家下棋

在test.c中
在这里插入图片描述
在game.h中
在这里插入图片描述
在game.c中
在这里插入图片描述

这里的判断条件
1.坐标必须在范围里
2.该坐标必须还未下子 ps:这里按照玩家的习惯行和列从1开始数,但在放子时一定要按计算机习惯从0开始,所以-1

2.电脑下棋

再test.c中
在这里插入图片描述
在game.h中
在这里插入图片描述
在game.c中
在这里插入图片描述

随机数生成方法

在这里插入图片描述

在这里插入图片描述
当然同样也别忘了再打印哦,同时我们需要让棋一直下,直到判断出结果,所以我们应该加个while哟
在这里插入图片描述

3.判断条件

1.外部大体判断

在这里插入图片描述

1.这里需要在玩家和电脑下棋后分别进行一次判断
2.电脑Iswin()赢返回‘#’
玩家赢返回‘*’
平局返回‘Q’
游戏继续返回‘C’

2.Iswin()函数具体判断

胜利条件:横排、竖排、x 交叉斜线(俩条)三个相同棋子连成一条线
平局条件:棋盘下满,无棋盘位可下

老规矩,先声明
在这里插入图片描述

在game.c中

横排判断

在这里插入图片描述

这里例如三子棋,有三列,如果count1=2就证明有3个相同的字母在同一行,我们只需要任意返回其中的一个字母就可以了

竖列判断

在这里插入图片描述

左上到右下判断

在这里插入图片描述

从右上到左下判断

在这里插入图片描述

平局判断

在这里插入图片描述

继续判断
当前面的判断全部无效时,直接返回C,继续游戏

在这里插入图片描述

ps:只需要改变宏定义中的ROW,COL的值,就可以实现N子棋啦
好啦以上就是三子棋的全部内容啦下面是源代码

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"

void menu()
{
	printf("*********************************\n");
	printf("*******    1.开始游戏     *******\n");
	printf("*******    0.退出游戏     *******\n");
	printf("*********************************\n");
}


void game()
{
	char ret;
	char Board[ROW][COL] = { 0 };//创建数组
	Initboard(Board, ROW, COL);
	//初始化数组,将数组每个元素都初始化为空格
	PrintBoard(Board, ROW, COL);
		//打印棋盘
		while (1)
		{
			Player(Board, ROW, COL);
			//玩家下棋

			//判断输赢
		    ret=Iswin(Board,ROW,COL);
			if (ret != 'C')//如果不为‘C’,则说明已经得出结果,故跳出循环
			{
				break;
			}

			Computer(Board, ROW, COL);
			//电脑下棋
			PrintBoard(Board, ROW, COL);

			//判断输赢
			ret=Iswin(Board,ROW,COL);
			if (ret != 'C')
			{
				break;
			}
		}
		if (ret == '*')
			printf("玩家赢\n");
		else if (ret == '#')
			printf("电脑赢\n");
		else if (ret == 'Q')
			printf("平局\n");
		//判断输赢
		//电脑赢返回‘#’
		//玩家赢返回‘*’
		//平局返回‘Q’
		//游戏继续返回‘C’

}
void test()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();
		printf("请输入:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("请重新输入");
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

game.h


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


#define ROW 3
//声明行有多少

#define COL 3
//声明列有多少

void Initboard(char Board[ROW][COL],int row ,int col);
//声明初始化棋盘这个函数


void PrintBoard(char Board[ROW][COL],int row,int col);
//声明打印棋盘这个函数


void Player(char Board[ROW][COL], int row, int col);
//声明玩家下棋这个函数


void Computer(char Board[ROW][COL],int row,int col);
//声明电脑下棋这个函数

char Iswin(char Board[ROW][COL], int row, int col);
//声明这个判断函数

game.c

#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 PrintBoard(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");//一行‘ %c | %c | %c |'打完,换下一行
		if (i < row - 1)//最后一行不需要’---‘
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)//最后一列不需要’|‘
				{
					printf("|");
				}
			}
			printf("\n");//一行’---|---|---‘换行
		}
	}
}



void Player(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)//如果坐标超出这个范围,则坐标非法
	 {//这里按照玩家的习惯从1开始数
		 if (Board[x - 1][y - 1] == ' ')//如果这里不是空格,则表明这已经下过子了
		 {//但这里要按照计算机的习惯从0开始,所以-1
			Board[x - 1][y - 1] = '*';
			break;//玩家下子后跳出下棋这个步骤
		  }
		 else
		 {
			printf("该坐标以被占用\n");
		 }
	 }
	 else
	 {
		printf("该坐标非法\n");
	 }
    }

}


void Computer(char Board[ROW][COL], int row, int col)
{
	int x = rand() % row;//生成0-2的随机数
	int y = rand() % col;//生成0-2的随机数
	while (1)
	{
		if (Board[x][y] == ' ')//如果该坐标未被占用,则放入#
		{
			Board[x][y] = '#';
			break;
		}
	}
}


char Iswin(char Board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	int count1 = 0;
	for (i = 0; i < row ; i++)
	{
		for (j = 0; j < col - 1; j++)//因为如果不减1,那么j+1就有可能越界
		{
			if (Board[i][j] == Board[i][j + 1] && Board[i][j] != ' ')
				count1++;
		}
		if (count1 == col - 1)
		{
			return Board[i][j];
		}
	}

	int count2 = 0;
	for (i = 0; i < row - 1; i++)//因为如果不减1,那么i+1就有可能越界
	{
		for (j = 0; j < col; j++)
		{
			if (Board[i][j] == Board[i + 1][j] && Board[i][j] != ' ')
				count2++;
		}
		if (count2 == row - 1)
		{
			return Board[i][j];
		}
	}

	int count3 = 0;
	for (i = 0; i < row ; i++)
	{
		if (Board[i][i] == Board[i + 1][i + 1] && Board[i][i] != ' ')
			count3++;
	}
	if (count3 == col - 1)
	{
		return Board[i][i];
	}

	int count4 = 0;
	for (i = 0; i < row-1; i++)
	{
		if (Board[i][row - 1 - i] == Board[i + 1][row - 2 - i] && Board[i][row - 1 - i] != ' ')
		{
			count4++;
		}
		if (count4 == row - 1)
		{
			return Board[i][row - 1 - i];
		}
	}

	int count5 = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (Board[i][j] != ' ')
				count5++;
		}
		if (count5 == col * row)
		{
			return 'Q';
		}
	}

	return 'C';
}



如果这篇博客对您有所帮助的话,请给个三连哟

在这里插入图片描述

  • 21
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 21
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

咸蛋挞

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

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

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

打赏作者

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

抵扣说明:

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

余额充值