C语言小游戏的实现——三子棋

news2024/11/18 18:43:37

前言

       Hello!友友们,前边我们已经学习了C语言的基础知识,但单纯的理论和简单的代码演示是无法真正做到巩固所学的知识的,那么今天我将会带领大家,根据之前所学的知识,来写一个三子棋小游戏。

目录

前言

 总体框架设计

多文件创建分装

各个功能模块化实现

棋盘初始化

棋盘打印

玩家下棋

电脑下棋

 结果判断

 平局

游戏逻辑的安排

总结


 总体框架设计

       在玩游戏时,我们在进入游戏都会有菜单选项,选择开始游戏,推出游戏等这些指令,说到选择,那么我们可以依据我们所学的循环和分支语句来先完成基本框架的设计。

首先我们进入游戏都是先显示选项,做出选择,并且在玩游戏时玩一局,还想玩怎么办(想一想我们前边的知识哪种结构符合先进入游戏出现菜单再循环这一需求)那肯定是do…while的循环结构更符合,那么我们就先使用函数来打印输出一个菜单选项


int main() {
	do {
		menu();//菜单
	} while ();
	return 0;
}

既然以及有了菜单提示,接下来就是玩家进行选择,这时就用到了我们的选择分支语句switch语句;

int main() {
	int input = 0;
	do {
		menu();
		printf("请输入:>\n");
		scanf("%d", &input);
		switch (input) {
		case 1:
			game();//游戏实现模块,后续通过函数模块化实现
			break;
		case 0:
			printf("退出游戏:>\n");
			break;
		default:
			printf("输入有误,请重新输入:>\n");
			break;
		}
	} while (input);
	return 0;
}

这样就使用do…while和switch语句基本实现了游戏框架的构建。那么接下来最重要的就是game()游戏模块的实现。当然也不能忘了我们的菜单提示;

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

 这里我们可以先把game()换成打印玩游戏。这里我们先测试一下程序运行是否正常,再进行下一步(对于功能复杂较多的程序我们都可以是写一点测试一点,这样更便于我们找到错误)。

多文件创建分装

当然根据之前的方法,我将程序分装到多文件,.h文件用于声明函数,test.c文件用于程序设计,game.c文件用于函数定义

注意:函数的定义和声明是不同的(详细请看函数那期内容)

函数声明

void Initboard(board);//初始化棋盘

函数定义

void Initboard(char board[ROW][COL]) {
}

具体文件创建如下:

各个功能模块化实现

棋盘初始化

三子棋,我们需要在棋盘中输入要下的位置,相当于是一个三乘三的数组(这里我们就用到了二维数组的知识),那么游戏开始前需要我们先对棋盘初始化(使数组中的元素都为空格),那么就是数组初始化赋值(只用循环遍历每一个元素并赋予空格就ok了)。

void Initboard(char board[ROW][COL]) {
	for (int i = 0; i < ROW; i++) {
		for (int j = 0; j < COL; j++) {
			board[i][j] = ' ';
		}
	}
}

 既然初始化已经完成,那么下棋总不能光秃秃没有棋盘,接下来就是棋盘的打印。

棋盘打印

要打印一个三乘三的棋盘不难,这里可直接打印棋盘,也可以选择使用循环的方式打印棋盘(单纯打印棋盘相对简单这里就不再演示),但是为了巩固我们所学知识,本文将会对使用循环的方式打印棋盘做讲解。

void DisPlayBoard(char board[ROW][COL]) {//ROW 和COL是为了便于修改定义的标识符常量为3
	for (int i = 0; i < ROW; i++) {
		for (int j = 0; j < COL; j++) {//为了实现 %c | %c | %c 的打印
			printf(" %c ", board[i][j]);
			if (j < COL - 1) {//为了不让最后一个|打印
				printf("|");
			}
		 }
		printf("\n");//打印一行及时换行
		if (i < ROW - 1) {//控制---|---|---打印次数为两次
			for (int i = 0; i < COL; i++) {//为了打印---|---|---
				printf("---");
				if (i < COL - 1) {
					printf("|");
				}
			}
		}
		printf("\n");//   |   |   
	}                //---|---|---为一个整体循环
}

游戏开始棋盘已经打印完成,那么接下来就是玩家下棋和电脑下棋

玩家下棋

玩家下棋首先就是判断下的位置是否越界,其次就是判断所下位置是否为空,当输入不合法就要提重新输入,直到输入合法为止,这里就形成了一个循环结构。当然玩游戏的人可能不知道数组下标从0开始。根据以上几点对程序进行设计。

void PlayerMove(char board[ROW][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) {
			if (board[x - 1][y - 1] != ' ') {
				printf("该位置已被占有,请重新选择:>\n");
			}
			else {
				board[x - 1][y - 1] = '*';
				break;
			}
		}
		else {
			printf("输入不合法,请重新输入>:\n");
		}
	}
}

 玩家下棋之后就是电脑下棋

电脑下棋

电脑下棋目前我们所学的知识不足以实现电脑下棋智能化,但是我们可以通过生成随机数的方式,让电脑下棋。

电脑下棋就简单的多,让他生成随机数并判断所下位置是否为空,不为空就一直循环,直到落子成功。
 

void ComputerMove(char board[ROW][COL]) {
	printf("电脑下>:\n");
	while (1) {              //注意引用头文件stdlib.h 和 time.h
		int x = rand() % ROW;//rand与srand搭配使用来实现真正的随机这里srand加在了主函数里
		int y = rand() % COL;//随机数与COL和ROW求余结果在(0~COL-1)之间
		if (board[x][y] == ' ') {
			board[x][y] = '#';
			break;
		}
	}
}

 结果判断

下棋肯定需要判断结果,是电脑赢还是玩家赢,或者是平局。

赢需要三个连续的位置有相同的棋子,那无非就是行,列以及对角线这几种情况。

char IsWin(char board[ROW][COL]) {
	for (int 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];//返回连成三个的字符
		}
		//列赢
		if (board[0][i] == board[1][i] && board[1][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];
		}
		if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ') {
			return board[0][2];
		}
		//平局
		if (IsFull(board) == 1) {
			return 'p';
		}
		//继续
		return 'c';
}

 平局

 最后就是判定平局,平局的规则:没有一方获胜,并且没有位置可以落子。这一步也是非常简单,只需遍历每一个数组元素,并判断是否为空就可以了。

int IsFull(char board[ROW][COL]) {
	for (int i = 0; i < ROW; i++) {
		for (int j = 0; j < COL; j++) {
			if (board[i][j] == ' ') {
				return 0;
			}
		}
	}
	return 1;
}

 以上便是游戏模块各个函数的定义与实现,接下来就是游戏逻辑安排。

游戏逻辑的安排

以上我们已实现初始化棋盘,打印棋盘,玩家下棋,电脑下棋,结果判断,接下来就要对这几个功能进行合理安排,以确保游戏运行正常。

首先我们初始化棋盘,并打印棋盘提示玩家落子,接下来是玩家落子,电脑落子,每次落子之后都需要判断输赢,并且落子是一个循环的过程。

void game() {
	char board[ROW][COL];
	Initboard(board);
	//打印棋盘
	DisPlayBoard(board);
	while (1) {
		PlayerMove(board);
		DisPlayBoard(board);
		//判断输赢
		if (IsWin(board) != 'c') {
			break;//判定出输赢及时跳出循环
		}
		ComputerMove(board);
		DisPlayBoard(board);
		if (IsWin(board) != 'c') {
			break;
		}
	}
	if (IsWin(board) == '*') {
		printf("玩家获胜!\n");
	}
	else if (IsWin(board) == '#') {
		printf("电脑获胜!\n");
	}
	else if(IsWin(board)=='p') {
		printf("平局!\n");
	}
}

 好了我们游戏设计与安排以及完成,下面我将完整代码附在下边

头文件:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
void Initboard(board);//初始化棋盘
void DisPlayBoard(board);//打印棋盘
void PlayerMove(board);//玩家下棋
void ComputerMove(board);//电脑下棋
int IsFull(board);//判断棋盘是否满
char IsWin(board);//判断输赢

函数定义文件:

#include"game.h"
void Initboard(char board[ROW][COL]) {
	for (int i = 0; i < ROW; i++) {
		for (int j = 0; j < COL; j++) {
			board[i][j] = ' ';
		}
	}
}
void DisPlayBoard(char board[ROW][COL]) {
	for (int i = 0; i < ROW; i++) {
		for (int j = 0; j < COL; j++) {
			printf(" %c ", board[i][j]);
			if (j < COL - 1) {
				printf("|");
			}
		 }
		printf("\n");
		if (i < ROW - 1) {
			for (int i = 0; i < COL; i++) {
				printf("---");
				if (i < COL - 1) {
					printf("|");
				}
			}
		}
		printf("\n");
	}
}
void PlayerMove(char board[ROW][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) {
			if (board[x - 1][y - 1] != ' ') {
				printf("该位置已被占有,请重新选择:>\n");
			}
			else {
				board[x - 1][y - 1] = '*';
				break;
			}
		}
		else {
			printf("输入不合法,请重新输入>:\n");
		}
	}
}
void ComputerMove(char board[ROW][COL]) {
	printf("电脑下>:\n");
	while (1) {
		int x = rand() % ROW;
		int y = rand() % COL;
		if (board[x][y] == ' ') {
			board[x][y] = '#';
			break;
		}
	}
}
int IsFull(char board[ROW][COL]) {
	for (int i = 0; i < ROW; i++) {
		for (int j = 0; j < COL; j++) {
			if (board[i][j] == ' ') {
				return 0;
			}
		}
	}
	return 1;
}
char IsWin(char board[ROW][COL]) {
	for (int 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];
		}
		//列赢
		if (board[0][i] == board[1][i] && board[1][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];
		}
		if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ') {
			return board[0][2];
		}
		//平局
		if (IsFull(board) == 1) {
			return 'p';
		}
		//继续
		return 'c';
}

 游戏框架:

#include"game.h"
void menu() {
	printf("***************************\n");
	printf("*******  1.play  **********\n");
	printf("*******  0.exit  **********\n");
	printf("***************************\n");
}
void game() {
	char board[ROW][COL];
	Initboard(board);
	//打印棋盘
	DisPlayBoard(board);
	while (1) {
		PlayerMove(board);
		DisPlayBoard(board);
		//判断输赢
		if (IsWin(board) != 'c') {
			break;
		}
		ComputerMove(board);
		DisPlayBoard(board);
		if (IsWin(board) != 'c') {
			break;
		}
	}
	if (IsWin(board) == '*') {
		printf("玩家获胜!\n");
	}
	else if (IsWin(board) == '#') {
		printf("电脑获胜!\n");
	}
	else if(IsWin(board)=='p') {
		printf("平局!\n");
	}
}
int main() {
	int input = 0;
	srand((unsigned int)time(NULL));
	do {
		menu();
		printf("请输入:>\n");
		scanf("%d", &input);
		switch (input) {
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏:>\n");
			break;
		default:
			printf("输入有误,请重新输入:>\n");
			break;
		}
	} while (input);
	return 0;
}


总结


以上就是今天要讲的内容,本文使用我们所学的C语言知识对小游戏——三子棋的实现,希望能够更好巩固前边所学的知识。好的本期内容到此结束,感谢阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/517279.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从C出发 31 --- 指针专题经典问题剖析

int a 0; int* p &a; //p作为指针指向了a, p 保存的是a 变量的内存地址&#xff0c;// p 这个指针本质是变量&#xff0c;这个变量有没有内存地址&#xff1f;// 有内存地址&#xff0c;为什么&#xff1f;// 因为它作为变量&#xff0c;肯定要占用内存空间的// p 这个变…

第十一章 使用Bind提供域名解析服务

文章目录 第十一章 使用Bind提供域名解析服务一、DNS域名解析服务1、DNS简介2、服务器类型3、13台根DNS服务器的具体信息 二、安装Bind服务程序1、Bind简介2、Bind安装3、关键配置文件4、修改主配置文件5、正向解析实验&#xff08;1&#xff09;、编辑区域配置文件&#xff08…

processing官方教程笔记(附加官网链接)更新中~

官方参考文档&#xff1a;https://processing.org/reference 官网视频&#xff1a;https://www.youtube.com/user/shiffman/playlists?view50&sortdd&shelf_id2 b站up主转载官方视频&#xff1a;https://www.bilibili.com/video/BV147411d7kY?p1&vd_source07ce5c…

【计算机三级网络技术】 第六篇 真题练习

文章目录 IPS&#xff08;入侵防护系统&#xff09;相关知识点蓝牙服务器技术DNS 服务器WWW 服务器FTP 服务器邮件&#xff08;Winmail 邮件服务器&#xff09;生成树协议IEEEVLAN 标识的描述DHCP 服务器 IPS&#xff08;入侵防护系统&#xff09;相关知识点 1、入侵防护系统&…

迪赛智慧数——柱状图(象形标识图):在选择另一半时,你更看重的是?

效果图 好看只排第六&#xff0c;第一确实众望所归&#xff01;当代男女择偶标准出炉&#xff0c;一张图带你看清。 女性挑选另一半时&#xff0c;她们更看重伴侣收入高、职业体面、工作能力强、受教育程度高&#xff0c;还得和自己有共同话题。 男性择偶观和女性恰恰相反&am…

第二届网刃部分WP

第二届网刃部分WP 玩坏的winxp 用VM打开附件时候打不开&#xff0c;后来用DiskGenius软件打开&#xff0c;发现桌面中存在有五张图片 在图片meiren.png中发现有隐藏压缩包 foremost分离文件&#xff0c;发现图片 010查看发现还有一层压缩包&#xff0c;再次分离发现压缩包…

自动售货机程序找零博图程序实现

1、操作界面 2、程序实现 REGION 找零确认 IF #找零确认 THEN //复位 #"50元张数" : 0.0; #"20元张数" : 0.0; #"10元张数" : 0.0; #"5元张数" : 0.0; #"1元张数…

Mysten Labs宣布推出积极贡献者和早期支持者ACES计划

Mysten Labs宣布推出积极贡献者和早期支持者&#xff08;ACES&#xff0c;Active Contributors & Early Supporters&#xff09;计划。这是对进入Sui主网的社区成员所做努力的巨大认可。 如果您在5月3日Sui主网启动之前就加入Sui Discord&#xff0c;请于5月18日凌晨2点&a…

JUC并发编程16 | CAS自旋锁

CAS自旋锁 是什么&#xff0c;干什么&#xff0c;解决了什么痛点&#xff1f;如何解决&#xff0c;如何使用。 原子类&#xff1a;java.util.concurrent.atomic 在没有CAS之前&#xff0c;多线程环境不使用原子类保证线程安全i等操作&#xff0c;会出现数据问题&#xff0c;…

LeetCode特训 -- Week3 (字符串)

目录 字符串基础 字符串基本操作 字符串匹配算法 字符串异位词问题 分组分类问题和快速查找数据结构之间存在一定的关系。 字符串回文串问题 留下悬念&#xff1a;高级字符串算法题目(字符串 dp) 字符串基础 字符串定义&#xff1a;n个字符顺次排列而成的序列. 子串&…

MySQL好玩新特性:离线模式

GreatSQL社区原创内容未经授权不得随意使用&#xff0c;转载请联系小编并注明来源。GreatSQL是MySQL的国产分支版本&#xff0c;使用上与MySQL一致。作者&#xff1a;Yejinrong/叶金荣文章来源&#xff1a;GreatSQL社区原创 继续吹MySQL 8.0~ 在以前&#xff0c;当需要对MySQL数…

CVPR 2023 | VoxelNeXt实现全稀疏3D检测跟踪,还能结合Seg Anything

在本文中&#xff0c;研究者提出了一个完全稀疏且以体素为基础的3D物体检测和跟踪框架VoxelNeXt。它采用简单的技术&#xff0c;运行快速&#xff0c;没有太多额外的成本&#xff0c;并且可以在没有NMS后处理的情况下以优雅的方式工作。VoxelNeXt在大规模数据集nuScenes、Waymo…

《编程思维与实践》1064.A-B(Big Integer)

《编程思维与实践》1064.A-B(Big Integer) 题目 思路 两个大整数做减法有可能出现结果为负的情况,因此结构体BIGINT需要补充符号位sign, 因为减法是个位对齐进行操作,为了方便起见,本题还是采用逆序(个位开始)存储. 注意到本题的两个整数均非负,所以不需要考虑转化为加法的情况…

TOOM舆情监测系统:从原理到应用

舆情监测系统是一种可以帮助企业、政府等机构了解公众对自己的看法和态度&#xff0c;提前发现和预测可能出现的危机或负面舆情&#xff0c;从而进行预警和应对的工具。本文将从原理到应用&#xff0c;通过国内具体案例分析&#xff0c;探讨舆情监测系统的相关知识。 一、舆情…

DSP:数字信号处理的原理及应用

什么是DSP&#xff1f;DSP一般有两种解释&#xff1a; 1、Digital Signal Processing&#xff0c;数字信号处理技术&#xff0c;简称DSP。是一门涉及许多学科而又广泛应用于许多领域的新兴学科。数字信号处理是围绕着数字信号处理的理论、实现和应用等几个方面发展起来的。数字…

有哪些好用的AI工具?

现在有很多好用的AI工具&#xff0c;以下是一些常用的&#xff1a; 1. TensorFlow&#xff1a;谷歌开发的深度学习框架&#xff0c;支持多种编程语言&#xff0c;包括Python、C、Java等。 2. PyTorch&#xff1a;Facebook开发的深度学习框架&#xff0c;易于使用&#xff0c;…

干货分享:PCB防静电设计的必要性

平时通过走路穿衣等日常活动带来的摩擦&#xff0c;会产生不同幅值的静电电压&#xff0c;但其能量很小不会对人体产生伤害&#xff0c;不过对于电子元器件来说&#xff0c;这种静电能量却是不能忽视的。 在干燥的环境下&#xff0c;人体静电&#xff08;ESD&#xff09;的电压…

matlab实验二可视化

学聪明点&#xff0c;自己改&#xff0c;别把我卖了 一、实验目的及要求 要求 1、掌握 MATLAB常用的二维和三维绘图函数 2、掌握MATLAB的图形注释 3、熟悉MATLAB常用的图形修饰 4、熟悉MATLAB的图形动画 实验原理 1、MATLAB二维绘图&#xff1a;plot,fplot,fimplicit&#xf…

Matlab 非线性迭代法(2)高斯牛顿法

一、思想 高斯牛顿法的对象是最小二乘法。 采用一定的方法对Hession 矩阵进行近似&#xff0c;这样的话可以减少计算量&#xff0c;只需要计算一阶偏导数得到雅可比矩阵即可。 minF(x)|| f(x)||^2 那么x在xk处的增量Δxk出的最小二乘法为 minF(xkΔxk)∣∣f(xk​Δxk​)∣…

Word处理控件Aspose.Words功能演示:使用 Java 处理 Word 文档的原始版本或修订版本

Aspose.Words是一种高级Word文档处理API&#xff0c;用于执行各种文档管理和操作任务。API支持生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现和打印文档&#xff0c;而无需在跨平台应用程序中直接使用Microsoft Word。 Aspose API支持流行文件格式处理&#xff0c;并…