哈哈哈~井字棋(无心版),快来初步感受一下代码世界的乐趣吧

前言

Hello everyone! 好久不见,forever 又来了,最近挺忙的所以好久没更新了,上次我介绍了函数相关知识,然后这次我们中间来个小插曲,来给大家看看井字棋游戏哈!不过由于最近时间比较紧张,所以就给大家看看无心版井字棋游戏,哈哈哈哈!所谓无心版就是电脑下棋时没有携带高级算法,不会和玩家进行一场真正的博弈哈!当然后面我还会继续跟进,将这个无心版本升级,让玩家和电脑能够针锋相对,体验体验那种刺激感哈!
所以今天大家先别着急,先随 forever 一起去看看无心版本,其实看完简单的无心版本之后,大家也可以尝试挑战一下,去写一写携带高级算法,给电脑端附上高级智慧,此时电脑所表现出来的高级智慧是你给的,也就体现出你的智慧啦!听完的友友们,是不是很想去试试哈!
接下来就跟着 forever 一起来感受感受井字棋的成长历程吧!

正文

一,游戏实现基本流程

1、创建工程,首先考虑自己的整个工程需要由多少头文件和源文件组成,forever 的详细工程创建如下面分析;
2、对应给每个文件分配什么作用,即给里面放什么内容;
3、接下来放主函数,以主函数为树干,然后分枝开叶;
4、打印游戏菜单;
5、棋盘初始化;
6、打印棋盘;
7、开始下棋:倘若定义玩家先下棋;
8、其次电脑下棋;
9、判断结果;
10、游戏结束。

二、游戏实现步骤

1、创建工程及分配功能

forever 将整个程序分为两个模块:头文件模块和源文件模块。头文件模块包含:game.h
(包含整个程序需要调用的头文件、宏定义以及函数的声明)
;源文件包含:main.cpp(放主函数的源文件)、game.cpp(游戏开始的源文件)、gamelogic.cpp(游戏整体逻辑框架源文件)、test.cpp(游戏具体操作内容源文件)。


//头文件模块
game.h   //包含整个程序需要调用的头文件、宏定义以及函数的声明
//源文件模块
main.cpp   //放主函数(main函数)
game.cpp  //游戏开始的实现
gamelogic.cpp  //游戏整体逻辑框架实现
test.cpp  //游戏具体操作内容实现

2、给头文件上内容

这里我就按顺序写,先写刚开始需要的,然后后面需要什么头文件,forever 会依次在每一步里面添加哈!这里就先给一个 从头到尾都需要的吧!

//game.h包含整个程序需要调用的头文件、宏定义以及函数的声明

#include<stdio.h>

3、当当当,主函数出场

//main.cpp放主函数(main函数)
#include "game.h"

int main()
{
	game();//调用游戏函数出场啦!
	return 0;
}

4、游戏函数里面:打印游戏菜单

友友们!玩游戏肯定都知道游戏菜单哈!就是那个界面啦!不过这个菜单超级简单,只有游戏开始和游戏结束。

//game.cpp 游戏开始的实现
#include "game.h"

void meau()
{
	printf("—————— 0.exit ——————n");
	printf("—————— 1.play ——————n");
}

这里面除了打印菜单还有一个游戏开始的函数即上面提到的 game() 函数,而此时头文件里面便会有一个game()函数的声明:


#include<stdio.h>

void game();//游戏总函数

而 game.cpp 里面的所有内容是:


#include "game.h"
//打印菜单
void meau()
{
	printf("—————— 0.exit ——————n");
	printf("—————— 1.play ——————n");
}
//游戏开始
void game()
{
	unsigned int number = 0;//用unsigned 修饰保证输入的是正整数
	do
	{
		meau();//打印菜单
		printf("请选择:>");
		scanf("%d", &number);
		switch (number)
		{
		case 0:printf("注意休息,保护眼睛哈,游戏结束啦!n");
			break;
		case 1:printf("打起精神,认真思考哈,游戏开始啦!n");
			playgame();//游戏整体内容框架
			break;
		default:
			printf("这位友友有点皮哟,请选择正确数字哈!n");
		}
	} while (number);
}

运行相关结果:请添加图片描述

5、棋盘初始化

这时就会创建一个二维字符数组来存入棋盘,因为后面这个二维字符数组会反复使用,所以此时字符数组的大小 forever 就用宏定义的方式给大家呈现出来吧!此时头文件里面就会加上宏定义,当然还有上面那个 playgame() 函数的声明:

#include<stdio.h>

#define LINE 3
#define LIST 3

void game();//游戏总函数
void playgame();//游戏整体逻辑框架
void Firstboard(char board[LINE][LIST], int line, int list);//初始化棋盘

宏定义的优点:
1、方便程序的修改;
2、提高程序的运行效率;
宏定义的展开是在程序的预处理阶段实现完成的,无需运行时后分配内存,能够部分实现函数的功能却没有函数调用时候的压栈等问题,效率高
3、增强代码可读性
4、增加代码的灵活性

这里将棋盘全部初始化为空格:


void Firstboard(char board[LINE][LIST], int line, int list)
{
	for (int i = 0; i < line; i++)
	{
		for (int j = 0; j < list; j++)
		{
			board[i][j] = ' ';
		}
	}
}

6、打印棋盘

这里头文件就会声明打印棋盘函数:

#include<stdio.h>

#define LINE 3
#define LIST 3

void game();//游戏总函数
void playgame();//游戏整体逻辑框架
void Firstboard(char board[LINE][LIST], int line, int list);//初始化棋盘
void printboard(char board[LINE][LIST], int line, int list);//打印棋盘

这里将棋盘打印呈现出来,首先给大家展示一个比较死板的版本:


void printboard(char board[line][list], int line, int list)
{
	for (int i = 0; i < line; i++)
	{
		printf(" %c | %c | %cn", board[i][0], board[i][1], board[i][2]);
		if (i < line - 1)
		{
			printf("---|---|---n");
		}
	}
}

运行结果:
请添加图片描述

这里的打印可以看出是那种简单粗暴直接式打印方法,当然这种方法最直接,最简单,但也最死板,如果此时我们想打印更多棋盘格子呢?是不是就做不到啦,又得修改好多,按这种方法打印就要打印好多,实在是降低了代码的灵活性。因此修改该代码如下:

void printboard(char board[LINE][LIST], int line, int list)
{
	int i = 0, j = 0;
	for (i = 0; i < line; i++)
	{
		for (j = 0; j < list; j++)
		{
			printf(" %c ",board[i][j]);
			if (j < list - 1)
			{
				printf("|");
			}
		}
		printf("n");
		if (i < line - 1)
		{
			for (j = 0; j < list; j++)
			{
				printf("---");
				if (j < list - 1)
				{
					printf("|");
				}
			}
			printf("n");
		}
	}
}

运行结果:
请添加图片描述

这里 forever 利用循环将整个代码写的灵活了,如果想要打印更多格子,直接对宏定义的量进行改变就行啦!所以友友们以后写代码尽量去注重一下代码的可读性,观赏性和灵活性,让你的写代码的水准更高,更牛哈!

7、玩家下棋

这里头文件就会声明玩家下棋函数:

#include<stdio.h>

#define LINE 3
#define LIST 3

void game();//游戏总函数
void playgame();//游戏整体逻辑框架
void Firstboard(char board[LINE][LIST], int line, int list);//初始化棋盘
void printboard(char board[LINE][LIST], int line, int list);//打印棋盘
void playergame(char board[LINE][LIST], int line, int list);//玩家下棋

倘若我们规定玩家先下棋,那么这里我们就得开始实现玩家下棋啦!这里我们定义一下玩家用 * 当棋子吧!


void playergame(char board[LINE][LIST], int line, int list)
{
	printf("玩家走n请输入坐标:>");
	int x = 0, y = 0;
	while (1)
	{
		scanf("%d %d", &x, &y);
		if (x >0 && x <= line && y >0 && y <= list)//x,y为1-3是方便玩家输入
		{
			if (board[x - 1][y - 1] == ' ')//这里x-1和y-1是为了对应数组元素
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("皮友友,该坐标已有棋子,请重新下哈!n");
			}
		}
		else
		{
			printf("这位友友有点皮哟,请输入正确范围坐标哈!n");
		}
	}
}

运行结果:
请添加图片描述

8、电脑下棋

一如既往,头文件会声明电脑下棋函数:


#include<stdio.h>
#include<stdlib.h>//rand()头文件调用
#include<time.h>//time头文件调用

#define LINE 3
#define LIST 3

void game();//游戏总函数
void playgame();//游戏整体逻辑框架
void Firstboard(char board[LINE][LIST], int line, int list);//初始化棋盘
void printboard(char board[LINE][LIST], int line, int list);//打印棋盘
void playergame(char board[LINE][LIST], int line, int list);//玩家下棋
void computergame(char board[LINE][LIST], int line, int list);//电脑下棋

此处电脑开始下棋啦!我们规定一下电脑下棋的棋子为 + 符号吧!


void computergame(char board[LINE][LIST], int line, int list)
{
	printf("电脑走n");
	int x = 0, y = 0;
	while (1)
	{
		x = rand() % line;//生成随机数
		y = rand() % list;
		if (board[x][y] == ' ')
		{
			board[x][y] = '+';
			break;
		}
	}
}

运行结果:
请添加图片描述

x = rand() % line; //生成随机数: 这里是让电脑下棋时生成随机坐标,即随机下棋,这也对应了我们标题里的无心版本啦!哈哈哈哈!就是没有思维,随机生成什么就是什么哈!当然这里在使用rand() 时,必须要在主函数里面使用一个 srand((unsigned int) time (NULL)) ,如下展示:


int main()
{
	srand((unsigned int)time(NULL));
	game();
	return 0;
}

9、判断结果

这里就要在头文件里声明一个判断是胜负的函数:


#include<stdio.h>
#include<stdlib.h>//rand()头文件调用
#include<time.h>//time头文件调用

#define LINE 3
#define LIST 3

void game();//游戏总函数
void playgame();//游戏整体逻辑框架
void Firstboard(char board[LINE][LIST], int line, int list);//初始化棋盘
void printboard(char board[LINE][LIST], int line, int list);//打印棋盘
char is_win(char board[LINE][LIST], int line, int list);//判断输赢
void playergame(char board[LINE][LIST], int line, int list);//玩家下棋
void computergame(char board[LINE][LIST], int line, int list);//电脑下棋
void is_guo(char ret);//判断最终结果

以上到这里就是头文件中的所有内容啦!

每下一步棋就需要判断该局是否结束,若未结束则继续互相博弈,若结束则还要判断胜负或平局。因此一共有四种情况:
1、未结束继续(返回 ‘w’)
2、结束后,玩家胜利(返回 ‘*’ )
3、结束后,电脑胜利(返回 ‘+’)
4、结束后平局(返回 ‘p’)

这里放判断输赢和最终结果的函数:


//判断输赢
char is_win(char board[LINE][LIST], int line, int list)
{
	//判断行
	for (int i = 0; i < line; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
		{
			return board[i][1];
		}
	}
	//判断列
	for (int j = 0; j < list; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
		{
			return board[1][j];
		}
	}
	//判断对角线
	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, line, list) == 1)
	{
		return 'p';
	}
	return 'w';
}

//判断最终结果
void is_guo(char ret)
{
	if (ret == '*')
	{
		printf("恭喜友友,你胜利啦!n");
	}
	else if (ret == '+')
	{
		printf("很遗憾,友友你输啦!,再接再厉哟!n");
	}
	else
	{
		printf("真不错,棋逢对手呀!n");
	}
}

然后在 is_win 函数里面放一个 is_full 函数判断棋盘是否满了 用来判断是否平局:


int is_full(char board[LINE][LIST], int line, int list)
{
	for (int i = 0; i < line; i++)
	{
		for (int j = 0; j < list; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
		return 1;
	}
}

三、游戏结果演示

1、恭喜友友获胜啦!

请添加图片描述

2、电脑获胜,很遗憾,再接再厉哈!

请添加图片描述

3、真是棋逢对手呀!

请添加图片描述

四、游戏模块

1、头文件模块


#include<stdio.h>
#include<stdlib.h>//rand()头文件调用
#include<time.h>//time头文件调用

#define LINE 3
#define LIST 3

void game();//游戏总函数
void playgame();//游戏整体逻辑框架
void Firstboard(char board[LINE][LIST], int line, int list);//初始化棋盘
void printboard(char board[LINE][LIST], int line, int list);//打印棋盘
char is_win(char board[LINE][LIST], int line, int list);//判断输赢
void playergame(char board[LINE][LIST], int line, int list);//玩家下棋
void computergame(char board[LINE][LIST], int line, int list);//电脑下棋
void is_guo(char ret);//判断最终结果

2、源文件模块

1、main.cpp(放主函数的源文件)模块


#include "game.h"
//放主函数(main函数)
int main()
{
	srand((unsigned int)time(NULL));
	game();
	return 0;
}

2、game.cpp(游戏开始的源文件)模块


#include "game.h"
//游戏开始实现
void meau()
{
	printf("—————— 0.exit ——————n");
	printf("—————— 1.play ——————n");
}
void game()
{
	unsigned int number = 0;
	do
	{
		meau();
		printf("请选择:>");
		scanf("%d", &number);
		switch (number)
		{
		case 0:printf("注意休息,保护眼睛哈,游戏结束啦!n");
			break;
		case 1:printf("打起精神,认真思考哈,游戏开始啦!n");
			playgame();
			break;
		default:
			printf("这位友友有点皮哟,请选择正确数字哈!n");
		}
	} while (number);
}

3、gamelogic.cpp(游戏整体逻辑框架源文件)模块


#include "game.h"
//游戏整体逻辑框架

void playgame()
{
	//创建一个二维字符数组
	char board[LINE][LIST] = { 0 };//LINE是宏定义后的行数,LIST是宏定义后的列数
	//棋盘初始化,将棋盘初始化为空格
	Firstboard(board, LINE, LIST);//调用该函数
	//打印棋盘
	printboard(board, LINE, LIST);
	//这里我们定义玩家先开始下棋
	char ret = 0;
	while (1)
	{
		playergame(board, LINE, LIST);
		printboard(board, LINE, LIST);
		ret = is_win(board, LINE, LIST);
		if (ret != 'w')
		{
			break;
		}
		电脑下棋 
		computergame(board, LINE, LIST);
		printboard(board, LINE, LIST);
		ret = is_win(board, LINE, LIST);
		if (ret != 'w')
		{
			break;
		}
	}
	//玩家胜利  *
	//电脑胜利  +
	//平局      p
	//未结束    w
	is_guo(ret);
}

4、test.cpp(游戏具体操作内容源文件)模块


#include "game.h"
//游戏具体操作内容
//棋盘初始化
void Firstboard(char board[LINE][LIST], int line, int list)
{
	for (int i = 0; i < line; i++)
	{
		for (int j = 0; j < list; j++)
		{
			board[i][j] = ' ';
		}
	}
}
//打印棋盘
void printboard(char board[LINE][LIST], int line, int list)
{
	int i = 0, j = 0;
	for (i = 0; i < line; i++)
	{
		for (j = 0; j < list; j++)
		{
			printf(" %c ",board[i][j]);
			if (j < list - 1)
			{
				printf("|");
			}
		}
		printf("n");
		if (i < line - 1)
		{
			for (j = 0; j < list; j++)
			{
				printf("---");
				if (j < list - 1)
				{
					printf("|");
				}
			}
			printf("n");
		}
	}
}

//开始下棋

//玩家下棋
void playergame(char board[LINE][LIST], int line, int list)
{
	printf("玩家走n请输入坐标:>");
	int x = 0, y = 0;
	while (1)
	{
		scanf("%d %d", &x, &y);
		if (x >0 && x <= line && y >0 && y <= list)
		{
			if (board[x - 1][y - 1] = ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("皮友友,该坐标已有棋子,请重新下哈!n");
			}
		}
		else
		{
			printf("这位友友有点皮哟,请输入正确范围坐标哈!n");
		}
	}
}

//电脑下棋
void computergame(char board[LINE][LIST], int line, int list)
{
	printf("电脑走n");
	int x = 0, y = 0;
	while (1)
	{
		x = rand() % line;
		y = rand() % list;
		if (board[x][y] == ' ')
		{
			board[x][y] = '+';
			break;
		}
	}
}

//判断棋盘是否满,从而判断是否为平局
int is_full(char board[LINE][LIST], int line, int list)
{
	for (int i = 0; i < line; i++)
	{
		for (int j = 0; j < list; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
		return 1;
	}
}

//判断输赢
char is_win(char board[LINE][LIST], int line, int list)
{
	//判断行相同
	for (int i = 0; i < line; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
		{
			return board[i][1];
		}
	}
	//判断列相同
	for (int j = 0; j < list; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
		{
			return board[1][j];
		}
	}
	//判断对角线相同
	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, line, list) == 1)
	{
		return 'p';
	}
	return 'w';
}

//判断最终结果
void is_guo(char ret)
{
	if (ret == '*')
	{
		printf("恭喜友友,你胜利啦!n");
	}
	else if (ret == '+')
	{
		printf("很遗憾,友友你输啦!,再接再厉哟!n");
	}
	else
	{
		printf("真不错,棋逢对手呀!n");
	}
}

四、整体代码实现

#include<stdio.h>
#include<stdlib.h>//rand()头文件调用
#include<time.h>//time头文件调用

#define LINE 3
#define LIST 3

void game();//游戏总函数
void playgame();//游戏整体逻辑框架
void Firstboard(char board[LINE][LIST], int line, int list);//初始化棋盘
void printboard(char board[LINE][LIST], int line, int list);//打印棋盘
char is_win(char board[LINE][LIST], int line, int list);//判断输赢
void playergame(char board[LINE][LIST], int line, int list);//玩家下棋
void computergame(char board[LINE][LIST], int line, int list);//电脑下棋
void is_guo(char ret);//判断最终结果

void meau()
{
	printf("—————— 0.exit ——————n");
	printf("—————— 1.play ——————n");
}

void game()
{
	unsigned int number = 0;
	do
	{
		meau();
		printf("请选择:>");
		scanf("%d", &number);
		switch (number)
		{
		case 0:printf("注意休息,保护眼睛哈,游戏结束啦!n");
			break;
		case 1:printf("打起精神,认真思考哈,游戏开始啦!n");
			playgame();
			break;
		default:
			printf("这位友友有点皮哟,请选择正确数字哈!n");
		}
	} while (number);
}

void playgame()
{
	//创建一个二维字符数组
	char board[LINE][LIST] = { 0 };//LINE是宏定义后的行数,LIST是宏定义后的列数
	//棋盘初始化,将棋盘初始化为空格
	Firstboard(board, LINE, LIST);//调用该函数
	//打印棋盘
	printboard(board, LINE, LIST);
	//这里我们定义玩家先开始下棋
	char ret = 0;
	while (1)
	{
		playergame(board, LINE, LIST);
		printboard(board, LINE, LIST);
		ret = is_win(board, LINE, LIST);
		if (ret != 'w')
		{
			break;
		}
		电脑下棋 
		computergame(board, LINE, LIST);
		printboard(board, LINE, LIST);
		ret = is_win(board, LINE, LIST);
		if (ret != 'w')
		{
			break;
		}
	}
	is_guo(ret);
}

void Firstboard(char board[LINE][LIST], int line, int list)
{
	for (int i = 0; i < line; i++)
	{
		for (int j = 0; j < list; j++)
		{
			board[i][j] = ' ';
		}
	}
}
//打印棋盘
void printboard(char board[LINE][LIST], int line, int list)
{
	int i = 0, j = 0;
	for (i = 0; i < line; i++)
	{
		for (j = 0; j < list; j++)
		{
			printf(" %c ",board[i][j]);
			if (j < list - 1)
			{
				printf("|");
			}
		}
		printf("n");
		if (i < line - 1)
		{
			for (j = 0; j < list; j++)
			{
				printf("---");
				if (j < list - 1)
				{
					printf("|");
				}
			}
			printf("n");
		}
	}
}

void playergame(char board[LINE][LIST], int line, int list)
{
	printf("玩家走n请输入坐标:>");
	int x = 0, y = 0;
	while (1)
	{
		scanf("%d %d", &x, &y);
		if (x >0 && x <= line && y >0 && y <= list)
		{
			if (board[x - 1][y - 1] = ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("皮友友,该坐标已有棋子,请重新下哈!n");
			}
		}
		else
		{
			printf("这位友友有点皮哟,请输入正确范围坐标哈!n");
		}
	}
}
//电脑下棋
void computergame(char board[LINE][LIST], int line, int list)
{
	printf("电脑走n");
	int x = 0, y = 0;
	while (1)
	{
		x = rand() % line;
		y = rand() % list;
		if (board[x][y] == ' ')
		{
			board[x][y] = '+';
			break;
		}
	}
}
int is_full(char board[LINE][LIST], int line, int list)
{
	for (int i = 0; i < line; i++)
	{
		for (int j = 0; j < list; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
		return 1;
	}
}

char is_win(char board[LINE][LIST], int line, int list)
{
	//判断行
	for (int i = 0; i < line; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
		{
			return board[i][1];
		}
	}
	//判断列
	for (int j = 0; j < list; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
		{
			return board[1][j];
		}
	}
	//判断对角线
	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, line, list) == 1)
	{
		return 'p';
	}
	return 'w';
}

void is_guo(char ret)
{
	if (ret == '*')
	{
		printf("恭喜友友,你胜利啦!n");
	}
	else if (ret == '+')
	{
		printf("很遗憾,友友你输啦!,再接再厉哟!n");
	}
	else
	{
		printf("真不错,棋逢对手呀!n");
	}
}

以上就是无心版井字棋啦!友友们下去可以尝试着玩玩,甚至也可以尝试去完善它哈!

结语

本期 forever 给大家带来了无心版井字棋,让大家体验体验代码中的乐趣,让大家从平时觉得枯燥乏味的代码中获取无限乐趣,去体验代码中的快乐。当然,在后期我也会继续完善这个无心版的井字棋,之后会给大家带来一个有心版的哈!
希望本作品能给大家带来快乐,也希望能让大家从中学到一些知识,如有不足或错误之处,还望大佬们批评指正,欢迎大佬们评论指正!
谢谢观看,再见!
以上代码均可运行,所用编译环境为 vs2019 ,运行时注意加上编译头文件#define _CRT_SECURE_NO_WARNINGS 1

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>