【C++】 C++游戏设计---五子棋小游戏

1. 游戏介绍

一个简单的 C++ 五子棋小游戏

1.1 游戏规则:
  • 双人轮流输入下入点坐标
  • 横竖撇捺先成五子连线者胜
  • 同一坐标点不允许重复输入
1.2 初始化与游戏界面

在这里插入图片描述

2. 源代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <limits>using namespace std;const int BOARD_SIZE = 15;
char board[BOARD_SIZE][BOARD_SIZE];void initBoard() {for (int i = 0; i < BOARD_SIZE; ++i) {for (int j = 0; j < BOARD_SIZE; ++j) {board[i][j] = '.';}}
}void printBoard() {for (int i = 0; i < BOARD_SIZE; ++i) {for (int j = 0; j < BOARD_SIZE; ++j) {cout << board[i][j] << " ";}cout << endl;}
}bool isBoardFull() {for (int i = 0; i < BOARD_SIZE; ++i) {for (int j = 0; j < BOARD_SIZE; ++j) {if (board[i][j] == '.') {return false;}}}return true;
}bool checkWin(int x, int y, char player) {int count;// 横向检查count = 0;for (int i = max(0, x - 4); i <= x; ++i) {if (board[y][i] == player) {count++;} else {count = 0;}}for (int i = x + 1; i < min(BOARD_SIZE, x + 5); ++i) {if (board[y][i] == player) {count++;} else {break;}}if (count >= 5) return true;// 纵向检查count = 0;for (int i = max(0, y - 4); i <= y; ++i) {if (board[i][x] == player) {count++;} else {count = 0;}}for (int i = y + 1; i < min(BOARD_SIZE, y + 5); ++i) {if (board[i][x] == player) {count++;} else {break;}}if (count >= 5) return true;// 斜向(从左上到右下)检查count = 0;for (int i = max(-4, -x); i <= 0; ++i) {if (x + i >= 0 && x + i < BOARD_SIZE && y + i >= 0 && y + i < BOARD_SIZE && board[y + i][x + i] == player) {count++;} else {count = 0;}}for (int i = 1; i <= min(4, BOARD_SIZE - 1 - x); ++i) {if (x + i >= 0 && x + i < BOARD_SIZE && y + i >= 0 && y + i < BOARD_SIZE && board[y + i][x + i] == player) {count++;} else {break;}}if (count >= 5) return true;// 斜向(从右上到左下)检查count = 0;for (int i = max(-4, -x); i <= 0; ++i) {if (x + i >= 0 && x + i < BOARD_SIZE && y - i >= 0 && y - i < BOARD_SIZE && board[y - i][x + i] == player) {count++;} else {count = 0;}}for (int i = 1; i <= min(4, BOARD_SIZE - 1 - x); ++i) {if (x + i >= 0 && x + i < BOARD_SIZE && y - i >= 0 && y - i < BOARD_SIZE && board[y - i][x + i] == player) {count++;} else {break;}}if (count >= 5) return true;return false;
}int main() {initBoard();bool isPlayerX = true;bool gameOver = false;while (!gameOver) {printBoard();int x, y;cout << (isPlayerX ? "Player X" : "Player O") << ", enter your move (row column): ";cin >> y >> x;if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE || board[y][x] != '.') {cout << "Invalid move. Try again." << endl;continue;}board[y][x] = isPlayerX ? 'X' : 'O';if (checkWin(x, y, board[y][x])) {printBoard();cout << (isPlayerX ? "Player X wins!" : "Player O wins!") << endl;gameOver = true;} else if (isBoardFull()) {printBoard();cout << "It's a draw!" << endl;gameOver = true;} else {isPlayerX = !isPlayerX;}}return 0;
}

3. 主要代码释解

这段代码是一个简单的五子棋游戏的实现,下面是对主要函数和异常错误处理机制的详解:

  1. initBoard()
    • 功能:初始化棋盘,将所有位置设置为’.',表示空白。
    • 实现:通过双重循环遍历二维数组board,并将每个元素设置为’.'。
  2. printBoard()
    • 功能:打印当前棋盘的状态。
    • 实现:通过双重循环遍历二维数组board,并打印每个元素。
  3. isBoardFull()
    • 功能:检查棋盘是否已满。
    • 实现:通过双重循环遍历二维数组board,如果所有位置都不是’.',则返回true,表示棋盘已满。
  4. checkWin(int x, int y, char player)
    • 功能:检查给定玩家是否在(x, y)位置获胜。
    • 实现:检查横向、纵向、两个对角线方向是否有连续的 5 个相同的棋子。如果找到,则返回true,表示该玩家获胜。
  5. main()
    • 功能:游戏的主循环,处理玩家的输入,更新棋盘状态,并判断游戏是否结束。
    • 实现
      • 初始化棋盘。
      • 在一个循环中交替让两个玩家输入他们的移动。
      • 检查移动是否有效(即在棋盘范围内且位置为空)。
      • 更新棋盘,并检查是否有玩家获胜或棋盘已满。

4. 异常和错误处理机制

  1. 输入有效性检查
    • main()函数中,玩家输入移动后,代码检查移动是否在棋盘范围内,以及对应位置是否为空。
    • 如果移动无效(即xy超出范围,或者对应位置不是’.'),则打印错误消息,并通过continue跳过当前循环的剩余部分,提示玩家重新输入。
  2. 棋盘满时结束游戏
    • 在玩家每次移动后,调用isBoardFull()检查棋盘是否已满。
    • 如果棋盘已满,则打印平局消息,并通过设置gameOvertrue结束游戏。
  3. 检查获胜条件
    • 在玩家每次移动后,调用checkWin()检查该玩家是否获胜。
    • 如果玩家获胜,则打印获胜消息,并通过设置gameOvertrue结束游戏。

5. 可改进点

  • 异常处理:代码中没有使用 C++ 的异常处理机制,例如try-catch块。在某些情况下,如果输入不是整数,cin会进入错误状态,这可能导致无限循环。可以通过检查cin的状态并清除错误标志来处理这种情况。
  • 边界条件检查:在checkWin()函数中,对斜向检查的边界条件处理可以进一步优化,以避免不必要的条件判断。
  • 代码重用checkWin()函数中的横向、纵向和斜向检查有大量重复代码,可以通过提取重复代码到单独的函数中来简化。

这个游戏实现简单,但包含了基本的游戏逻辑和错误处理机制,适合作为学习C++和游戏编程的入门项目。



6. 追更

  • 6.1 优化了判胜代码
// 检查给定玩家是否在(x, y)位置沿一个方向获胜
bool checkDirection(int x, int y, int dx, int dy, char player) {int count = 0;for (int i = 0; i < 5; ++i) {int checkX = x + i * dx;int checkY = y + i * dy;if (checkX >= 0 && checkX < BOARD_SIZE && checkY >= 0 && checkY < BOARD_SIZE && board[checkY][checkX] == player) {count++;} else {break;}}return count == 5;
}// 检查给定玩家是否在(x, y)位置获胜
bool checkWin(int x, int y, char player) {// 检查水平方向if (checkDirection(x, y, 1, 0, player) || checkDirection(x, y, -1, 0, player)) {return true;}// 检查垂直方向if (checkDirection(x, y, 0, 1, player) || checkDirection(x, y, 0, -1, player)) {return true;}// 检查两个斜线方向if (checkDirection(x, y, 1, 1, player) || checkDirection(x, y, -1, -1, player)) {return true;}if (checkDirection(x, y, 1, -1, player) || checkDirection(x, y, -1, 1, player)) {return true;}return false;
}
6.2 完整代码
  • 优化了判胜代码并增加了try-catch块捕获异常,仅供参考
#include <iostream>
#include <vector>
#include <limits>using namespace std;const int BOARD_SIZE = 15;
char board[BOARD_SIZE][BOARD_SIZE];// 初始化棋盘
void initBoard() {for (int i = 0; i < BOARD_SIZE; ++i) {for (int j = 0; j < BOARD_SIZE; ++j) {board[i][j] = '.';}}
}// 打印棋盘
void printBoard() {for (int i = 0; i < BOARD_SIZE; ++i) {for (int j = 0; j < BOARD_SIZE; ++j) {cout << board[i][j] << " ";}cout << endl;}
}// 检查棋盘是否已满
bool isBoardFull() {for (int i = 0; i < BOARD_SIZE; ++i) {for (int j = 0; j < BOARD_SIZE; ++j) {if (board[i][j] == '.') {return false;}}}return true;
}// 检查给定玩家是否在(x, y)位置沿一个方向获胜
bool checkDirection(int x, int y, int dx, int dy, char player) {int count = 0;for (int i = 0; i < 5; ++i) {int checkX = x + i * dx;int checkY = y + i * dy;if (checkX >= 0 && checkX < BOARD_SIZE && checkY >= 0 && checkY < BOARD_SIZE && board[checkY][checkX] == player) {count++;} else {break;}}return count == 5;
}// 检查给定玩家是否在(x, y)位置获胜
bool checkWin(int x, int y, char player) {// 检查水平方向if (checkDirection(x, y, 1, 0, player) || checkDirection(x, y, -1, 0, player)) {return true;}// 检查垂直方向if (checkDirection(x, y, 0, 1, player) || checkDirection(x, y, 0, -1, player)) {return true;}// 检查两个斜线方向if (checkDirection(x, y, 1, 1, player) || checkDirection(x, y, -1, -1, player)) {return true;}if (checkDirection(x, y, 1, -1, player) || checkDirection(x, y, -1, 1, player)) {return true;}return false;
}int main() {initBoard();bool isPlayerX = true;bool gameOver = false;while (!gameOver) {printBoard();int x, y;cout << (isPlayerX ? "Player X" : "Player O") << ", enter your move (row column): ";try {cin >> y >> x;if (cin.fail()) {cin.clear(); // 清除错误标志cin.ignore(numeric_limits<streamsize>::max(), '\n'); // 忽略错误输入throw runtime_error("Invalid input. Please enter numbers.");}if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE || board[y][x] != '.') {throw runtime_error("Invalid move. Try again.");}board[y][x] = isPlayerX ? 'X' : 'O';if (checkWin(x, y, board[y][x])) {printBoard();cout << (isPlayerX ? "Player X wins!" : "Player O wins!") << endl;gameOver = true;} else if (isBoardFull()) {printBoard();cout << "It's a draw!" << endl;gameOver = true;} else {isPlayerX = !isPlayerX;}} catch (const runtime_error& e) {cout << e.what() << endl;// 可以选择在这里处理错误,例如跳过当前玩家的回合// 或者让玩家重新输入,取决于你的游戏规则}}return 0;
}

在这个修改后的代码中,try-catch块被用来捕获两种异常情况:

  1. cin接收到非数字输入时,会进入错误状态。cin.fail()检查输入流是否失败,如果是,则清除错误标志,并忽略错误输入直到下一个换行符。然后抛出一个runtime_error异常。
  2. 当用户输入的坐标无效时(即不在棋盘范围内或该位置已被占用),也会抛出一个runtime_error异常。
    catch块中,我们捕获了runtime_error异常,并打印出异常信息。根据你的游戏规则,你可以选择让当前玩家重新输入,或者跳过当前玩家的回合,或者采取其他适当的错误处理措施。

在这个例子中,我们只是打印了错误信息,然后循环会继续,提示玩家重新输入。

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

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

相关文章

树-好难-疑难_GPT

// // Created by 徐昌真 on 2024/11/10. // #include <iostream> using namespace std;template<typename T> struct ListNode{ //新建链表节点T data; //指向下一个子节点 ListNode< TreeNode<T>* > childHead; 这里的 T 是TreeNde类型的…

Suricata

02-Suricata 一 ICMP流量预警 一条ICMP报文有四个重要内容&#xff0c;可与相应的ICMP关键字相匹配。它们是&#xff1a;消息的类型、代码、ID和序列。 通过ICMP的type进行匹配 alert icmp any any <> any any (msg:"icmp流量预警";itype:8;threshold:type t…

分享一些Kafka集群优化的最佳实践?

以下是一些 Kafka 集群优化的最佳实践&#xff1a; 复制策略配置&#xff1a; 在 server.properties 文件中配置 default.replication.factor 来指定每个主题的默认副本因子&#xff0c;以及 min.insync.replicas 来配置每个分区中必须要保持同步的最小副本数。这可以提高 Kafk…

web前端动画按钮(附源代码)

效果图 源代码 HTML部分 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> …

实操篇:容器服务如何启动系统?

容器服务如何启动系统&#xff1f;容器服务的启动主要依赖Docker和Kubernetes。Docker通过镜像创建和管理容器&#xff0c;支持多种重启策略以确保容器稳定运行。Kubernetes则负责自动化部署、扩展和管理容器化应用&#xff0c;其核心是Pod&#xff0c;包含一个或多个容器。用户…

conda与pip 安装软件包的 代理/换源 解决方案

方案0&#xff1a;终端set proxy set http_proxyhttp://127.0.0.1:7890 set https_proxyhttps://127.0.0.1:7890 export http_proxyhttp://127.0.0.1:7890 export https_proxyhttps://127.0.0.1:7890查看 set | grep proxy echo $https_proxy区别 使用set可以设置和查看变量…

最全Web自动化测试面试题

1、Selenium 中 hidden 或者是 display none 的元素是否可以定位到&#xff1f; 不可以。可以写 JavaScript 将标签中的 hidden 先改为 0&#xff0c;再进行定位元素。 2、Selenium 中如何保证操作元素的成功率&#xff1f;也就是说如何保证我点击的元素一 定是可以点击的&a…

PHP爬虫快速获取京东商品详情(代码示例)

在当今互联网时代&#xff0c;数据的重要性不言而喻。对于电商领域来说&#xff0c;获取商品信息是数据分析、市场研究和价格监控的基础。本文将介绍如何使用PHP编写一个简单的爬虫&#xff0c;以快速获取京东商品的详情信息。 1. 概述 京东是中国领先的电商平台之一&#xff…

一、HTML

一、基础概念 1、浏览器相关知识 这五个浏览器市场份额都非常大&#xff0c;且都有自己的内核。 什么是内核&#xff1a; 内核是浏览器的核心&#xff0c;用于处理浏览器所得到的各种资源。 例如&#xff0c;服务器发送图片、视频、音频的资源&#xff0c;浏览…

记录一次非常奇怪的MIME type of “text/html“报错

报错现象 访问指定地址&#xff0c;一直转圈打不开&#xff0c;打开游览器控制台发现有如下报错&#xff1a; Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of “text/html”. Strict MIME type checking i…

Windows10/11开启卓越性能模式 windows开启卓越性能电源模式 工作电脑开启卓越性能模式 电脑开启性能模式

Windows10/11开启卓越性能模式 windows开启卓越性能电源模式 工作电脑开启卓越性能模式 电脑开启性能模式 1、所要用到的激活工具2、开启电脑卓越性能模式Windows11Windows10在电源模式中选择卓越性能模式 3、将系统版本切换为 工作站版本 1、所要用到的激活工具 KMS激活工具(…

膜计算 MATLAB例程(仅例程,无背景)

膜计算的实现可以用 MATLAB 进行简单的模拟。以下是一个基础的膜计算模型的示例代码&#xff0c;模拟了膜内部对象的产生和转化过程。这个例子使用简单的对象和规则来演示膜计算的基本思想。 文章目录 主要概念应用领域优势与挑战代码MATLAB 膜计算示例代码代码说明运行代码总结…

Request和Response

前言 这一节主要讲的是Request和Response还有一些实例 1. 介绍 就是这两个参数 WebServlet("/demo7") public class ServletDemo7 extends HttpServlet {Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletExcepti…

Vue全栈开发旅游网项目(10)-设计用户模型

1.设计用户模型 文件地址&#xff1a;accounts/models.py 1.1 用户详细信息 内容包括&#xff1a;性别 手机号 年龄 生日 真实姓名 创建常量&#xff1a;1-男&#xff0c;0-女&#xff1b;editableFalse不许循环 class Profile(models.Model):SEX_CHOICES{(1,男),(0,女)}u…

C++初阶——vector

一、什么是vector vector是表示可变大小的数组的序列容器&#xff0c;就像数组一样&#xff0c;vector也采用连续空间来存储元素。也就是说它的访问和数组一样高效&#xff0c;但是它的大小是动态可变的&#xff0c;并且它的大小会被容器自动处理。 二、vector的构造 常用的构…

迁徙线,动态轨迹线

使用canvas结合贝塞尔曲线实现&#xff0c;效果如下 <template><div class"box"><div class"mapBox"><div class"map"><img src"/img/dataCockpit/map.png" alt"" /><div class"dot&…

SQLI LABS | Less-39 GET-Stacked Query Injection-Intiger Based

关注这个靶场的其它相关笔记&#xff1a;SQLI LABS —— 靶场笔记合集-CSDN博客 0x01&#xff1a;过关流程 输入下面的链接进入靶场&#xff08;如果你的地址和我不一样&#xff0c;按照你本地的环境来&#xff09;&#xff1a; http://localhost/sqli-labs/Less-39/ 本关是堆…

NVM 介绍及使用指南

在日常的开发工作中&#xff0c;我们往往会遇到需要在同一台机器上同时管理多个版本的 Node.js 的情况。为了解决这个问题&#xff0c;我一个同事推荐了NVM&#xff08;Node Version Manager&#xff09;。NVM 是一个用于管理 Node.js 版本的工具&#xff0c;可以方便地在不同的…

web——[SUCTF 2019]EasySQL1——堆叠注入

这个题主要是讲述了堆叠注入的用法&#xff0c;来复现一下 什么是堆叠注入 堆叠注入&#xff1a;将多条SQL语句放在一起&#xff0c;并用分号;隔开。 1.查看数据库的名称 查看数据库名称 1;show databases; 发现有名称为ctftraining的数据库 2.对表进行查询 1;show tabl…

【ARM】MDK-烧录配置文件无权限访问

【更多软件使用问题请点击亿道电子官方网站】 1、 问题场景 客户代码编译正常、调试出现报错<Error: Flash Download failed - "Cortex-M4"> 仿真器识别正常&#xff0c;keil-Debug内显示相关信息、设备启动正常。 记录排查步骤&#xff0c;找到配置文件位…