C语言初阶习题【19】三子棋游戏
1.实现三子棋游戏
2.思路
我们把游戏实现部分放在game.c和game.h中,把游戏的测试代码放到test.c中
main函数在test.c中。
2.1 test.c中
- 先写main 函数,在main函数中调用test函数。
int main()
{test();return 0;
}
- test.c函数实现让玩家进行选择是否要进行游戏
这里用到了do…while语句,先上来打印一个菜单,让玩家进行输入,根据玩家输入进入不同的分支。
void test()
{int input = 0;do{manu();printf("请输入你的选择:\n");scanf("%d", &input);switch(input){case 1:game();break;case 0:printf("您已退出游戏,欢迎下次再来!\n");break;default:printf("您的选择有误,请重新输入:\n");}} while (input);
}
- manu()函数很简单,直接print打印即可。和我们之前的猜数字游戏是一样的思路
void manu(void)
{printf("=====================\n");printf("=====1:开始游戏=====\n");printf("=====0:退出游戏=====\n");printf("=====================\n");
}
这里写完,可以把game()函数先屏蔽掉看看效果,输入其他数值直接报错让玩家继续输,输入1直接break,循环继续,输入0就直接退出了。
2.2 game()的实现
game()函数实现这部分是游戏流程。game()也是放在test.c中。但是涉及到game函数具体实现都会放到game.c中去。
我们先表示棋盘:创建一个 3*3的二维数组,每个元素是一个char类型,'X’表示玩家1、'O’表示玩家2、'空格’表示空白。 我在game.c函数实现中设计了如果是和局的话用‘h’表示
因为只要游戏没有结束,就要一直下棋,所以要用到循环while
- 游戏流程:
(1)创建棋盘,并初始化~把所有位置都设为空格
(2)打印棋盘
while(1)
{
(3)玩家进行落子,让玩家来输入一组坐标(row,col),进行落子
(4)进行判定,有任何一方获胜或者平局就break;
(5)电脑进行落子~ 电脑随机落子
(6)进行判定,有任何一方获胜或者平局就break;
}
(7)判定是哪一方获胜或者平局了 - 代码实现
void game()
{//0.创建棋盘char chessBoard[ROW_MAX][COL_MAX] = { 0 };//1.初始化棋盘init(chessBoard, ROW_MAX, COL_MAX);//2.打印棋盘print(chessBoard, ROW_MAX, COL_MAX);char ret = ' ';//这个需要定义在while之外while (1){//3.玩家下棋palyer(chessBoard, ROW_MAX, COL_MAX);print(chessBoard, ROW_MAX, COL_MAX);ret = is_Win(chessBoard, ROW_MAX, COL_MAX);if ( ret!= ' '){break;}//4.电脑下棋computer(chessBoard, ROW_MAX, COL_MAX);print(chessBoard, ROW_MAX, COL_MAX);ret = is_Win(chessBoard, ROW_MAX, COL_MAX);if (ret != ' '){break;}}if (ret == 'X'){printf("玩家获胜\n");}else if (ret== 'O'){printf("电脑获胜\n");}else if(ret== 'h'){printf("平局\n");}}
2.3 game.c函数实现
我们注意game.c和game.h是配套使用的,game.c中的函数需要在game.h中进行声明。
在.c文件中需要引入我们自己写的.h头文件,用的是“ ”,一般引用库函数用的< >
#include "game.h"
2.3.1 棋盘初始化
init(chessBoard, ROW_MAX, COL_MAX);
最简单的写法就是使用for循环直接遍历,给每个元素初始化为空格,后面有学到了用memset函数,直接初始化。
memset函数的头文件是<string.h> 。这个的使用可以自己搜下,比较简单有三个参数,第一个是要初始化的元素地址,我们这里就是数组首元素,第二个参数是要初始化的值,我们这里是空格,第三个就是要初始化的长度,
//棋盘初始化
void init(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{
#if 0for (int row = 0; row < MAX_ROW; row++){for (int col = 0; col < MAX_COL; col++){chessBoard[row][col] = ' ';}}
#endifmemset(chessBoard, ' ', ROW_MAX * COL_MAX * sizeof(char));
}
2.3.2 棋盘打印
void print(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
思路:这个地方要考虑到打印我们的棋盘,否则全是空格就看不到任何输出。
void print(char chessBoard[ROW_MAX][COL_MAX], int row, int col){for (int row = 0; row < ROW_MAX; row++){printf("+---+---+---+\n");printf("| %c | %c | %c |\n", chessBoard[row][0], chessBoard[row][1], chessBoard[row][2]);}printf("+---+---+---+\n");
}
2.3.2 玩家下棋
- void palyer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
- 思路:只要位置不为空就可以下棋,要注意限制玩家输入范围。
- 代码实现
//玩家下棋
void palyer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{printf("玩家下棋:\n");int x = 0;int y = 0;while (1){printf("请输入要下棋的坐标:x y\n");scanf("%d %d", &x, &y);if (x<0 || x>=ROW_MAX || y<0 || y>=COL_MAX){printf("您的输入坐标有误请重新输入:\n");continue;}if (chessBoard[x][y] != ' '){printf("您下的位置已经有棋子了。请重新输入:\n");continue;}else{chessBoard[x][y] = 'X';break;}}
}
2.3.3 电脑下棋
- void computer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
- 思路:电脑需要使用rand()函数生成随机数进行下棋,注意两个点,其一要限制输入0 1 2不能超过3,其二需要配合srand()函数一起使用,srand()需要用到时间戳time()函数,我们这个只需要调用一次放在了test函数中。这个在猜数字游戏里面也有实现过。rand函数的头文件是<stdlib.h> time函数的头文件是<time.h>
- 代码实现
void test()
{int input = 0;srand((unsigned int)time(NULL)); //在循环外面do{manu();printf("请输入你的选择:\n");scanf("%d", &input);switch(input){case 1://game();break;case 0:printf("您已退出游戏,欢迎下次再来!\n");break;default:printf("您的选择有误,请重新输入:\n");}} while (input);
}
//电脑下棋
void computer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{printf("电脑下棋:\n");while (1){int a = rand() % ROW_MAX;int b = rand() % COL_MAX;if (chessBoard[a][b] != ' '){continue;}chessBoard[a][b] = 'O';break;}}
2.3.4 判断输赢
-
char is_Win(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
-
思路:这里之所以是char类型的返回值,是为了能够方便我们进行判断是谁赢了。判断的思路很简单,判断三行是否一致,三列是否一致,对角线是否一致,棋盘是否下满为和局,这里涉及到一个棋盘是否满的函数,这个函数我们只需要我们的game.c中使用,所以给添加了static,关闭它的外部属性,其他.c文件都不能调用我们这个函数。
-
代码实现
static int is_Full(char chessBoard[ROW_MAX][COL_MAX])
{int i = 0;int j = 0;for (i = 0; i < ROW_MAX; i++){for (j = 0; j < COL_MAX; j++){if (chessBoard[i][j] == ' '){return 0;}}}return 1;
}char is_Win(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{//判断三行int i = 0;for (i = 0; i < row; i++){if (chessBoard[i][0] ==chessBoard[i][1] && chessBoard[i][1] == chessBoard[i][2]&& chessBoard[i][0] != ' '){return chessBoard[i][0];}}//判断三列for (i = 0; i < col; i++){if (chessBoard[0][i] == chessBoard[1][i] && chessBoard[1][i] == chessBoard[2][i]&& chessBoard[0][i] != ' '){return chessBoard[0][i];}}//判断对角线if (chessBoard[0][0] == chessBoard[1][1] && chessBoard[1][1] == chessBoard[2][2]&& chessBoard[0][0] != ' '){return chessBoard[0][0];}if (chessBoard[2][0] == chessBoard[2][2] && chessBoard[2][2] == chessBoard[0][2]&& chessBoard[0][2] != ' '){return chessBoard[0][2];}if (is_Full(chessBoard)){return 'h';//和局}return ' ';//游戏继续}
我在写这部分的时候各种出错,有时候是少了一个等号,有时候是用错了循环变量,调试真的很重要,当发现自己的错误的时候有时候真的哭笑不得,还好有调试功能,可以让我一步一步跟着代码走排查自己的问题。
3.代码实现
- test.c
#include "game.h"void manu(void)
{printf("=====================\n");printf("=====1:开始游戏=====\n");printf("=====0:退出游戏=====\n");printf("=====================\n");
}void game()
{//0.创建棋盘char chessBoard[ROW_MAX][COL_MAX] = { 0 };//1.初始化棋盘init(chessBoard, ROW_MAX, COL_MAX);//2.打印棋盘print(chessBoard, ROW_MAX, COL_MAX);char ret = ' ';while (1){//3.玩家下棋palyer(chessBoard, ROW_MAX, COL_MAX);print(chessBoard, ROW_MAX, COL_MAX);ret = is_Win(chessBoard, ROW_MAX, COL_MAX);if ( ret!= ' '){break;}//4.电脑下棋computer(chessBoard, ROW_MAX, COL_MAX);print(chessBoard, ROW_MAX, COL_MAX);ret = is_Win(chessBoard, ROW_MAX, COL_MAX);if (ret != ' '){break;}}if (ret == 'X'){printf("玩家获胜\n");}else if (ret== 'O'){printf("电脑获胜\n");}else if(ret== 'h'){printf("平局\n");}}void test()
{int input = 0;srand((unsigned int)time(NULL));do{manu();printf("请输入你的选择:\n");scanf("%d", &input);switch(input){case 1:game();break;case 0:printf("您已退出游戏,欢迎下次再来!\n");break;default:printf("您的选择有误,请重新输入:\n");}} while (input);
}int main()
{test();}
- game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>#define ROW_MAX 3
#define COL_MAX 3//棋盘初始化
void init(char chessBoard[ROW_MAX][COL_MAX],int row,int col );//棋盘打印
void print(char chessBoard[ROW_MAX][COL_MAX], int row, int col);//玩家下棋
void palyer(char chessBoard[ROW_MAX][COL_MAX], int row, int col);//电脑下棋
void computer(char chessBoard[ROW_MAX][COL_MAX], int row, int col);//判断输赢
char is_Win(char chessBoard[ROW_MAX][COL_MAX], int row, int col);
- game.c
#include "game.h"//棋盘初始化
void init(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{memset(chessBoard, ' ', ROW_MAX * COL_MAX * sizeof(char));
}//棋盘打印
void print(char chessBoard[ROW_MAX][COL_MAX], int row, int col){for (int row = 0; row < ROW_MAX; row++){printf("+---+---+---+\n");printf("| %c | %c | %c |\n", chessBoard[row][0], chessBoard[row][1], chessBoard[row][2]);}printf("+---+---+---+\n");
}//玩家下棋
void palyer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{printf("玩家下棋:\n");int x = 0;int y = 0;while (1){printf("请输入要下棋的坐标:x y\n");scanf("%d %d", &x, &y);if (x<0 || x>=ROW_MAX || y<0 || y>=COL_MAX){printf("您的输入坐标有误请重新输入:\n");continue;}if (chessBoard[x][y] != ' '){printf("您下的位置已经有棋子了。请重新输入:\n");continue;}else{chessBoard[x][y] = 'X';break;}}
}//电脑下棋
void computer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{printf("电脑下棋:\n");while (1){int a = rand() % ROW_MAX;int b = rand() % COL_MAX;if (chessBoard[a][b] != ' '){continue;}chessBoard[a][b] = 'O';break;}}static int is_Full(char chessBoard[ROW_MAX][COL_MAX])
{int i = 0;int j = 0;for (i = 0; i < ROW_MAX; i++){for (j = 0; j < COL_MAX; j++){if (chessBoard[i][j] == ' '){return 0;}}}return 1;
}//判断输赢
//返回X表示玩家获胜
//返回O表示电脑获胜
//返回h表示和局
//返回j表示游戏继续char is_Win(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{//判断三行int i = 0;for (i = 0; i < row; i++){if (chessBoard[i][0] ==chessBoard[i][1] && chessBoard[i][1] == chessBoard[i][2]&& chessBoard[i][0] != ' '){return chessBoard[i][0];}}//判断三列for (i = 0; i < col; i++){if (chessBoard[0][i] == chessBoard[1][i] && chessBoard[1][i] == chessBoard[2][i]&& chessBoard[0][i] != ' '){return chessBoard[0][i];}}//判断对角线if (chessBoard[0][0] == chessBoard[1][1] && chessBoard[1][1] == chessBoard[2][2]&& chessBoard[0][0] != ' '){return chessBoard[0][0];}if (chessBoard[2][0] == chessBoard[2][2] && chessBoard[2][2] == chessBoard[0][2]&& chessBoard[0][2] != ' '){return chessBoard[0][2];}if (is_Full(chessBoard)){return 'h';//和局}return ' ';//游戏继续}
相关文章:

C语言初阶习题【19】三子棋游戏
1.实现三子棋游戏 2.思路 我们把游戏实现部分放在game.c和game.h中,把游戏的测试代码放到test.c中 main函数在test.c中。 2.1 test.c中 先写main 函数,在main函数中调用test函数。 int main() {test();return 0; }test.c函数实现让玩家进行选择是否…...

Linux day 1129
家人们今天继续学习Linux,ok话不多说一起去看看吧 三.Linux常用命令 3.1 Linux命令体验 3.1.1 常用命令演示 在这一部分中,我们主要介绍几个常用的命令,让大家快速感 受以下 Linux 指令的操作方式。主要包含以下几个指令: ls命…...

【优化算法】梯度优化算法:一种新的原启发式优化算法算法
目录 1.摘要2.算法原理3.结果展示4.参考文献5.获取代码 1.摘要 本文提出了一种新型的元启发式优化算法——梯度优化器(Gradient-based Optimizer, GBO)。GBO算法灵感来源于牛顿法,采用两个主要操作:梯度搜索规则(Grad…...

内部类(3)
大家好,今天我们继续来看看内部类,今天我们来学习一下内部类的分类,我们来看看一共有几种,它们有什么作用,那么话不多说,我们直接开始。 9.1 内部类的分类 先来看下,内部类都可以在一个类的哪些位置进行定…...

svn分支相关操作(小乌龟操作版)
在开发工作中进行分支开发,涉及新建分支,分支切换,合并分支等 新建远程分支 右键选择branch/tagert按钮 命名分支的路径名称 点击确定后远程分支就会生成一个当时命名的文件夹(开发分支) 分支切换 一般在开发阶段&a…...
rust_shyper
title: 探索 Rust_Shyper:系统编程的新前沿 date: ‘2024-12-30’ category: blog tags: Rust_ShyperRust 语言系统编程性能与安全 sig: Virt archives: ‘2024-12’ author:way_back summary: Rust_Shyper 作为基于 Rust 语言的创新项目,在系统编程领域…...

HAL 库 HAL_UARTEx_ReceiveToIdle_IT 函数解析
一、存在位置:stm32f1xx_hal_uart.c 二、具体代码 二、返回值:HAL_StatusTypeDef 通过查看返回值HAL_StatusTypeDef在stm32f1xx_hal_edf.h文件中定义为结构体类型。 status:(进展的)状况,情形 三、函数名…...

【ArcGIS Pro】完整的nc文件整理表格模型构建流程及工具练习数据分享
学术科研啥的要用到很多数据,nc文件融合了时间空间数据是科研重要文件。之前分享过怎样将nc文件处理成栅格后整理成表格。小编的读者还是有跑不通整个流程的,再来做一篇总结篇,也分享下练习数据跟工具,如果还是弄不了的࿰…...

REDIS的集群
REDIS的集群模式: 主从模式:redis高可用的基础,哨兵和集群都是建立在此基础之上 特点: 主从模式和数据库的主从模式(工作模式)是一样的,主负责写入,然后把写入到数据同步到从&…...
酒店管理系统的设计与实现【源码+文档+部署讲解】
酒店管理系统的设计与实现 摘 要 中国经济近几年来取得蓬勃飞速发展,使得人民生活水平的要求和生活的质量有了很高的要求。因此人们对外出旅游和就餐的需求也越来越大。同时,随着我国科技水平的兴起和对互联网新时代的大力支持,酒店管理系统在…...

[论文阅读] (34)ESWA2024 基于SGDC的轻量级入侵检测系统
《娜璋带你读论文》系列主要是督促自己阅读优秀论文及听取学术讲座,并分享给大家,希望您喜欢。由于作者的英文水平和学术能力不高,需要不断提升,所以还请大家批评指正,非常欢迎大家给我留言评论,学术路上期…...

从社区共识到资本效能:解析SYNBO的去中心化投资协议创新
Web3 资本市场正处于深刻变革的关键节点。随着去中心化技术的不断进化,传统风险投资模式逐渐显现出效率、透明性与公平性等方面的局限性。而 SYNBO 的出现,为这一市场注入了全新的可能性。 作为新一代去中心化风险投资协议,SYNBO 不仅创新性地…...
一、数据库 Sqlite3 资料
SQLite3 教程 SQLite3 是一个轻量级的嵌入式数据库引擎,它不需要单独的服务器进程,数据库直接存储在磁盘文件中。Python 内置了 sqlite3 模块,可以方便地操作 SQLite 数据库。以下是 SQLite3 的详细教程。 1. SQLite3 简介 SQLite3 是一个自…...
Passlib库介绍及使用指南
什么是Passlib? Passlib是一个强大的Python密码哈希库,它支持多种哈希算法和工具。 Passlib不仅提供了易于使用的API,还集成了多种安全特性,如加盐、密钥派生函数等,广泛应用于用户账户系统、敏感数据保护和多因素认证…...

模型选择+过拟合欠拟合
训练误差和泛化误差 训练误差:模型在训练数据上的误差 泛化误差:模型在新数据上的误差 验证数据集:一个用来评估模型好坏的数据集 例如拿出50%的数据作为训练 测试数据集:只能用一次 K则交叉验证 在没有足够数据时使用 算法…...

绝美的数据处理图-三坐标轴-散点图-堆叠图-数据可视化图
clc clear close all %% 读取数据 load(MyColor.mat) %读取颜色包for iloop 1:25 %提取工作表数据data0(iloop) {readtable(data.xlsx,sheet,iloop)}; end%% 解析数据 countzeros(23,14); for iloop 1:25index(iloop) { cell2mat(table2array(data0{1,iloop}(1,1)))};data(i…...
损失函数-二分类和多分类
二分类和多分类的损失函数 二分类 损失函数 L ( y , y ^ ) − ( y l o g ( y ^ ) ) ( 1 − y ) l o g ( 1 − y ^ ) L(y,\hat{y}) -(ylog(\hat{y})) (1-y)log(1-\hat{y}) L(y,y^)−(ylog(y^))(1−y)log(1−y^) 其中真实标签表示为y(取值为 0 或 1&#…...

汽车损坏识别检测数据集,使用yolo,pasical voc xml,coco json格式标注,6696张图片,可识别11种损坏类型,识别率89.7%
汽车损坏识别检测数据集,使用yolo,pasical voc xml,coco json格式标注,6696张图片,可识别11种损坏类型损坏: 前挡风玻璃(damage-front-windscreen ) 损坏的门 (damaged-d…...
从 Elastic 迁移到 Easysearch 指引
从 Elasticsearch 迁移到 Easysearch 需要考虑多个方面,这取决于当前使用的 Elasticsearch 版本、能容忍的停机时间、应用需求等。在此背景下,我们梳理了一下通用的升级指引,方便大家进行迁移工作。 迁移路径 Elasticsearch 版本快照兼容推…...

Yapi RCE 复现和批量编写
一、漏洞复现 首先祭出fofa,搜索语句为 app"yapi",但是为了避开国内,所以使用 app"yapi" && country"SG",SG为新加坡,结果如图 虽然有30页,但是能利用的可能也没几…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...
32单片机——基本定时器
STM32F103有众多的定时器,其中包括2个基本定时器(TIM6和TIM7)、4个通用定时器(TIM2~TIM5)、2个高级控制定时器(TIM1和TIM8),这些定时器彼此完全独立,不共享任何资源 1、定…...
多元隐函数 偏导公式
我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式,给定一个隐函数关系: F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 🧠 目标: 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z、 …...