Mercurial > repo
view interps/bf_txtgen/textgen.java @ 12518:2d8fe55c6e65 draft default tip
<int-e> learn The password of the month is release incident pilot.
author | HackEso <hackeso@esolangs.org> |
---|---|
date | Sun, 03 Nov 2024 00:31:02 +0000 |
parents | 859f9b4339e6 |
children |
line wrap: on
line source
//==================================================================== // 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 ""; } } }