使用 C# 开发智能手机软件:推箱子(五)

    这是“ 使用 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( 0 1 ),  new  Size( 1 0 ),  new  Size( 0 - 1 ),  new  Size( - 1 0 ) };
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  ==   0 return   false //  无法到达出发点
75          to  =  q.Dequeue();  //  出队,继续寻找,这是广度优先搜索,因为前面已经把四周能够走的路全部加入队列中了.
76        }
77         return   true //  找到一条路线
78      }
79    }
80  }
81 
    上面的源程序已经对搜索算法作了很好的注释。我们还是来看两幅反映算法运行时地图上各标记值的图片吧:

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

上一篇: 使用 C# 开发智能手机软件:推箱子(四)
下一篇: 使用 C# 开发智能手机软件:推箱子(六)
返回目录
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值