First we try, then we trust

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  183 随笔 :: 111 文章 :: 2983 评论 :: 339 引用

十六、 WinHRD的设计

基本组件的编写工作完成后,我们设计一个程序测试一下。在提供的源代码中提供了两个例子。一个是ConsoleHRD(DOS环境下的求解程序),比较简单。另外一个是Windows界面的WinHRD。

 

我们这里来看看WinHRD的设计:首先主窗口要实现IResultHandler接口以处理华容道组件提供的信息。例如当前搜索到了多少层级,以及求解的结果是什么。用户可以自己单独设计一个实现IResultHandler接口的类来处理这些事情。只要将该类的实例提供给Mediator对象就行了。

public class frmMain : Form, IResultHandler
{
  …………
  
public void HandleResult(ChessStep[] steps)
  
{
    
// 处理搜索结果
    …………
    
return;
  }


  
public void HandleInfo(int currentStep)
  
{
    
// 处理搜索中的信息
    this.lblInfo.Text = "搜索深度: " + currentStep.ToString();
    
this.lblInfo.Refresh();
  }

}

在窗体的初始化代码中初始化各个组件:

public frmMain()
{
  InitializeComponent();

  
// 初始化自动求解程序
  mediator = new Mediator();
  mediator.avlTree 
= new AVLTree();
  mediator.treeList 
= new TreeLinkedList();
  mediator.resultHandler 
= this;
}

为了确保程序的运行效率,我们在单独的线程中运行主处理程序。因此,我们将主要的处理程序封装到一个Process方法中,并将其运行在单独的线程中,线程的优先性设置为BelowNormal,IsBackground设置为true。代码如下(部分简化):

private void btnBegin_Click(object sender, System.EventArgs e)
{
  layoutFactory.mediator 
= mediator;
  mediator.circleList 
= new CircularLinkedList(layoutFactory);
  mediator.resultHandler 
= this;

  mediator.Init(
1000);

  Thread trd 
= new Thread(new ThreadStart(this.Process));
  trd.Priority 
= ThreadPriority.BelowNormal;
  trd.IsBackground 
= true;
  trd.Start();
}


private void Process()
{
  
if(!mediator.BeginProcess())
    
this.txtResult.Text = "此题无解!";

  mediator.Release();  
// 及时释放内存;
}


private void btnStop_Click(object sender, System.EventArgs e)
{
  mediator.Stop();
}

至此,我们就完成了客户端的设计。主运算运行在单独的线程中,并可以随时被终止。不会给用户带来任何停滞的感觉。


十七、 性能大比拼

完成了程序的主体工作后,就需要对效率进行一下评价了。我将自己的程序与河北石家庄李智广的"华容道全能版 V1.1"进行了效率对比。在我的机器上(P4 2.0G、512M DDR400内存)得到如下测试结果:

 

从表中可以看出,在一些比较简单的布局中,"华容道全能版"拥有比较高的运算效率。但当搜索的节点数超过40000时,"华容道全能版"的搜索效率急剧下降。运算时间均在10秒甚至15秒以上。本程序在运算上效率较高,尤其是在复杂布局的求解上也拥有令人满意的效率。究其原因,本人认为有以下几点:

1、本程序将布局转换为4字节整数消耗了过多的CPU时间(需要排序操作),因此为了节省内存而损失了效率。

2、AVLTree带来了良好搜索性能。即使搜索节点超过40000节点,AVLTree也能确保最多在16次比较后就能判断出是否有重复布局(2^16=65532)。

3、种种迹象表明,"华容道全能版"在判断下一步可行走法时,仅仅判断了四种情况:上、下、左、右。而本程序判断了九种情况,除上下左右外还包括上移两步、下移两步、左移两步、右移两步以及转弯(专门针对卒)。因此"华容道全能版"在一步的判断上速度要快很多,但增加了搜索深度(从表中的数据也可以看出来),并且不能正确求得华容道求解的最小步数。

"智能算法爱好者"的结论是:走一格尽管深度增加,但一个递归层的节点宽度比走两格的节点宽度窄了很多,比较的有效节点差不多,但比较的总节点数少了很多,所以走一格比走两格要少很多时间,大约为走两格的70%(用我的同一程序测试),并且只有走两格才能找到最少步数(最优解)。

如果对内存的使用可以放宽松一些的化,我们可以考虑采用其它的方式存储棋盘布局(不再使用4字节表示),这样虽会使AVLTree的构建过程有所减慢,但华容道求解速度会有所提升(不再需要执行排序操作了)。总体来说,对布局搜索速度会有提升(这只是我的猜测,未经验证)。




关于《华容道与数据结构》的内容到此就全部完成。本文中的最终程序代码可以从http://www2.cnblogs.com/Files/zhenyulu/HRD.rar下载。如果时间允许,我会继续完成《华容道与设计模式》,给这个程序添加一个更丰富的客户端界面,允许更好的人机交互,实践并应用一些设计模式在里面。

(全文完)

posted on 2005-02-11 22:23 吕震宇 阅读(3164) 评论(13)  编辑 收藏 所属分类: 华容道与数据结构

评论

解题速度还是有点慢.我的华容道程序有30多关,包括上面这些关,任何一关只需零点几秒(即点即出),最长时间为0.571秒(即上面的第四关).从与"华容道全能版"比较,我的笔记本(CPU2.2G/内存196M)性能低于上面这个电脑,因为在我的电脑上运行"华容道全能版"时,时间最长的是上面第二关34.53秒,第四关33.43秒,几乎都是上面第一栏数据的两倍.我的华容道有走一格(一小步)或两格(一大步)的选项,走一格尽管深度增加,但一个递归层的节点宽度比走两格的节点宽度窄了很多,比较的有效节点差不多,但比较的总节点数少了很多,所以走一格比走两格要少很多时间,大约为走两格的70%(用我的同一程序测试),并且只有走两格才能找到最少步数(最优解).
另外解题时间不仅仅与算法和效率有关,而且与编程语言也有很大关系!因为我用VB,VC都做个算法,相差太大.
献给致力于华容道算法的朋友!
  回复  引用    

#2楼 [楼主] 2005-02-14 16:35 吕震宇      
@智能算法爱好者

非常感谢!不知道能否将算法交流一下呢?我非常想了解一下象我这样的数据结构设计是否存在一些问题。你的程序是用VC写的吗?
  回复  引用  查看    

我的程序是用VC写的,算法其实很简单很普通,没什么,5X4数组,分配一个存储空间,用64位字长进行比较,节点比较时仅只比较前两层递归的所有节点;搜索以棋子为搜索对象.
另外,选取的对象不同,解题时间也有差别.走棋规则部分的代码顺序也稍有关系,上下左右的方向先判断左还是右,判断的顺序不一样,产生的节点不一样.
  回复  引用    

#4楼 [楼主] 2005-02-15 21:17 吕震宇      
@智能算法爱好者

“节点比较时仅只比较前两层递归的所有节点”,很有创意!虽然可能搜索不到所有的已经出现过的布局,但涵盖的绝大多数的可能性。一个非常好的用内存换效率的方法,我从来没有想到过的。

“走棋规则部分的代码顺序也稍有关系”,对于我的程序似乎关系不大。在前面我曾经写了一篇随笔,说的就是让人费解的效率问题,走棋顺序对于我的程序的效率提升几乎不起作用,令人苦恼。我想这根C#的动态编译以及内部运行机制有一定的关系。

非常感谢你的指点!
  回复  引用  查看    

吕老师:
你的华容道程序现在解题是否速度如飞了,我没有仔细看你的文章,只快速浏览了部分文字,你对比较谈的不多,所以我猜想你的程序慢的原因可能在比较上,比较是华容道解题效率的第一致命点,这个比较在效率上不是几倍的关系,还是几十倍的关系,尤其在较慢的电脑更能体现它的数值量,效率的第二个因素才是比较数据压缩,一个画面比较20个数据和比较一个数据也是近20倍的关系.
  回复  引用    

#6楼 [楼主] 2005-02-16 16:14 吕震宇      
@智能算法爱好者

速度还是原来的速度,没有太大的改进。我想这与.net的特点有一定关系。在比较上我没有做任何改进。因为我在数据结构设计上使用了AVL树,这种数据结构也限制了我使用“只比较前两层递归的所有节点”的方法。不过AVL是一个平衡二叉树,对于一个有4万节点的树来说,最多比较16次就能判断出是否有重复(2^16=65532),因此我的程序在比较上最多16次就能判断出是否是重复布局。

我正在尝试进行改进其它方面的内容。但带来非常大的效率提升的可能性恐怕不太大了。有了你提供的数据,我会继续努力优化代码的!
  回复  引用  查看    

#7楼 [楼主] 2005-02-16 20:51 吕震宇      
@智能算法爱好者

多谢你的提醒,我发现了我程序的一个性能瓶颈!居然是在Exception上面!我正在整理这方面的资料,随后发表到随笔中。现在我的程序运行第4关的时间不再是6.67秒了,而是1.55秒!性能应当还可以进一步提升。
  回复  引用  查看    

吕老师:
这一下效率可提高了不小,算是一个大突破!
  回复  引用    

#9楼  2005-11-08 11:23 浩思 [未注册用户]
不管这个程序设计的多么优良,我这边有一个活生生的人可以完全凭他的记忆走出最少的步法,即通常所说的“横刀立马”的81步,他是完全没有前人的基础上走出来的。我很是为他的这种精神而鼓舞,随说他是一个残疾人,我觉的我在这里有必要说一下他,他也算是在这方面的一个突破吧!
最后,我希望对“华容道”有意的同志们能够关注一下他。
我的邮箱caoyuelong888@126.com
  回复  引用    

#10楼  2005-11-21 09:46 Walter.xu [未注册用户]
关于这个游戏的比较数据都比较让人失望,其实,116步和81步根本不是从一种定义上去定义的,116步指的是单独的小步(比如,转弯算两步,移动两格算两步),而81步则将这些都算做一步,所以结果当然是不对的了.
其实科学最重要的是讲实事求是,而不是贬低他人,提高自己,这是我们做科学研究最基本的要求.
另外,在文中对算法的模型介绍并不有到位,并没有对关键的建模作描述,这对问题的探讨是不利的.
文中还讲了对方程序的计算节在超过40000后就会出现效率下降的情况,这对比较本身也是无可厚非的,不过我觉得也并不能借此说明自己有多优秀,事实上,除非对方对内在作了限制,否则就不会出现这种情况,只能是对方程序在设计时的一个干扰因素而已.
华容道游戏用计算机破解的思路相信大家都比较明确,其实关键的问题在于如何剔除干扰项(基本上就是重复的节如何避免),第二个问题就是如何实现多线程的问题了,一般说来,这种问题的算法都多少程序涉及递归,而多线程往往就比较起不到很大的作用,因为数据集并不能根据某种规则作细分,因此,需要阶段性的同步.其它的不说多了,有兴趣的话可以联系walter.xu@utstar.com,大家一起继续探讨.
  回复  引用    

@智能算法爱好者

看了吕老师的文章, 真的获益匪浅. 但看了智能算法爱好者的回复, 更对"智能算法爱好者"的源码异常兴趣. 也想进"智能算法爱好者"的随笔集看看, 苦于找不到地址, 恳请原者告知(不知道"智能算法爱好者"有没有blog)
  回复  引用    

我在visual studio 下运行winHRD,当程序运行后,我点击开始按钮出现

InvalidOperationException was unhandled

Cross- thread operation not valid: Control 'txtResult' accessed from a thread other than the thread it was created on.
  回复  引用    

#13楼 [楼主] 2007-03-18 22:09 吕震宇      
@devhotmail

当时做这个程序的时候是在.net 1.1环境下,我不知道你现在是不是在.net 2.0环境下运行?我这个程序确实在这里存在问题:

现在对Windows界面控件内容的修改命令只能执行在应用程序线程内,而为了提高运行效率,我使用了多线程,在一个新线程中是不能对当前窗体元素进行操作的,因此就出现了你看到的问题。

解决办法就是使用委派机制,你可以从网上查找到相关资料自己改动一下,应当很简单。
  回复  引用  查看    


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2005-02-17 12:01 编辑过


相关链接: