三子棋小游戏---(C语言)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

前言

1.菜单的打印

2.三子棋构思

3.实现三子棋

3.1使用宏的方式定义数组

3.2打印棋盘

3.3玩家下棋

3.4电脑随机下棋

3.5判断结局

4.源码

4.1test.c

4.2game.c 

4.3game.h 


❤博主CSDN:啊苏要学习

  ▶专栏分类C语言

  C语言的学习是为我们今后学习其它语言打好基础C生万物

  开始我们的C语言之旅吧✈

前言

  在学完二维数组的知识后我们来应用一下二维数组中的行列思维敲上三子棋这个小游戏。

链接二维数组---行列抽象思维

1.菜单的打印

  和前面讲到的猜数字一样。玩游戏前需要打印一个菜单让玩游戏的人知道这是个什么游戏怎么玩需要玩家做什么等我们通过封装一个菜单函数来实现

void menu()
{
    printf("********************\n");
	printf("*****  1.play ******\n");
	printf("*****  0.exit ******\n");
	printf("********************\n");
}
int main()
{
    //接收玩家输入的值
    int input = 0;
    menu();
    printf("这是一个三字棋游戏请输入>:");
    scanf("%d", &input);
    return 0;
}

  这个时候在控制台打印出来的效果如下

  光标闪烁在等待我们输入值。接下来的一步就是对玩家输入的值进行相应不同的处理玩家输入1进入玩游戏的分支玩家输入0退出程序当然不排除一些调皮捣蛋的玩家喜欢鼓弄我们使用default(默认)来应付

  补充return 0;语句在制定规则的时候一部分人提出希望程序最后可以省略这句话最终通过了当主函数(仅对主函数)结束时没遇到return 0;语句则自动使用return 0返回。相当于有写return 0;但我们最好写上去

  当然我们不只是每次都选择一次就结束掉程序比如我玩一把游戏后还觉得挺好玩想再来一把相应的需要把这段代码写成一个循环才能实现

  分析一运行程序就让我们选择玩还是不玩如果不玩选择0就退出游戏结束循环如果玩选择了1在游戏结束后再次打印菜单让我们重新选择玩不玩。还有就是输入非法值我们得重新进行选择最后直到我们输入0退出循环结束程序

  在这个过程中一运行程序不管什么都让我们选择玩不玩游戏这是循环里的循环部分符合这种特性的循环是do while循环一上来就执行一次循环体while()判断部分我们仔细一想在选择的时候选择0退出游戏选择1或选择输入非法值的时候重新执行一次循环体。对应到循环如果判断表达式是0则退出循环非0(1或非法值)则继续循环我们可以得出使用input做循环的判断条件最合适了

  这上面相当于是一个模块我们理解里面的思想(主要是循环用input当判断条件)就没问题了。博主把这部分当成菜单模块。

2.三子棋构思

  在写代码之前需要初步思考实现三子棋需要用什么方式实现

  这个棋子与棋子之间分割线我们使用循环来控制打印就可以了然后是玩家下棋每下一步棋都会改变数组里的元素接着是电脑下棋电脑下棋也是一样会改变数组元素的到最后直到有一方胜出或平局结束游戏

  通过简单分析我们需要创建一个三行三列的二维数组这个数组起初存放的值我们都初始化为空格因为空格打印出来看不见接着就是实现玩家下棋的函数、电脑下棋的函数、判断输赢的函数

3.实现三子棋

3.1使用宏的方式定义数组

  函数的声明、头文件的包含宏的定义都放在.h文件里。.c文件里包含.h文件就可以正常使用.h里定义的标识符以及引用的头文件里的库函数

3.2打印棋盘

  也许对于初学者打印棋盘是最难消化接收的一个没事咱们娓娓道来。

  • 打印数据行

 

  “井”字有三行二维数组也是有三行。其实棋盘是根据二维数组的大小来变换的我们来看到数据行数据行有两部分组成一部分是空格+%c+空格另一部分是|(竖杠)

  相信大家都已经懂数据行的打印了doge我们看分割行的部分(---|---|---):

  • 打印分割行

  不难发现打印分割行第的时候最右边的|还是不需要打印简直就像是把数据行中用---替代空格+%c+空格|还是|一样

  ok到这里最难的棋盘打印就讲完了这时候如果我们改变标识符ROW、COL的值棋盘的大小也会随之改变因为我们都是使用rowcol做控制的当然这个循环就有变得性啦~ 

3.3玩家下棋

  下棋就是说把二维数组里的元素改成玩家用的棋子字符就行这样打印的时候相当于数组相应位置放了棋子一样。电脑下棋也是同理既然这样那我们快点来实现吧。

  这里需要提的点是坐标合法部分为什么是x(1-3)y(1-3)。而且在下棋的时候反而减掉1这不是没事找事做吗直接输入(0-2)之间的数不就好了吗是的数组的访问下标是从0开始我们知道是因为我们是程序猿但玩家不知道呀把这个游戏放出去随便拉一个玩家让他输入一个坐标下棋子玩家想下第一行第一列必定会输入1 1。所以我们程序猿要考虑下用户的习惯这叫做用户友好用户并不需要知道程序内部是进行了什么样的操作根据常识玩游戏就可以了

3.4电脑随机下棋

  我们这里实现的是电脑随机下棋如果想提升难度可以对电脑下棋的位置进行更多的操作判断也就是说当玩家下了某一个棋子后电脑不是随机下棋而是根据棋盘上的情况选择下棋这个棋子对围堵玩家的棋子有效或是对电脑进一步取胜有效

  我们先看一下test.c文件里的调用接口函数情况吧:

  我们说应该是游戏有结果了也就是人机下棋应该是一个循环下棋下到能判断输赢还是平局才能退出来。所以应该是这样的~

  那么有读者会问了如何退出这个一直下棋的循环呢我们使用判断输赢的函数Is_win玩家下棋后判断游戏是不是结束了(有一方赢了或棋盘满了)电脑下棋后判断游戏是不是结束了来退出循环

3.5判断结局

  我们应该怎么设计这个判断结局的函数呢我们知道三子棋要赢的话横三列、竖三行两条对角线都是其中一方的棋子的时候这时就有一方获胜如果棋盘满了我们也没有继续的必要了那么我们如何将某一方获胜或棋盘满了或还没到结局需要继续下棋的状态告诉主调函数game呢我们使用如下的返回值

  • 某一方赢就返回赢的条件里任意一个位置的棋子看下面就理解了~
  • 棋盘没有满返回字符'C'告诉主调函数说:"继续下棋"
  • 棋盘满了返回字符'F'说明棋盘满了

   我们来看一下主调函数的部分

  再来看实现判断结局部分

  横三列和竖三行

  对角线

  判断满没满的函数

  好啦这就是三字棋的全部实现啦。都到这份上了不玩一把很难收场博主替大家玩一把并把截图放出来证明可行性~

  抱歉图片有点长哈哈~

  其实对于三子棋还有一些改进的地方比如我们可以设置成五子棋呀;把电脑下棋设智能一点;这些也是可以实现的。还有设置一个图形化游戏界面等等。博主暂且先不研究后期学有余力再研究写篇博客出来~

4.源码

4.1test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"


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

void game()
{
	char board[ROW][COL];//ROW是3行COL是3列
	int ret = 0;
	//初始化棋盘将数组元素都初始化成空格字符' ',
	Initboard(board, ROW, COL);
	DisPlayboard(board, ROW, COL);
	while (1)
	{
		PlayerMove(board, ROW, COL);
		DisPlayboard(board, ROW, COL);
		ret = Is_win(board, ROW, COL);
		if (ret != 'C')//如果ret不是C那就是游戏有结果了退出下棋
			break;
		ComputerMove(board, ROW, COL);
		DisPlayboard(board, ROW, COL);
		ret = Is_win(board, ROW, COL);
		if (ret != 'C')
			break;
	}
	if (ret == '*')//这里就体现出来返回赢方胜利条件的某一位置元素的好处了
		printf("恭喜你你赢了\n");//比如玩家第一行连成三子棋Is_win返回其中一个棋子代表使用这个棋子的一方获胜
	else if (ret == '#')
		printf("很遗憾你输了\n");
	else
		printf("该局平局\n");
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("这是一个三子棋游戏请输入:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("不要调皮捣蛋输入规定的值请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

4.2game.c 

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

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++)
	{
		int j = 0;
		//数据行有col列
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			//数据行的分割符数是列数少1也就是col-1
			if (j < col - 1)
			{
				printf("|");
			}
		}
		//打印完数据行换行
		printf("\n");
		//分割行是行数减1也就是row-1
		if (i < row - 1)
		{
			//分割行里有相应的列数
			for (j = 0; j < col; j++)
			{
				printf("---");
				//最后的一个|不用打印
				if(j < col - 1)
					printf("|");
			}
		}
		//打印分割行完后换行
		printf("\n");
	}
}

void PlayerMove(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)//坐标合法
		{
			//判断这个位置是不是一个可以下的空位
			if (board[x - 1][y - 1] == ' ')
			{
				//玩家的棋子假设是*
				board[x - 1][y - 1] = '*';
				break;//当我们成功下了一颗棋后就不能还是玩家下棋了退出循环
			}
			else//这个位置有棋子了重新输入这里也提醒我们需要使用循环
			{
				printf("这个位置已有棋不能重复下请重新输入\n");
			}
		}
		else//坐标不合法来到这里发现需要重新输入的步骤我们就加上循环。
		{
			printf("输入坐标非法请重新输入\n");
		}
	}
}

void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋>:\n");
	while (1)
	{
		//x,y取模row、co;后坐标一定是合法的只需要判断这个位置是不是空位就可以了
		//使用rand生成随机数记得在程序执行起来的时候使用srand设置一次随机数生成起点
		int x = rand() % row;
		int y = rand() % col;
		//找到合适的位置下棋
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			//成功下完一颗棋子就退出
			break;
		}
	}
}

int Is_Full(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;
		}
	}
	//遍历完前面所有元素都不是空格那就是满了返回1
	return 'F';
}

int Is_win(char board[ROW][COL], int row, int col)
{
	//先假设棋盘满了
	int flag = 'F';
	int i = 0;
	//横三列
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
		{
			return board[i][1];
		}
	}
	//竖三行
	for (int i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
		{
			return board[1][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 (flag == Is_Full(board, row, col))//如果判断棋盘的函数返回'F',条件表达式成立返回flag('F')
	{									 //如果没满函数返回0条件表达式成立程序走到最后返回'C',继续下棋
		return flag;
	}
	//前面所有情况都不成立那就是游戏没结束继续下棋
	return 'C';
}

4.3game.h 

#pragma once

#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 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);
int Is_win(char board[ROW][COL], int row, int col);

  OK到此三子棋简易实现结束~

结语希望读者读完有所收获在学C的路上祝福我们能越来越C!✔

  读者对本文不理解的地方或是发现文章在内容上有误等请在下方评论区留言告诉博主哟~也可以对博主提出一些文章改进的建议感激不尽最后的最后

  ❤求点赞求关注你的点赞是我更新的动力一起努力进步吧。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6