用c++或c 做一个深度遍历的 棋谱树,我用来 做围棋棋谱的教学,要求节省内存、效率高,便于保存(棋谱)和拷贝棋谱

news2024/12/28 13:44:22

为了实现一个高效且节省内存的围棋棋谱树,我们可以使用如下思路和方法:

    1.    数据结构设计:

    •    使用一个树结构,每个节点表示棋局的一步(包括坐标和落子的颜色)。

    •    每个节点存储子节点的指针,表示该步之后的可能变化。

    •    为了节省内存,可以使用指针列表或数组管理子节点。

    •    节点还应包括对父节点的指针,便于回溯。

    2.    效率优化:

    •    使用紧凑的结构体存储棋局信息(例如,用一个 char 存储坐标,用一个 bool 存储黑白方)。

    •    使用内存池管理节点,减少频繁的动态内存分配开销。

    •    通过深度优先遍历(DFS)进行棋谱操作。

    3.    便于保存和拷贝:

    •    使用序列化和反序列化方法将棋谱存储为文件或字符串。

    •    提供简单的接口来拷贝整个棋谱树。

 

以下是一个示例实现:

 

代码实现

 

#include <iostream>

#include <vector>

#include <string>

#include <memory>

#include <fstream>

 

// 棋谱节点结构

struct MoveNode {

    int x, y;               // 落子坐标

    bool isBlack;           // 是否为黑子

    std::vector<MoveNode*> children; // 子节点

    MoveNode* parent;       // 父节点

 

    // 构造函数

    MoveNode(int x, int y, bool isBlack, MoveNode* parent = nullptr)

        : x(x), y(y), isBlack(isBlack), parent(parent) {}

 

    ~MoveNode() {

        for (auto child : children) {

            delete child;

        }

    }

};

 

// 棋谱树类

class GoTree {

private:

    MoveNode* root; // 根节点

 

public:

    // 构造函数

    GoTree() {

        root = new MoveNode(-1, -1, false); // 虚拟根节点

    }

 

    ~GoTree() {

        delete root;

    }

 

    // 添加棋谱节点

    MoveNode* addMove(MoveNode* parent, int x, int y, bool isBlack) {

        auto* newNode = new MoveNode(x, y, isBlack, parent);

        parent->children.push_back(newNode);

        return newNode;

    }

 

    // 深度优先遍历(打印棋谱)

    void printTree(MoveNode* node, int depth = 0) {

        if (node->x != -1 && node->y != -1) { // 跳过虚拟根节点

            std::cout << std::string(depth * 2, ' ')

                      << (node->isBlack ? "Black" : "White") << " (" << node->x << ", " << node->y << ")\n";

        }

        for (auto* child : node->children) {

            printTree(child, depth + 1);

        }

    }

 

    // 保存棋谱到文件

    void saveTree(MoveNode* node, std::ostream& os) {

        if (node->x != -1 && node->y != -1) {

            os << (node->isBlack ? "B" : "W") << "," << node->x << "," << node->y << "\n";

        }

        for (auto* child : node->children) {

            saveTree(child, os);

        }

        os << "END\n"; // 用END标记一个节点的子节点结束

    }

 

    // 从文件加载棋谱

    MoveNode* loadTree(std::istream& is, MoveNode* parent = nullptr) {

        std::string line;

        MoveNode* currentNode = parent ? parent : root;

        while (std::getline(is, line)) {

            if (line == "END") {

                return currentNode; // 子节点结束

            }

            char color;

            int x, y;

            if (sscanf(line.c_str(), "%c,%d,%d", &color, &x, &y) == 3) {

                bool isBlack = (color == 'B');

                currentNode = addMove(currentNode, x, y, isBlack);

                loadTree(is, currentNode);

            }

        }

        return currentNode;

    }

 

    MoveNode* getRoot() {

        return root;

    }

};

 

int main() {

    GoTree tree;

 

    // 构建棋谱

    auto* move1 = tree.addMove(tree.getRoot(), 3, 3, true);   // 黑3,3

    auto* move2 = tree.addMove(move1, 16, 16, false);         // 白16,16

    tree.addMove(move2, 4, 4, true);                          // 黑4,4

 

    // 打印棋谱

    std::cout << "棋谱树:\n";

    tree.printTree(tree.getRoot());

 

    // 保存棋谱

    std::ofstream outFile("goboard.txt");

    tree.saveTree(tree.getRoot(), outFile);

    outFile.close();

 

    // 加载棋谱

    std::ifstream inFile("goboard.txt");

    GoTree loadedTree;

    loadedTree.loadTree(inFile);

    inFile.close();

 

    // 打印加载后的棋谱

    std::cout << "\n加载后的棋谱树:\n";

    loadedTree.printTree(loadedTree.getRoot());

 

    return 0;

}

 

功能说明

    1.    数据结构:

    •    每一步棋局存储为一个 MoveNode,包含坐标、落子颜色、子节点和父节点。

    •    使用 std::vector 存储子节点,可以动态扩展子节点数量。

    2.    操作与接口:

    •    addMove:添加棋谱节点。

    •    printTree:深度优先遍历打印棋谱树。

    •    saveTree 和 loadTree:实现棋谱的保存和加载。

    3.    文件格式:

    •    保存为简单的 CSV 格式:B,3,3 表示黑棋落在 (3,3),END 表示子节点结束。

 

优点

    •    节省内存:使用紧凑的节点结构体和动态内存管理。

    •    效率高:支持快速的棋谱构建、保存和加载。

    •    可扩展性:可以根据需求增加功能,如支持回溯、分支删除等。

 

你可以根据实际需求进一步优化,比如将 std::vector 替换为固定大小的数组以进一步节省内存。

 

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

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

相关文章

Kubernetes 安装 Nginx以及配置自动补全

部署 Nginx &#xff1a; [rootk8s-master ~]# kubectl create deployment nginx --imagenginx:1.14-alpine deployment.apps/nginx created暴露端口&#xff1a; [rootk8s-master ~]# kubectl expose deployment nginx --port80 --typeNodePort service/nginx exposed查看服…

“库存管理软件的用户体验”:界面与交互设计

3.1可行性分析 开发者在进行开发系统之前&#xff0c;都需要进行可行性分析&#xff0c;保证该系统能够被成功开发出来。 3.1.1技术可行性 开发该库存管理软件所采用的技术是vue和MYSQL数据库。计算机专业的学生在学校期间已经比较系统的学习了很多编程方面的知识&#xff0c;同…

基于openEuler22.09部署OpenStack Yoga云平台(一)

OpenStack Yoga部署 安装OpenStack 一、基础准备 基于OpenStack经典的三节点环境进行部署&#xff0c;三个节点分别是控制节点&#xff08;controller&#xff09;、计算节点&#xff08;compute&#xff09;、存储节点&#xff08;storage&#xff09;&#xff0c;其中存储…

AutoDL服务器深度学习使用过程

前期准备 Xshell,Xftp,Pycharm专业版 step 1:实例开机&#xff08;无卡or有卡&#xff09;&#xff0c;Xshell连接 新建xshell会话&#xff1a; 登录指令格式为&#xff1a; ssh -p 38076 rootregion-1.autodl.com 在ssh -p 38076 rootregion-1.autodl.com命令中&#xff0…

【RabbitMQ的死信队列】

死信队列 什么是死信队列死信队列的配置方式死信消息结构 什么是死信队列 消息被消费者确认拒绝。消费者把requeue参数设置为true(false)&#xff0c;并且在消费后&#xff0c;向RabbitMQ返回拒绝。channel.basicReject或者channel.basicNack。消息达到预设的TTL时限还一直没有…

详解从输入url到页面渲染

当你在浏览器中输入一个 URL 并按下回车键&#xff0c;浏览器会经历一系列步骤来加载并渲染页面。这些步骤包括 DNS 解析、缓存处理、建立连接、发送请求、接收响应、解析 HTML、构建 DOM 树和 CSSOM 树、执行 JavaScript、布局和绘制等。以下是这些步骤的详细解释&#xff0c;…

从 GitLab.com 到 JihuLab.com 的迁移指南

本文分享从 GitLab.com 到 JihuLab.com 的迁移指南。 近期&#xff0c;GitLab Inc. 针对其 SaaS 产品做了限制&#xff0c;如果被判定为国内用户&#xff0c;则会建议使用其在国内的发布版本极狐GitLab。从 GitLab SaaS 产品&#xff08;GitLab.com&#xff09;迁移到极狐GitL…

AIA - IMSIC之二(附IMSIC处理流程图)

本文属于《 RISC-V指令集基础系列教程》之一,欢迎查看其它文章。 1 ​​​​​​​通过IMSIC接收外部中断的CSR 软件通过《AIA - 新增的CSR》描述的CSR来访问IMSIC。 machine level 的 CSR 与 IMSIC 的 machine level interrupt file 可相互互动;而 supervisor level 的 CSR…

Python爬虫实战(保姆级登网页信息爬取教程)

此blog为爬虫实战教学&#xff0c;代码已附上&#xff0c;可以复制运行。若要直接看实战代码翻到博客后半部分。 本文使用selenium库进行爬虫&#xff0c;实现爬取数据操作&#xff0c;此库是通过模仿用户的操作进行对页面的处理。了解了这个思维模式&#xff0c;可以对代码进…

国产三维CAD正强势崛起

CAD软件作为现代工业设计和制造领域不可或缺的核心工具&#xff0c;其重要性不言而喻。它极大地提升了设计效率与精度&#xff0c;缩短了产品开发周期&#xff0c;为企业的创新与发展注入了强大动力。随着全球市场竞争的日益激烈&#xff0c;以及当前国际局势的复杂多变&#x…

编码滤波技术-SAO

1. AVS中的SAO样值偏移自适应补偿技术&#xff0c;首先将正在处理的块往左上移动了四行四列&#xff0c;超过图像边界的部分丢弃&#xff0c;右、下图像边界部分补齐。 也就是偏移前在图像边缘的块&#xff0c;进行去除和扩展得到偏移后的块。图像内部的块&#xff0c;正常往左…

Leetcode打卡:查询数组中元素出现的位置

执行结果&#xff1a;通过 题目 3159 查询数组中元素出现的位置 给你一个整数数组 nums &#xff0c;一个整数数组 queries 和一个整数 x 。 对于每个查询 queries[i] &#xff0c;你需要找到 nums 中第 queries[i] 个 x 的位置&#xff0c;并返回它的下标。如果数组中 x 的出…

【游戏设计原理】32 - 消费者剩余

1. 如何理解消费者剩余原理&#xff1f; 消费者剩余是一种经济学概念&#xff0c;表示消费者愿意为商品支付的最大金额与实际支付金额之间的差额。 简单来说&#xff0c;消费者剩余衡量了消费者从交易中获得的“额外价值”或“剩余利益”。 在传统商业模式下&#xff0c;由于…

肝功能不正常可以过教师入职体检吗?

如何看肝功能报告单 转氨酶正常等于肝功能正常吗?要想看懂肝功能报告单就要看懂各指标含义。 1、总胆红素TbiL正常值是 1.7-17.1μmol/L 急性黄疸型肝炎活动性肝炎肝坏死、肝癌、胰头癌都异常偏高。 2、直接胆红素 DbiL正常值是 0-6.84μmol/L 结石病、肝癌、胰头癌与这项…

CH340系列芯片驱动电路·CH340系列芯片驱动!!!

目录 CH340基础知识 CH340常见类型 CH340引脚功能讲解 CH340驱动电路 CH340系列芯片数据手册 编写不易&#xff0c;仅供学习&#xff0c;请勿搬运&#xff0c;感谢理解 常见元器件驱动电路文章专栏连接 LM7805系列降压芯片驱动电路降压芯片驱动电路详解-CSDN博客 ME62…

(公开源码)基于springboot+vue的在线课程教学管理系统 计算机毕业设计P10046

项目说明 本号所发布的项目均由我部署运行验证&#xff0c;可保证项目系统正常运行&#xff0c;以及提供完整源码。 如需要远程部署/定制/讲解系统&#xff0c;可以联系我。定制项目未经同意不会上传&#xff01; 项目源码获取方式放在文章末尾处 注&#xff1a;项目仅供学…

UE5 把场景转成HDR图

目录 使用影片渲染队列 使用影片渲染队列 以下方法实测 UE5.4 有效 1.打开影片渲染队列窗口。依次打开&#xff1a;窗口—过场动画—影片渲染队列 2.添加Sequence动画。点击“渲染”按钮&#xff0c;选择要渲染的Sequence。 3.设置输出配置。 点击“Unsaved Config”打开配置…

使用RKNN进行YOLOv8人体姿态估计的实战教程:yolov8-pose.onnx转yolov8-pose.rknn+推理全流程

之前文章有提到“YOLOv8的原生模型包含了后处理步骤,其中一些形状超出了RK3588的矩阵计算限制,因此需要对输出层进行一些裁剪”,通过裁剪后得到的onnx能够顺利的进行rknn转换,本文将对转rnkk过程,以及相应的后处理进行阐述。并在文末附上全部源码、数据、模型的百度云盘链…

嵌入式硬件杂谈(八)电源的“纹波”到底是什么?

纹波的引入&#xff1a;在我们嵌入式设备中&#xff0c;很多时候电路电源的纹波很敏感&#xff0c;纹波太大会导致系统不工作&#xff0c;因此设计一个纹波很小的电路就是我们的需求了。 电路的纹波是什么&#xff1f; 纹波&#xff08;Ripple&#xff09;是指电源输出中叠加在…

水电站视频智能监控系统方案设计与技术应用方案

一、背景需求 水电站作为国家重要的能源基地&#xff0c;其安全运行对于保障能源供应和社会稳定具有重要意义。然而&#xff0c;传统的人工监控方式存在着诸多问题&#xff0c;如人力成本高、监控范围有限、反应不及时等。因此&#xff0c;水电站急需引进一种先进的视频智能监控…