华容道问题求解_详细设计(五)之hash值和回放功能

(续上文)

布局的hash 值计算

笔者也参考了之前的一些文章,很多文章提到了怎么节省存贮空间来查找最优解,这不是笔者的目的。笔者的目的比较单一,就是找到最优解就行了。因此并没有在存贮上面进行过多的优化,曾经尝试使用移位指令进行棋子的移动,然而并没有发现运行速度比使用庞大的对象速度更快。(或许是算法的问题)因此索性就使用了高级语言的高级方法,放弃了对存贮空间的限制和约束。基于前面的设计,每个布局保存在一个4*5的整数数组里面(保存的棋子的ID),因此为了简单起见笔者将这个20个整数构成一个字符串,然后利用C#提供的现有的字符串hash函数,就得到了这个布局的hash值。这个方法简单粗暴,并不美丽,但是解决问题就行了。
一个细节:在实际棋子的移动过程当中,我们关心的是棋子的形状而非棋子的名字,因此在棋子布局的时候,尽管每个棋子都赋予了名字,在进行查找的时候,是忽略了这些名字的。因此在使用DFS结合Dijkstra 算法查找时会出现名字改变的情况,这里笔者没有对名字进行一致处理,因为这种处理对解法其实没有什么帮助,只是界面看着更连贯些。(具体原因也不解释了,很简单)。在BFS的查找过程当中,不会有这个问题。
hash 函数如下:

      public int GetMyHashCode(GameState gameState){string val = string.Empty;for (int i = 1; i <= 4; i++){for (int j = 1; j <=5; j++){var pcs  = gameState.layoutOfObj[i, j];val += pcs.GetHrdType().ToString();}}return val.GetHashCode();}

注意上面只取了Type值进行hash处理。

回放功能

找到了解法,还要能进行回放,否则也看不到效果,也不能证明是否成功了,因此增加回放功能很有必要。
回放功能,就是记录每个布局的hash值和布局,然后根据hash值从布局记录中查找对应的布局,在映射到UI上就可以了。

最佳结果保存在如下定义的数据字典里

       // the shorest path will be stored in the following variable.// key:the hash code of the current layout, value.item1, the hashcode of the source layout , item2 the number of the shortest steps.Dictionary<int, (int,int)> hCodeAndShotShortPathDict = new Dictionary<int, (int,int)>();

hash值和布局快照保存在如下定义的数据字典中

// store the hash code and the layout shot , selpcs index,dstPcs.idx Dictionary<int, (Piece[],int,int)> hCodeAndShotDict = new Dictionary<int, (Piece[], int, int)>();
回放时,将这两个数据字典结合起来,就可以找到快照,将快照映射到界面上就可以了。

具体的保存过程

DFS中的用了Dijkstra 算法,算法本身就包括了最短路径的记录,因此这里不再赘述。
BFS算法中,找到的方法都是对应不同布局的最佳步骤,因此在尝试移动棋子的过程当中,记录当前的布局就可以了。
代码如下:
在AddEdgeToGraph 中的函数AdjustShortPath 就是用于记录解法的。
       private void AddEdgeToGraph(StateShot source, StateShot dest){var toHashCode = GetMyHashCode(dest);var frmHashCode = GetMyHashCode(source);AdjustShortPath(dest, toHashCode, frmHashCode);AddEdge(frmHashCode, toHashCode, 1);}private void PushState(StateS

AdjustShortPath 代码如下:

      private void AdjustShortPath(StateShot dest, int toHashCode, int frmHashCode){(int, int) lastItem;if (hCodeAndShotShortPathDict.TryGetValue(toHashCode, out lastItem)){if (lastItem.Item2 > dest.bestSteps){//这是笔者增加的视图记录最短路径的判断,DFS时,找到了比原来步骤少的方法,但是不是最优的。BFS时,这里执行不到。hCodeAndShotShortPathDict[toHashCode] = (frmHashCode, dest.bestSteps);}//hCodeAndShotShortPathDict.Add(toHashCode, (dest.basePcs, selPcs.idx, dstPcs.idx, frmHashCode, pathLen));}else{// 查找过程记录,BFS时,记录的就是最佳结果hCodeAndShotShortPathDict.Add(toHashCode, (frmHashCode, dest.bestSteps));}}

回放过程

程序先找到要回放的结果布局,然后将这个结果布局的对应的保存的所有过程布局,放到一个数组中,每执行一步,数组的索引加一,指向下一个过程布局。代码如下:

     private void MoveNext(){//allShortPath = allShortPath2;if (allShortPath == null){MessageBox.Show(string.Format("The shortest path is now being searched ,wait for a moment."), "Notice", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);return;}//solutionPcsIdx 布局数组索引//cbbSolutionIdx 保存在CBB 中的结果布局索引(hash 值)if (solutionPcsIdx >= 0 && solutionPcsIdx < allShortPath[cbbSolutionIdx].Count){if (solutionPcsIdx < allShortPath[cbbSolutionIdx].Count - 1)solutionPcsIdx++;var lastKey = allShortPath[cbbSolutionIdx][solutionPcsIdx - 1];//txt_Notice.Text = string.Format("Layout code:{0} Graph node info {1}\r\n{2}",lastKey, _hrdGame.adjacencyList[lastKey],txt_Notice.Text);var lastLayoutArr = _hrdGame.GetLayoutIdxArrByHashCode(lastKey);var key = allShortPath[cbbSolutionIdx][solutionPcsIdx];var layoutArr = _hrdGame.GetLayoutIdxArrByHashCode(key);//get the moving pieces by comparing the two layoutsvar movedPcs = GetMovedPieces(lastLayoutArr.Item1, layoutArr.Item1);var frmIdx = layoutArr.Item2;var toIdx = frmIdx;// layoutArr.Item3;var srcPcs = movedPcs.Item1;var dstPcs = movedPcs.Item2;var passPcs = movedPcs.Item3;// animation moving var selPos = srcPcs.GetHrdPos();var emptySpPos = dstPcs.GetHrdPos();var passPos = passPcs.GetHrdPos();// the following used to add animation effectvar srcPos = new HrdPoint(selPos.X, selPos.Y);var dstPos = new HrdPoint(emptySpPos.X, emptySpPos.Y);_hrdGame.gameState.pieces = layoutArr.Item1;_hrdGame.MovePcsWithAnimation(srcPcs, srcPos, dstPos, passPos, dstPcs, null);btn_ShowSteps.Text = string.Format("{0}/{1}", solutionPcsIdx, allShortPath[cbbSolutionIdx].Count - 1);//MessageBox.Show(string.Format("Click for next step, current step: {0}/{1}", i, allPath[0].Count));}}

函数中增加了 动画部分,因此做了相应的处理,这一部分将在后文赘述。

回放时,需要用户点击回放按钮。也支持了Undo功能,以方便用户观察棋子的移动过程。目前,执行Undo功能时没有做动画处理。

说明如下:
首先在下拉列表中选择一个布局的Hash值,例如第一个(就应该是最少步骤那个,BFS决定的)
在这里插入图片描述

点击[>>],棋子移动一步

在这里插入图片描述
点击[<<],恢复到上一步

在这里插入图片描述
(待续)
MaraSun BJFWDQ
2024-03-10

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

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

相关文章

Linux系统adb调试小米手机调试不成功出现Exception occurred while executing ‘put‘:问题解决

参考文章&#xff1a;执行android settings命令报错原因Exception occurred while executing put: java.lang.SecurityException: Pe... - 简书 (jianshu.com) 解决Android U无法通过adb安装应用(Caller has no access to session -1)的问题_performing streamed install-CSDN…

P3405 [USACO16DEC] Cities and States S题解

题目 Farmer John有若干头奶牛。为了训练奶牛们的智力&#xff0c;Farmer John在谷仓的墙上放了一张美国地图。地图上表明了每个城市及其所在州的代码&#xff08;前两位大写字母&#xff09;。 由于奶牛在谷仓里花了很多时间看这张地图&#xff0c;他们开始注意到一些奇怪的…

消息队列 MQ

文章目录 1. MQ 相关概念1.1 什么是 MQ1.2 为什么要用 MQ1.3 MQ 分类1.4 MQ 的选择 1. MQ 相关概念 1.1 什么是 MQ MQ(message queue)&#xff0c;从字面意思上看&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&#xff0c;只不过队列中存放的内容是 message 而已&#x…

【 React 】state和props有什么区别?

1. state 一个组件的显示形态可以由数据状态和外部参数所决定&#xff0c;而数据状态就是state&#xff0c;一般在constructor中初始化 当需要修改里面的值的状态需要通过调用setState来改变&#xff0c;从而达到更新组件内部数据的作用&#xff0c;并且重新调用组件render方法…

阿里云DSW做AI绘画时的显卡选择A10?V100?

V100是Volta架构&#xff0c;A10是Ampere架构&#xff0c;架构上讲A10先进点&#xff0c;其实只是制程区别&#xff0c;用起来没区别。 V100是HBM的内存读取&#xff0c;带宽大&#xff0c;但是DDR5的。 二块卡都是全精度为主的算力卡&#xff0c;半精度优势不明显。 需要用…

uniapp 开发app,如何使用模拟器

1、开发app &#xff0c;设置模拟器 &#xff08;uniapp 如何设置模拟器&#xff09; https://blog.csdn.net/sweetsoft/article/details/130727169 2、运行到模拟器 注意&#xff1a;1、模拟器所在的位置&#xff1a;“D:\Program Files\Nox\bin”&#xff0c;在该文件夹下找…

FPN(Feature Pyramid Network)

参考&#xff1a; 【目标检测】FPN(Feature Pyramid Network) - 知乎 Feature pyramid network是CVPR2017年的一篇文章&#xff0c;它在目标检测中融入了特征金字塔&#xff0c;提高了目标检测的准确率&#xff0c;尤其体现在小物体的检测上。 1. 动机(Motivation) 识别不同…

【三两波折】char *foo[]和char(*foo)[]有何不同?

1、先谈优先级 最高级别 —— 有四个&#xff0c;他们并不像运算符&#xff1a; []数组下标左到右结合()用于&#xff08;表达式&#xff09; or 函数名(形参表)左到右结合.读取结构体成员左到右结合->读取结构体成员&#xff08;通过指针&#xff09;左到右结合 第二级别…

【读书笔记】针对ICS的ATTCK矩阵详解(一)

Techniques - ICS | MITRE ATT&CKhttps://attack.mitre.org/techniques/ics/ 一、初始访问&#xff08;Initial Access&#xff09; 该阶段&#xff1a;攻击者正在尝试进入ICS环境。 初始访问包括攻击者可能用作入口向量&#xff0c;从而可以在 ICS 环境中获得初始立足点的…

pytorch实现分割模型TransUNet

TransUNet是一个非常经典的图像分割模型。该模型出现在Transformer引入图像领域的早期&#xff0c;所以结构比较简单&#xff0c;但是实际上效果却比很多后续花哨的模型更好。所以有必要捋一遍pytorch实现TransUNet的整体流程。 首先&#xff0c;按照惯例&#xff0c;先看一下…

逼疯快递员的送货上门,谁来背锅?

快递上门的问题近几年来一直争论不休。 最近&#xff0c;随着新修订的《快递市场管理办法》正式实施&#xff0c;这个话题又成为了焦点。 消费者希望快递能够送上门省去麻烦&#xff0c;快递员希望统一送到代收点提高效率。 是消费者要求太高&#xff1f;快递员太过怠慢&…

LightDB24.1插件oracle_fdw需要支持oracle.date和oracle.varchar2类型

背景介绍 oracle.date和oracle.varchar2是LightDB中新增的类型&#xff0c;对应于Oracle数据库的date和varchar2类型。oracle_fdw是第三方插件&#xff0c;所以不支持oracle.date和oracle.varchar2类型。从LightDB24.1版本开始&#xff0c;oracle_fdw插件开始支持oracle.date和…

理解自相关图AC和偏自相关图PAC Plots

when we talk about the time-series data, many factors affect the time series, but the only thing that affects the lagged version of the variable is the time series data itself. by Yugesh Verma 时序数据按照时间点的先后顺序进行排列,变化是在邻近的时间段之间发…

2.1基本算法之枚举1978:生理周期

人生来就有三个生理周期&#xff0c;分别为体力、感情和智力周期&#xff0c;它们的周期长度为23天、28天和33天。每一个周期中有一天是高峰。在高峰这天&#xff0c;人会在相应的方面表现出色。例如&#xff0c;智力周期的高峰&#xff0c;人会思维敏捷&#xff0c;精力容易高…

[金三银四] 系统调用相关

2.36 系统调用的详细流程 Linux 在x86上的系统调用通过 int 0x80 实现&#xff0c;用系统调用号来区分入口函数。操作系统实现系统调用的基本过程是&#xff1a; 应用程序调用库函数&#xff08;API&#xff09;&#xff1b;API 将系统调用号存入寄存器&#xff08;EAX&#…

CKA备考攻略:掌握Pod日志收集,事半功倍的秘诀!

往期精彩文章 : 提升CKA考试胜算&#xff1a;一文带你全面了解RBAC权限控制&#xff01;揭秘高效运维&#xff1a;如何用kubectl top命令实时监控K8s资源使用情况&#xff1f;CKA认证必备&#xff1a;掌握k8s网络策略的关键要点提高CKA认证成功率&#xff0c;CKA真题中的节点维…

稳定性三——wachdog机制与分析发方法

文章目录 1. 介绍2 watchdog 机制2.1 初始化2.2 添加Watchdog监测对象2.3 监测机制 3 问题分析3.1 日志分类3.2 定位3.3 场景还原 4. 实例分析5. 总结 1. 介绍 最早引入Watchdog是在单片机系统中&#xff0c;由于单片机的工作环境容易受到外界磁场的干扰&#xff0c;导致程序“…

uniapp上拉加载、下拉刷新

我这个是自定义header、main、和footer的布局&#xff0c;是盒子中的上拉加载、下拉刷新&#xff0c;不是页面的&#xff0c;废话不说&#xff0c;直接上代码&#xff01; <template><view class"assembly"><u-navbar title"个人中心" lef…

2.JavaWebMySql基础

导语&#xff1a; 一、数据库基本概念 1.什么是数据库 2.关于MySql数据库 二、MySQL的安装与卸载 安装步骤&#xff1a; 卸载步骤&#xff1a; 三、MySQL服务操作 1.服务启动和关闭&#xff1a; 2.登录和退出MySQL&#xff1a; 3.服务自启动&#xff1a; 4.命令行登…

Python实现线性查找算法

Python实现线性查找算法 以下是使用 Python 实现线性查找算法的示例代码&#xff1a; def linear_search(arr, target):"""线性查找算法:param arr: 要搜索的数组:param target: 目标值:return: 如果找到目标值&#xff0c;返回其索引&#xff1b;否则返回 -1…