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页,但是能利用的可能也没几…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...