Mercurial > repo
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/interps/bf_txtgen/textgen.java Sun Dec 09 19:30:08 2012 +0000 @@ -0,0 +1,474 @@ +//==================================================================== +// TEXTGEN -- BrainF*** Genetic Text Generator +// textgen.java +// Copyright (C) 2003, 2004 by Jeffry Johnston +// Version 0.20 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation. See the file LICENSE +// for more details. +// +// Online resource used: +// http://www.genetic-programming.com/gpflowchart.html +// +// I have not read any books and have seen very little information +// online about GP implementation. Any suggestions are most welcome. +// +// Inspiration: +// 111-byte "Hello World!" with newline (assumed optimal) +// ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++. +// <<+++++++++++++++.>.+++.------.--------.>+.>. +// +// Version history: +// 0.20 11 Aug 2004 Added -i and -o options +// 0.10 01 Dec 2003 Initial release +//==================================================================== + +import java.io.*; +import java.util.*; + +//******************************************************************** +// textgen +//******************************************************************** +public class textgen { + static final String VERSION = "0.20"; + static Random r = new Random(); + + //------------------------------------------------------------------ + // main + //------------------------------------------------------------------ + public static void main(String[] cmdline) { + int terms = 4, population = 500, generations = 0; + String text = "Default text?!"; + double toppercent = 0.10; + String fileout = null; + + // display copyright text + System.out.println("TEXTGEN BrainF*** Genetic Text Generator, version " + VERSION + "."); + System.out.println("Copyright (c) 2003 Jeffry Johnston."); + System.out.println(); + + // process command line + for (int n = 0; ; n++) { + try { + if (cmdline[n].equals("-?") || cmdline[n].equals("/?") || cmdline[n].equals("--?") + || cmdline[n].equals("--help") ) { + usage(); + System.exit(0); + } else if (cmdline[n].equalsIgnoreCase("-i")) { + // open file + DataInputStream filein = null; + try { + filein = new DataInputStream(new FileInputStream(cmdline[n + 1])); + } catch (FileNotFoundException e) { + System.out.println("Error opening input file. File not found"); + System.exit(1); + } + // read file + byte[] data = null; + int size = 0; + try { + size = filein.available(); + data = new byte[size]; + filein.readFully(data); + } catch (IOException e) { + System.out.println("Error reading input file."); + System.exit(1); + } + // close file + try { + filein.close(); + } catch (IOException e) { + System.out.println("Error closing input file."); + System.exit(1); + } + try { + text = new String(data, "ISO-8859-1"); + } catch (UnsupportedEncodingException e) { + System.out.println("This program requires ISO-8859-1 character set support."); + } + n++; + } else if (cmdline[n].equalsIgnoreCase("-o")) { + fileout = cmdline[n + 1]; + n++; + } else if (cmdline[n].equalsIgnoreCase("-g")) { + generations = Integer.parseInt(cmdline[n + 1]); + if (generations < 1) { + System.out.println("Must have at least 1 generation."); + System.exit(1); + } + n++; + } else if (cmdline[n].equalsIgnoreCase("-t")) { + terms = Integer.parseInt(cmdline[n + 1]); + if (terms < 1) { + System.out.println("Must have at least 1 term."); + System.exit(1); + } + n++; + } else if (cmdline[n].equalsIgnoreCase("-p")) { + population = Integer.parseInt(cmdline[n + 1]); + if (terms < 2) { + System.out.println("Must have population of at least 10."); + System.exit(1); + } + n++; + } else if (cmdline[n].equalsIgnoreCase("-%")) { + int tp = Integer.parseInt(cmdline[n + 1]); + if (tp < 0 || tp > 100) { + System.out.println("Percentage out of range (0, 100)."); + System.exit(1); + } + toppercent = (double) tp / 100; + n++; + } else { + text = cmdline[n]; + if (text.charAt(0) == '\"') { + text = text.substring(1); + } + if (text.charAt(text.length() - 1) == '\"') { + text = text.substring(0, text.length()); + } + } + } catch (ArrayIndexOutOfBoundsException e) { + break; + } catch (NumberFormatException e) { + System.out.println("Invalid number"); + System.exit(1); + } + } + int top = (int) (toppercent * population); + int bottom = population - top; + + if (fileout == null) { + System.out.println("Text: \"" + text + "\""); + } + System.out.print("Generations: "); + if (generations == 0) { + System.out.println("Infinite"); + } else { + System.out.println(generations); + } + System.out.println("Terms: " + terms); + System.out.println("Population: " + population); + System.out.println("Top %: " + toppercent); + System.out.println(); + + CompareIndividuals compare = new CompareIndividuals(); + + // generate initial population + Individual[] citizen = new Individual[population]; + for (int n = 0; n < population; n++) { + citizen[n] = new Individual(text, terms); + } + + // keep looking for the best program + int best = Integer.MAX_VALUE; + for(int generation = 1; (generation <= generations) || (generations == 0); + generation++) { + // choose a top citizen to copy and tweak number order + for (int n = bottom; n < population; n++) { + citizen[n].tweak(citizen[r.nextInt(top)]); + } + + // genetic stimulation + for (int n = 1; n < population; n++) { + int p = r.nextInt(population); + if (p < n) { // less mutation with good, more mutation with bad + citizen[n].mutate(); + } else { + p = r.nextInt(top); + citizen[n].crossover(citizen[p]); + } + } + + // get rid of the duds + Arrays.sort(citizen, compare); + for (int n = bottom; n < population; n++) { + citizen[n].restart(); + } + + // display progress + Arrays.sort(citizen, compare); + if (citizen[0].getFitness() < best) { + String temptext; + System.out.println((best = citizen[0].getFitness()) + " " + (temptext = citizen[0].getCode()) + + " [" + generation + "]"); + System.out.println(); + if (fileout != null) { + PrintStream out; + try { + out = new PrintStream(new FileOutputStream(fileout)); + out.print(temptext); + out.close(); + } catch (IOException e) { + System.out.println("Error writing output file."); + System.exit(1); + } + } + } + + } + } + + //------------------------------------------------------------------ + // getRandomBoolean() + //------------------------------------------------------------------ + public static boolean getRandomBoolean() { + return r.nextBoolean(); + } + + //------------------------------------------------------------------ + // getRandomInt() + //------------------------------------------------------------------ + public static int getRandomInt(int n) { + return r.nextInt(n); + } + + //------------------------------------------------------------------ + // usage -- prints usage information + //------------------------------------------------------------------ + public static void usage() { + System.out.println("Usage: textgen [-i file] [-o file] [-t #] [-p #] [-% #] \"text\" [-?]"); + System.out.println("Where: \"text\" Text to generate"); + System.out.println(" -i Input filename (in place of \"text\")"); + System.out.println(" -o Output filename, default: screen only"); + System.out.println(" -g Generations, default: infinite"); + System.out.println(" -t Number of terms, default: 4"); + System.out.println(" -p Population, default: 500"); + System.out.println(" -% Percent to rank as top, default: 10"); + System.out.println(" -? Display usage information"); + } + +} + +//******************************************************************** +// CompareIndividuals +//******************************************************************** +class CompareIndividuals implements Comparator { + public int compare(Object o1, Object o2) { + return (((Individual) o1).getFitness() - ((Individual) o2).getFitness()); + } +} + +//******************************************************************** +// Individual +//******************************************************************** +class Individual { + int letters, mult, terms, fitness = -1; + int[] term, finder, fixer; + String expected; + + //------------------------------------------------------------------ + // (constructor) + //------------------------------------------------------------------ + Individual(String expected, int terms) { + this.expected = expected; + letters = expected.length(); + this.terms = terms; + term = new int[terms]; + restart(); + } + + //------------------------------------------------------------------ + // restart() + //------------------------------------------------------------------ + public void restart() { + // multiplier (1 to 15) + mult = textgen.getRandomInt(15) + 1; + // value of each term (0 to 15) + for (int n = 0; n < terms; n++) { + term[n] = textgen.getRandomInt(16); + } + // ><+- multiple before each dot (one for each letter) + finder = new int[letters]; + fixer = new int[letters]; + for (int n = 0; n < letters; n++) { + finder[n] = textgen.getRandomInt(terms); + } + fitness = -1; + } + + //------------------------------------------------------------------ + // mutate() + //------------------------------------------------------------------ + public void mutate() { + int n; + // mutate item + if (textgen.getRandomBoolean()) { + // term + n = textgen.getRandomInt(terms); + term[n] = textgen.getRandomInt(16); + } else { + // finder + n = textgen.getRandomInt(letters); + finder[n] = textgen.getRandomInt(terms); + } + fitness = -1; + } + + //------------------------------------------------------------------ + // tweak() + //------------------------------------------------------------------ + public void tweak(Individual giver) { + if ((textgen.r).nextBoolean()) { + // copy the giver exactly + mult = giver.getMult(); + for (int n = 0; n < terms; n++) { + term[n] = giver.getTerm(n); + } + } else { + // copy the giver, but use a new multiplier, adjust the terms accordingly + mult = textgen.getRandomInt(15) + 1; + for (int n = 0; n < terms; n++) { + term[n] = Math.round(giver.getTerm(n) * giver.getMult() / (float) mult); + } + } + // copy the finder + for (int n = 0; n < letters; n++) { + finder[n] = giver.getFinder(n); + } + + // swap two of the terms to see if it helps (can be the same term) + int n1 = textgen.getRandomInt(terms); + int n2 = textgen.getRandomInt(terms); + int n3 = term[n2]; + term[n2] = term[n1]; + term[n1] = n3; + + // swap finders to match swapped terms + for (int n = 0; n < letters; n++) { + if (finder[n] == n1) { + finder[n] = n2; + } else if (finder[n] == n2) { + finder[n] = n1; + } + } + + fitness = -1; + } + + //------------------------------------------------------------------ + // crossover() + //------------------------------------------------------------------ + public void crossover(Individual giver) { + int n; + if ((textgen.r).nextBoolean()) { + // term + n = textgen.getRandomInt(terms); + int n2 = textgen.getRandomInt(terms); + term[n2] = giver.getTerm(n); + } else { + // finder + n = textgen.getRandomInt(letters); + finder[n] = giver.getFinder(n); + } + fitness = -1; + } + + //------------------------------------------------------------------ + // getMult() + //------------------------------------------------------------------ + public int getMult() { + return mult; + } + + //------------------------------------------------------------------ + // getTerms() + //------------------------------------------------------------------ + public int getTerms() { + return terms; + } + + //------------------------------------------------------------------ + // getTerm() + //------------------------------------------------------------------ + public int getTerm(int n) { + return term[n]; + } + + //------------------------------------------------------------------ + // getFinder() + //------------------------------------------------------------------ + public int getFinder(int n) { + return finder[n]; + } + + //------------------------------------------------------------------ + // getFitness() + //------------------------------------------------------------------ + public int getFitness() { + if (fitness < 0) { + int length = 4 + mult + terms * 2 + letters; // mult [ terms> terms< -]> letters. + int[] memory = new int[terms]; + for (int n = 0; n < terms; n++) { + length += term[n]; + memory[n] = (mult * term[n]) % 256; + } + int mp = 0; + for (int n = 0; n < letters; n++) { + length += Math.abs(finder[n] - mp); + mp = finder[n]; + fixer[n] = expected.charAt(n) - memory[mp]; + int n2 = Math.abs(fixer[n]); + if (Math.abs(fixer[n]) > 128) { + n2 = 256 - n2; + if (fixer[n] > 0) { + n2 = -n2; + } + } + length += Math.abs(fixer[n]); + memory[mp] = expected.charAt(n); + } + + // combine results + fitness = length; + + if (fitness < 0) { fitness = Integer.MAX_VALUE; } + + } + return fitness; + } + + //------------------------------------------------------------------ + // getCode() + //------------------------------------------------------------------ + public String getCode() { + String code = getBF(mult, '+', '+') + "["; + for (int n = 0; n < terms; n++) { + code += ">" + getBF(term[n], '+', '+'); + } + code += getBF(terms, '<', '<') + "-]>"; + int mp = 0; + for (int n = 0; n < letters; n++) { + code += getBF(finder[n] - mp, '>', '<'); + mp = finder[n]; + code += getBF(fixer[n], '+', '-') + "."; + } + return code; + } + + //------------------------------------------------------------------ + // getBF() { + //------------------------------------------------------------------ + public String getBF(int n, char pos, char neg) { + char ch = ' '; + if (n > 0) { + ch = pos; + } else if (n < 0) { + ch = neg; + } + n = Math.abs(n); + if (n != 0) { + char[] c = new char[Math.abs(n)]; + Arrays.fill(c, ch); + return new String(c); + } else { + return ""; + } + } + +} + + +