七步手把手教你实现三子棋(c语言)

C语言实现三子棋

一. 整体思路

首先第一步 我们试着创建三个工程文件

test.c 它的作用是帮助我们来测试我们的代码是否可以运行
game.h 用来声明我们的函数
game.c 用于函数的实现

然后呢 我们要在开始玩游戏之前 创建一个菜单 这个菜单要有以下的功能

1 要让我们可以选择游玩和退出
2 要可以多次游玩

当然啦 如果大家想到了什么有意思的功能也可以加上去

二. 创建菜单

实现功能

1 要让我们可以选择游玩和退出
2 要可以多次游玩

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
	printf("---------------------------------------\n");
	printf("--------     1.游戏开始     -----------\n");
	printf("--------     0.游戏结束     -----------\n");
	printf("---------------------------------------\n");
}

上面这段代码其实挺有意思的

通过这里我们能获取到两个知识点

第一点
我们使用了printf函数但是却没有include它的头文件 这是为什么捏
玄机就在于上面的game.h上
在game.h文件里面 我们已经include了我们游戏内所需要的几个头文件 所以说这里只需要导入下 game.h就好啦
是不是很神奇
第二点
我们让玩家输入1来开始游戏 0来结束游戏 这样在我们使用while循环的时候如果玩家想玩游戏就可以一直循环啦
如果不想玩游戏 只要输入一个0就可以退出啦 又是一个小细节

代码如下

void menu()
{
	printf("---------------------------------------\n");
	printf("--------     1.游戏开始     -----------\n");
	printf("--------     0.游戏结束     -----------\n");
	printf("---------------------------------------\n");
}

int main()
{
	int input = 0;
	
	do
	{
		menu();
		scanf("%d\n", &input);

	} while (input);
}

我们先来看看效果嗷
在这里插入图片描述
咦 好像看上去实现的不错 但是呢 这里有一个小bug就是如果输入2 3 4这些值呢 它也会进入循环 因为除

0以外的所有数字都为真嘛

那我们就在下一个章节来解决掉这些可能出现的bug。

三. 调试菜单(解决一些bug 完善功能)

当我们选择1或者0的时候 不能光看着它打印菜单吧 那这个游戏也太无聊啦

那么我们来写个switch case语句来将我们选择的功能进行下去

	switch (input)
		{
		case 1:
			break;
		case 0:
			break;
		default:
			break;
		}

这样子就看上去舒服多啦

然后我们试着给每一个选项加上功能

实现代码如下

	switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误 请重新输入\n");
			break;
		}

看看调试结果怎么样
在这里插入图片描述

不错不错 运行的很好

那么到目前为止我们就完成菜单的功能啦

接下来让我们开始设计游戏

四. 设计游戏(棋盘)

在这里插入图片描述

我们说 在下棋的时候想要在上面这样一个棋盘里面来进行游戏

看上去很简单嘛 只需要设计一个3x3的数组 然后再用这样的格式将棋盘包裹再里面就好啦

按照这个思路 我们首先来设计一个3x3的数组

再game.h的头文件里面先定义一个行和列 这样子就可以直接用定义的符号来表示啦

代码如下

char board[3][3] = {0};
void init(char board[row][col], int x, int y)
{
	int i = 0;
	for ( i = 0; i < x; i++)
	{
		int j = 0;
		for ( j = 0; j < y; j++)
		{
			board[i][j] == ' ';
		}
	}
}


我们 试着将它打印出来
在这里插入图片描述

咦 形状有点奇怪

我们仔细分析下 怎么每一行之间只打印了两个空格的数据

在我们上一篇文章里 已经详细说明了 ‘\0’的ascll码值是0 这也就是为什么没有将%c打印出来的原因

知道这个原因之后 后面就容易多了 我们将数组初始化成空格就可以

初始化代码如下

void init(char board[row][col], int x, int y)
{
	int i = 0;
	for ( i = 0; i < x; i++)
	{
		int j = 0;
		for ( j = 0; j < y; j++)
		{
			board[i][j] = ' ';
		}
	}
}

在这里插入图片描述
我们发现 这样子打印出来的代码就好看多了

但是呢 这样子还有几个问题

下面最后一行应该是不打印的 那我们再修改下代码

	printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
		if (i<x-1)
		{
			printf("---|---|---\n");

		}

这样子修改之后看着就舒服多啦
在这里插入图片描述

五. 设计游戏(玩家)

这一步要来设计玩家的行动

我们可以假设玩家使用的棋子是‘*’号 电脑使用的棋子是‘#’号 玩家的每一步都要下在九宫格里面

如果下的位置有棋子已经落了 那么就要提醒玩家重新落子

这里有一点特别要注意!!!
因为玩家有可能并不是程序员 所以我们在设计输入坐标的时候 要加一才可以

代码表示如下

void player_move(char board[row][col], int x, int y)
{
	int i = 0;
	int j = 0;
	
	// 判断坐标合法性 
	// 判断坐标是否被占用
	while (1)
	{
		printf("玩家下棋->\n");
		scanf("%d %d", &i, &j);

		if ((i >= 1 && i <= 3) && (j >= 1 && j <= 3))
		{
			if (board[i-1][j-1] == ' ')
			{
				board[i-1][j-1] = '*';
				break;
			}
			
			else
			{
				printf("坐标被占用 请重新输入\n");
			}
		}
		else
		{
			printf("坐标不合法 请重新输入\n");
		}
	}

五. 设计游戏(电脑)

这里我们的电脑就设计的简单一点 让他随机下期就好啦

随机的x y坐标 判断合法性

然后落子

关于如何实现随机数 可以参考下我的这篇文章

猜数字游戏

完整电脑下棋代码如下

void computer_move(char board[row][col], int x, int y)
{
	
	printf("电脑下棋->\n");
	while (1)
	{
		int i = rand() % x;
		int j = rand() % y;
		if (board[i][j] == ' ')
		{
			board[i][j] = '#';
			break;
		}
	}
}

六. 判断胜利条件以及结束条件

我们可以设定一个参数 ret

当ret返回‘*’时 玩家获胜
当ret返回‘#’时 电脑获胜
当ret返回‘Q’时 游戏结束
当ret返回‘C’时 游戏继续

代码如下

char is_win(char board[row][col], int x, int y)
{
	int i = 0;
	for ( i = 0; i < x; 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 < y; 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[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 (is_full(board,row,col)==1)
	{
		return 'q';
	}
	else
	{
		return 'c';
	}
}
static int is_full(char board[row][col], int x, int y)
{
	int i = 0;
	for (size_t i = 0; i < x; i++)
	{
		int j = 0;
		for (size_t j = 0; j < y; j++)
		{
			if (' ' == board[i][j])
			{
				return 0;
			}
		}
	}
	return 1;
}

七. 总结常见错误

1错误1:数据类型出错
例如本来要传输的是char 类型的数组 传递成了int 类型的数组导致出错

错误2:传递参数出错
例如要传递一个数组的地址作为参数 而自己却传递了一个数组元素board[i][j]过去 导致出错

错误3:形参类型未定义或者与define定义的常量冲突
例如在定义函数数据类型时 使用define定义的row col 或者是不定义变量类型 导致出错

实现的效果图如下
在这里插入图片描述
以上就是本期博客的全部内容啦

由于博主的知识浅薄 难免会出现一些纰漏 发现错误欢迎大佬在评论区或者私信指正~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

学习同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值