当前位置: 首页 > 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 管理取决于软件包…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...