IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言趣味小游戏——三子棋的实现过程详解 -> 正文阅读

[C++知识库]C语言趣味小游戏——三子棋的实现过程详解

三子棋游戏的条件和内容


游戏的条件

1.根据坐标和电脑下棋,玩家一步棋,电脑一步棋,且不能悔棋

2.玩完一盘可以继续

可以学到的内容

1.打印一个简单的菜单

2.一些细节的用户体验

3.自定义函数 , 时间戳的运用 , #define定义

4.程序语言的一些入门逻辑

5.C语言的知识

一个简易的游戏菜单


首先来一个简简单单的代码三部曲(写在test.c的文件下,后期有妙用)

//    测试三子棋游戏的逻辑

#include<stdio.h>

int main()
{

	return 0;
}

写一个返回值为void的test函数,且调用它

void test()
{

}

int main()
{
	test();

	return 0;
}

因为是玩游戏,所以写一个do while,并且打印菜单,和猜数字异曲同工

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

void test()
{
	do
	{
		menu();    //    菜单

	} while ();

}

选择以及退出


看到菜单之后就做出选择

void test()
{
	int input = 0;	//	初始化
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);	//	输入

	} while ();

}

定义一个整型并初始化,方便后期输入

void test()
{
	int input = 0;	//	初始化
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);    //    输入

	} while ();	
}

?
加入switch语句

不懂得switch,case,default语句和do while循环可以看下这个,1分钟就懂了

https://blog.csdn.net/W20223161730/article/details/126200624?spm=1001.2014.3001.5502

void test()
{
	int input = 0;	//	初始化
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);	//	输入
		switch(input)		//	这里使用input的原因是根据输入的值进入对应的case语句
		{
		case 1:
			//		假设这里有三子棋游戏
			printf("玩游戏!\n");
			break;
		case 0:
			printf("选择退出,游戏结束!\n");
			break;
		default :
			printf("选择错误,请重新输入!\n");
			break;
		}
	} while (input);	//		这里使用input的原因是根据input判断是否继续,如果输入的是1 为真(继续),否则 0为假(结束)

}

开始实现游戏的主体


(需要先去了解一下什么是二维数组)

1:游戏开始肯定会呈现一个九宫格的棋盘,三行三列,且中间什么都没有,输入坐标下棋后会被覆盖

2:被覆盖之后会被打印出来,也就是说,棋盘以及玩家和电脑的棋子会被存储起来

3:如果想要实现棋盘中间什么的没有,那么中间肯定是空格

存放下棋的数据

正片开始 : 初始化一个名为board的二维数组,得是三行三列

void game()
{
	//	存放下棋的数据
	char board[3][3] = { 0 };
}

初始化棋盘


再初始化棋盘为全空格,后面还会有更多这样的操作,为了方便所以就直接封装成函数,分模块来写

void game()
{
	//	存放下棋的数据
	char board[3][3] = { 0 };

	//	初始化棋盘为全空格

	Initboard(board, 3, 3);
}

所以再添加一个game.c 和game.h 的两个文件

在test.c文件里面有了这个函数之后,声明就放在game.h的头文件里面

在函数声明的时候需要告诉函数它的返回类型,参数等

//        名字为game.h 的头文件

//	初始化棋盘		棋盘			      行   	   列

void Initboard(char board[3][3], int row, int col);

然后再用define在.h中定义一下行和列,免得后期更改比较麻烦

#define ROW 3
#define COL 3

//	初始化棋盘		棋盘			      行   	   列

void Initboard(char board[3][3], int row, int col);

把文件里的行和列都替换成define定义的ROW和COL

记得在文件中包含game.h ↓

#include"game.h"

这样做的目的是其他文件包含game.h,而game.h文件又包含了行和列还有三部曲的第一部,会节省很多时间

//    game.h 文件
#pragma once

#include<stdio.h>

#define ROW 3
#define COL 3

//	初始化棋盘		棋盘			      行   	   列

void Initboard(char board[ROW][COL], int row, int col);



//       game.c 文件

#include"game.h"

void Initboard(char board[ROW][COL], int row, int col)
{

}



//       test.c 文件

#include"game.h"

然后声明完了放到game.c 的文件中实现

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] = ' ';
		}
		printf("\n");
	}
}

打印棋盘


在test.c文件中来一个打印棋盘的函数

void game()
{
	//	存放下棋的数据
	char board[ROW][COL] = { 0 };

	//	初始化棋盘为全空格

	Initboard(board, ROW, COL);

	//	打印棋盘

	Displayboard(board, ROW, COL);
}

还是头文件

void Displayboard(char board[ROW][COL], int row, int col);

game.c文件

void Displayboard(char board[ROW][COL], int row, int col)
{
	
}

棋盘的设计


棋盘打印还是需要精心设计的,这里就不过多赘述,直接上代码

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]);
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");

		}
	}
}

棋盘的效果图


?
效果图

棋盘的效果图

玩家下棋的函数实现


后面就开始重中之重了,玩家和电脑是如何下棋的

还是继续写一个函数 用来实现玩家下棋

//    test.c

	Player_move(board, ROW, COL);

//    game.c

void Player_move(char board[ROW][COL], int row, int col)
{

}

//    game.h

void Player_move(char board[ROW][COL], int row, int col);

需要提前考虑到两点

1:玩家的非法输入

2:玩家输入并不知道数组的下标是从0开始,所以需要加1

void Player_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋!\n");
	printf("请输入坐标!\n");
	scanf("%d %d", &x, &y);

	if (x >= 1 && x <= row && y >= 1 && y <= col)
	{
    
	}
	else
	{
		printf("坐标输入错误,请重新输入!\n");
	}

}

玩家不可能就输入错误一次,所以加上一个循环才是合理的

void Player_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋!\n");

	while (1)
	{
		printf("请输入坐标!\n");
		scanf("%d %d", &x, &y);

		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{

		}
		else
		{
			printf("坐标输入错误,请重新输入!\n");
		}
	}

}

下一步

if (x >= 1 && x <= row && y >= 1 && y <= col)
{
	if (board[x - 1][y - 1] == ' ')		//	玩家输入的要减1,因为数组的下标是从0开始的
										
		//		如果输入的是一个空格,那么就说明这个位置没有被占用
	{
		board[x - 1][y - 1] == '*';		//	那么就把空格替换成 * 来当作玩家下的棋
            
            break;
        
        //    一定要记得break,不然一直死循环    
	}
	else
	{
		printf("该坐标被占用,请重新输入!\n");
	}
}

再重新打印一下棋盘

void game()
{
	//	存放下棋的数据
	char board[ROW][COL] = { 0 };

	//	初始化棋盘为全空格

	Initboard(board, ROW, COL);

	//	打印棋盘

	Displayboard(board, ROW, COL);

	//	玩家下棋

	Player_move(board, ROW, COL);

    //    重新打印

	Displayboard(board, ROW, COL);

}

玩家下棋的效果图


玩家下棋

电脑下棋的函数框架


然后开始写一个简单的电脑下棋函数,以后感兴趣可以自行加上堵截,优先胜利的代码,这次就先不过多介绍,因为是入门先理解

//    test.c

	Computer_move(board, ROW, COL);

//    game.c

void Computer_move(char board[ROW][COL], int row, int col)
{

}

//    game.h

void Computer_move(char board[ROW][COL], int row, int col);

控制电脑下棋三个函数的详解


那么问题来了,怎么控制让电脑在规定的范围内,且不重复的下棋

需要简单的了解rand,srand,time函数

请添加图片描述
请添加图片描述

在这里插入图片描述在这里插入图片描述

这个函数调用一次,每次就归零一次(重新开始),所以不需要频繁的调用,只需要调用一次就可以了, 所以直接放到主函数的test函数里面

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

在game.h的头文件包含一下

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

电脑下棋函数的实现


电脑下棋的实现

void Computer_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋!\n");
	while (1)
	{
		x = rand() % row;	//	值为0到2	
		y = rand() % col;	//	值为0到2
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}

}

玩家和电脑下完棋都打印一下 ,下棋不可能只下一步,所以放到循环里面

void game()		//	因为是传参,所以要带上ROW和COL
{
	//	存放下棋的数据
	char board[ROW][COL] = { 0 };

	//	初始化棋盘为全空格

	Initboard(board, ROW, COL);

	//	打印棋盘

	Displayboard(board, ROW, COL);

	while (1)
	{
		//	玩家下棋

		Player_move(board, ROW, COL);

		//	下完棋打印一下
		Displayboard(board, ROW, COL);


		//	电脑下棋
		Computer_move(board, ROW, COL);

		//	下完棋打印一下
		Displayboard(board, ROW, COL);
	}

}

电脑下棋的效果图


在这里插入图片描述 在这里插入图片描述

游戏输赢判断的大致框架


什么情况下属于游戏结束

1:玩家赢 2:电脑赢 3:平局 或者 :继续

所以封装成一个函数来用是最方便的 那么直接硬写肯定是不太行的

所以当目的达到了,返回一个特定的符号,如果是返回的情况,一定需要一个用来接收的内容

//		玩家赢---'*'
// 
//		电脑赢---'#'
// 
//		平局---'Q'
// 
//		继续---'C'
//

而且每下完一步棋,都需要判断一下,所以这个判断输赢的函数要放在玩家和电脑下完棋之后

void game()		
{
	//	接收is_win的返回类型

	char ret = 0;

	//	存放下棋的数据
	char board[ROW][COL] = { 0 };

	//	初始化棋盘为全空格

	Initboard(board, ROW, COL);

	//	打印棋盘

	Displayboard(board, ROW, COL);

	while (1)
	{
		//	玩家下棋

		Player_move(board, ROW, COL);

		//	下完棋打印一下
		Displayboard(board, ROW, COL);

		//	再判断一下输赢
		ret = is_win(board, ROW, COL);
		if (ret != 'C')			//	等于'C'继续,不等于'C'就是有胜利的一方或者平局
		{
			break;
		}

		//	电脑下棋
		Computer_move(board, ROW, COL);

		//	下完棋打印一下
		Displayboard(board, ROW, COL);

		//	再判断一下输赢
		ret = is_win(board, ROW, COL);
		if (ret != 'C')			//	等于'C'继续,不等于'C'就是有胜利的一方或者平局
		{
			break;
		}
	}
	//		break结束跳到这里

}

再来判断输赢或者平局

	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}

游戏输赢判断的详解


最后一步,实现判断输赢函内容的细节

三子棋输赢的判断就是三个棋子在行,列,对角线是否三子相连

1: 用来判断行是否相等

	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][2];
		}
	}

灵魂画手上线
在这里插入图片描述
如果玩家赢,返回的就是玩家的棋子 * ,如果电脑赢,返回的就是电脑的棋子 #

2: 用来判断列是否相等

	int i = 0;
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
		{
			return board[2][i];
		}
	}

??????在这里插入图片描述
一定要加上不等于 ’ ’ 因为要把空格排除在外

3: 用来判断两条对角线是否相等
在这里插入图片描述

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

4: 判断平局的情况

在game.c的文件中实现一个判断平局的函数,不需要在.h文件中实现,因为这个函数并不是全局的,仅仅用于判断平局

加上 static 只能在本文件下使用


static 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;		//		棋盘还没被下满
			}
		}
	}

	return 1;		//		棋盘被下满了
}

放到 is_win函数内部来使用

	//		用来判断平局
	if (is_full(board, row, col) == 1)
	{
		return 'Q';
	}

	//		游戏继续
	return 'C';

最后: 整体代码不会放出来的,希望大家能一步步的看,一步步的实现,多的不说了,加油!

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-04 00:51:43  更:2022-09-04 00:53:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:46:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码