当前位置: 首页 > news >正文

利用C语言实现三子棋游戏

文章目录

  • 1.游戏界面
  • 2.游戏内容
    • 2.1 棋盘类型
    • 2.2棋盘的初始化
    • 2.3 打印棋盘的界面展示
  • 3.游戏操作
    • 3.1 玩家操作
    • 3.2 电脑操作
    • 3.3 胜负判定
  • 4.代码整合

1.游戏界面

无论写任何程序,我们都需要先去了解它的大概框架,这里我们先把它的初始界面写出来。一个游戏的初始界面会有菜单可供选择,这里我写了一个最基础的游戏菜单,只支持开始游戏和退出游戏。为了能够在不退出游戏的情况下一直游玩,所以这里我写了一个do while循环来让游戏一直进行下去。

#include <stdio.h>
void menu()
{printf("*************************\n");printf("******* 1.play    *******\n");printf("******* 0.exit    *******\n");printf("*************************\n");}
int main()
{int input = 0;do{menu()//菜单printf("请选择>");scanf"%d",&input);switch(input){case 1:game();break;case 0:printf("退出游戏!\n");break;default:break;}}while(input);return 0;
}

2.游戏内容

2.1 棋盘类型

写完游戏的界面就轮到了游戏的内容了,让我们来想想三子棋有什么特点,最先想到就是它那3*3的棋盘了,为了实现这个棋盘我们要利用数组来实现。用什么类型的数组呢?这里我会用字符类型的数组,毕竟下棋用数字来作为棋子还是不容易区分的。

void game()
{//创建棋盘char chess[4][4] = {0};
}

2.2棋盘的初始化

选择了用字符数组来作为棋盘,初始化我会用‘ ’(空格)来初始化。空格初始化的好处就是不可见,当我们下好棋子后用相应的字符去覆盖掉空格就可以了。
这里我用4*4的数组是为了后续普通用户在用下标下棋时,不用考虑数组下标是0开始的,增加用户的受众。
为什么用多文件编写代码,多文件的编写可以便于后续的修改,多文件可以让代码的可读性更高。
注意头文件game.h放的是函数的声明,game.c放的是函数的定义 test.c是对程序的测试

//game.h
#include <stdio.h>
//以row为行,col为列void InitChess(char chess[4][4],int row,int col);//game.c
#include "game.h"
void InitChess(char chess[4][4],int row,int col)
{for(int i = 1;i<4;++i){for(int j = 1;j<4;++j){chess[i][j] = ' ';}}
}//test.c
#include "game.h"
void game()
{//创建棋盘char chess[4][4] = {0};//初始化棋盘InitChess(chess,4,4);
}

对函数拓展性的优化,这里的棋盘已经被固定,如果后续我们想要修改棋盘的大小是很麻烦的,所以我们可以定义标识常量。

//game.h
#include <stdio.h>
//以row为行,col为列
#define Row 4
#define Col 4void InitChess(char chess[Row][Col],int row,int col);//game.c
#include "game.h"
void InitChess(char chess[Row][Col],int row,int col)
{for(int i = 1;i<row;++i){for(int j = 1;j<col;++j){chess[i][j] = ' ';}}
}//test.c
#include "game.h"
void game()
{//创建棋盘char chess[Row][Col] = {0};//初始化棋盘InitChess(chess,Row,Col);
}

2.3 打印棋盘的界面展示

如果我们直接打印这个数组是什么也看不到的,为了让游玩的人可以轻松知道棋盘各个点的坐标,我们要把棋盘打印成这个样子。
打印棋盘

void ChessBoard(char chess[Row][Col], int row, int col)
{for (int i = 1; i < row; ++i){for (int j = 1; j < col; ++j){printf(" %c ", chess[i][j]);if (j < col - 1)//否则打印最后一个'|',导致右端封闭printf("|");}printf("\n");if (i < row - 1){for (int j = 1; j < col; ++j){printf("--- ");}printf("\n");}}
}

3.游戏操作

3.1 玩家操作

三子棋的游戏操作就是在3*3的方格当中选一个未被下过的方格中落子。
当前游戏并不支持双人对战,所以只能实现人机对战。下面为玩家操作:

void Gamer(char chess[Row][Col], int row, int col)
{int x = 0;//横坐标int y = 0;//纵坐标while (1){printf("选择落子坐标>\n");printf("坐标之间用空格区分\n");scanf("%d %d", &x, &y);//判断坐标是否合法if (x<1 || x>Row - 1 || y<1 || y>Col - 1){printf("坐标不合法\n");}//判断所选坐标是否被占据else if (chess[x][y] != ' '){printf("该坐标被占据\n");}else{chess[x][y] = 'O';printf("落子成功\n");break;}}
}

3.2 电脑操作

电脑的逻辑和玩家一样,这里我们让电脑随机下棋。

void Computer(char chess[Row][Col], int row, int col)
{int x = 0;int y = 0;while (1){x = rand() % (row - 1) + 1;y = rand() % (col - 1) + 1;if (chess[x][y] != ' '){//}else{chess[x][y] = 'X';break;}}
}

因为这了我们用了rand函数,所以我必须在前面写上srand来给rand函数提供随机种子,为此我们还需要用到time为srand提供数字来帮助它输出随机种子.
记得加上相应的头文件

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:break;}}while(input);return 0;
}

3.3 胜负判定

在三子棋当中,任何以方的棋子连成一条线就会判断为获胜,无论是一行还是一列还是斜方向。因为只有少量的情况。我能把所有获胜的情况全部都枚举出来就可以了。
关于返回值,因为我们要根据棋盘字符的连线来判断谁是赢家。
规定:返回 ‘O’表示玩家赢,‘X’表示电脑赢 'D’表示平局 'C’表示游戏继续

char Winer(char chess[Row][Col], int row, int col)
{for (int i = 1; i < row; ++i){if (chess[i][1] == chess[i][2] && chess[i][2] == chess[i][3] && chess[i][1] != ' '){return chess[i][1];}}for (int j = 1; j < col; ++j){if (chess[1][j] == chess[2][j] && chess[2][j] == chess[3][j] && chess[1][j] != ' '){return chess[1][j];}}if (chess[1][1] == chess[2][2] && chess[2][2] == chess[3][3] & chess[1][1] != ' '){return chess[1][1];}if (chess[1][3] == chess[2][2] && chess[2][2] == chess[3][1] && chess[2][2] != ' '){return chess[1][3];}//平局,判断棋盘是不是已经满了if (IsFull(chess, row, col)){return 'D';}return 'C';
}

判断棋盘是否已经下满

bool IsFull(char chess[Row][Col], int row, int col)
{for (int i = 1; i < row; ++i){for (int j = 1; j < col; ++j){if (chess[i][j] == ' ')return false;}}return true;
}

4.代码整合

关于三子棋的简单游戏逻辑就是这么多了,下面我们要把我们写到的函数整合到一起。

//game.h
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>//rand和srand的头文件
#include <time.h>//time的头文件
#define Row 4
#define Col 4void InitChess(char chess[Row][Col], int row, int col);void ChessBoard(char chess[Row][Col], int row, int col);void Gamer(char chess[Row][Col], int row, int col);void Computer(char chess[Row][Col], int row, int col);char Winer(char chess[Row][Col], int row, int col);bool IsFull(char chess[Row][Col], int row, int col);//game.c#include "game.h"void InitChess(char chess[Row][Col], int row, int col)
{for (int i = 1; i < row; ++i){for (int j = 1; j < col; ++j){chess[i][j] = ' ';}}
}void ChessBoard(char chess[Row][Col], int row, int col)
{for (int i = 1; i < row; ++i){for (int j = 1; j < col; ++j){printf(" %c ", chess[i][j]);if (j < col - 1)//否则打印最后一个'|',导致右端封闭printf("|");}printf("\n");if (i < row - 1){for (int j = 1; j < col; ++j){printf("--- ");}printf("\n");}}
}void Gamer(char chess[Row][Col], int row, int col)
{int x = 0;//横坐标int y = 0;//纵坐标while (1){printf("选择落子坐标>\n");printf("坐标之间用空格区分\n");scanf("%d %d", &x, &y);//判断坐标是否合法if (x<1 || x>Row - 1 || y<1 || y>Col - 1){printf("坐标不合法\n");}//判断所选坐标是否被占据else if (chess[x][y] != ' '){printf("该坐标被占据\n");}else{chess[x][y] = 'O';printf("落子成功\n");break;}}
}void Computer(char chess[Row][Col], int row, int col)
{int x = 0;int y = 0;while (1){x = rand() % (row - 1) + 1;y = rand() % (col - 1) + 1;if (chess[x][y] != ' '){//}else{chess[x][y] = 'X';break;}}
}char Winer(char chess[Row][Col], int row, int col)
{for (int i = 1; i < row; ++i){if (chess[i][1] == chess[i][2] && chess[i][2] == chess[i][3] && chess[i][1] != ' '){return chess[i][1];}}for (int j = 1; j < col; ++j){if (chess[1][j] == chess[2][j] && chess[2][j] == chess[3][j] && chess[1][j] != ' '){return chess[1][j];}}if (chess[1][1] == chess[2][2] && chess[2][2] == chess[3][3] & chess[1][1] != ' '){return chess[1][1];}if (chess[1][3] == chess[2][2] && chess[2][2] == chess[3][1] && chess[2][2] != ' '){return chess[1][3];}//平局,判断棋盘是不是已经满了if (IsFull(chess, row, col)){return 'D';}return 'C';
}bool IsFull(char chess[Row][Col], int row, int col)
{for (int i = 1; i < row; ++i){for (int j = 1; j < col; ++j){if (chess[i][j] == ' ')return false;}}return true;
}//test.c
#include "game.h"void game()
{//创建棋盘char chess[Row][Col] = { 0 };//初始化棋盘InitChess(chess, Row, Col);char w = 0;while (1){//打印棋盘ChessBoard(chess, Row, Col);//玩家操作Gamer(chess, Row, Col);//输赢判断w = Winer(chess, Row, Col);if (w != 'C')break;//电脑操作Computer(chess, Row, Col);//输赢判断char w = Winer(chess, Row, Col);if (w != 'C')break;}ChessBoard(chess, Row, Col);if (w == 'D')printf("平局\n");else if (w == 'O')printf("玩家获胜\n");elseprintf("电脑获胜\n");
}
void menu()
{printf("*************************\n");printf("******* 1.play    *******\n");printf("******* 0.exit    *******\n");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:break;}} while (input);return 0;
}

相关文章:

利用C语言实现三子棋游戏

文章目录 1.游戏界面2.游戏内容2.1 棋盘类型2.2棋盘的初始化2.3 打印棋盘的界面展示 3.游戏操作3.1 玩家操作3.2 电脑操作3.3 胜负判定 4.代码整合 1.游戏界面 无论写任何程序&#xff0c;我们都需要先去了解它的大概框架&#xff0c;这里我们先把它的初始界面写出来。一个游戏…...

大学教师门诊预约小程序-计算机毕业设计源码73068

摘要 在当今数字化、信息化的浪潮中&#xff0c;大学校园的服务管理正朝着智能化、便捷化的方向迈进。为了优化大学教师的医疗体验&#xff0c;提升门诊预约的效率和便捷性&#xff0c;我们基于Spring Boot框架设计并实现了一款大学教师门诊预约小程序。该小程序不仅提供了传统…...

Python PyCryptodome库介绍与实例

Python PyCryptodome库介绍与实例 1. 安装2. 基本概念3. 使用场景和示例代码3.1 对称加密 - AES3.2 非对称加密 - RSA3.3 哈希函数 - SHA2563.4 消息认证码 - HMAC 4. 总结 PyCryptodome是一个强大的Python加密库,提供了各种加密算法和工具。本文将介绍PyCryptodome的基本概念和…...

《框架封装者 · 自定义初始化事件》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…...

ActiViz实战:使用vtkImageClip和vtkImageActor根据滑动条来显示当前图像数据切面

文章目录 一、效果预览二、代码实现三、源码地址一、效果预览 ActiViz实现图像数据切面显示 二、代码实现 public partial class Form1 : Form {private vtkRenderWindowInteractor _interactor;private vtkRenderer _renderer...

【论文笔记】BEVCar: Camera-Radar Fusion for BEV Map and Object Segmentation

原文链接&#xff1a;https://arxiv.org/abs/2403.11761 0. 概述 本文的BEVCar模型是基于环视图像和雷达融合的BEV目标检测和地图分割模型&#xff0c;如图所示。模型的图像分支利用可变形注意力&#xff0c;将图像特征提升到BEV空间中&#xff0c;其中雷达数据用于初始化查询…...

圆通寄15kg30kg一般多少钱?寄大件物品怎么寄最便宜?

作为一名即将毕业的大学生&#xff0c;搬家成了我和室友们共同的难题。尤其是在寄送大件物品时&#xff0c;如何省钱、如何打包、选择哪家快递公司等问题让我们头疼不已。今天&#xff0c;我就来分享一些寄大件物品的省钱技巧以及打包方法&#xff0c;希望对大家有所帮助。 一…...

transformer初探

transformer初探 self-attentionmultihead-attentionencoderdecoder self-attention 其实就是三个矩阵&#xff0c; W q W_q Wq​、 W k W_k Wk​、 W v W_v Wv​&#xff0c;这三个矩阵就是需要训练的参数。分别得到每个token对应的 q q q k k k v v v&#xff0c;其中 q …...

JUC并发编程基础(包含线程概念,状态等具体实现)

一.JUC并发编程基础 1. 并行与并发 1.1 并发: 是在同一实体上的多个事件是在一台处理器上"同时处理多个任务"同一时刻,其实是只有一个事件在发生. 即多个线程抢占同一个资源. 1.2 并行 是在不同实体上的多个事件是在多台处理器上同时处理多个任务同一时刻,大家…...

集中管理和分析日志:使用 ELK 套件构建强大的日志管理平台

集中管理和分析日志&#xff1a;使用 ELK 套件构建强大的日志管理平台 日志是监控和调试应用程序和系统的重要工具。集中管理和分析日志可以帮助你快速定位问题、了解系统运行状况和性能&#xff0c;并提高你的日志管理效率。ELK 是一个流行的日志管理解决方案&#xff0c;由 …...

深度学习 - 模型的保存与部署方式汇总

深度学习模型保存和加载格式科普 在深度学习中&#xff0c;模型的保存和加载是非常重要的环节。不同的格式有不同的特点和适用场景。本文将为新手朋友们介绍几种常见的模型格式&#xff0c;包括它们的简介、保存方式、加载方式、优缺点以及应用场景。 1. PyTorch (.pth, .pt)…...

人工智能对网络安全有何影响?

人工智能网络安全在短期、中期和长期如何变化 当今数字时代网络安全的重要性 在谈论人工智能在网络安全中的作用时&#xff0c;必须首先考虑短期影响&#xff0c;因为它们是最明显的&#xff0c;而且它是一个未知的领域&#xff0c;需要超越直接炒作的能力。 因此&#xff0…...

Oracle的RECYCLEBIN回收站:轻松恢复误删对象

目录 Oracle的RECYCLEBIN回收站&#xff1a;轻松恢复误删对象一、概念二、工作原理三、使用方法1 查看回收站中的对象2 恢复回收站中的对象2.1 恢复表&#xff08;TABLE&#xff09;2.2 恢复索引&#xff08;INDEX&#xff09;2.3 恢复视图&#xff08;VIEW&#xff09;2.4 恢复…...

Android 内存原理详解以及优化(二)

上一篇讲了内存原理&#xff0c;如果还没看可以先看上一篇&#xff1a;Android 内存原理详解以及优化&#xff08;一&#xff09; 这一篇我总结一下我们经常遇到的内存优化问题&#xff1a; 1.内存抖动 自定义view的ondraw是会被频繁调用的&#xff0c;那在这个方法里面就不能频…...

Shell学习——Shell变量

文章目录 Shell变量使用变量只读变量删除变量变量类型字符串变量&#xff1a; 在 Shell中&#xff0c;变量通常被视为字符串。整数变量&#xff1a; 在一些Shell中&#xff0c;你可以使用 declare 或 typeset 命令来声明整数变量。数组变量&#xff1a; Shell 也支持数组&#…...

Java中的持续集成与持续部署(CI/CD)

Java中的持续集成与持续部署&#xff08;CI/CD&#xff09; 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将深入探讨Java中的持续集成&#xff08;Co…...

极狐GitLab 将亮相2024空天信息大会暨数字地球生态峰会,携手中科星图赋能空天行业开发者

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…...

Beats:使用 Filebeat 从 Python 应用程序中提取日志

本指南演示了如何从 Python 应用程序中提取日志并将其安全地传送到 Elasticsearch Service 部署中。你将设置 Filebeat 来监控具有标准 Elastic Common Schema (ECS) 格式字段的 JSON 结构日志文件&#xff0c;然后你将在 Kibana 中查看日志事件发生的实时可视化。虽然此示例使…...

51单片机第23步_定时器1工作在模式0(13位定时器)

重点学习51单片机定时器1工作在模式0的应用。 在51单片机中&#xff0c;定时器1工作在模式0&#xff0c;它和定时器0一样&#xff0c;TL1占低5位&#xff0c;TH1占高8位&#xff0c;合计13位&#xff0c;也是向上计数。 1、定时器1工作在模式0 1)、定时器1工作在模式0的框图…...

linux的服务管理

systemd systemd 是一个系统和服务管理器&#xff0c;用于Linux操作系统中&#xff0c;旨在替代传统的Unix系统V初始化系统&#xff08;SysV init&#xff09;。 不一定所有使用 yum 安装的软件都可以通过 systemctl start 来管理。能否通过 systemctl start 管理取决于软件包…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...