C语言——三子棋小游戏

目录

🍁一、基本步骤:

 🍁二、具体实现

🌕(一).本次实现采用多文件的方式,适合初学者进行拓展学习。即:

(1).函数的声明放在game.h文件

(2).函数的定义放在game.c文件

(3).main函数放在test.c文件

🌕(二).因为是游戏,可以循环玩,所以考虑用do while()循环套用switch case语句作为main函数主体结构,如下:

 🌕(三)、因为考虑到棋盘大小可以改变,所以用宏定义定义两个常量作为棋盘的长宽

🌕(四).就可以开始在game函数里面实现游戏了


今天学习到了一个有趣的东西,用C语言实现三子棋,(核心知识——二维数组,函数),非常适合初学者练习,使初学者对二维数组与函数有更加深刻的认识。

🍁一、基本步骤:

1.创建一个3*3的二维数组作为棋盘

2.初始化棋盘

3.玩家下棋——判断输赢

4.电脑下棋——判断输赢

5.得出结果

 🍁二、具体实现

🌕(一).本次实现采用多文件的方式,适合初学者进行拓展学习。即:

(1).函数的声明放在game.h文件
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 3
#define COL 3

Initboard(char board[ROW][COL], int row, int col);//初始化棋盘

Display(char broad[ROW][COL], int row, int col);//打印棋盘

void Playmove(char board[ROW][COL], int row, int col);//玩家下棋

Computermove(char board[ROW][COL], int row,int col);//电脑下棋

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

这里值的注意的是:因为我们会在.c文件中引我们自定义的头文件game.h,所以对于一些库函数,宏定义的使用,我们可以放在game.h中,这样就不用重复使用了

(2).函数的定义放在game.c文件
#include "game.h"

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] = ' ';
		}
	}
}

Display(char broad[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < row; j++)//打印一行的内容
		{
			printf(" %c ", broad[i][j]);
			if(j<row-1)
			printf("|");
		}
		printf("\n");
		for (j = 0; j < row; j++)//打印分隔符
		{
			printf("---");
			if (j < row - 1)
			printf("|");
		}
		printf("\n");
	}
}
void Playmove(char board[ROW][COL], int row, int col)
{
	int x = 0,y = 0;
	printf("玩家下棋:\n");
	while (1)
	{
		printf("请输入坐标,(注意用空格隔开):>");
		scanf("%d %d", &x, &y);
		if (x - 1 >= 0 && x - 1 < row && y - 1 >= 0 && y - 1 < col)//判断坐标是否正确
		{
			if (board[x - 1][y - 1] == ' ')//判断此坐标是否已经落子
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("此坐标以被下,请重新落子\n");
			}
		}
		else
		{
			printf("坐标错误,请重新落子\n");
		}
	}

}

Computermove(char board[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	printf("电脑下棋:\n");
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (x >= 0 && x < row && y >= 0 && y < col)//判断坐标是否正确
		{
			if (board[x][y] == ' ')//判断此坐标是否已经落子
			{
				board[x][y] = '#';
				break;
			}
		}

	}
}

char Iswin(char board[ROW][COL], int row, int col)
{
	//玩家赢—'*'   电脑赢—'#'   平局—'a'    继续—'b'

	//某家赢
	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];
		}
		else if (board[0][i] == board[1][i] && board[0][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[0][0] != ' ')//判断对角线
	{
		return board[0][0];
	}
	else if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][0] != ' ')//判断对角线
	{
		return board[0][2];
	}

	//没有一家赢
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
				return 'b';//继续
		}
	}
	return 'a';//平局
}
(3).main函数放在test.c文件
#include"game.h"

void menu()
{
	printf("***************************\n");
	printf("*******    1.play     *****\n");
	printf("*******    0.exit     *****\n");
	printf("***************************\n");
}

void game()
{
	char rew = '0';
	char board[ROW][COL];
	Initboard(board,ROW,COL);//初始化棋盘为空格
	Display(board, ROW, COL);//打印棋盘
	while (1)
	{
		//玩家下棋
		Playmove(board, ROW, COL);
		Display(board, ROW, COL);//打印棋盘
		//判断输赢
		rew=Iswin(board, ROW, COL);
		if (rew == '*')
		{
			printf("玩家赢!\n");
			break;
		}
		//电脑下棋
		Computermove(board,ROW,COL);
		Display(board, ROW, COL);//打印棋盘
		//判断输赢
		rew=Iswin(board,ROW,COL);
		if (rew == '#')
		{
			printf("电脑赢!\n");
			break;
		}
		if (rew == 'b')
		{
			printf("平局!\n");
			break;
		}
	}

}

int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();//菜单函数
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 2:
			printf("退出成功\n");
			break;
		default:
			printf("输入失败,请重新输入\n");
			break;
		}

	} while (input);
	return 0;
}

这里就有必要说说多文件的好处了,一是可以使main函数内部代码简洁,二是使总体代码层次更鲜明,三是可以多人一起操作等等,有兴趣的小伙伴可以自行了解。

🌕(二).因为是游戏,可以循环玩,所以考虑用do while()循环套用switch case语句作为main函数主体结构,如下:

int input = 0;
	do
	{
		menu();//菜单函数
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 2:
			printf("退出成功\n");
			break;
		default:
			printf("输入失败,请重新输入\n");
			break;
		}

	} while (input);

 🌕(三)、因为考虑到棋盘大小可以改变,所以用宏定义定义两个常量作为棋盘的长宽

#define ROW 3
#define COL 3

🌕(四).就可以开始在game函数里面实现游戏了

1.创建一个3*3二维数组,并创建Initboard函数对其进行初始化,既然是棋盘,刚开始棋盘肯定不能有东西,所以想到用两个For循环将其全部初始化为空格

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] = ' ';
		}
	}
}

2.现在棋盘全是空格,所以需要增加一些东西,是棋盘更好看。效果如下:

所以就需要考虑创建一个函数Display(),将修饰后的棋盘打印出来:

(1).由图可以思考,对于行,可以将 (空格%c空格  |  ) 看做一组数据,打印一排,(根据前面宏定义常量ROW==COL==3),共有ROW组,且最后一组的‘  | ’不打印,所以自然想到循环,代码实现如下:

int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < row; j++)//打印一行的内容
		{
			printf(" %c ", broad[i][j]);
			if(j<row-1)
			printf("|");
		}

 (2).一行数据打印我们就该换行printf("\n");

 (3).对于列,可以将(_ _ _ |)看做一组,且最后一组的‘  _ _ _  ’不打印,共有COL组,代码实现如下:

for (j = 0; j < row; j++)//打印分隔符
		{
			printf("---");
			if (j < row - 1)
			printf("|");
		}
		printf("\n");

3.处理好棋盘就可以开始下棋了(设 玩家棋子——‘*’,电脑棋子——‘#’)

值得注意的是:不论电脑还是玩家下棋,都应该考虑(1).输入的坐标有没有超出棋盘范围

                                                                                   (2).此坐标在之前有没有落过子

(1).玩家先下棋,创建Playermove()函数,因为可能输入非法坐标,所以采用while循环输入,并且注意,我们应该站在用户的角度思考,正常情况坐标从1开始,而数组下标从0开始,所以用户输入进的数据在代码中应该减1,在最为数组坐标

1).玩家输入坐标

2).if语句判断坐标是否超出棋盘范围,超出则重新输入,没超出则进入if

3).再用if语句判断此坐标是否在之前落过子,落过则重新输入,没落过则将此坐标的‘空格’改为‘*’

4).代码实现如下

void Playmove(char board[ROW][COL], int row, int col)
{
	int x = 0,y = 0;
	printf("玩家下棋:\n");
	while (1)
	{
		printf("请输入坐标,(注意用空格隔开):>");
		scanf("%d %d", &x, &y);
		if (x - 1 >= 0 && x - 1 < row && y - 1 >= 0 && y - 1 < col)//判断坐标是否正确
		{
			if (board[x - 1][y - 1] == ' ')//判断此坐标是否已经落子
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("此坐标以被下,请重新落子\n");
			}
		}
		else
		{
			printf("坐标错误,请重新落子\n");
		}
	}

}

(2).电脑下棋,因为电脑是自动下棋,所以这里我们采用随机数让电脑落子,其余操作与玩家下棋一样,只是需要将电脑棋子改为——‘#’,对于随机数的相关知识,有兴趣的小伙伴可自行了解,代码实现如下:

Computermove(char board[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	printf("电脑下棋:\n");
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (x >= 0 && x < row && y >= 0 && y < col)//判断坐标是否正确
		{
			if (board[x][y] == ' ')//判断此坐标是否已经落子
			{
				board[x][y] = '#';
				break;
			}
		}

	}
}

5.根据逻辑,不论是玩家下棋后,还是电脑下棋后,我们都应该考虑一次输赢。现在先实现输赢的标志。

1).创建函数char Iswin(),并用该函数的返回值来判断输赢

玩家赢——返回“*”

电脑赢——返回“#”

平局——返回“a”

继续——返回“b”

2).某一方赢的标志即看数组的某一行、某一列、某一条对角线相等且不等于“空格”。若有一方赢,则返回相应的符号;若没有一家赢,则判断棋盘是否占满,即遍历数组,看是否还具有“空格”,然后返回相应符号。代码实现如下:

char Iswin(char board[ROW][COL], int row, int col)
{
	//玩家赢—'*'   电脑赢—'#'   平局—'a'    继续—'b'

	//某家赢
	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];
		}
		else if (board[0][i] == board[1][i] && board[0][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[0][0] != ' ')//判断对角线
	{
		return board[0][0];
	}
	else if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][0] != ' ')//判断对角线
	{
		return board[0][2];
	}

	//没有一家赢
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
				return 'b';//继续
		}
	}
	return 'a';//平局
}

这里小编没有想到合适的方法判断,只有暴力穷举,所以如果更改棋盘大小,此方法就不适用了,有兴趣的小伙伴可以自行思考。

6.判断输赢函数实现后,就要将它套入下棋里面,即:

(1).玩家落一次子,则调用一次此函数,用临时变量接收返回值并判断是否为“*”,是则玩家赢,不是则电脑下子

(2).电脑落一次子,调用一次此函数,用临时变量接收返回值并判断是否为“#”,是则电脑赢,不是则玩家下子

(3).若不是以上两种,则重新判断是“a”还是“b”

a则平局,游戏结束

b则继续下棋.

(4).代码实现如下:
 

void game()
{
	char rew = '0';
	char board[ROW][COL];
	Initboard(board,ROW,COL);//初始化棋盘为空格
	Display(board, ROW, COL);//打印棋盘
	while (1)
	{
		//玩家下棋
		Playmove(board, ROW, COL);
		Display(board, ROW, COL);//打印棋盘
		//判断输赢
		rew=Iswin(board, ROW, COL);
		if (rew == '*')
		{
			printf("玩家赢!\n");
			break;
		}
		//电脑下棋
		Computermove(board,ROW,COL);
		Display(board, ROW, COL);//打印棋盘
		//判断输赢
		rew=Iswin(board,ROW,COL);
		if (rew == '#')
		{
			printf("电脑赢!\n");
			break;
		}
		if (rew == 'b')
		{
			printf("平局!\n");
			break;
		}
	}

}

好了,游戏实现到这里就基本结束了,下面来看看效果吧!

后续小伙伴们可以自行思考,添加更多功能,或者运行图形库等相关知识使界面更精美等等等等,此次知识到这里就结束了,拜拜!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

成工小白

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

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

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

打赏作者

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

抵扣说明:

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

余额充值