算法我就不多说了,上述文章里面讲得很清楚。直接看我做的小软件吧。
刚开始初始化一个迷宫,一般是走不通的,但你点击一个格子它就会变色,由路变为墙,或由墙变为路。
点击“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