c语言小游戏之三子棋,保姆级教学

    三子棋想必大家小时候都有和小伙伴们一起玩过吗,今天咬咬带大家一起来用c语言写一个简单的三子棋小游戏!

介绍游戏:

    三子棋顾名思义,玩家和电脑在一个类似井字的棋盘上轮流下子,先让自己的三个子连成一条线的一方获得胜利:

                            

 框架整理:

     首先在vs中创建一个头文件,两个源文件:

     我们将基本的游戏框架放入三子棋.c

     将游戏中需要用到的函数声明放入game.h

     将函数的实现放入game.c

游戏实现:

菜单制作:

    首先打开游戏出现一个菜单,输入1开始游戏,输入0退出游戏,输入其他的重新输入,所以我们可以用一个do while循环和一个menu函数来实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void menu()
{
	printf("*************************\n");
	printf("*****   1.开始游戏  *****\n");
	printf("*****   0.退出游戏  *****\n");
	printf("*************************\n");
	printf("请选择>:\n");
}
int main()
{
	int input = 0;
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 0:
			printf("游戏结束\n");
			break;
		case 1:
		//	game();
			break;
		default:
			printf("选择错误请重新输入\n");
			break;
		}
	} while(input);

    现在运行代码进行简单的测试:

 已经达到了我们的预想,接下来把函数整理一下,在game.h中声明,在game.c中实现,在三子棋.c中使用:

      整理完毕,后面每个函数我都会像这样一样存放,不再一一展示。

接下来就是对game函数也就是游戏主体的实现了,要想玩这款游戏肯定要先做出棋盘。

棋盘制作:

先大致设想一下棋盘是不是就大概是一个3行3列的数组所以我们可以先设定一个数组:

    char board[3][3] = { 0 };

这样写的话如果想要改行数或者列数时,就要把后面出现的所有3改一遍,非常麻烦,所以我们在game.h定义一下行和列分别为row和col:

char board[row][col] = { 0 };

    接下来我们刚开始游戏的时候要先初始化棋盘,保证每个位置都是空位可以放子,我现在设定空位用空格来表示,用一个initboard函数来实现棋盘的初始化:

void initboard(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++)
		{
			board[i][j] = ' ';//遍历整个数组将每个元素变为空格
		}
	}
}

这个函数实现是放在game.c里的

    接下来棋盘初始化了我们是不是应该将棋盘打印出来让我们看一下,所以我们可以写一个displayboard函数来实现展示棋盘:

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]);
		}
		printf("\n");//打印一行后换行
	}
}

    现在我们测试一下能否打印出空格:

 可以看到输入1后打印出了3×3的空格,可是这样的棋盘太过简陋,我想要优化一下下面是我的设想:

   |   |   
---|---|---
   |   |   
---|---|---
   |   |   

现在我为了更直观把落子的地方用*号代替:

 * | * | * 
---|---|---
 * | * | * 
---|---|---
 * | * | * 

这样的棋盘是不是玩起来更加方便呢,现在就是用代码来实现这个棋盘,这个棋盘看起来复杂,其实我们可以分析一下:

 所以我们将这个棋盘分为3块:

 每一块都由一行数据行一行分割行组成,只有最后一块没有分割行,所以我们可以先打印数据行,再打印分割行,最后一块不打印分割行:

数据行: * | * | *      注意*为数据,初始化为空格

分割行:---|---|---

void displayboard(char board[ROW][COL], int row, int col)//展示棋盘
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);//数据行
		if (i < row - 1)//保证最后一行不打印分割行
			printf("---|---|---\n");//分割行
	}
}

运行一下代码测试一下棋盘:

 已经满足了我们的设想,接下来就是玩家下子了,就需要写一个playermove函数来实现玩家落子:

void playermove(char board[ROW][COL], int row, int col)
{
	printf("玩家下棋\n");
	while (1)
	{
		printf("请选择你的下棋坐标>:\n");
		int x, y = 0;
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col && board[x - 1][y - 1] == ' ')//确保该地可以落子
		{
			board[x - 1][y - 1] = '#';//玩家落子#
			break;
		}
		else
			printf("坐标不合理或者已经被占用请重新选择\n");
	}
}

现在玩家下完了,接下来是电脑落子,同样写一个computermove函数来实现,这里我们把电脑弄笨一点,随机落子,这就需要用到rand函数了:

void computermove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋>;\n");
	int x, y = 0;
	while (1)
	{
		x = rand() % row;//生成0-2的随机数
		y = rand() % col;//生存0-2的随机数
		if (board[x][y] == ' ')//确保该地可以落子
		{
			board[x][y] = '*';//电脑下子*
			break;
		}

	}
}

使用rand函数记得在game.h中加上两个头文件:

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

并且在最开始前加上一句:

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

例如现在在我的三子棋.c中:

#include "game.h"
char board[ROW][COL] = { 0 };
void game()
{
	initboard(board, ROW, COL);//初始化棋盘
	displayboard(board, ROW, COL);//展示棋盘
	playermove(board, ROW, COL);//玩家落子
	computermove(board, ROW, COL);//电脑落子

}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));//随机数种子
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 0:
			printf("游戏结束\n");
			break;
		case 1:
			game(board,ROW,COL);
			break;
		default:
			printf("选择错误请重新输入\n");
			break;
		}
	} while(input);


	return 0;
}

好,按照逻辑来讲玩家下棋电脑下棋后应该展示一下棋盘所以

void game()
{
	initboard(board, ROW, COL);//初始化棋盘
	displayboard(board, ROW, COL);//展示棋盘
	playermove(board, ROW, COL);//玩家落子
	computermove(board, ROW, COL);//电脑落子
	displayboard(board, ROW, COL);//展示棋盘
}

现在运行代码测试一下:

目前一切正常!

 好现在要做电脑和玩家轮流下棋,其实是不是只要将一次玩家下棋和电脑下棋放入一个while循环里就行了:

void game()
{
	initboard(board, ROW, COL);//初始化棋盘
	displayboard(board, ROW, COL);//展示棋盘
	while(1)
	{
		playermove(board, ROW, COL);//玩家落子
		computermove(board, ROW, COL);//电脑落子
		displayboard(board, ROW, COL);//展示棋盘
	}
}

像这样每次落子后我们是不是要进行一次判断输赢,来决定是否结束游戏,这时候可以写一个iswin函数来实现:

在这个函数内部,为了逻辑清晰,如果玩家赢返回一个#,电脑赢返回一个*,还未分出胜负返回一个c,棋盘填满平局返回一个q:

char iswin(char board[ROW][COL], int row, int col)
{
	int i = 0;
	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][0];//返回对应的棋子
	}
	int j = 0;
	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[2][2] != 0)//   \连线成功
		return board[0][0];//返回对应的棋子
	else if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[0][2] != 0)//   /连线成功
		return board[0][2];//返回对应的棋子
	for (i = 0;i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (isfull(board,ROW,COL))//棋盘满了
				return 'q';//平局返回q
			else
				return 'c';//未分出胜负游戏继续
		}
	}


}

棋盘是否满了,我们用一个函数来判断,也就是isfull,现在我们来实现一下这个函数:

int isfull(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++)
		{
			if (board[i][j] == ' ')//找到空格棋盘没满
				return 0;//返回0为假,没有平局
		}
	}
	return 1;//循环结束没找到空格,返回1为真,平局
}

函数内部完成了,我们是不是应该在函数外部接受一下返回的值,来产生结果:

void game()
{
	initboard(board, ROW, COL);//初始化棋盘
	displayboard(board, ROW, COL);//展示棋盘
	while (1)
	{
		playermove(board, ROW, COL);//玩家落子
		displayboard(board, ROW, COL);//展示棋盘
		char ret = iswin(board, ROW, COL);//判断输赢
		if (ret == '#')
		{
			printf("玩家胜利\n");
			break;
		}
		else if (ret == '*')
		{
			printf("电脑胜利\n");
			break;
		}
		else if (ret == 'q')
		{
			printf("平局\n");
			break;
		}
		else if (ret == 'c')
		{
			//游戏继续不作出指令
		}
		computermove(board, ROW, COL);//电脑落子
		displayboard(board, ROW, COL);//展示棋盘
		iswin(board, ROW, COL);//判断输赢
		if (ret == '#')
		{
			printf("玩家胜利\n");
			break;
		}
		else if (ret == '*')
		{
			printf("电脑胜利\n");
			break;
		}
		else if (ret == 'q')
		{
			printf("平局\n");
			break;
		}
		else if (ret == 'c')
		{
			//游戏继续不作出指令
		}
	}
}

上面是game函数内部,现在所有功能都已经完成,每一次落子后都会先判断输赢返回一个值,再根据这个值确认是否结束游戏,若继续游戏则展示棋盘,一直循环,直到返回的值导致游戏结束。

现在整个游戏就已经完成了,我现在将整个代码发一下:

game.h

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define ROW 3
#define	COL 3
void menu();//菜单
void initboard(char board[ROW][COL], int row, int col);//初始化棋盘
void displayboard(char board[ROW][COL], int row, int col);//展示棋盘
void playermove(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

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"
void menu()
{
	printf("*************************\n");
	printf("*****   1.开始游戏  *****\n");
	printf("*****   0.退出游戏  *****\n");
	printf("*************************\n");
	printf("请选择>:\n");
}
void initboard(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++)
		{
			board[i][j] = ' ';//遍历整个数组将每个元素变为空格
		}
	}
}
void displayboard(char board[ROW][COL], int row, int col)//展示棋盘
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);//数据行
		if (i < row - 1)//保证最后一行不打印分割行
			printf("---|---|---\n");//分割行
	}
}
// * | * | * 
//---|---|---
// * | * | * 
//---|---|---
// * | * | * 
void playermove(char board[ROW][COL], int row, int col)
{
	printf("玩家下棋\n");
	while (1)
	{
		printf("请选择你的下棋坐标>:\n");
		int x, y = 0;
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col && board[x - 1][y - 1] == ' ')//确保该地可以落子
		{
			board[x - 1][y - 1] = '#';//玩家落子#
			break;
		}
		else
			printf("坐标不合理或者已经被占用请重新选择\n");
	}
}

void computermove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋>;\n");
	int x, y = 0;
	while (1)
	{
		x = rand() % row;//生成0-2的随机数
		y = rand() % col;//生存0-2的随机数
		if (board[x][y] == ' ')//确保该地可以落子
		{
			board[x][y] = '*';//电脑下子*
			break;
		}

	}
}

int isfull(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++)
		{
			if (board[i][j] == ' ')//找到空格棋盘没满
				return 0;//返回0为假,没有平局
		}
	}
	return 1;//循环结束没找到空格,返回1为真,平局
}
char iswin(char board[ROW][COL], int row, int col)
{
	int i = 0;
	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][0];//返回对应的棋子
	}
	int j = 0;
	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[2][2] != 0)//   \连线成功
		return board[0][0];//返回对应的棋子
	else if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[0][2] != 0)//   /连线成功
		return board[0][2];//返回对应的棋子
	for (i = 0;i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (isfull(board,ROW,COL))//棋盘满了
				return 'q';//平局返回q
			else
				return 'c';//未分出胜负游戏继续
		}
	}
}

三子棋.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
char board[ROW][COL] = { 0 };
void game()
{
	initboard(board, ROW, COL);//初始化棋盘
	displayboard(board, ROW, COL);//展示棋盘
	while (1)
	{
		playermove(board, ROW, COL);//玩家落子
		displayboard(board, ROW, COL);//展示棋盘
		char ret = iswin(board, ROW, COL);//判断输赢
		if (ret == '#')
		{
			printf("玩家胜利\n");
			break;
		}
		else if (ret == '*')
		{
			printf("电脑胜利\n");
			break;
		}
		else if (ret == 'q')
		{
			printf("平局\n");
			break;
		}
		else if (ret == 'c')
		{
			//游戏继续不作出指令
		}
		computermove(board, ROW, COL);//电脑落子
		displayboard(board, ROW, COL);//展示棋盘
		iswin(board, ROW, COL);//判断输赢
		if (ret == '#')
		{
			printf("玩家胜利\n");
			break;
		}
		else if (ret == '*')
		{
			printf("电脑胜利\n");
			break;
		}
		else if (ret == 'q')
		{
			printf("平局\n");
			break;
		}
		else if (ret == 'c')
		{
			//游戏继续不作出指令
		}
	}
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));//随机数种子
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 0:
			printf("游戏结束\n");
			break;
		case 1:
			game(board,ROW,COL);
			break;
		default:
			printf("选择错误请重新输入\n");
			break;
		}
	} while(input);


	return 0;
}

现在进行一把游戏来测试一下:

 代码成功跑起来了。

那么三子棋游戏现在就已经写完了,赶快自己动手来写一个自己的三子棋小游戏吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

咬_咬

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

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

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

打赏作者

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

抵扣说明:

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

余额充值