银河

SKYIV STUDIO

  博客园 :: 首页 ::  ::  :: 订阅 订阅 :: 管理 ::
  105 随笔 :: 2 文章 :: 753 评论 :: 22 引用
    这是“使用 C# 开发智能手机软件:推箱子”系列文章的第五篇。在这篇文章中,介绍经过改进后的  Common/FindPath.cs 源程序文件。也就是说,已经实现了“使用 C# 开发智能手机软件:推箱子(四)”的第二个评论中的想法,将地图 ushort[,] map 改为 byte[,] map 了。下面就是改进后的 FindPath 类:
 1 using System;
 2 using System.Drawing;
 3 using System.Collections.Generic;
 4 
 5 namespace Skyiv.Ben.PushBox.Common
 6 {
 7   /// <summary>
 8   /// 寻找最短路线
 9   /// </summary>
10   static class FindPath
11   {
12     static Size[] offsets = { new Size(01), new Size(10), new Size(0-1), new Size(-10) };
13     static Direction[] directions = { Direction.South, Direction.East, Direction.North, Direction.West };
14 
15     /// <summary>
16     /// 寻找最短路线
17     /// </summary>
18     /// <param name="map">地图</param>
19     /// <param name="from">出发点</param>
20     /// <param name="to">目的地</param>
21     /// <returns>最短路线</returns>
22     public static Queue<Direction> Seek(byte[,] map, Point from, Point to)
23     {
24       Queue<Direction> moveQueue = new Queue<Direction>(); // 路线
25       int value; // 与离目的地距离相关的一个量,变化规律:  => 2 => 1 => 3 => 2 => 1 => 3 => 2 => 1
26       if (Seek(map, to, out value)) // 找到了一条路线
27       {
28         Point here = from; // 出发点(即工人的位置)
29         Point nbr = new Point(); // 四周的邻居
30         for (value = (value + 1% 3 + 1; here != to; value = (value + 1% 3 + 1// 逐步走向目的地
31         {
32           for (int i = 0; i < offsets.Length; i++)
33           {
34             nbr = Fcl.Add(here, offsets[i]); // 开始寻找四周的邻居
35             if (Block.Value(map[nbr.Y, nbr.X]) == value) // 就往这个方向走
36             {
37               moveQueue.Enqueue(directions[i]); // 路线向目的地延伸一步
38               break;
39             }
40           }
41           here = nbr; // 继续前进
42         }
43       }
44       Block.CleanAllMark(map); // 清除所有标志,恢复现场
45       return moveQueue; // 所寻找的路线,如果无法到达目的地则为该路线的长度为零
46     }
47 
48     /// <summary>
49     /// 寻找最短路线,使用广度优先搜索
50     /// </summary>
51     /// <param name="map">地图</param>
52     /// <param name="to">目的地</param>
53     /// <param name="value">输出:搜索完成时标记的值</param>
54     /// <returns>是否成功</returns>
55     static bool Seek(byte[,] map, Point to, out int value)
56     {
57       Queue<Point> q = new Queue<Point>();
58       Block.Mark(ref map[to.Y, to.X], 1); // 从目的地开始往回寻找出发点,目的地标记为1
59       Point nbr = Point.Empty; // 四周的邻居
60       for (; ; )
61       {
62         value = Block.Value(map[to.Y, to.X]) % 3 + 1// 与离目的地距离相关的一个量,用作标记,变化规律:
63         for (int i = 0; i < offsets.Length; i++)      // 1 => 2 => 3 => 1 => 2 => 3 => 1 => 2 => 3 => 
64         {
65           nbr = Fcl.Add(to, offsets[i]); // 开始寻找四周的邻居
66           if (Block.IsMan(map[nbr.Y, nbr.X])) break// 到达出发点(即工人的位置)
67           if (Block.IsBlank(map[nbr.Y, nbr.X])) // 可以走的路
68           {
69             Block.Mark(ref map[nbr.Y, nbr.X], value); // 标记,防止以后再走这条路
70             q.Enqueue(nbr); // 加入队列,等待以后继续寻找
71           }
72         }
73         if (Block.IsMan(map[nbr.Y, nbr.X])) break// 到达出发点
74         if (q.Count == 0return false// 无法到达出发点
75         to = q.Dequeue(); // 出队,继续寻找,这是广度优先搜索,因为前面已经把四周能够走的路全部加入队列中了.
76       }
77       return true// 找到一条路线
78     }
79   }
80 }
81 
    上面的源程序已经对搜索算法作了很好的注释。我们还是来看两幅反映算法运行时地图上各标记值的图片吧:

    图中,带圆圈的红色的数字“1”是“目的地”,也就是算法开始的地方,因为该算法是从目的地开始往回寻找出发点。在改进后的算法中,标记值始终是在“1、2、3”这三个数中循环,而不是象以前一样一直增大。在图中,算法按“红、黄、绿、蓝、粉红、青”的顺序从目的地往外搜索,直到遇到“工人”而返回成功,或者填满能够到达的空地而返回失败。
    算法经过这次改进,搜索的距离就不象原来一样受限于 8192 步。而且也将地图所占用的内存空间减少到原来的二分之一。
    这次改进,除了仔细重写了 FindPath 类以外,程序其余地方只是将所有的“ushort”替换为“byte”就行了,因为本程序只在涉及地图的地方使用过“ushort”。

上一篇:使用 C# 开发智能手机软件:推箱子(四)
下一篇:使用 C# 开发智能手机软件:推箱子(六)
返回目录
posted on 2007-08-19 21:16 银河 阅读(2390) 评论(14)  编辑 收藏 所属分类: .NET Compact Framework

评论

#1楼  2007-08-19 22:01 二手的程序员      
你和李银河是什么关系,哈哈,沙发
  回复  引用  查看    

#2楼  2007-08-19 22:59 空间/IV      

http://www.cnblogs.com/yaotong/archive/2007/01/27/632049.html

二楼楼主的这篇文章有些意思,哈哈。

楼主和李银河没关系。


  回复  引用  查看    

#3楼 [楼主] 2007-08-19 23:14 银河      
@空间/IV
@二手的程序员
“父系血统的生物学基础”很趣,特别是最后一句话。
我和李银河没有关系。


  回复  引用  查看    

#4楼  2007-08-20 10:36 空间/IV      
建议增加两个单元格状态(这样就要用4个二进位表示状态了):

Block.Box2; // 箱子放在地上(被选中)
Block.Box3; // 箱子放在槽上(被选中)

还要考虑图形中怎么表示,在被选中的箱子上画一个红色的圆圈?

单击某个箱子就切换其选中状态,一个时刻最多只能选中一个箱子,选中某个箱子会导致先前被选中的其他箱子取消选中。

如果没有箱子被选中,单击“空地”或“槽”,就表示试图让工人走到那个位置。

如果有箱子被选中,单击“空地”或“槽”,且工人可以把被选中的箱子按直线路线推到那个位置,则先让工人走到合适位置(必要时),然后推箱子到指定位置,并取消箱子的选中状态。否则表示试图让工人走到指定位置,且不改变箱子的选中状态。

  回复  引用  查看    

#5楼  2007-08-20 10:57 空间/IV      
也就是说,要推某个箱子,不必先走到那个箱子后面,而是先选中箱子,然后单击目的地就好了(目的地必须是直线可到达的)。

考虑到经常要连续推同一个箱子,似乎推箱子到指定位置后,不取消箱子的选中状态更好些。


  回复  引用  查看    

#6楼 [楼主] 2007-08-20 11:04 银河      
@空间/IV
你的这个想法有意思。
虽然需要四个二进位表示状态,但不影响磁盘上的数据文件的内容,因为这两个新的单元格状态仅需要运行时在内存中使用。而且改进后的搜索算法只需要二个二进位,一个字节也完全够用。这个想法实现起来也不难。
但是,如果采用这个想法,想要推箱子就一定要先选中箱子,比起不想推着箱子时要先往旁边移动一下,是不是有得不偿失?
我以前只能在计算机上运行的旧版本是用鼠标右键来表示要推着箱子的,但是在智能手机上可没有鼠标右键可用。

  回复  引用  查看    

#7楼  2007-08-20 11:13 空间/IV      
总的说来,先选中箱子更节省操作,因为推选中的箱子时,工人会自动走到合适的位置(被选中的箱子的后面),这样就大大减少了移动工人的操作。

以箱子为中心考虑问题,思考时不必考虑怎么移动工人,只要考虑怎么推动箱子就好了,说不定更符合推箱子这个游戏的本意。


  回复  引用  查看    

#8楼  2007-08-20 11:34 空间/IV      
另建议:在“槽”中的箱子不仅用颜色加以标识,最好是在箱子上画一个小小的“OK”或画一面小红旗,被选中的箱子则画一个蓝色的圆圈。这样在单色的显示设备上也能用,且对色盲人士是友好的。


  回复  引用  查看    

#9楼 [楼主] 2007-08-20 13:58 银河      
@空间/IV
> 另建议:在“槽”中的箱子不仅用颜色加以标识,最好是在箱子上画一个小小的“OK”或画一面小红旗,

这个建议非常好。
而且在箱子上画一面小红旗并不需要修改 cs 程序,只需要修改
Images/PushBox12.bmp
Images/PushBox16.bmp
Images/PushBox20.bmp
Images/PushBox24.bmp
这四个 bmp 图像文件就可以了。

至于以箱子为中心的问题,由于操作习惯上改变太大,还是再想想看,以后再说。
  回复  引用  查看    

#10楼  2007-08-20 14:21 gzj [未注册用户]
最流行的vc6.0的那个开源推箱子程序界面比这个好看,直接把那个
代码拿来改更好。
  回复  引用    

#11楼 [楼主] 2007-08-20 15:23 银河      
@gzj
> 最流行的vc6.0的那个开源推箱子程序界面比这个好看,直接把那个代码拿来改更好。
到哪里下载?能给个 URL 吗?
我在 google 上搜索一下,找到一个 用 VC++6.0 开发的推箱子游戏:
http://www.vckbase.com/code/listcode.asp?mclsid=7&sclsid=721&page=2
不知您说的是不是这个?如果是这个,界面和功能都不算很好。

  回复  引用  查看    

#12楼  2007-08-20 16:46 钝刀。 [未注册用户]
至少有两个字相同,哈哈,
  回复  引用    

#13楼  2007-08-20 17:22 二手的程序员      
@银河
其实李银河的观点是正确的,但在中国实现还需要一个很长的过程,搞不好会出现很多问题。
  回复  引用  查看    


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-10-25 07:58 编辑过
"五向定位"职业成长路线公开课(上海、南京、大连)
Google站内搜索


相关链接: