C语言初阶习题【19】三子棋游戏

1.实现三子棋游戏

2.思路

我们把游戏实现部分放在game.c和game.h中,把游戏的测试代码放到test.c中
main函数在test.c中。

2.1 test.c中

  1. 先写main 函数,在main函数中调用test函数。
int main()
{test();return 0;
}
  1. 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);
}
  1. 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 ' ';//游戏继续}

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

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

相关文章

金融租赁系统的创新发展与市场竞争力提升探讨

内容概要 随着经济的快速发展&#xff0c;金融租赁系统逐渐成为金融市场中不可或缺的一环。它不仅提供了灵活的资金解决方案&#xff0c;还促进了企业的资本结构优化与资源配置效率。因此&#xff0c;了解该系统的市场背景与发展现状至关重要。 在现今环境下&#xff0c;新兴…

设计模式与游戏完美开发(2)

更多内容可以浏览本人博客&#xff1a;https://azureblog.cn/ &#x1f60a; 该文章主体内容来自《设计模式与游戏完美开发》—蔡升达 第二篇 基础系统 第四章 游戏主要类——外观模式&#xff08;Facade&#xff09; 一、游戏子功能的整合 一个游戏程序常常由内部数个不同的…

linux自动化批量分发SSH密钥同时批量测试SSH连接教程(包含自动化脚本代码)

1、检查端口 检查分发对象22端口是否打开 nmap -p22 ip地址如果要批量检查端口可以参考我写的这篇文章&#xff1a;linux自动化一键批量检查主机端口 2、命令行分发密钥原理 Linux分发密钥原理主要涉及SSH&#xff08;Secure Shell&#xff09;协议&#xff0c;该协议用于…

OpenHarmony源码编译后烧录镜像教程,RK3566鸿蒙开发板演示

本文介绍瑞芯微主板/开发板编译OpenHarmony源码后烧录镜像的教程&#xff0c;触觉智能Purple Pi OH鸿蒙开发板演示。搭载了瑞芯微RK3566四核处理器&#xff0c;树莓派卡片电脑设计&#xff0c;支持开源鸿蒙OpenHarmony3.2-5.0系统&#xff0c;适合鸿蒙开发入门学习。 编译源码…

【GO基础学习】gin框架路由详解

文章目录 gin框架路由详解&#xff08;1&#xff09;go mod tidy&#xff08;2&#xff09;r : gin.Default()&#xff08;3&#xff09;r.GET()路由注册 &#xff08;4&#xff09;r.Run()路由匹配 总结 gin框架路由详解 先创建一个项目&#xff0c;编写一个简单的demo&#…

vue之axios基本使用

文章目录 1. axios 网络请求库2. axiosvue 1. axios 网络请求库 <body> <input type"button" value"get请求" class"get"> <input type"button" value"post请求" class"post"> <!-- 官网提供…

ubuntu快速入门

1.进入某个文件夹 cd workspace/2.tab自动补全 3.列出当前文件夹所有文件 ls列出所有文件包括隐藏文件 ls -a 4.创建文件夹 mkdir linuxLearn 5.创建文件 gedit command.sh在commmand.sh键入 echo hello echo hi? echo how are you? PS:touch hello.txt(也可以创建新…

优化 invite_codes 表的 SQL 创建语句

-- auto-generated definition create table invite_codes (id int auto_incrementprimary key,invite_code varchar(6) not null comment 邀请码&#xff0c;6位整数&#xff0c;确保在有效期内…

FATE-LLM简介;FATE-LLM集成了多种参数高效微调方法

FATE-LLM简介 FATE-LLM是一个支持联邦大语言模型训练的框架,其架构及核心技术原理如下: 架构概述 FATE-LLM主要由模型层、参数高效微调层、隐私保护与安全机制、通信与聚合模块等组成,致力于在保护数据隐私的前提下,利用联邦学习技术整合各方数据与算力资源,提升大语言模…

小程序租赁系统构建指南与市场机会分析

内容概要 在当今竞争激烈的市场环境中&#xff0c;小程序租赁系统正崭露头角&#xff0c;成为企业转型与创新的重要工具。通过这个系统&#xff0c;商户能够快速推出自己的小程序&#xff0c;无需从头开发&#xff0c;节省了大量时间和资金。让我们来看看这个系统的核心功能吧…

数据库系列之分布式数据库下误删表怎么恢复?

数据的完整性是数据库可用性的基本功能&#xff0c;在实际应用数据库变更操作过程中可能因为误操作导致误删表或者truncate操作影响业务的正常访问。本文介绍了分布式数据库中在误删表场景下的数据恢复方案&#xff0c;并进行了对比。 1、数据库误删表恢复方案 应用数据的完整…

论文阅读:Towards Faster Deep Graph Clustering via Efficient Graph Auto-Encoder

论文地址&#xff1a;Towards Faster Deep Graph Clustering via Efficient Graph Auto-Encoder | ACM Transactions on Knowledge Discovery from Data 代码地址&#xff1a; https://github.com/Marigoldwu/FastDGC 摘要 深度图聚类&#xff08;Deep Graph Clustering, DGC…

Python爬虫教程——7个爬虫小案例(附源码)_爬虫实例

本文介绍了7个Python爬虫小案例&#xff0c;包括爬取豆瓣电影Top250、猫眼电影Top100、全国高校名单、中国天气网、当当网图书、糗事百科段子和新浪微博信息&#xff0c;帮助读者理解并实践Python爬虫基础知识。 包含编程资料、学习路线图、源代码、软件安装包等&#xff01;【…

BMS存储模块的设计

目的 电池管理系统中存在着数据本地存储的要求&#xff0c;保证控制器重新上电后能够根据存储器中的一些参数恢复控制状态&#xff0c;和信息的下电存储1.继电器故障信息的存储。2. 系统性故障的存储。3.SOC、SOH相关信息的存储。4.均衡参数的存储。5.系统时间信息。6.出厂信息…

Python爬取城市天气信息,并存储到csv文件中

1.爬取的网址为&#xff1a;天气网 (weather.com.cn) 2.需要建立Weather.txt文件&#xff0c;并在里面加入如下形式的字段&#xff1a; 101120701济宁 101010100北京 3.代码运行后&#xff0c;在命令行输入Weather.txt文件中添加过的城市&#xff0c;如&#xff1a;济宁。 …

MySQL线上事故:使用`WHERE`条件`!=xxx`无法查询到NULL数据

前言 在一次 MySQL 的线上查询操作中&#xff0c;因为 ! 的特性导致未能正确查询到为 NULL 的数据&#xff0c;险些引发严重后果。本文将详细解析 NULL 在 SQL 中的行为&#xff0c;如何避免类似问题&#xff0c;并提供实际操作建议。 1. 为什么NULL会查询不到&#xff1f; 在…

Solidworks打开无法获得许可,提示(-15,10,10061)错误解决办法

参考文章&#xff1a; https://blog.csdn.net/2301_81263647/article/details/140904773

【电路理论四】正弦电流电路

正弦电流 正弦量是随时间按正弦规律变动的电路变量。 随时间按正弦规律变动的电流称为正弦电流。 正弦电流的瞬时值表达式&#xff1a; 称为正弦电流的三要素。 分别为振幅/幅值&#xff0c;角频率&#xff0c;初相。 幅值为正弦电流的最大值&#xff0c;恒为正。 为正弦电…

解决Windows无法同时使用有线网和无线网WIFI的问题

参考资料 电脑无线网wifi和有线网同时使用&#xff08;内网外网同时使用&#xff09;用route命令解决Wifi和网卡不能同时上内外网问题 解决方法 对于Windows系统同时连接有线网和无线网Wifi时&#xff0c;只会有一个网关生效&#xff0c;因此我们需要手动通过route命令设置网…

FOC控制原理-ADC采样时机

0、文章推荐 SimpleFOC移植STM32&#xff08;五&#xff09;—— 电流采样及其变换_极对数对电流采样的影响-CSDN博客 FOC 电流采样方案对比&#xff08;单电阻/双电阻/三电阻&#xff09; - 知乎 (zhihu.com) FOC中的三种电流采样方式&#xff0c;你真的会选择吗&#xff1f;…