用遗传算法走出迷宫(Java版)

算法我就不多说了,上述文章里面讲得很清楚。直接看我做的小软件吧。

刚开始初始化一个迷宫,一般是走不通的,但你点击一个格子它就会变色,由路变为墙,或由墙变为路。

点击“Run"之后,遗传算法在后台运行,把出路给你找出来,然后在迷宫上把路径标出来。

点击"Evolution Chart"查看进入情况,即每一代中最优的个体的适应度是多少。

点击"Options"对遗传算法的参数进行重新设置。

换用更大规模的迷宫进行实验。

FAIL了,查看一下进化情况。

当然也有可能成功

对于遗传找出的结果如果存在原路返回的情况,我的代码可以检测出来,将这段路径剪去。但是如果出现绕圈子的情况检测不出来,比如下面的结果明显就是绕圈子了

下面给出核心算法GA类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
package  GA;
 
import  java.util.ArrayList;
import  java.util.Collections;
import  java.util.Iterator;
import  java.util.LinkedList;
import  java.util.List;
import  java.util.Random;
 
/**
  * 用遗传算法走迷宫
  *
  * @author Orisun
  *
  */
public  class  GA {
 
     int  gene_len; // 基因长度
     int  chrom_len; // 染色体长度
     int  population; // 种群大小
     double  cross_ratio; // 交叉率
     double  muta_ratio; // 变异率
     int  iter_limit; // 最多进化的代数
     List< boolean []> individuals; // 存储当代种群的染色体
 
     Labyrinth labyrinth;
     int  width;      //迷宫一行有多少个格子
     int  height;     //迷宫有多少行
 
     public  class  BI {
         double  fitness;
         boolean [] indv;
 
         public  BI( double  f, boolean [] ind) {
             fitness = f;
             indv = ind;
         }
 
         public  double  getFitness() {
             return  fitness;
         }
 
         public  boolean [] getIndv() {
             return  indv;
         }
     }
 
     List<BI> best_individual; // 存储每一代中最优秀的个体
 
     public  GA(Labyrinth labyrinth) {
         this .labyrinth=labyrinth;  
         this .width = labyrinth.map[ 0 ].length;
         this .height = labyrinth.map.length;
         chrom_len = 4  * (width+height);
         gene_len = 2 ;
         population = 20 ;
         cross_ratio = 0.83 ;
         muta_ratio = 0.002 ;
         iter_limit = 300 ;
         individuals = new  ArrayList< boolean []>(population);
         best_individual = new  ArrayList<BI>(iter_limit);
     }
 
     public  int  getWidth() {
         return  width;
     }
 
     public  void  setWidth( int  width) {
         this .width = width;
     }
 
     public  double  getCross_ratio() {
         return  cross_ratio;
     }
 
     public  List<BI> getBest_individual() {
         return  best_individual;
     }
 
     public  Labyrinth getLabyrinth() {
         return  labyrinth;
     }
     public  void  setLabyrinth(Labyrinth labyrinth) {
         this .labyrinth = labyrinth;
     }
     public  void  setChrom_len( int  chrom_len) {
         this .chrom_len = chrom_len;
     }
 
     public  void  setPopulation( int  population) {
         this .population = population;
     }
 
     public  void  setCross_ratio( double  cross_ratio) {
         this .cross_ratio = cross_ratio;
     }
 
     public  void  setMuta_ratio( double  muta_ratio) {
         this .muta_ratio = muta_ratio;
     }
 
     public  void  setIter_limit( int  iter_limit) {
         this .iter_limit = iter_limit;
     }
 
     // 初始化种群
     public  void  initPopulation() {
         Random r = new  Random(System.currentTimeMillis());
         for  ( int  i = 0 ; i < population; i++) {
             int  len = gene_len * chrom_len;
             boolean [] ind = new  boolean [len];
             for  ( int  j = 0 ; j < len; j++)
                 ind[j] = r.nextBoolean();
             individuals.add(ind);
         }
     }
 
     // 交叉
     public  void  cross( boolean [] arr1, boolean [] arr2) {
         Random r = new  Random(System.currentTimeMillis());
         int  length = arr1.length;
         int  slice = 0 ;
         do  {
             slice = r.nextInt(length);
         } while  (slice == 0 );
         if  (slice < length / 2 ) {
             for  ( int  i = 0 ; i < slice; i++) {
                 boolean  tmp = arr1[i];
                 arr1[i] = arr2[i];
                 arr2[i] = tmp;
             }
         } else  {
             for  ( int  i = slice; i < length; i++) {
                 boolean  tmp = arr1[i];
                 arr1[i] = arr2[i];
                 arr2[i] = tmp;
             }
         }
     }
 
     // 变异
     public  void  mutation( boolean [] individual) {
         int  length = individual.length;
         Random r = new  Random(System.currentTimeMillis());
         individual[r.nextInt(length)] ^= false ;
     }
 
     // 轮盘法选择下一代,并返回当代最高的适应度值
     public  double  selection() {
         boolean [][] next_generation = new  boolean [population][]; // 下一代
         int  length = gene_len * chrom_len;
         for  ( int  i = 0 ; i < population; i++)
             next_generation[i] = new  boolean [length];
         double [] cumulation = new  double [population];
         int  best_index = 0 ;
         double  max_fitness = getFitness(individuals.get(best_index));
         cumulation[ 0 ] = max_fitness;
         for  ( int  i = 1 ; i < population; i++) {
             double  fit = getFitness(individuals.get(i));
             cumulation[i] = cumulation[i - 1 ] + fit;
             // 寻找当代的最优个体
             if  (fit > max_fitness) {
                 best_index = i;
                 max_fitness = fit;
             }
         }
         Random rand = new  Random(System.currentTimeMillis());
         for  ( int  i = 0 ; i < population; i++)
             next_generation[i] = individuals.get(findByHalf(cumulation,
                     rand.nextDouble() * cumulation[population - 1 ]));
         // 把当代的最优个体及其适应度放到best_individual中
         BI bi = new  BI(max_fitness, individuals.get(best_index));
         // printPath(individuals.get(best_index));
         //System.out.println(max_fitness);
         best_individual.add(bi);
         // 新一代作为当前代
         for  ( int  i = 0 ; i < population; i++)
             individuals.set(i, next_generation[i]);
         return  max_fitness;
     }
 
     // 折半查找
     public  int  findByHalf( double [] arr, double  find) {
         if  (find < 0  || find == 0  || find > arr[arr.length - 1 ])
             return  - 1 ;
         int  min = 0 ;
         int  max = arr.length - 1 ;
         int  medium = min;
         do  {
             if  (medium == (min + max) / 2 )
                 break ;
             medium = (min + max) / 2 ;
             if  (arr[medium] < find)
                 min = medium;
             else  if  (arr[medium] > find)
                 max = medium;
             else
                 return  medium;
 
         } while  (min < max);
         return  max;
     }
 
     // 计算适应度
     public  double  getFitness( boolean [] individual) {
         int  length = individual.length;
         // 记录当前的位置,入口点是(1,0)
         int  x = 1 ;
         int  y = 0 ;
         // 根据染色体中基因的指导向前走
         for  ( int  i = 0 ; i < length; i++) {
             boolean  b1 = individual[i];
             boolean  b2 = individual[++i];
             // 00向左走
             if  (b1 == false  && b2 == false ) {
                 if  (x > 0  && labyrinth.map[y][x - 1 ] == true ) {
                     x--;
                 }
             }
             // 01向右走
             else  if  (b1 == false  && b2 == true ) {
                 if  (x + 1  < width && labyrinth.map[y][x + 1 ] == true ) {
                     x++;
                 }
             }
             // 10向上走
             else  if  (b1 == true  && b2 == false ) {
                 if  (y > 0  && labyrinth.map[y - 1 ][x] == true ) {
                     y--;
                 }
             }
             // 11向下走
             else  if  (b1 == true  && b2 == true ) {
                 if  (y + 1  < height && labyrinth.map[y + 1 ][x] == true ) {
                     y++;
                 }
             }
         }
         int  n = Math.abs(x - labyrinth.x_end) + Math.abs(y -labyrinth.y_end) + 1 ;
//      if(n==1)
//          printPath(individual);
         return  1.0  / n;
     }
 
     // 运行遗传算法
     public  boolean  run() {
         // 初始化种群
         initPopulation();
         Random rand = new  Random(System.currentTimeMillis());
         boolean  success = false ;
         while  (iter_limit-- > 0 ) {
             // 打乱种群的顺序
             Collections.shuffle(individuals);
             for  ( int  i = 0 ; i < population - 1 ; i += 2 ) {
                 // 交叉
                 if  (rand.nextDouble() < cross_ratio) {
                     cross(individuals.get(i), individuals.get(i + 1 ));
                 }
                 // 变异
                 if  (rand.nextDouble() < muta_ratio) {
                     mutation(individuals.get(i));
                 }
             }
             // 种群更替
             if  (selection() == 1 ) {
                 success = true ;
                 break ;
             }
         }
         return  success;
     }
 
//  public static void main(String[] args) {
//      GA ga = new GA(8, 8);
//      if (!ga.run()) {
//          System.out.println("没有找到走出迷宫的路径.");
//      } else {
//          int gen = ga.best_individual.size();
//          boolean[] individual = ga.best_individual.get(gen - 1).indv;
//          System.out.println(ga.getPath(individual));
//      }
//  }
 
     // 根据染色体打印走法
     public  String getPath( boolean [] individual) {
         int  length = individual.length;
         int  x = 1 ;
         int  y = 0 ;
         LinkedList<String> stack= new  LinkedList<String>();
         for  ( int  i = 0 ; i < length; i++) {
             boolean  b1 = individual[i];
             boolean  b2 = individual[++i];
             if  (b1 == false  && b2 == false ) {
                 if  (x > 0  && labyrinth.map[y][x - 1 ] == true ) {
                     x--;
                     if (!stack.isEmpty() && stack.peek()== "右" )
                         stack.poll();
                     else
                         stack.push( "左" );
                 }
             } else  if  (b1 == false  && b2 == true ) {
                 if  (x + 1  < width && labyrinth.map[y][x + 1 ] == true ) {
                     x++;
                     if (!stack.isEmpty() && stack.peek()== "左" )
                         stack.poll();
                     else
                         stack.push( "右" );
                 }
             } else  if  (b1 == true  && b2 == false ) {
                 if  (y > 0  && labyrinth.map[y - 1 ][x] == true ) {
                     y--;
                     if (!stack.isEmpty() && stack.peek()== "下" )
                         stack.poll();
                     else
                         stack.push( "上" );
                 }
             } else  if  (b1 == true  && b2 == true ) {
                 if  (y + 1  < height && labyrinth.map[y + 1 ][x] == true ) {
                     y++;
                     if (!stack.isEmpty() && stack.peek()== "上" )
                         stack.poll();
                     else
                         stack.push( "下" );
                 }
             }
         }
         StringBuilder sb= new  StringBuilder(length/ 4 );
         Iterator<String> iter=stack.descendingIterator();
         while (iter.hasNext())
             sb.append(iter.next());
         return  sb.toString();
     }
}

  

原文来自:博客园(华夏35度)http://www.cnblogs.com/zhangchaoyang 作者:Orisun
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值