C++实现汉诺塔游戏自动完成

news2025/6/3 11:17:00

目录

  • 一、汉诺塔的规则
  • 二、数学递归推导式
  • 三、步骤实现
    • (一)汉诺塔模型
    • (二)递归实现
    • (三)显示
      • 1.命令行显示
      • 2.SDL图形显示
  • 四、处理用户输入及SDL环境配置
  • 五、总结
  • 六、源码下载

一、汉诺塔的规则

游戏由3根柱子和若干大小不一的圆盘组成,初始状态下,所有的圆盘按照大小顺序从大到小堆叠在其中一根柱子上。将所有圆盘从初始柱子移动到目标柱子上即算完成目标。但须遵守以下规则:

  1. 每次只能移动1个圆盘.
  2. 圆盘可以放置在任何1根柱子上,但不能放在比它小的圆盘上.

比如3个盘子的汉诺塔,1个可能的解法是这样的:
在这里插入图片描述

二、数学递归推导式

一个脑筋急转弯:把大象关冰箱要几步?

只要3步!1.把冰箱打开,2.把大象装进去,3.把冰箱关上。看似简单的道理,其实蕴含着数学递归思维在其中。
从a柱向b柱移动n个盘子,同样采用的是递归思维在里面,将其定义f(a,b,n),则可以有如下推导式:
f(a,b,n) = f(a,c,n-1) + f(a,b,1) + f(c,b,n-1)

解释一下:

f(a,b,n)代表从a柱向b柱移动n个盘子的过程,则先将n-1个盘子从a移到中间柱c上,再将a柱最底下的大盘子移到b柱上,最后将c柱上的n-1个盘子移到b柱上。当然只要n不为1,就一直递归下去,直到最基础的移动1个盘子。
设g(n)代表这个过程的盘子移动次数,则g(n)= 2g(n-1)+1,由此可得g(n)= 2 n 2^n 2n-1。

三、步骤实现

使用SDL库实现了图形显示,若对SDL库不了解的请阅读如下2篇引文(同时也实现了命令行显示,不了解SDL库也不影响理解):

  • 如何在Linux平台使用SDL库进行2D/3D游戏开发
  • SDL开发实战(二):SDL2.0核心API解析

(一)汉诺塔模型

这里涉及的知识点包括:类的定义、SDL_Renderer渲染器也就是画布。

//汉诺塔柱子,简化盘子为正整数
class Stick {
    public:
    deque<int> plates; //柱子放置盘子的栈
    int x, y; //柱子底中心位置
    int width, height; //柱子宽、高
    unsigned char r, g, b; //柱子颜色
    int pside, pheight; //盘子边长、厚度
    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*); //在指定渲染器绘制画面
};

//整个汉诺塔模型
class Hanoi {
    private:
    SDL_Renderer * render; // 内置窗口渲染器指针
    public:
    Stick sticks[3]; //3根柱子
    Hanoi(SDL_Renderer *, int); //构造函数
    bool movePlate(int a, int b); //将1个盘子从a柱移到b柱
    void movePlates(int a, int b, int count); //将count个盘子从a柱移到b柱
    void show(); //在窗口绘制画面
};

(二)递归实现

这里涉及的知识点包括:类外实现、函数递归调用、deque容器,其中movePlate函数是移动1个盘子的基本操作,而movePlates则是移动多个盘子的函数,它通过递归调用逐渐缩小盘子数量,直到最后剩1个盘子后调用基本操作函数。

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->sticks[a].plates.pop_back();
    this->sticks[b].plates.push_back(plateA);
    this->show(); //显示
    return true;
}

void Hanoi::movePlates(int a, int b, int count) {
    if (count == 1) {
        this->movePlate(a, b);
        return;
    }
    //求出中间柱(0,1,2) -> (1,2,3) ->(0,1,2)
    int c = ((a+1) ^ (b+1)) - 1;
    this->movePlates(a, c, count-1); //从a柱移count-1个盘子到c柱
    this->movePlate(a, b); //从a柱移最后1个盘子到b柱
    this->movePlates(c, b, count-1); //从c柱移count-1个盘子到b柱
}

(三)显示

分为2个显示模块,1个是Hanoi汉诺塔模型的显示函数,而它继续调用每根柱子的显示函数。

1.命令行显示

void Hanoi::show() {
    //逐根绘制
    for (int n = 0; n < 3; n++) {
        //画柱子和柱子上的盘子
        cout << "第" << n << "根柱:";  //命令行显示
        this->sticks[n].show();
    }
    cout << endl;// 命令行显示
    //显示
    SDL_Delay(1500); //1.5秒刷新
}

void Stick::show() {
    //画盘子
    for (int i = 0; i < this->plates.size(); i++) {
        cout << this->plates.at(i) << " "; //命令行显示   
    }
    cout << ","; //命令行显示
}

以3层为例,显示结果如下:

第0根柱:3 2 1 ,第1根柱:,第2根柱:,
第0根柱:3 2 ,第1根柱:,第2根柱:1 ,
第0根柱:3 ,第1根柱:2 ,第2根柱:1 ,
第0根柱:3 ,第1根柱:2 1 ,第2根柱:,
第0根柱:,第1根柱:2 1 ,第2根柱:3 ,
第0根柱:1 ,第1根柱:2 ,第2根柱:3 ,
第0根柱:1 ,第1根柱:,第2根柱:3 2 ,
第0根柱:,第1根柱:,第2根柱:3 2 1 ,

2.SDL图形显示

在命令行显示基础上进行扩充:

void Hanoi::show() {
    //先用白色背景清屏
    SDL_SetRenderDrawColor(this->render, 255, 255, 255, 255);
    SDL_RenderClear(this->render);
    //逐根绘制
    for (int n = 0; n < 3; n++) {
        //画柱子和柱子上的盘子
        cout << "第" << n << "根柱:";  //命令行显示
        this->sticks[n].show(render);
    }
    cout << endl; // 命令行显示
    //显示
    SDL_RenderPresent(this->render);
    SDL_Delay(1500); //1.5秒刷新
}

void Stick::show(SDL_Renderer * render) {
    //画柱子
    SDL_Rect rect = {x - width/2, y, width, height}; //x, y,宽、高
    SDL_SetRenderDrawColor(render, r, g, b, 255); //不透明
    SDL_RenderFillRect(render, &rect);
    //画盘子
    for (int i = 0; i < this->plates.size(); i++) {
        cout << this->plates.at(i) << " "; //命令行显示
        int px = this->x - this->plates.at(i) * this->pside / 2; //盘子左边沿,盘子单位长为20
        int py = 600 - (i + 1) * this->pheight; //窗口高600,盘子上边沿,盘子单位厚度为10
        SDL_Rect rect = {px, py, this->plates.at(i)*this->pside, this->pheight}; //盘子坐标(px, py)、边长、厚
        //填色
        SDL_SetRenderDrawColor(render, this->pr, this->pg, this->pb, 255); //盘子为天蓝色,不透明
        SDL_RenderFillRect(render, &rect);
        //画黑色边框
        SDL_SetRenderDrawColor(render, 0, 0, 0, 255); 
        SDL_RenderDrawRect(render, &rect);
        
    }
    cout << ","; //命令行显示
}

四、处理用户输入及SDL环境配置

放置在main函数中,最后显示出来就是文章开头展示的动图了。

    int n; //汉诺塔层数
    cout << "请输入汉诺塔层数:" << flush;
    cin >> n;

    //初始化SDL成视频模式
    SDL_Init(SDL_INIT_VIDEO);
    //初始化窗口,标题为汉诺塔,位置(x,y)默认,尺寸800X600,窗口为显示模式
    SDL_Window *window = SDL_CreateWindow("汉诺塔", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_SHOWN);
    if (!window) {
        cout << "窗口生成异常" << endl;
        return 1;
    }
    //初始化窗口渲染器,相当于画布,-1表示默认的渲染设备,使用软件渲染
    SDL_Renderer *render = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
    if (!render) {
        cout << "渲染器生成异常" << endl;
        return 1;
    }
    //初始化汉诺塔
    Hanoi hanoi(render, n);
    hanoi.show(); //修复刚启动黑屏bug
    hanoi.show();
    hanoi.movePlates(0, 2, n);

    SDL_DestroyRenderer(render);
    SDL_DestroyWindow(window);
    SDL_Quit();

五、总结

本篇文章摘记了使用C++语言实现汉诺塔游戏电脑自动完成的步骤,还没有实现用户交互,无多少可玩性,仅抛砖引玉,希望大家有所收获,如有好的建议欢迎留言,谢谢大家!

六、源码下载

C++语言实现汉诺塔自动完成

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

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

相关文章

pikachu靶场通关笔记07 XSS关卡03-存储型XSS

目录 一、XSS 二、存储型XSS 三、源码分析 四、渗透实战 1、输入mooyuan试一试 2、注入Payload 3、查看数据库 4、再次进入留言板页面 本系列为通过《pikachu靶场通关笔记》的XSS关卡(共10关&#xff09;渗透集合&#xff0c;通过对XSS关卡源码的代码审计找到XSS风险的…

OpenCV CUDA模块直方图计算------用于在 GPU 上执行对比度受限的自适应直方图均衡类cv::cuda::CLAHE

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::cuda::CLAHE 是 OpenCV 的 CUDA 模块中提供的一个类&#xff0c;用于在 GPU 上执行对比度受限的自适应直方图均衡&#xff08;Contrast Limi…

华为OD机试真题——矩形绘制(2025A卷:200分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 200分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

JDBC连不上mysql:Unable to load authentication plugin ‘caching_sha2_password‘.

最近为一个spring-boot项目下了mysql-9.3.0&#xff0c;结果因为mysql版本太新一直报错连不上。 错误如下&#xff1a; 2025-06-01 16:19:43.516 ERROR 22088 --- [http-nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispat…

MacOS安装Docker Desktop并汉化

1. 安装Docker Desktop 到Docker Desktop For Mac下载对应系统的Docker Desktop 安装包&#xff0c;下载后安装&#xff0c;没有账号需要注册&#xff0c;然后登陆即可。 2. 汉化 前往汉化包下载链接下载对应系统的.asar文件 然后将安装好的文件覆盖原先的文件app.asar文件…

Centos系统搭建主备DNS服务

目录 一、主DNS服务器配置 1.安装 BIND 软件包 2.配置主配置文件 3.创建正向区域文件 4.创建区域数据文件 5.检查配置语法并重启服务 二、从DNS服务配置 1.安装 BIND 软件包 2.配置主配置文件 3.创建缓存目录 4.启动并设置开机自启 一、主DNS服务器配置 1.安装 BIN…

使用 HTML + JavaScript 实现在线考试系统

在现代的在线教育平台中&#xff0c;在线考试系统是不可或缺的一部分。本文将通过一个完整的示例&#xff0c;演示如何使用 HTML、CSS 和 JavaScript 构建一个支持多种题型的在线考试系统。 效果演示 项目概述 本项目主要包含以下核心功能&#xff1a; 支持4种常见题型&…

谷歌工作自动化——仙盟大衍灵机——仙盟创梦IDE

下载地址 https://chromewebstore.google.com/detail/selenium-ide/mooikfkahbdckldjjndioackbalphokd https://chrome.zzzmh.cn/info/mooikfkahbdckldjjndioackbalphokd

秒杀系统—1.架构设计和方案简介

大纲 1.秒杀系统的方案设计要点 2.秒杀系统的数据 页面 接口的处理方案 3.秒杀系统的负载均衡方案底层相关 4.秒杀系统的限流机制和超卖问题处理 5.秒杀系统的异步下单和高可用方案 1.秒杀系统的方案设计要点 (1)秒杀促销活动的数据处理 (2)秒杀促销活动的页面处理 (…

基于FashionMnist数据集的自监督学习(生成式自监督学习AE算法)

目录 一&#xff0c;生成式自监督学习 1.1 简介 1.2 核心思想 1.3 常见算法 1.3.1 自动编码器&#xff08;Autoencoder&#xff09; 1.3.2 生成对抗网络&#xff08;GANs&#xff09; 1.3.3 变分自编码器&#xff08;VAE&#xff09; 1.3.4 Transformer-based 模型&…

从监控到告警:Prometheus+Grafana+Alertmanager+告警通知服务全链路落地实践

文章目录 一、引言1.1 监控告警的必要性1.2 监控告警的基本原理1.2.1 指标采集与存储1.2.2 告警规则与触发机制1.2.3 多渠道通知与闭环 二、技术选型与架构设计2.1 为什么选择 Prometheus 及其生态2.1.1 Prometheus 优势分析2.1.2 Grafana 可视化能力2.1.3 Alertmanager 灵活告…

WPF【09】WPF基础入门 (三层架构与MVC架构)

9-2 【操作】WPF 基础入门 新建一项目 Create a new project - WPF Application (A project for creating a .NET Core WPF Application) - Next - .NET 5.0 (Current) - Create 项目创建完成&#xff0c;VS自动打开 GUI用户界面&#xff0c;格式是 .xaml文件&#xff0c;跟xm…

macOS 风格番茄计时器:设计与实现详解

macOS 风格番茄计时器&#xff1a;设计与实现详解 概述 本文介绍一款采用 macOS 设计语言的网页版番茄计时器实现。该计时器完全遵循苹果的人机界面指南(HIG)&#xff0c;提供原汁原味的 macOS 使用体验&#xff0c;同时具备响应式设计和深色模式支持。 核心特性 原生 macOS…

oracle goldengate实现远程抽取postgresql 到 postgresql的实时同步【绝对无坑版,亲测流程验证】

oracle goldengate实现postgresql 到 postgresql的实时同步 源端&#xff1a;postgresql1 -> postgresql2 流复制主备同步 目标端&#xff1a;postgresql 数据库版本&#xff1a;postgresql 12.14 ogg版本&#xff1a;21.3 架构图&#xff1a; 数据库安装以及流复制主备…

ISCC-2025-web-wp

web 校赛 校赛靠着ENOCH师傅发力&#xff0c;也是一路躺进了区域赛&#xff0c;E师傅不好意思发这抽象比赛的wp(这比赛确实啥必到让人大开眼界&#xff0c;反正明年我是肯定不会打了)&#xff0c;我就顺手要过来连着区域赛的一起发了 web 150分 按照提示进入/includes/fla…

King3399(ubuntu文件系统)iic(i2c)功能测试

0 引言 前面两篇博文简要介绍了板子上uart部分的内容&#xff0c;但在驱动开发时&#xff0c;我们遇到的外设更多的是以i2c或spi进行通信&#xff0c;本文将对king3399的i2c进行测试并对硬件电路、设备树与驱动程序进行分析 如果使用的i2c设备不是mma8452&#xff0c;建议先看…

德思特新闻 | 德思特与es:saar正式建立合作伙伴关系

德思特新闻 2025年5月9日&#xff0c;德思特科技有限公司&#xff08;以下简称“德思特”&#xff09;与德国嵌入式系统专家es:saar GmbH正式达成合作伙伴关系。此次合作旨在将 es:saar 的先进嵌入式开发与测试工具引入中国及亚太市场&#xff0c;助力本地客户提升产品开发效率…

基于原生JavaScript前端和 Flask 后端的Todo 应用

Demo地址&#xff1a;https://gitcode.com/rmbnetlife/todo-app-js-flask.git Python Todo 应用 这是一个使用Python Flask框架开发的简单待办事项(Todo)应用&#xff0c;采用前后端分离架构。本项目实现了待办事项的添加、删除、状态切换等基本功能&#xff0c;并提供了直观…

MIT 6.S081 2020 Lab6 Copy-on-Write Fork for xv6 个人全流程

文章目录 零、写在前面一、Implement copy-on write1.1 说明1.2 实现1.2.1 延迟复制与释放1.2.2 写时复制 零、写在前面 可以阅读下 《xv6 book》 的第五章中断和设备驱动。 问题 在 xv6 中&#xff0c;fork() 系统调用会将父进程的整个用户空间内存复制到子进程中。**如果父…

第304个Vulnhub靶场演练攻略:digital world.local:FALL

digital world.local&#xff1a;FALL Vulnhub 演练 FALL (digitalworld.local: FALL) 是 Donavan 为 Vulnhub 打造的一款中型机器。这款实验室非常适合经验丰富的 CTF 玩家&#xff0c;他们希望在这类环境中检验自己的技能。那么&#xff0c;让我们开始吧&#xff0c;看看如何…