C语言实现【三子棋小游戏】

news2025/1/22 8:05:22

      Hello,各位小伙伴们好啊,这篇博客是用C语言实现了三子棋的游戏,感兴趣的友友可以试试玩哦~

咦,当我们以玩家的身份和电脑玩这个游戏的时候,有哪些步骤呢?那么,反过来,我们设计游戏的人应该怎么去设计呢?

接下来就先讲讲几个关键点吧:

(1) 打印棋盘:

为了让玩家玩的开心也让棋盘的格式清晰一点,可以使用函数,循环等方式打印棋盘;

(2)玩家下棋:

打印棋盘----->下棋(这里又分为两种情况,当玩家输入他所要下的棋子的坐标是合法的还是非法的,此时就需要分类讨论)

(3)电脑下棋:

利用随机函数产生一个棋子的坐标

(4)判断输赢:

玩游戏嘛有输有赢很正常,所以可以对玩家赢,电脑赢或者双方打成平局的这几种情况利用所学知识进行分类讨论的设计吆;

接下来,重头戏来啦......

 在这种设计游戏的过程中,分文件写代码就显得格外清楚也格外有优势了

这里我们就可以创建三个文件:

一个头文件:game.h  用于声明函数,宏定义等;

一个源文件:game.h 用于实现头文件中所有声明的函数;

一个源文件:test.h 用于控制整个小游戏的整个大轮廓。

(为什么要这么设计呢,就是为了让整个代码整洁,清楚,不啰嗦)

那在刚进入游戏,怎么让玩家进行选择呢?这里我们就可以简单打印一个菜单,小调皮一下哦

void menu()
{
	printf("*************************************\n");
	printf("*************  1.开始啦  **************\n");
	printf("*************  0.退出喽  **************\n");
	printf("*************************************\n");
}

完整的游戏代码:

game.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);
//判断输赢
char IsWin(char board[ROW][COL], int row, int col);
//若玩家赢,打印' * ';  若电脑赢,打印' # '; 
//若打成平局,打印"Q";
//若未分胜负,则打印"C";

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

//打印菜单
void menu()
{
	printf("*************************************\n");
	printf("*************  1.开始啦  **************\n");
	printf("*************  0.退出喽  **************\n");
	printf("*************************************\n");
}
void game()
{
	//定义一个数组
	char board[ROW][COL] = { 0 };
	//初始化棋盘
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisPlayBoard(board, ROW, COL);
	//开始下棋
	char ret = 0;
	while (1)
	{
		//玩家下棋
		PlayerMove(board, ROW, COL);
		//打印棋盘
		DisPlayBoard(board, ROW, COL);
		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}

		//电脑下棋
		ComputerMove(board, ROW, COL);
		//打印棋盘
		DisPlayBoard(board, ROW, COL);
		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}
	if (ret == '*')
		printf("玩家赢喽\n");
	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;
}

     在这个test.c 文件中,我们得完全把整个游戏大概的框架构造出来,可以让整体轮廓走起来。

(1)游戏的进入;

(2)游戏的退出;

(3)游戏的主体;

下面的代码分支就是所有关于游戏主体的每个详细部分啦〰

game.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"  //在game.h中已经包含了其他头文件,所以在这里只需要引用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;
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		//打印分割线
		if (i < row - 1)
		{
			int j = 0;
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\n");
		}
	}
	int j = 0;
	for (j = 0; j < col;j++)
	{
		printf("%c", board[i][j]);
	}
	printf("\n");*/
}

玩家下棋:

(1)玩家输入的坐标合法:

a:可以下棋;

b:不可以下棋(当玩家所输入的棋子坐标已被占用时) 

(2)玩家输入的坐标不合法:提醒玩家重新输入棋子坐标;

//玩家下棋
void PlayerMove(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)
		{
			//满足前面的条件后,如果保证坐标x,y都为空格
			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)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋:>\n");
	while (1)
	{
		x = rand() % row;//产生的随机数取 row 的模,得到的结果肯定是0 --- row-1 之间的数;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

判断棋盘是否已满 :

//判断棋盘是否已满
int IsFull(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;
}

判断输赢:(由于这个小游戏的规则特殊,我们在玩家和电脑下完棋的每一步都可以调用这个函数从而对比赛结果进行一个判断,确保程序的逻辑)

(1)如果赢了,可分为四种情况:(整行,整列,主对角线,反对角线);

(2)如果双方打成平局;

(3)未分胜负;

//判断输赢
char IsWin(char board[ROW][COL], int row, int col)
{
	
	//如果是一整行
	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];
		}
	}
	//如果是一整列
	for (i = 0; i < row; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][1] != ' ')
		{
			return board[0][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 (IsFull(board, row, col) == 1)
	{
		return 'Q';
	}
	//如果未分胜负,继续
	return 'C';
}

下面呢,就是这个小游戏简单实现的视频录制,有对的地方,也有刻意输错体现程序的地方哦

 http:// https://b23.tv/xo6GwrI 

   写代码从来不是一鼓作气写成功的,都是在不断的测试中调试代码,不断的测试中优化代码,行百里路半九十九,无论写简单的代码还是较为复杂的代码,不能急促,不能盲目追求结果,一步一个脚印的走,结果肯定不会太差哦。所有人,加油吖!

    各位大佬,小伙伴们;若有错误之处,欢迎指点吆~

 

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

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

相关文章

C++智能指针的原理、分类、使用

1. 智能指针介绍 为解决裸指针可能导致的内存泄漏问题。如&#xff1a; a&#xff09;忘记释放内存&#xff1b; b&#xff09;程序提前退出导致资源释放代码未执行到。 就出现了智能指针&#xff0c;能够做到资源的自动释放。 2. 智能指针的原理和简单实现 2.1 智能指针的原…

『python爬虫』19. aiohttp模块应用之下载图片(保姆级图文)

目录 1. aiohttp库安装2. 代码解析3. 实现代码总结 欢迎关注 『python爬虫』 专栏&#xff0c;持续更新中 欢迎关注 『python爬虫』 专栏&#xff0c;持续更新中 通过爬取下载得到图片 1. aiohttp库安装 pip install aiohttp这个库的作用基本上和request一致&#xff0c;理解…

SpringBoot——RUST风格以及如何快速发送不同方式的请求

RUST风格&#xff1a; 简单来说&#xff0c;RUST就是一种将请求方式融合到路径中的一种请求路径书写风格&#xff0c;注意这里是风格&#xff0c;不是规定&#xff0c;我们也可以不使用他或者不是非常严格的按照他规定的样式来写&#xff0c;但是由于行业中大多数的人在编程的…

Firefox 112 发布:右键单击显示密码、改进标签管理等!

Firefox 发布 112 版本&#xff0c;为我们带来了显示密码的新选择、同时改进了标签管理等。 Mozilla 于 2023 年 4 月 11 日发布了 Firefox 112&#xff0c;新版本包含一些令人兴奋的新功能和改进。该浏览器的最新版本带来了一些功能以增强用户体验和提高性能。 在 Ubuntu 上运…

UNIAPP实战项目笔记69 订单确认时显示为默认地址

UNIAPP实战项目笔记69 订单确认时显示为默认地址 思路 需要用到vuex 默认显示isDefault为1的地址 案例截图 订单结算页面 地址页面 代码 shopcart.vue <template><view class"shop-cart"><template v-if" list.length > 0 "><!-…

【Linux学习笔记】设备驱动模型详解——总线、设备、驱动和类

学习内容 设备驱动模型视频讲解 简介 设备驱动是计算机系统中的重要组成部分&#xff0c;它们允许操作系统与硬件交互。设备驱动模型是一种通用的抽象框架&#xff0c;用于描述操作系统如何管理硬件设备。这里我们将介绍设备驱动模型中的四个关键概念&#xff1a;总线、设备…

GitLab+Drone CI持续集成自动部署web项目

一、环境介绍 1.gitlab服务器 172.16.11.1 搭建参考&#xff1a;Gitlab教程 2.Drone服务器 172.16.11.2 搭建参考: 基于gitlab搭建Drone CI 3.web服务器 172.16.11.3 已配置好nginx相关web服务&#xff0c;这里nginx配置的web目录为/www/test 还有生成ssh key密钥即可&am…

编程的未来

从 ChatGPT 诞生至今&#xff0c;在程序员的圈子里&#xff0c;我们一直有两种讨论&#xff1a; 最开始所恐慌的&#xff1a;编程没有未来&#xff0c;ChatGPT 是不是要取代程序员。编程的方式前所未有地发生了变化。 现如今&#xff0c;GitHub Copilot Chat 可以让开发者们直…

算法修炼之练气篇——练气十八层

博主&#xff1a;命运之光 专栏&#xff1a;算法修炼之练气篇 前言&#xff1a;每天练习五道题&#xff0c;炼气篇大概会练习200道题左右&#xff0c;题目有C语言网上的题&#xff0c;也有洛谷上面的题&#xff0c;题目简单适合新手入门。&#xff08;代码都是命运之光自己写的…

支付系统设计三:渠道网关设计02-客户端报文解析

文章目录 前言一、后台配置管理1.1 渠道配置1.1.1 渠道基本信息新增1.1.2 渠道交易类型配置1.1.3 渠道商户信息配置1.1.4 账户配置1.1.5 交易类型机构配置 1.2 渠道通讯配置1.2.1 内部渠道通讯1.2.1 外部渠道通讯 1.3 资源配置1.4 证书管理1.5 路由配置 二、运行时逻辑处理1. 控…

Fluent的视角设置

1 背景 针对不同设计方案在同一工况下的差异点进行细节分析&#xff0c;其中一个很重要的要求就是需要在同一视角下比较不同设计方案的差异性。设置视角并进行快速重用是很重要的提高仿真效率的方法。 2 视角设置 视角设置有2类方法&#xff1a;手动拖拉和定量指定。 手动拖拉即…

一图看懂 tomli 模块:一个 TOML解析器、使用 mformat -toc 生成的目录,资料整理+笔记(大全)

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 一图看懂 tomli 模块&#xff1a;一个 TOML解析器、使用 mformat -toc 生成的目录&#xff0c;资料整理笔记&#xff08;大全&#xff09; &#x1f9ca;摘要&#x1f9ca;模块图&am…

前端开发中,定位bug的几种常用方法

目录 第一章 前言 第二章 解决bug的方法 2.1 百度 2.2 有道翻译 2.3 debugger 2.4 console.log 日志打印 2.5 请求体是否携带参数 2.6 注释页面渲染代码 2.7 其他 第三章 尾声 备注&#xff1a;该文章只是本人在工作/学习中常用的几种方法&#xff0c;如果有不对大家…

智慧园区移动应用发展面临瓶颈,如何解决?

智慧园区移动应用将在多元化服务、生态建设、智能化管理和跨界融合等方面发展&#xff0c;成为园区管理和服务的重要手段之一&#xff0c;为员工和企业提供更加智能化和便捷化的管理和服务。伴随着智慧城市的建设和智慧园区的崛起&#xff0c;智慧园区数字一体化建设成为园区发…

docker搭建nginx负载均衡

一点小背景 docker起了几个服务&#xff0c;没有配置端口映射&#xff0c;导致不能通过网络访问。当然&#xff0c;更简单的方式是加端口映射&#xff0c;笔者的情况更复杂一些&#xff0c;就想到了用nginx映射一下。 Nginx&#xff08;发音同“engine X”&#xff09;是异步框…

避免“文献综抄”,5种写作结构助你完成文献综述→

很多作者可能有过这样的体验&#xff1a;读了很多文献&#xff0c;但在写综述的时候总感觉不像是在写文献综述&#xff0c;更像在写文献总结 如果引用方面不注意&#xff0c;甚至会成为文献综抄。 那么&#xff0c;你可以参考下我们整理的以下资料哦~ 01 文献总结和文献综述的…

DCDC反馈电阻的阻值如何取值?

DCDC芯片的反馈电阻 下图为我们公司现在常用的两款DCDC芯片&#xff0c;TPS54335ADDA/TI和LMR14050SDDA/TI。 其中RFBT和RFBB都是反馈电阻&#xff0c;可以通过调节这两个电阻的比值来输出 预期电压。 FBT&#xff1a;feedback top&a…

保姆级丨XAMPP安装使用

0x00 前言 XAMPP 是一个完全免费&#xff0c;易于安装的 Apache 发行版&#xff0c;包含 MariaDB &#xff0c; PHP 和 Perl 。 XAMPP 开源软件包已经设置为非常容易安装和使用。 0x01 环境说明 Windows 11xampp-windows-x64-8.2.4-0-VS16-installer 0x02 准备工作 首先要访问…

数据库分区;pgAdmin操作pgsql分区;修改pgsql数据库名字

目录 分区 什么是分区 分区的优势 pgAdmin操作pgsql分区 创建父表 创建分区 数据入库分区 扩展&#xff08;按天创建分区脚本&#xff09; 修改数据库名字 链接 分区 什么是分区 指将一个大的表或索引分成多个小的、独立的部分&#xff0c;每个部分称为一个分区&#x…

带你了解家居智能的心脏:物联网关

本文将介绍家庭物联网关的相关内容&#xff0c;将明白物联网关在家庭这个场景当中的应用。现在市面上各种各样的智能家居的家电或者其他设备非常多&#xff0c;那么这就需要一个智能的设备去对所有的家电进行管控。这样一个设备就是家庭智能网关&#xff0c;家庭物联网关是家居…