利用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.游戏界面 无论写任何程序,我们都需要先去了解它的大概框架,这里我们先把它的初始界面写出来。一个游戏…...
大学教师门诊预约小程序-计算机毕业设计源码73068
摘要 在当今数字化、信息化的浪潮中,大学校园的服务管理正朝着智能化、便捷化的方向迈进。为了优化大学教师的医疗体验,提升门诊预约的效率和便捷性,我们基于Spring Boot框架设计并实现了一款大学教师门诊预约小程序。该小程序不仅提供了传统…...
Python PyCryptodome库介绍与实例
Python PyCryptodome库介绍与实例 1. 安装2. 基本概念3. 使用场景和示例代码3.1 对称加密 - AES3.2 非对称加密 - RSA3.3 哈希函数 - SHA2563.4 消息认证码 - HMAC 4. 总结 PyCryptodome是一个强大的Python加密库,提供了各种加密算法和工具。本文将介绍PyCryptodome的基本概念和…...
《框架封装者 · 自定义初始化事件》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…...
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
原文链接:https://arxiv.org/abs/2403.11761 0. 概述 本文的BEVCar模型是基于环视图像和雷达融合的BEV目标检测和地图分割模型,如图所示。模型的图像分支利用可变形注意力,将图像特征提升到BEV空间中,其中雷达数据用于初始化查询…...
圆通寄15kg30kg一般多少钱?寄大件物品怎么寄最便宜?
作为一名即将毕业的大学生,搬家成了我和室友们共同的难题。尤其是在寄送大件物品时,如何省钱、如何打包、选择哪家快递公司等问题让我们头疼不已。今天,我就来分享一些寄大件物品的省钱技巧以及打包方法,希望对大家有所帮助。 一…...
transformer初探
transformer初探 self-attentionmultihead-attentionencoderdecoder self-attention 其实就是三个矩阵, W q W_q Wq、 W k W_k Wk、 W v W_v Wv,这三个矩阵就是需要训练的参数。分别得到每个token对应的 q q q k k k v v v,其中 q …...
JUC并发编程基础(包含线程概念,状态等具体实现)
一.JUC并发编程基础 1. 并行与并发 1.1 并发: 是在同一实体上的多个事件是在一台处理器上"同时处理多个任务"同一时刻,其实是只有一个事件在发生. 即多个线程抢占同一个资源. 1.2 并行 是在不同实体上的多个事件是在多台处理器上同时处理多个任务同一时刻,大家…...
集中管理和分析日志:使用 ELK 套件构建强大的日志管理平台
集中管理和分析日志:使用 ELK 套件构建强大的日志管理平台 日志是监控和调试应用程序和系统的重要工具。集中管理和分析日志可以帮助你快速定位问题、了解系统运行状况和性能,并提高你的日志管理效率。ELK 是一个流行的日志管理解决方案,由 …...
深度学习 - 模型的保存与部署方式汇总
深度学习模型保存和加载格式科普 在深度学习中,模型的保存和加载是非常重要的环节。不同的格式有不同的特点和适用场景。本文将为新手朋友们介绍几种常见的模型格式,包括它们的简介、保存方式、加载方式、优缺点以及应用场景。 1. PyTorch (.pth, .pt)…...
人工智能对网络安全有何影响?
人工智能网络安全在短期、中期和长期如何变化 当今数字时代网络安全的重要性 在谈论人工智能在网络安全中的作用时,必须首先考虑短期影响,因为它们是最明显的,而且它是一个未知的领域,需要超越直接炒作的能力。 因此࿰…...
Oracle的RECYCLEBIN回收站:轻松恢复误删对象
目录 Oracle的RECYCLEBIN回收站:轻松恢复误删对象一、概念二、工作原理三、使用方法1 查看回收站中的对象2 恢复回收站中的对象2.1 恢复表(TABLE)2.2 恢复索引(INDEX)2.3 恢复视图(VIEW)2.4 恢复…...
Android 内存原理详解以及优化(二)
上一篇讲了内存原理,如果还没看可以先看上一篇:Android 内存原理详解以及优化(一) 这一篇我总结一下我们经常遇到的内存优化问题: 1.内存抖动 自定义view的ondraw是会被频繁调用的,那在这个方法里面就不能频…...
Shell学习——Shell变量
文章目录 Shell变量使用变量只读变量删除变量变量类型字符串变量: 在 Shell中,变量通常被视为字符串。整数变量: 在一些Shell中,你可以使用 declare 或 typeset 命令来声明整数变量。数组变量: Shell 也支持数组&#…...
Java中的持续集成与持续部署(CI/CD)
Java中的持续集成与持续部署(CI/CD) 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将深入探讨Java中的持续集成(Co…...
极狐GitLab 将亮相2024空天信息大会暨数字地球生态峰会,携手中科星图赋能空天行业开发者
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab :https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署…...
Beats:使用 Filebeat 从 Python 应用程序中提取日志
本指南演示了如何从 Python 应用程序中提取日志并将其安全地传送到 Elasticsearch Service 部署中。你将设置 Filebeat 来监控具有标准 Elastic Common Schema (ECS) 格式字段的 JSON 结构日志文件,然后你将在 Kibana 中查看日志事件发生的实时可视化。虽然此示例使…...
51单片机第23步_定时器1工作在模式0(13位定时器)
重点学习51单片机定时器1工作在模式0的应用。 在51单片机中,定时器1工作在模式0,它和定时器0一样,TL1占低5位,TH1占高8位,合计13位,也是向上计数。 1、定时器1工作在模式0 1)、定时器1工作在模式0的框图…...
linux的服务管理
systemd systemd 是一个系统和服务管理器,用于Linux操作系统中,旨在替代传统的Unix系统V初始化系统(SysV init)。 不一定所有使用 yum 安装的软件都可以通过 systemctl start 来管理。能否通过 systemctl start 管理取决于软件包…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
