吴昊品游戏核心算法 Round 16 —— 吴昊教你玩口袋妖怪 第九弹 冰系道馆

 

  道馆之战!!!这一次,道馆由电系变为了冰系,和龙系的道馆不一样,冰系的道馆有冰系的规定。如图所示,一共有三层,上面一层总是比下面一层要复杂一些。在冰系道馆中,有如下的两个规则:(1)我们不会在冰面上划来划去了,但是冰是会破裂的,也就是说,你每在上面走过之后,就不能继续在上面行走了(2)你只有走完了这一层的所有冰块,上面一层的门才会向你开启,直到最后的道馆馆主。

  网上口袋妖怪大神的策略:

  首先,我们还是来看一看那些大神们是来解决这一问题的:

 

  如图,这是中间一层的行走方式,貌似也只有这一种情况了。起点位于圆圈的地方。由于右边有一个石头遮掩着,而左边没有,所以我们考虑从左边开始行走,这样,我们有了第一条原则,就是,看一行或者一列,如果沿着这一行或者这一列前进的方向上没有岩石的阻挡而可以直接到达底部的话(如果那一点已经走过,则可以标记为石头),那么就往这个方向走。这当然是一个贪心的想法,其正确性没有得到验证,而且,有时候是不行的。比如,如果主角在中央,而其左边和右边都没有石头的话,则无法选择一个稳定的一条路了。

  我们的AI策略:

  我们的AI策略如下,考虑到我在Round 13中,也就是吴昊教你走迷宫的另一种变式中的一个技法,这里只需要略作更改,即可。我们不妨对比一下两者的区别,可以得到如下的结论:

  A)这里没有定式炸弹,也没有定时炸弹的重置器,问题会简单许多。

  B)与之不同的是,当经过了一个冰块之后,这里的冰块会发生破裂,也就是以后就不能经过了,于是,这里必须标记一个数字,以区别冰块破裂之前与破裂之后的区别,所以,我们将破裂之前的冰块以数字1标识而破裂之后的冰块以数字5来标识。

  C)终点的条件不同,在Round  13中,终点的条件为在定时炸弹还没有爆炸之前逃离出口,而在我们这里,终点的条件为到达终点时,这一区域内的所有的冰块全部破裂。

  D)这里有三层,也就是三种不同的地图,我们也可以理解成,这三个样例只有都满足条件,我们才能见到最后的BOSS

  有了以下的分析,我们这里做一个约定,用一个int类型的二维数组来表征地图,数字2代表我们的主角小智的起点,3代表终点,4代表障碍物,1代表还没有破裂的冰块,而当冰块破裂之后,我们将其重新设置为数字5。这样,对于每一个输入的地图,我们都可以判断出是否可以最终达到终点(如果要拿到具体的路径的话,我们可以设置一个标记,当然,这很容易实现了,这里略去)。

  Solve:

  1 #include<iostream>
  2 
  3  //这里还是运用队列容器来实现  
  4 
  5  #include<queue>  
  6 
  7  using namespace std;    
  8 
  9  
 10 
 11  //首先是地图map[][],n,m为地图的实际的长和宽,(si,sj)为开始的点,mins
 12 
 13  int map[9][9],n,m,si,sj;
 14 
 15  bool success;  
 16 
 17  
 18 
 19  //方向数组
 20 
 21  int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};  
 22 
 23  
 24 
 25  //障碍物的总数
 26 
 27  int w;
 28 
 29  
 30 
 31  struct node  
 32 
 33  {  
 34 
 35    //cnt走格子数
 36 
 37    int x,y,cnt; 
 38 
 39  };  
 40 
 41  
 42 
 43  node f;  
 44 
 45  
 46 
 47  void bfs()  
 48 
 49  {  
 50 
 51    f.x=si;
 52 
 53    f.y=sj;
 54 
 55    //已经走过的格子数为0  
 56 
 57    f.cnt=0;
 58 
 59    queue<node> q;  
 60 
 61    q.push(f); 
 62 
 63    //如果队列整个空了,则退出  
 64 
 65    while(!q.empty())  
 66 
 67    {  
 68 
 69      node t=q.front();  
 70 
 71      map[t.x][t.y]=5;
 72 
 73      q.pop();  
 74 
 75      if(map[t.x][t.y]==3)  
 76 
 77      {  
 78 
 79        //找到终点了,如果还剩余时间的话,将已经花费的时间输出
 80 
 81        if(t.cnt==(n*m-w))  
 82 
 83        {  
 84 
 85          success=true;  
 86 
 87          return;  
 88 
 89        }  
 90 
 91        else continue;  
 92 
 93      }  
 94 
 95      for(int k=0;k<4;k++)  
 96 
 97      {  
 98 
 99        //定义一个NEXT结点,这个在前面的吴昊系列已经阐述过了
100 
101        node b;  
102 
103        b.x=t.x+dir[k][0];  
104 
105        b.y=t.y+dir[k][1];
106 
107        //将已经花费的时间++,而剩余的时间--  
108 
109        b.cnt=t.cnt+1;     
110 
111        /*
112 
113          入队的条件,这里有如下一些条件:
114 
115          (1)首先,必须在迷宫的范围之内
116 
117          (2)这个位置不是一堵墙 
118 
119          (3)这个位置还没有被走过
120 
121        */
122 
123        if(b.x<=n&&b.x>0&&b.y<=m&&b.y>0&&map[b.x][b.y]!=5)  
124 
125        {  
126 
127          q.push(b);  
128 
129        }  
130 
131      }  
132 
133    }  
134 
135  }  
136 
137  
138 
139  int main()  
140 
141  {  
142 
143    int t;
144 
145    //样例的总数  
146 
147    cin>>t;  
148 
149    while(t--)  
150 
151    {
152 
153      w=0;
154 
155      //地图的长与宽
156 
157      cin>>n>>m;  
158 
159      for(int i=1;i<=n;i++)  
160 
161      {  
162 
163        for(int j=1;j<=m;j++)  
164 
165        {
166 
167          //将地图中的元素进行分类
168 
169          cin>>map[i][j];  
170 
171          if(map[i][j]==2)
172 
173          {  
174 
175            si=i;
176 
177            sj=j;     
178 
179          }  
180 
181          if(map[i][j]==4)
182 
183          {
184 
185            w++;               
186 
187          }
188 
189        }  
190 
191      }   
192 
193      bfs();  
194 
195      if(success==true)  
196 
197        cout<<"success"<<endl;  
198 
199      else cout<<"false"<<endl;  
200 
201    }
202 
203    return 0;  
204 
205  }

  最后,我还是废话一句吧!口袋妖怪中,这种冰面破碎的场景并不一定局限在道馆战役中,有时候,它甚至和龙系道馆的某些场景结合起来,比如下面一个场景,我想大家应该都还印象深刻吧!

如图所示,当你踩着一辆自行车的时候,首先,你不得不滑动,只能借助障碍物进行移动,另外,在踩过的地面上,如果你再踩一脚的话,则会破碎,你不得不陷入进去。所以,我说这一场景其实是冰系道馆场景与冰系道馆场景的完美结合,也是任天堂的口袋妖怪系列游戏的魅力!

 

posted on 2013-04-01 11:34  吴昊系列  阅读(975)  评论(0编辑  收藏  举报

导航