用c++实现五子棋小游戏

五子棋是一款经典小游戏,今天我们就用c++实现简单的五子棋小游戏

目录

用到的算法:

思路分析

定义变量 

开始写代码

 

完整代码 

结果图:


用到的算法:

  1. 合法移动的判断:isValidMove 函数通过检查指定位置是否在棋盘范围内,并且该位置是否为空位来确定是否为合法的移动。

  2. 获胜条件的检查:checkWin 函数通过遍历四个方向(水平、垂直、两个对角线)来检查是否存在连续的五个相同类型的棋子。它使用两个 while 循环,一个向一个方向移动,另一个向相反方向移动,以统计横向、纵向和对角线上相同类型棋子的数量。

  3. 棋盘状态的打印:printBoard 函数使用嵌套的 for 循环来遍历棋盘的每个位置,并输出相应的符号来表示该位置的状态。

  4. 棋盘是否已满的检查:isBoardFull 函数使用嵌套的 for 循环来遍历棋盘的每个位置,检查是否存在空位。如果不存在空位,则棋盘已满

思路分析

  1. 初始化:创建一个空的棋盘,大小为15x15,用二维向量表示。初始时所有位置都是空位。

  2. 循环游戏:进入一个无限循环,在每一轮中依次执行以下步骤:

    • 打印当前棋盘状态;
    • 根据当前轮到的玩家,提示玩家输入下子位置;
    • 检查输入的下子位置是否合法,即在棋盘范围内且为空位,如果不合法则提示重新输入;
    • 在棋盘上下子,并判断是否获胜或棋盘已满;
    • 如果获胜或棋盘已满,根据情况打印相应的信息,并结束游戏。
  3. 判断获胜和棋盘是否已满:

    • 每次下子后,调用 checkWin 函数来检查当前位置是否连成五子,如果是则返回获胜;
    • 如果没有获胜,则调用 isBoardFull 函数来判断棋盘是否已满,如果棋盘已满则返回平局。
  4. 输出棋盘状态:

    • printBoard 函数使用嵌套的 for 循环遍历棋盘的每个位置,根据该位置的状态输出相应的符号,用于展示当前棋盘状态

定义变量 

  • BOARD_SIZE 定义了棋盘的大小,这里设置为15x15。
  • EMPTYBLACK 和 WHITE 定义了棋盘上的三种状态:空位、黑棋和白棋。
  • board 是一个二维向量,表示棋盘,初始时所有位置都是空位。
  • isValidMove 函数用于判断某个位置是否可以下子。合法的位置必须在棋盘范围内,并且为空位。
  • checkWin 函数用于判断某个位置下子后是否获胜。它检查当前位置在四个方向上(水平、垂直、两个对角线)是否有连续的连续的五个相同类型棋子。如果有则返回 true,否则返回 false。
  • printBoard 函数用于打印当前棋盘的状态。
  • isBoardFull 函数用于判断棋盘是否已经满了(即没有空位),如果棋盘已满,则返回 true,否则返回 false。
  • main 函数是程序的入口。它使用一个无限循环,每次循环轮流让玩家下子,然后判断是否游戏结束。如果有一方获胜或者棋盘已满,则打印相应的信息,并结束游戏。

开始写代码

void printBoard() {for (int i = 0; i < BOARD_SIZE; i++) {for (int j = 0; j < BOARD_SIZE; j++) {cout << board[i][j] << " ";}cout << endl;}cout << endl;
}

 

这段代码为打印棋盘状态的函数printBoard(),使用了嵌套的循环来遍历棋盘,并输出每个位置的状态。

具体的实现逻辑如下:

  1. 外层循环for (int i = 0; i < BOARD_SIZE; i++)遍历棋盘的行数,从第一行开始到最后一行。
  2. 内层循环for (int j = 0; j < BOARD_SIZE; j++)遍历棋盘的列数,从第一列开始到最后一列。
  3. 在内层循环中,通过board[i][j]获取当前位置的状态值,并使用cout输出该状态值。
  4. 输出一个空格,以分隔不同位置的状态值。
  5. 内层循环结束后,通过cout << endl;输出换行符,以换行显示下一行的棋盘状态。
  6. 外层循环结束后,通过cout << endl;再次输出一个换行符,以在棋盘状态的输出之间添加空行。

这样,调用printBoard()函数可以按照指定格式输出当前棋盘的状态。每个位置上的状态值可以是空格、X或O等字符,表示空位、玩家1和玩家2的棋子。通过这个函数,可以直观地展示游戏棋盘的状态给玩家。

bool isValidMove(int row, int col) {return (row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE && board[row][col] == EMPTY);
}

 

这段代码是用于判断玩家落子是否合法的函数isValidMove(row, col),其中rowcol分别表示玩家输入的坐标值。

具体的实现逻辑如下:

  1. 首先,通过row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE判断玩家输入的坐标值是否在棋盘范围内。如果超出了棋盘范围,则此次落子不合法。
  2. 否则,通过board[row][col] == EMPTY判断该位置是否已有棋子(即状态值是否为EMPTY)。如果该位置上没有棋子,则此次落子合法,返回true
  3. 如果该位置上已经有棋子,则此次落子不合法,返回false

通过这个函数,可以快速判断玩家输入的坐标是否合法。如果不合法,则需要提示玩家重新输入坐标;如果合法,则可以继续进行游戏。

 


bool checkWin(int row, int col, char player) {int directions[4][2] = {{1, 0}, {0, 1}, {1, 1}, {-1, 1}};for (int i = 0; i < 4; i++) {int count = 1;int dx = directions[i][0], dy = directions[i][1];int r = row + dx, c = col + dy;while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE && board[r][c] == player) {count++;r += dx;c += dy;}dx = -dx, dy = -dy;r = row + dx, c = col + dy;while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE && board[r][c] == player) {count++;r += dx;c += dy;}if (count >= 5)return true;}return false;
}

 

这段代码是用于检查玩家是否取得胜利的函数checkWin(row, col, player),其中rowcol表示最后一次落子的坐标,player表示当前玩家的符号。

具体的实现逻辑如下:

  1. 首先,定义一个二维数组directions[4][2]来表示四个方向,分别为向下、向右、右下、左下。每个方向由两个元素组成,分别表示在行方向和列方向上的增量。
  2. 使用一个循环遍历四个方向。
  3. 在循环内部,初始化一个计数器count为1,表示已经有一颗当前玩家的棋子。
  4. 根据当前方向的增量(dx, dy),计算下一个检查的位置(r, c),并检查该位置是否在棋盘范围内且值等于当前玩家的符号。
  5. 如果满足条件,将计数器count加1,并更新下一个位置(r, c)为当前位置加上增量(dx, dy)
  6. 重复步骤4和步骤5,直到碰到越界或者不是当前玩家的棋子。
  7. 然后,将增量(dx, dy)取相反数,即改变方向。
  8. 再次计算下一个检查的位置(r, c),并检查该位置是否在棋盘范围内且值等于当前玩家的符号。
  9. 如果满足条件,将计数器count加1,并更新下一个位置(r, c)为当前位置加上增量(dx, dy)
  10. 重复步骤8和步骤9,直到碰到越界或者不是当前玩家的棋子。
  11. 检查计数器count是否大于等于5,如果是,则表示当前玩家在其中一个方向上取得了胜利,返回true
  12. 如果四个方向都遍历完毕,仍未满足取胜条件,则返回false

通过这个函数,可以判断当前玩家是否在最后一次落子后取得了胜利。根据游戏规则,只有当任意一方在横、竖、斜对角线方向上连续五个棋子时才算获胜。

完整代码 

#include <iostream>
#include <vector>using namespace std;const int BOARD_SIZE = 15;
const char EMPTY = '-';
const char BLACK = 'X';
const char WHITE = 'O';vector<vector<char> > board(BOARD_SIZE, vector<char>(BOARD_SIZE, EMPTY));bool isValidMove(int row, int col) {return (row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE && board[row][col] == EMPTY);
}bool checkWin(int row, int col, char player) {int directions[4][2] = {{1, 0}, {0, 1}, {1, 1}, {-1, 1}};for (int i = 0; i < 4; i++) {int count = 1;int dx = directions[i][0], dy = directions[i][1];int r = row + dx, c = col + dy;while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE && board[r][c] == player) {count++;r += dx;c += dy;}dx = -dx, dy = -dy;r = row + dx, c = col + dy;while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE && board[r][c] == player) {count++;r += dx;c += dy;}if (count >= 5)return true;}return false;
}void printBoard() {for (int i = 0; i < BOARD_SIZE; i++) {for (int j = 0; j < BOARD_SIZE; j++) {cout << board[i][j] << " ";}cout << endl;}cout << endl;
}bool isBoardFull() {for (int i = 0; i < BOARD_SIZE; i++) {for (int j = 0; j < BOARD_SIZE; j++) {if (board[i][j] == EMPTY)return false;}}return true;
}int main() {int row, col;char currentPlayer = BLACK;while (true) {printBoard();cout << "Player " << currentPlayer << ", enter your move (row col): ";cin >> row >> col;if (!isValidMove(row, col)) {cout << "Invalid move! Try again." << endl;continue;}board[row][col] = currentPlayer;if (checkWin(row, col, currentPlayer)) {cout << "Player " << currentPlayer << " wins!" << endl;break;} else if (isBoardFull()) {cout << "It's a draw!" << endl;break;}currentPlayer = (currentPlayer == BLACK) ? WHITE : BLACK;}printBoard();return 0;
}

 

在这个五子棋游戏代码中,可以通过以下方式进行输入和输出:

输入:

  1. 玩家输入下子位置:可以通过命令行提示玩家输入坐标,例如,要求玩家输入行和列的数字,表示下子位置的坐标。
  2. 其他玩家操作:例如,要求玩家输入指令来选择重新开始游戏或退出游戏。

输出:

  1. 打印当前棋盘状态:使用嵌套的循环遍历棋盘,根据棋盘上每个位置的状态输出相应的符号,可以使用空格、X和O等字符来表示空位、玩家1和玩家2的棋子。
  2. 提示玩家操作:例如,提示玩家输入坐标来下子,或者提示玩家输入指令以进行其他操作。
  3. 游戏结果输出:当游戏结束时,根据游戏结果输出胜利者或者平局信息。
  4. 错误提示:如果玩家输入了无效的指令或下子位置,可以输出错误提示信息,要求玩家重新输入。

在代码中,可以使用适当的输入函数,如input()来接收玩家输入,并使用适当的输出函数,如print()来输出信息到控制台。通过合理地组织输入和输出,可以实现与玩家的有效交互,并提供友好的游戏体验。

结果图:

如果想要更加华丽美观的代码,关注博主赞赏2元回复“五子棋华丽代码”即可。

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

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

相关文章

基于matlab实现的 BPSK调制AWGN通道未编码数据误码率程序

完整程序&#xff1a; clear; close all; clc; c0; rate1; %Code rate N10000000; %Number of bits for EbNoc0:1:10 %Ratio of bit energy to no…

Stream流处理快速上手最佳实践 | 京东物流技术团队

一 引言 JAVA1.8得益于Lambda所带来的函数式编程&#xff0c;引入了一个全新的Stream流概念Stream流式思想类似于工厂车间的“生产流水线”&#xff0c;Stream流不是一种数据结构&#xff0c;不保存数据&#xff0c;而是对数据进行加工处理。Stream可以看作是流水线上的一个工…

【基础篇】ClickHouse 表引擎详解

文章目录 0. 引言1. 什么是表引擎2. 不同表引擎使用场景1. MergeTree:2. Log:3. Memory:4. Distributed:5. Kafka:6. MaterializedView:7. File和URL: 3. MergeTree 家族3.1. MergeTree:3.2. ReplacingMergeTree:3.3. SummingMergeTree:3.4. AggregatingMergeTree:3.5. Collaps…

【AI】机器学习——感知机

文章目录 4.1 感知机基本概念4.2 策略4.2.1 数据集的线性可分性4.2.2 学习策略目标损失函数的构造关于距离的解释 4.3 算法4.3.1 原始形式损失函数的梯度下降法 4.3.2 PLA例题4.3.3 算法收敛性 4.4 PLA对偶形式4.4.1 原始PLA分析4.4.2 PLA对偶形式4.4.3 优点 4.1 感知机基本概念…

office mac苹果办公软件安装包安装教程详解

软件下载 软件&#xff1a;mac office版本&#xff1a;2021语言&#xff1a;简体中文大小&#xff1a;4.27G安装环境&#xff1a;mac硬件要求&#xff1a;CPU2.0GHz 内存4G(或更高&#xff09;下载通道 百度网盘 https://pan.baidu.com/s/1WGSB-icELUxweFkI8iIbzA 首先&#…

什么是JavaScript的事件驱动编程(event-driven programming)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 事件&#xff08;Event&#xff09;⭐ 事件监听器&#xff08;Event Listener&#xff09;⭐ 回调函数&#xff08;Callback Function&#xff09;⭐ 非阻塞和异步⭐ 事件循环&#xff08;Event Loop&#xff09;⭐ 触发事件&#xff08;…

知识竞赛活动舞台搭建需要多少钱

知识竞赛活动舞台搭建的费用会根据不同的竞赛活动规模和要求而有所不同。对于小型的知识竞赛活动&#xff0c;如学校内部组织的知识竞赛或社区的知识竞赛活动&#xff0c;舞台搭建的费用往往相对较低。在这种情况下&#xff0c;可能只需要一些简单的装饰和道具&#xff0c;例如…

【C++进阶】:哈希(一)

哈希 一.unordered_map二.底层结构1.哈希概念2.解决哈希冲突1.闭散列2.开散列 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可达到 l o g 2 N log_2N log2​N&#xff0c;即最差情况下需要比较红黑树的高度次&#xff0c;当树中的…

Linux:基础开发工具之yum,vim,gcc的使用

文章目录 yumvimgcc 本篇主要总结的是Linux下开发工具 yumvimgcc/g yum 什么是yum&#xff1f; 不管是在手机移动端还是pc端&#xff0c;不管是什么操作系统&#xff0c;当用户想要下载一些内容或者工具的时候&#xff0c;都需要到一个特定的位置进行下载&#xff0c;例如在…

初识Java 9-2 内部类

目录 为什么需要内部类 闭包和回调 内部类和控制框架 继承内部类 内部类的重写&#xff08;并不能&#xff09; 局部内部类 内部类标识符 本笔记参考自&#xff1a; 《On Java 中文版》 为什么需要内部类 在一些情况下&#xff0c;我们无法享受接口带来的便利&#xff0…

c刷题(四)

目录 获得月份天数 判断字母 字母大小写转换 网购 下列程序段的输出结果 字符逆序 自幂数 a的前n项之和 最小公倍数 倒置字符串 获得月份天数 获得月份天数_牛客题霸_牛客网 这道题可以用switch case语句解&#xff0c;不过这道题更简单的方法是数组&#xff0c;关…

AE-如何制作湖面水波纹波动的效果

目录 1.新建水面合成 2.新建纯色层命名为“分形杂色”&#xff0c;并添加“分形杂色”效果&#xff0c;设置相关参数 3.添加3D效果&#xff0c;并添加摄像机和空对象 4.新建中秋节合成&#xff0c;导入背景图&#xff0c;新建调整图层&#xff0c;并在调整图层上增加“焦散…

【C++】动态内存管理(79分钟写的文章哪里看不懂了,快来学)

动态内存管理目录&#xff1a; 一、C/C内存分布 在学习了C/C内存区域的划分后&#xff0c;我们来做几道题巩固一下&#xff1a; 1. 选择题&#xff1a;选项 : A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)globalVar在哪里&#xff1f;____ staticGlobalVar在哪里&#x…

一个Binder的前生今世 (一):Service的创建

一个Binder的前生今世 (一):Service的创建 一个Binder的前生今世Binder的历史 (字面意义的前生今世)Binder的生命周期(抽象意义的前生今世)Binder 应用及系统层关系图Binder应用层的架构设计Binder应用层实现Binder的创建服务端Binder的创建服务端Binder的传递Binder在客…

实现按钮悬停动画

知识点与技巧 伪元素 使用伪元素来作为按钮悬停效果动画展示的元素 z-index 的使用技巧 使用z-index属性来控制按钮和伪元素的层次关系 transform、transition 复习 使用transform、transition两个属性来实现动画的展示 按钮边框动画 切换效果 核心代码 .btn.btn-border-…

2023面试知识点一

1、新生代和老年代的比例 默认的&#xff0c;新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 )&#xff0c;即&#xff1a;新生代 ( Young ) 1/3 的堆空间大小。老年代 ( Old ) 2/3 的堆空间大小。其中&#xff0c;新生代 ( …

Unity减少发布打包文件的体积——获取精灵图片的信息限制它的大小

一、起因 一个工程&#xff0c;打包成webGL且压缩成zip文件后&#xff0c;接近400M&#xff0c;后来把大的精灵图片设置最大尺寸&#xff0c;降低大小后&#xff0c;再次发布&#xff0c;zip文件缩减到250M 二、如何一键获得工程里面的精灵图片信息 三、获取精灵图片信息 1、…

esp32-S3-electric-vehicle-expansion(EVE_V2)硬件分享

一. 简介 本次将给大家分享一个QSPI圆形屏幕DIY的小项目&#xff0c;这是我做的第二个版本的&#xff0c;相较于第一个版本有了比较大的改动(第一版就不放出来了&#xff0c;需要的可以私聊)&#xff0c;可以在上面实现更多的功能&#xff0c;做些更有趣的项目 &#xff0c;也…

[libc-2.31 off_by_null] N0wayBack ezheap练习

以前保留了个WP&#xff0c;但是没复现过也没法用&#xff0c;用了两个晚上慢慢理复现一下。 先看这个题 while ( 1 ){menu();__isoc99_scanf("%d", &v3);switch ( v3 ){case 1:m1add(); //带readbreak;case 2:m2free();break;case 3:m3edit(); //溢出br…

视频监控系统/安防监控/视频AI智能分析:小动物识别算法场景汇总

随着人们对生态环境的关注日益提升&#xff0c;大家对动物保护意识也逐渐增强。旭帆科技智能分析网关小动物识别算法应运而生。除了对保护动物的识别以外&#xff0c;旭帆科技AI智能分析网关还可以识别常见的老鼠等动物&#xff0c;助力明厨亮灶监管&#xff0c;保卫食品安全。…