C++实现汉诺塔游戏用户交互

news2025/7/23 16:29:29

目录

  • 一、模型调整
    • (一)模型定义
    • (二)模型实现
      • 1.电脑自动完成部分
      • 2.SDL图形显示
        • 2.1拿起放下盘子的函数
        • 2.2左右移动手指的函数
  • 二、处理用户输入,进行人机分流
  • 三、总结
  • 四、源码下载

上篇文章使用C++语言实现汉诺塔游戏电脑自动完成的步骤,还没有实现用户交互,无多少可玩性,本篇继续探索,加入方向键交互功能。

在这里插入图片描述

一、模型调整

(一)模型定义

这里更新的知识点包括:类的静态变量、类的构造函数。

//汉诺塔柱子,将大部分属性静态化
class Stick {
    public:
    deque<int> plates; //柱子放置盘子的栈
    int x, y; //柱子底中心位置
    static int width, height; //柱子宽、高
    static unsigned char r, g, b; //柱子颜色
    static int pside, pheight; //盘子边长、厚度
    static unsigned char pr, pg, pb; //盘子颜色

    Stick(int x, int y, int width, int height, unsigned char r, unsigned char g, unsigned char b,
    int pside, int pheight, unsigned char pr, unsigned char pg, unsigned char pb); //构造函数

    void show(SDL_Renderer*); //在指定渲染器绘制画面
};

//定义静态变量
int Stick::width; int Stick::height;
unsigned char Stick::r; unsigned char Stick::g; unsigned char Stick::b;
int Stick::pside; int Stick::pheight;
unsigned char Stick::pr; unsigned char Stick::pg = pg; unsigned char Stick::pb = pb;

//默认构造函数,柱子在左边沿位置,宽6,高300,棕色,盘子边长40、厚10、天蓝色
Stick::Stick(int x = 0, int y = 300, int width = 6, int height = 300, 
    unsigned char r = 95, unsigned char g = 60, unsigned char b = 10,
    int pside = 40, int pheight = 10, unsigned char pr = 0, unsigned char pg = 255, unsigned char pb = 255):x(x), y(y) {
        Stick::width = width; Stick::height = height;
        Stick::r = r; Stick::g = g; Stick::b = b;
        Stick::pside = pside; Stick::pheight = pheight;
        Stick::pr = pr; Stick::pg = pg; Stick::pb = pb;
    }
    
//整个汉诺塔模型,新增手指、空中盘子2个变量,新增upPlate、downPlate、leftFiger、rightFinger4个成员函数
//更新了显示函数,使用户可以设置刷新频率
class Hanoi {
     private:
    SDL_Renderer * render; // 内置窗口渲染器指针
    Finger finger; //手指
    int airPlate; //空中的盘子号
    public:
    Stick sticks[3]; //3根柱子
    Hanoi(SDL_Renderer *, int, int); //构造函数
    bool movePlate(int a, int b); //将1个盘子从a柱移到b柱
    void movePlates(int a, int b, int count); //将count个盘子从a柱移到b柱
    bool upPlate(); //从手指处拾起1个盘子
    bool downPlate(); //在手指处放下1个盘子
    void leftFinger(); //手指左移1下
    void rightFinger(); //手指右移1下
    void show(); //在窗口绘制画面
    void show(int); //在窗口以指定时间间隔绘制画面
};

//手指颜色默认未拿起时为蓝色,在第0根柱子上
Hanoi::Hanoi(SDL_Renderer *render, int n, int index=0): render(render), finger({index, 0, 0, 255}) {
    //初始化空中无盘子
    airPlate = 0;
    //初始化第0根柱子,盘子从n到1压栈
    for (int i = n; i >0; i--) {
        sticks[0].plates.push_back(i);
    }
    //明确3根柱子位置
    sticks[0].x = 200; sticks[1].x = 400, sticks[2].x = 600;
}

//手指模型
typedef struct Finger {
    int index; //柱号
    unsigned char r, g, b; //手指颜色
} Finger;

(二)模型实现

1.电脑自动完成部分

这里更新的知识点包括:移动圆盘前后SDL显示、手指状态显示

bool Hanoi::movePlate(int a, int b) {
    int plateA, plateB; //2根柱子顶端的盘子
    plateA = this->sticks[a].plates.back();
    if (!this->sticks[b].plates.empty()) {
        plateB = this->sticks[b].plates.back();
        if (plateA > plateB) return false;
    }
    //小盘子可以放在大盘子上
    this->finger.index = a;
    this->finger.r = 255; this->finger.b = 0; //让手指变红成拿起圆盘状态
    this->show();
    this->sticks[a].plates.pop_back();
    this->sticks[b].plates.push_back(plateA);
    this->finger.index = b;
    this->finger.r = 0; this->finger.b = 255; //让手指变蓝成旆圆盘状态
    this->show(); //显示
    return true;
}

2.SDL图形显示

这里更新的知识点包括:SDL事件捕获与响应

SDL_Event event;
while(true) {
    SDL_PollEvent(&event); //等待事件
// cout << event.type << " " << flush;
    if (event.type == SDL_QUIT) { // 退出
        break;
    } else if (event.type == SDL_KEYDOWN) { // 按键
        //防抖
        while(true) {
            SDL_PollEvent(&event); //等待事件
            if ((event.type == SDL_KEYUP)) break;
        }
            switch (event.key.keysym.sym) { //检测按了哪个方向键
            case SDLK_UP:
                hanoi.upPlate();
            break;
            case SDLK_DOWN:
                hanoi.downPlate();
            break;
            case SDLK_LEFT:
                hanoi.leftFinger();
            break;
            case SDLK_RIGHT:
                hanoi.rightFinger();
            break;
            }
    }
    hanoi.show(20); //20毫秒刷新一次
2.1拿起放下盘子的函数
bool Hanoi::upPlate() {
    if (this->sticks[this->finger.index].plates.empty() || this->airPlate) return false; //柱子为空或已经有空中盘子
    // 弹出圆盘
    this->airPlate = this->sticks[this->finger.index].plates.back();
    this->sticks[this->finger.index].plates.pop_back();
    // 手指变红
    this->finger.r = 255; this->finger.b = 0;
    return true;
}

bool Hanoi::downPlate() {
    //空中无圆盘或下方圆盘小都不能放
    if (this->airPlate == 0) return false; 
    if (this->sticks[this->finger.index].plates.size() > 0 && this->sticks[this->finger.index].plates.back() < this->airPlate)
        return false;
    // 压入圆盘
    this->sticks[this->finger.index].plates.push_back(this->airPlate);
    this->airPlate = 0;
    // 手指变蓝
    this->finger.r = 0; this->finger.b = 255;
    return true;
}
2.2左右移动手指的函数
void Hanoi::leftFinger() {
    this->finger.index = (this->finger.index + 2) % 3;
}

void Hanoi::rightFinger() {
    this->finger.index = (this->finger.index + 1) % 3;
}

二、处理用户输入,进行人机分流

放置在main函数中:

    int n; //汉诺塔层数
    int mode; //游戏模式
    while (true) {
        cout << "请输入汉诺塔层数:" << flush;
        cin >> n;
        cout << "选择模式:1:电脑完成,2:玩家完成" << endl;
        cin >> mode;
        if (mode != 1 && mode !=2) {
            cout << "模式错误" << endl;
        } else {
            //初始化SDL部分
            //...
            //初始化汉诺塔部分
            Hanoi hanoi(render, n);
            hanoi.show(); //修复刚启动黑屏bug
            if (mode == 1) { //电脑自动完成部分
                hanoi.movePlates(0, 2, n);
            } else { //mode == 2,用户交互部分
                //进行事件捕获与响应
                //...
            }
            //SDL销毁部分
            //...
        }
    }

三、总结

本篇文章摘记了使用C++语言实现汉诺塔游戏电脑自动完成和用户交互功能的步骤,希望大家有所收获,如有好的建议欢迎留言,谢谢大家!

四、源码下载

C++实现图形化汉诺塔游戏源代码

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

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

相关文章

谷歌地图手机版(Google maps)v11.152.0100安卓版 - 前端工具导航

谷歌地图(Google maps)是由谷歌官方推出的一款手机地图应用。软件功能强大&#xff0c;支持本地搜索查找世界各地的地址、地点和商家&#xff1b;支持在街景视图中查看世界各地的360度全景图&#xff1b;支持查找乘坐火车、公交车和地铁的路线&#xff0c;或者查找步行路线等 …

C++核心编程_关系运算符重载

4.5.5 关系运算符重载 作用&#xff1a;重载关系运算符&#xff0c;可以让两个自定义类型对象进行对比操作 /*#### 4.5.5 关系运算符重载 **作用&#xff1a;**重载关系运算符&#xff0c;可以让两个自定义类型对象进行对比操作 */class Person { public:Person(string name, …

T/CCSA 663-2025《医疗科研云平台技术要求》标准解读与深度分析

参考地址:https://www.doc88.com/p-30280431175529.html 引言 随着医疗信息化建设的深入推进,医疗行业正经历从"业务驱动"向"数据驱动"的转型。在这一背景下,中国通信标准化协会(CCSA)于2025年发布了T/CCSA 663-2025《医疗科研云平台技术要求》标准,并…

win11回收站中出现:查看回收站中是否有以下项: WPS云盘回收站

好久没更新了&#xff0c;首先祝所有大朋友、小朋友六一儿童节快乐&#xff0c;真的希望我们永远都不会长大呀&#xff0c;长大真的好累呀(•_•) 免责声明 笔者先来个免责声明吧&#xff0c;被网上的阴暗面吓到了 若读者参照笔者的这篇文章所执行的操作中途或后续出现的任何…

SCDN如何同时保障网站加速与DDoS防御?

在互联网时代&#xff0c;网站既要面对用户访问量的激增&#xff0c;又要抵御层出不穷的网络攻击&#xff0c;特别是DDoS攻击的威胁。SCDN&#xff08;安全内容分发网络&#xff09;作为融合加速与安全的解决方案&#xff0c;如何实现“加速”与“防御”的双重保障&#xff1f;…

项目前置知识——不定参以及设计模式

1.C语言不定参宏函数 c语言中&#xff0c;printf就是一个不定参函数&#xff0c;在使用不定参宏函数时&#xff0c;我们使用__VA_ARGS__来解析不定参&#xff1a; #include <iostream> #include <cstdarg>#define LOG(fmt/*格式*/, .../*用...表示不定参*/) prin…

04powerbi-度量值-筛选引擎CALCULATE()

1、calculate calculate 的参数分两部分&#xff0c;分别是计算器和筛选器 2、多条件calculater与表筛选 多条件有不列的多条件 相同列的多条件 3、calculatertable &#xff08;表&#xff0c;筛选条件&#xff09;表筛选 与calculate用法一样&#xff0c;可以用创建表&…

chromedriver 下载失败

问题描述 chromedriver 2.46.0 下载失败 淘宝https://registry.npmmirror.com/chromedriver/2.46/chromedriver_win32.zip无法下载 解决方法 找到可下载源 https://cdn.npmmirror.com/binaries/chromedriver/2.46/chromedriver_win32.zip &#xff0c;先将其下载到本地目录(D…

Weather app using Django - Python

我们的任务是使用 Django 创建一个 Weather 应用程序&#xff0c;让用户可以输入城市名称并查看当前天气详细信息&#xff0c;例如温度、湿度和压力。我们将通过设置一个 Django 项目&#xff0c;创建一个视图来从 OpenWeatherMap API 获取数据&#xff0c;并设计一个简单的模板…

机器视觉2,硬件选型

机器视觉1&#xff0c;学习了硬件的基本知识和选型&#xff0c;现在另外的教材巩固知识 选相机 工业相机选型的保姆级教程_哔哩哔哩_bilibili 1.先看精度多少mm&#xff0c;被检测物体长宽多少mm》分辨率&#xff0c; 选出合理范围内的相机 2.靶面尺寸&#xff0c;得出分…

电阻电容的选型

一、电阻选型 1.1安装方式 贴片电阻体积小&#xff0c;适用于SMT生产&#xff1b;功率小&#xff1b;易拆解插件电阻体积大&#xff1b;功率大&#xff1b;不易脱落 1.2阻值 电阻的阻值是离散的&#xff0c;其标称阻值根据精度分为E6、E12、E24、E48、E96、E192六大系列&am…

12.springCloud AlibabaSentinel实现熔断与限流

目录 一、Sentinel简介 1.官网 2.Sentinel 是什么 3.Sentinel 的历史 4.Sentinel 基本概念 资源 规则 5.Sentinel 功能和设计理念 (1).流量控制 什么是流量控制 流量控制设计理念 (2).断降级 什么是熔断降级 熔断降级设计理念 (3).系统自适应保护 6.主要工作机制…

vSOME/IP与ETAS DSOME/IP通信的问题解决方案

✅ 一、服务版本不匹配导致 Handover 问题 —— 需要更新 VSOMEIP 代码逻辑 📌 问题描述: 在 SOME/IP 通信中,发布者(offer)与订阅者(subscribe)之间存在服务版本不一致的问题,导致 Handover(切换)失败。 ✅ 解决方案: 需要在 offer_service 和 subscribe 接口中…

软考-系统架构设计师-第十五章 信息系统架构设计理论与实践

信息系统架构设计理论与实践 15.2 信息系统架构风格和分类15.3 信息系统常用的架构模型15.4 企业信息系统总体框架15.5 信息系统架构设计方法 15.2 信息系统架构风格和分类 信息系统架构风格 数据流体系结构风格&#xff1a;批处理、管道-过滤器调用/返回体系结构风格&#x…

MySQL 8 完整安装指南(Ubuntu 22.04)

MySQL 8 完整安装指南&#xff08;Ubuntu 22.04&#xff09; 本教程详细说明如何在 Ubuntu 22.04 上安装和配置 MySQL 8&#xff0c;包含安全优化及远程访问设置。 1️⃣ 添加 MySQL 官方 APT 仓库 官网仓库下载地址&#xff1a;MySQL APT 仓库下载页 下载仓库配置包&#…

安卓jetpack compose学习笔记-UI基础学习

哲学知识应该用哲学的方式学习&#xff0c;技术知识也应该用技术的方式学习。没必要用哲学的态度来学习技术。 学完安卓技术能做事就ok了&#xff0c;安卓技术肯定是有哲学的&#xff0c;但是在初学阶段没必要讨论什么安卓哲学。 学习一们复杂技术的路径有很多&#xff0c;这里…

蓝桥杯_DS18B20温度传感器---新手入门级别超级详细解析

目录 一、引言 DS18B20的原理图 单总线简介&#xff1a; ​编辑暂存器简介&#xff1a; DS18B20的温度转换与读取流程 二、代码配置 maic文件 疑问 关于不同格式化输出符号的使用 为什么要rd_temperature()/16.0&#xff1f; onewire.h文件 这个配置为什么要先读lo…

C++中锁与原子操作的区别及取舍策略

文章目录 锁与原子操作的基本概念锁&#xff08;Lock&#xff09;原子操作&#xff08;Atomic Operations&#xff09; 锁与原子操作的区别1. **功能**2. **性能**3. **复杂性**4. **适用场景** 锁与原子操作的取舍策略1. **简单变量操作**2. **复杂共享资源**3. **性能敏感场景…

C++语法系列之类型转换

前言 类型转换是经常存在的情况&#xff0c;类型转换分为隐式类型转化 和 显式类型转化 隐式类型转化&#xff1a;编译器在编译阶段自动进行&#xff0c;能转就转&#xff0c;不能转就编译失败 double i 3.3; int b i; //隐式类型转化 double -> intC搞出来了四种强制类…

详解开漏输出和推挽输出

开漏输出和推挽输出 以上是 GPIO 配置为输出时的内部示意图&#xff0c;我们要关注的其实就是这两个 MOS 管的开关状态&#xff0c;可以组合出四种状态&#xff1a; 两个 MOS 管都关闭时&#xff0c;输出处于一个浮空状态&#xff0c;此时他对其他点的电阻是无穷大的&#xff…