Knight Path Plan<update20060115>

来源:互联网 发布:为什么淘宝地址改不了 编辑:程序博客网 时间:2024/06/07 05:06
昨天玩chessmaster的时候发现里面tutorial部分里演示马的走法的动画相当有趣,它可以显示出在任意一格中的马要跳到其他格子里所需要的步数。例如:
+---+---+---+---+---+---+---+---+
| 5 | 4 | 5 | 4 | 5 | 4 | 5 | 6 |
+---+---+---+---+---+---+---+---+
| 4 | 3 | 4 | 3 | 4 | 5 | 4 | 5 |
+---+---+---+---+---+---+---+---+
| 3 | 4 | 3 | 4 | 3 | 4 | 5 | 4 |
+---+---+---+---+---+---+---+---+
| 2 | 3 | 2 | 3 | 4 | 3 | 4 | 5 |
+---+---+---+---+---+---+---+---+
| 3 | 2 | 3 | 2 | 3 | 4 | 3 | 4 |
+---+---+---+---+---+---+---+---+
| 2 | 1 | 4 | 3 | 2 | 3 | 4 | 5 |
+---+---+---+---+---+---+---+---+
| 3 | 4 | 1 | 2 | 3 | 4 | 3 | 4 |
+---+---+---+---+---+---+---+---+
| 0 | 3 | 2 | 3 | 2 | 3 | 4 | 5 |
+---+---+---+---+---+---+---+---+
左下角的0表示起始位置,走到右上角需要6步。感觉上不是很难实现,我的做法是用一个数组记录跳过的格子,以上图为例,初始的时候数组里只有元素(0,0),然后看(0,0)可以走到哪些格子里去,这里是(1,2)和(2,1),把他们标成1,接着在这两个点的基础上在分别看他们能走到哪些格子上去,标成2,依次类推直到填满所有的格子。注意,每次马都只往空格子里跳,这样(1,2)就不会跳回(0,0)里去。当然,马不能跳出边界。

注:跳马的条件我最初设置了两个,另外一个是比自己的起跳位置大2,就是说找到了一条更好的路径,比如某个格子已经标上了10,接着有一个马要从标着8的位置上跳过来,这样就有了一条9的路径。后面的这个条件纯粹是直觉上的可能性,但实际上似乎是多余的条件,即使几百×几百的棋盘都不会有这种情况。仔细再想想好像也是,按我遍历的方法是先找到2步可以到的格子然后才开始走第三步,怎么可能会出现worse的路径反而先被标记的情况呢?

这个plan并没有记住中间步骤,所以要是问右上角6步究竟是哪6步,程序就不知道了,不过既然有了这个path plan,要知道最优路径也不难,最简单的办法就是在这个plan上搜索一下,按不断向目标接近的原则稍微剪一下枝,马上就能得到走到任意一格的最优路径了。

顺便提一下,knight有一个不输给8queen的问题,Knight's tour,类似哈密尔顿回路,把所有的格子跳一遍后回到起点。这里有两篇mathworld上的文章:

http://mathworld.wolfram.com/KnightsTour.html

http://mathworld.wolfram.com/news/2003-08-06/magictours/


<update>:
跳到最后的时候往往会发生跳错格子的情况,比如第5步跳到(6,7)或者(7,6)里去,这样就郁闷了。琢磨了老半天没有好办法。只好用笨办法。先列出一个点可能的下一步,然后计算它们到目标的距离,排序,取最短的两条出来,再取这两个点所有可能下一步,算距离,排序。。。直至终点。把这些中间点统统记下来,从终点往回检查,去掉不对的点就可以找到一条路径了。

所谓不对的点是指这样的点,比如从(0,0)到(0,7),(0,0)出发可以到(1,2)和(2,1),但下一步取的是(0,4)和(2,4),这样虽然(2,1)被记录下来了但这个点实际上是没用的。这里有个特殊情况,从(0,0)到(5,4),两条路径都是正确的,这时随便取一条就可以了。

p.s. 多插一句,我是用java实现的,java的迭代器似乎不能反向迭代啊?还要我自己reverse序列。

另外,当初也没多想,坐标就用数组[]来表示,后来往容器里填也ok,可是最后却发现一个小问题,郁闷了我老半天,基本数组也是对象,和primitive是有本质区别的,所以象这样的代码一定是false。看来我是java用太久,要是cpp,怎么都不会在这个上面摔跟头。
List<int[]> trace1 = new ArrayList<int[]>(); int[] abc = {1,2}; int[] def = {1,2}; trace1.add(abc);  if(trace1.contains(def)){ System.out.println("true"); }else  System.out.println("false"); 
原创粉丝点击