Mercurial > repo
comparison interps/bf_txtgen/textgen.java @ 996:859f9b4339e6
<Gregor> tar xf egobot.tar.xz
author | HackBot |
---|---|
date | Sun, 09 Dec 2012 19:30:08 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
995:6883f5911eb7 | 996:859f9b4339e6 |
---|---|
1 //==================================================================== | |
2 // TEXTGEN -- BrainF*** Genetic Text Generator | |
3 // textgen.java | |
4 // Copyright (C) 2003, 2004 by Jeffry Johnston | |
5 // Version 0.20 | |
6 // | |
7 // This program is free software; you can redistribute it and/or | |
8 // modify it under the terms of the GNU General Public License as | |
9 // published by the Free Software Foundation. See the file LICENSE | |
10 // for more details. | |
11 // | |
12 // Online resource used: | |
13 // http://www.genetic-programming.com/gpflowchart.html | |
14 // | |
15 // I have not read any books and have seen very little information | |
16 // online about GP implementation. Any suggestions are most welcome. | |
17 // | |
18 // Inspiration: | |
19 // 111-byte "Hello World!" with newline (assumed optimal) | |
20 // ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++. | |
21 // <<+++++++++++++++.>.+++.------.--------.>+.>. | |
22 // | |
23 // Version history: | |
24 // 0.20 11 Aug 2004 Added -i and -o options | |
25 // 0.10 01 Dec 2003 Initial release | |
26 //==================================================================== | |
27 | |
28 import java.io.*; | |
29 import java.util.*; | |
30 | |
31 //******************************************************************** | |
32 // textgen | |
33 //******************************************************************** | |
34 public class textgen { | |
35 static final String VERSION = "0.20"; | |
36 static Random r = new Random(); | |
37 | |
38 //------------------------------------------------------------------ | |
39 // main | |
40 //------------------------------------------------------------------ | |
41 public static void main(String[] cmdline) { | |
42 int terms = 4, population = 500, generations = 0; | |
43 String text = "Default text?!"; | |
44 double toppercent = 0.10; | |
45 String fileout = null; | |
46 | |
47 // display copyright text | |
48 System.out.println("TEXTGEN BrainF*** Genetic Text Generator, version " + VERSION + "."); | |
49 System.out.println("Copyright (c) 2003 Jeffry Johnston."); | |
50 System.out.println(); | |
51 | |
52 // process command line | |
53 for (int n = 0; ; n++) { | |
54 try { | |
55 if (cmdline[n].equals("-?") || cmdline[n].equals("/?") || cmdline[n].equals("--?") | |
56 || cmdline[n].equals("--help") ) { | |
57 usage(); | |
58 System.exit(0); | |
59 } else if (cmdline[n].equalsIgnoreCase("-i")) { | |
60 // open file | |
61 DataInputStream filein = null; | |
62 try { | |
63 filein = new DataInputStream(new FileInputStream(cmdline[n + 1])); | |
64 } catch (FileNotFoundException e) { | |
65 System.out.println("Error opening input file. File not found"); | |
66 System.exit(1); | |
67 } | |
68 // read file | |
69 byte[] data = null; | |
70 int size = 0; | |
71 try { | |
72 size = filein.available(); | |
73 data = new byte[size]; | |
74 filein.readFully(data); | |
75 } catch (IOException e) { | |
76 System.out.println("Error reading input file."); | |
77 System.exit(1); | |
78 } | |
79 // close file | |
80 try { | |
81 filein.close(); | |
82 } catch (IOException e) { | |
83 System.out.println("Error closing input file."); | |
84 System.exit(1); | |
85 } | |
86 try { | |
87 text = new String(data, "ISO-8859-1"); | |
88 } catch (UnsupportedEncodingException e) { | |
89 System.out.println("This program requires ISO-8859-1 character set support."); | |
90 } | |
91 n++; | |
92 } else if (cmdline[n].equalsIgnoreCase("-o")) { | |
93 fileout = cmdline[n + 1]; | |
94 n++; | |
95 } else if (cmdline[n].equalsIgnoreCase("-g")) { | |
96 generations = Integer.parseInt(cmdline[n + 1]); | |
97 if (generations < 1) { | |
98 System.out.println("Must have at least 1 generation."); | |
99 System.exit(1); | |
100 } | |
101 n++; | |
102 } else if (cmdline[n].equalsIgnoreCase("-t")) { | |
103 terms = Integer.parseInt(cmdline[n + 1]); | |
104 if (terms < 1) { | |
105 System.out.println("Must have at least 1 term."); | |
106 System.exit(1); | |
107 } | |
108 n++; | |
109 } else if (cmdline[n].equalsIgnoreCase("-p")) { | |
110 population = Integer.parseInt(cmdline[n + 1]); | |
111 if (terms < 2) { | |
112 System.out.println("Must have population of at least 10."); | |
113 System.exit(1); | |
114 } | |
115 n++; | |
116 } else if (cmdline[n].equalsIgnoreCase("-%")) { | |
117 int tp = Integer.parseInt(cmdline[n + 1]); | |
118 if (tp < 0 || tp > 100) { | |
119 System.out.println("Percentage out of range (0, 100)."); | |
120 System.exit(1); | |
121 } | |
122 toppercent = (double) tp / 100; | |
123 n++; | |
124 } else { | |
125 text = cmdline[n]; | |
126 if (text.charAt(0) == '\"') { | |
127 text = text.substring(1); | |
128 } | |
129 if (text.charAt(text.length() - 1) == '\"') { | |
130 text = text.substring(0, text.length()); | |
131 } | |
132 } | |
133 } catch (ArrayIndexOutOfBoundsException e) { | |
134 break; | |
135 } catch (NumberFormatException e) { | |
136 System.out.println("Invalid number"); | |
137 System.exit(1); | |
138 } | |
139 } | |
140 int top = (int) (toppercent * population); | |
141 int bottom = population - top; | |
142 | |
143 if (fileout == null) { | |
144 System.out.println("Text: \"" + text + "\""); | |
145 } | |
146 System.out.print("Generations: "); | |
147 if (generations == 0) { | |
148 System.out.println("Infinite"); | |
149 } else { | |
150 System.out.println(generations); | |
151 } | |
152 System.out.println("Terms: " + terms); | |
153 System.out.println("Population: " + population); | |
154 System.out.println("Top %: " + toppercent); | |
155 System.out.println(); | |
156 | |
157 CompareIndividuals compare = new CompareIndividuals(); | |
158 | |
159 // generate initial population | |
160 Individual[] citizen = new Individual[population]; | |
161 for (int n = 0; n < population; n++) { | |
162 citizen[n] = new Individual(text, terms); | |
163 } | |
164 | |
165 // keep looking for the best program | |
166 int best = Integer.MAX_VALUE; | |
167 for(int generation = 1; (generation <= generations) || (generations == 0); | |
168 generation++) { | |
169 // choose a top citizen to copy and tweak number order | |
170 for (int n = bottom; n < population; n++) { | |
171 citizen[n].tweak(citizen[r.nextInt(top)]); | |
172 } | |
173 | |
174 // genetic stimulation | |
175 for (int n = 1; n < population; n++) { | |
176 int p = r.nextInt(population); | |
177 if (p < n) { // less mutation with good, more mutation with bad | |
178 citizen[n].mutate(); | |
179 } else { | |
180 p = r.nextInt(top); | |
181 citizen[n].crossover(citizen[p]); | |
182 } | |
183 } | |
184 | |
185 // get rid of the duds | |
186 Arrays.sort(citizen, compare); | |
187 for (int n = bottom; n < population; n++) { | |
188 citizen[n].restart(); | |
189 } | |
190 | |
191 // display progress | |
192 Arrays.sort(citizen, compare); | |
193 if (citizen[0].getFitness() < best) { | |
194 String temptext; | |
195 System.out.println((best = citizen[0].getFitness()) + " " + (temptext = citizen[0].getCode()) | |
196 + " [" + generation + "]"); | |
197 System.out.println(); | |
198 if (fileout != null) { | |
199 PrintStream out; | |
200 try { | |
201 out = new PrintStream(new FileOutputStream(fileout)); | |
202 out.print(temptext); | |
203 out.close(); | |
204 } catch (IOException e) { | |
205 System.out.println("Error writing output file."); | |
206 System.exit(1); | |
207 } | |
208 } | |
209 } | |
210 | |
211 } | |
212 } | |
213 | |
214 //------------------------------------------------------------------ | |
215 // getRandomBoolean() | |
216 //------------------------------------------------------------------ | |
217 public static boolean getRandomBoolean() { | |
218 return r.nextBoolean(); | |
219 } | |
220 | |
221 //------------------------------------------------------------------ | |
222 // getRandomInt() | |
223 //------------------------------------------------------------------ | |
224 public static int getRandomInt(int n) { | |
225 return r.nextInt(n); | |
226 } | |
227 | |
228 //------------------------------------------------------------------ | |
229 // usage -- prints usage information | |
230 //------------------------------------------------------------------ | |
231 public static void usage() { | |
232 System.out.println("Usage: textgen [-i file] [-o file] [-t #] [-p #] [-% #] \"text\" [-?]"); | |
233 System.out.println("Where: \"text\" Text to generate"); | |
234 System.out.println(" -i Input filename (in place of \"text\")"); | |
235 System.out.println(" -o Output filename, default: screen only"); | |
236 System.out.println(" -g Generations, default: infinite"); | |
237 System.out.println(" -t Number of terms, default: 4"); | |
238 System.out.println(" -p Population, default: 500"); | |
239 System.out.println(" -% Percent to rank as top, default: 10"); | |
240 System.out.println(" -? Display usage information"); | |
241 } | |
242 | |
243 } | |
244 | |
245 //******************************************************************** | |
246 // CompareIndividuals | |
247 //******************************************************************** | |
248 class CompareIndividuals implements Comparator { | |
249 public int compare(Object o1, Object o2) { | |
250 return (((Individual) o1).getFitness() - ((Individual) o2).getFitness()); | |
251 } | |
252 } | |
253 | |
254 //******************************************************************** | |
255 // Individual | |
256 //******************************************************************** | |
257 class Individual { | |
258 int letters, mult, terms, fitness = -1; | |
259 int[] term, finder, fixer; | |
260 String expected; | |
261 | |
262 //------------------------------------------------------------------ | |
263 // (constructor) | |
264 //------------------------------------------------------------------ | |
265 Individual(String expected, int terms) { | |
266 this.expected = expected; | |
267 letters = expected.length(); | |
268 this.terms = terms; | |
269 term = new int[terms]; | |
270 restart(); | |
271 } | |
272 | |
273 //------------------------------------------------------------------ | |
274 // restart() | |
275 //------------------------------------------------------------------ | |
276 public void restart() { | |
277 // multiplier (1 to 15) | |
278 mult = textgen.getRandomInt(15) + 1; | |
279 // value of each term (0 to 15) | |
280 for (int n = 0; n < terms; n++) { | |
281 term[n] = textgen.getRandomInt(16); | |
282 } | |
283 // ><+- multiple before each dot (one for each letter) | |
284 finder = new int[letters]; | |
285 fixer = new int[letters]; | |
286 for (int n = 0; n < letters; n++) { | |
287 finder[n] = textgen.getRandomInt(terms); | |
288 } | |
289 fitness = -1; | |
290 } | |
291 | |
292 //------------------------------------------------------------------ | |
293 // mutate() | |
294 //------------------------------------------------------------------ | |
295 public void mutate() { | |
296 int n; | |
297 // mutate item | |
298 if (textgen.getRandomBoolean()) { | |
299 // term | |
300 n = textgen.getRandomInt(terms); | |
301 term[n] = textgen.getRandomInt(16); | |
302 } else { | |
303 // finder | |
304 n = textgen.getRandomInt(letters); | |
305 finder[n] = textgen.getRandomInt(terms); | |
306 } | |
307 fitness = -1; | |
308 } | |
309 | |
310 //------------------------------------------------------------------ | |
311 // tweak() | |
312 //------------------------------------------------------------------ | |
313 public void tweak(Individual giver) { | |
314 if ((textgen.r).nextBoolean()) { | |
315 // copy the giver exactly | |
316 mult = giver.getMult(); | |
317 for (int n = 0; n < terms; n++) { | |
318 term[n] = giver.getTerm(n); | |
319 } | |
320 } else { | |
321 // copy the giver, but use a new multiplier, adjust the terms accordingly | |
322 mult = textgen.getRandomInt(15) + 1; | |
323 for (int n = 0; n < terms; n++) { | |
324 term[n] = Math.round(giver.getTerm(n) * giver.getMult() / (float) mult); | |
325 } | |
326 } | |
327 // copy the finder | |
328 for (int n = 0; n < letters; n++) { | |
329 finder[n] = giver.getFinder(n); | |
330 } | |
331 | |
332 // swap two of the terms to see if it helps (can be the same term) | |
333 int n1 = textgen.getRandomInt(terms); | |
334 int n2 = textgen.getRandomInt(terms); | |
335 int n3 = term[n2]; | |
336 term[n2] = term[n1]; | |
337 term[n1] = n3; | |
338 | |
339 // swap finders to match swapped terms | |
340 for (int n = 0; n < letters; n++) { | |
341 if (finder[n] == n1) { | |
342 finder[n] = n2; | |
343 } else if (finder[n] == n2) { | |
344 finder[n] = n1; | |
345 } | |
346 } | |
347 | |
348 fitness = -1; | |
349 } | |
350 | |
351 //------------------------------------------------------------------ | |
352 // crossover() | |
353 //------------------------------------------------------------------ | |
354 public void crossover(Individual giver) { | |
355 int n; | |
356 if ((textgen.r).nextBoolean()) { | |
357 // term | |
358 n = textgen.getRandomInt(terms); | |
359 int n2 = textgen.getRandomInt(terms); | |
360 term[n2] = giver.getTerm(n); | |
361 } else { | |
362 // finder | |
363 n = textgen.getRandomInt(letters); | |
364 finder[n] = giver.getFinder(n); | |
365 } | |
366 fitness = -1; | |
367 } | |
368 | |
369 //------------------------------------------------------------------ | |
370 // getMult() | |
371 //------------------------------------------------------------------ | |
372 public int getMult() { | |
373 return mult; | |
374 } | |
375 | |
376 //------------------------------------------------------------------ | |
377 // getTerms() | |
378 //------------------------------------------------------------------ | |
379 public int getTerms() { | |
380 return terms; | |
381 } | |
382 | |
383 //------------------------------------------------------------------ | |
384 // getTerm() | |
385 //------------------------------------------------------------------ | |
386 public int getTerm(int n) { | |
387 return term[n]; | |
388 } | |
389 | |
390 //------------------------------------------------------------------ | |
391 // getFinder() | |
392 //------------------------------------------------------------------ | |
393 public int getFinder(int n) { | |
394 return finder[n]; | |
395 } | |
396 | |
397 //------------------------------------------------------------------ | |
398 // getFitness() | |
399 //------------------------------------------------------------------ | |
400 public int getFitness() { | |
401 if (fitness < 0) { | |
402 int length = 4 + mult + terms * 2 + letters; // mult [ terms> terms< -]> letters. | |
403 int[] memory = new int[terms]; | |
404 for (int n = 0; n < terms; n++) { | |
405 length += term[n]; | |
406 memory[n] = (mult * term[n]) % 256; | |
407 } | |
408 int mp = 0; | |
409 for (int n = 0; n < letters; n++) { | |
410 length += Math.abs(finder[n] - mp); | |
411 mp = finder[n]; | |
412 fixer[n] = expected.charAt(n) - memory[mp]; | |
413 int n2 = Math.abs(fixer[n]); | |
414 if (Math.abs(fixer[n]) > 128) { | |
415 n2 = 256 - n2; | |
416 if (fixer[n] > 0) { | |
417 n2 = -n2; | |
418 } | |
419 } | |
420 length += Math.abs(fixer[n]); | |
421 memory[mp] = expected.charAt(n); | |
422 } | |
423 | |
424 // combine results | |
425 fitness = length; | |
426 | |
427 if (fitness < 0) { fitness = Integer.MAX_VALUE; } | |
428 | |
429 } | |
430 return fitness; | |
431 } | |
432 | |
433 //------------------------------------------------------------------ | |
434 // getCode() | |
435 //------------------------------------------------------------------ | |
436 public String getCode() { | |
437 String code = getBF(mult, '+', '+') + "["; | |
438 for (int n = 0; n < terms; n++) { | |
439 code += ">" + getBF(term[n], '+', '+'); | |
440 } | |
441 code += getBF(terms, '<', '<') + "-]>"; | |
442 int mp = 0; | |
443 for (int n = 0; n < letters; n++) { | |
444 code += getBF(finder[n] - mp, '>', '<'); | |
445 mp = finder[n]; | |
446 code += getBF(fixer[n], '+', '-') + "."; | |
447 } | |
448 return code; | |
449 } | |
450 | |
451 //------------------------------------------------------------------ | |
452 // getBF() { | |
453 //------------------------------------------------------------------ | |
454 public String getBF(int n, char pos, char neg) { | |
455 char ch = ' '; | |
456 if (n > 0) { | |
457 ch = pos; | |
458 } else if (n < 0) { | |
459 ch = neg; | |
460 } | |
461 n = Math.abs(n); | |
462 if (n != 0) { | |
463 char[] c = new char[Math.abs(n)]; | |
464 Arrays.fill(c, ch); | |
465 return new String(c); | |
466 } else { | |
467 return ""; | |
468 } | |
469 } | |
470 | |
471 } | |
472 | |
473 | |
474 |