[Home]Simonton/RoboleagueScripting

Robo Home | Simonton | Changes | Preferences | AllPages

Showing revision 2
I don't know the best place to do this, so here goes: I hacked together some mods for Roboleague to let me try all combinations of different parameters in my bot. I hope to start making good use of it tonight. WARNING: THIS IS A SERIOUS HACK. Using it is not pretty. But it works. I can't find licencing info on Roboleague, so I'm just going to paste my mods on here & let you paste them into the soure & compile. Please treat this code as "open source" & share any improvements you make!

This is in roboleague.gui.RoboLeagueGui. Starting from the end of the constructor:


		// new Thread() {
		// public void run() {
		bg_initialize();
		// }
		// }.start();

		run(args);
	}

	private void run(String[] args) {
		if (args.length == 0) {
			return;
		}

		int i = 0;
		String file = args[i++];
		if (!file.endsWith(".xml")) {
			System.out.println(file + " should end with .xml");
			return;
		}

		if (args.length == 1) {
			if (load(new File(file))) {
				runSeasons(1);
			}
			return;
		}

		int numSeasons = Integer.parseInt(args[i++]);
		List<Variable> vars = new LinkedList<Variable>();
		while (i < args.length) {
			i = makePropertyList(args, vars, i);
		}
		String fileBase = file.substring(0, file.length() - 4);
		for (int season = 1; season > 0 && season <= numSeasons; ++season) {
			season = run(vars, 0, fileBase, file, season);
			System.out.println("FINISHED SEASON " + season);
		}
		System.out.println("DONE!");
	}

	private boolean load(File file) {
		CompetitionDataModel before = loadedDataModel;
		bg_openDataModel(file);
		if (loadedDataModel == null || loadedDataModel == before) {
			System.out.println("Load failed");
			return false;
		}
		return true;
	}

	// returns min seasons run, or -1 when there was an inturrupt
	private int run(List<Variable> vars, int i, String baseFilename,
			String originalFile, int curSeason) {
		if (i == vars.size()) {
			File file = new File(baseFilename + ".xml");
			if (exists(file, originalFile) && load(file)) {
				int seasonCount = getCompletedSeasonCount();
				if (seasonCount < curSeason) {
					runSeasons(1);
					try {
						runSeasonJob.join();
					} catch (InterruptedException e) {
						// no prob, we'll abort when inturrupted
						// possible race condition if inturrupted right away,
						// but the job is still running, we get the old season
						// count, then the new non-terminated state (it depends
						// on the order in which the state & season count are
						// updated)
					}
					int newSeasonCount = getCompletedSeasonCount();
					if (newSeasonCount == seasonCount) {
						return -1;
					}
					assert newSeasonCount == seasonCount + 1;
					return newSeasonCount;
				}
				System.out.println(baseFilename + " already ran season "
						+ curSeason);
				return seasonCount;
			}
			System.out.println("Couldn't find, create, or run " + file);
			return Integer.MAX_VALUE;
		}
		Variable var = vars.get(i);
		baseFilename += "_" + var.name + "-";
		int minCount = Integer.MAX_VALUE;
		for (String val : var.values) {
			System.setProperty(var.name, val.toString());
			System.out.println(System.getProperty("patternDepth"));
			int count = run(vars, i + 1, baseFilename + val, originalFile,
					curSeason);
			if (count == -1) {
				return -1;
			}
			if (count < minCount) {
				minCount = count;
			}
		}
		return minCount;
	}

	public int getCompletedSeasonCount() {
		int num = 0;
		if (loadedDataModel instanceof Division) {
			Division division = (Division) loadedDataModel;
			num = division.getSeasonCount();
		} else if (loadedDataModel instanceof League) {
			League league = (League) loadedDataModel;
			num = league.getSeasonCount();
		} else {
			// loadedDataModel is null, maybe?
			return 0;
		}
		if (!loadedDataModel.getTerminated()) {
			--num;
		}
		return num;
	}

	private boolean exists(File file, String originalFile) {
		if (file.isFile()) {
			return true;
		}

		// nope ... try to make it!
		try {
			InputStream in = new FileInputStream(originalFile);
			OutputStream out = new FileOutputStream(file);
			for (int b = in.read(); b != -1; b = in.read()) {
				out.write(b);
			}
			in.close();
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	// <property> <numvals> <value> <value> <value> ...
	// <property> number <start> <end> <step>
	private int makePropertyList(String[] args, List<Variable> vars, int i) {
		String property = args[i++];
		List<String> vals = new LinkedList<String>();
		String type = args[i++];
		if ("number".equals(type)) {
			double start = Double.parseDouble(args[i++]);
			double end = Double.parseDouble(args[i++]);
			double step = Double.parseDouble(args[i++]);
			for (double val = start; val <= end; val += step) {
				vals.add(Double.toString(val));
			}
		} else {
			for (int j = Integer.parseInt(type); j > 0; --j) {
				vals.add(args[i++]);
			}
		}
		vars.add(new Variable(property, vals));
		return i;
	}

	class Variable {
		final String name;
		final List<String> values;
		Variable(String name, List<String> values) {
			this.name = name;
			this.values = values;
		}
	}

Now, to use the new mod, pass command line aruments to roboleague in this form:

  java roboleague.gui.RoboLeagueGui? {base-xml-file} {target-number-of-seasons} {variable}*

Where a variable is in the form:

  {variable-name} {number-of-values} {value} {value} {value} ...
or
  {variable-name} number {start-value} {end-value} {step-size}

This will set the appropriate values for each variable in System.properties, as many of them as you want, and run them in every combination. The results for each combination of variables will be stored in a file starting with the name of the base xml file, followed by the names of the variables and their values for the runs in that file. So, test.xml becomes test_var1-value1.xml and test_var1-value2.xml. Note that test.xml itself should not contain any results, or else they will be carried over into every run.

The code is well behaved if you inturrupt it, and it knows how to start back up again where it left off the next time you run Roboleague with the same command line args.

To make use of these variables in System.properties (where the new mod puts them), do something like this:

		int variable = default-value;
		String cmdVariable = System.getProperty("variable-name-in-command-line");
		if (cmdVariable != null) {
			try {
				variable = (int) Double.parseDouble(cmdVariable);
			} catch (NumberFormatException err) {
				System.out.println("Couldn't understand " + cmdVariable);
			}
		}
		System.out.println("Using pattern depth " + variable);

Notice that all "number" variables on the command line get stored in System.properties using Double.toString(value), so they should be de-coded with Double.parseDouble(valueString), not, for example, Integer.parseInt(...).


Robo Home | Simonton | Changes | Preferences | AllPages
Edit revision 2 of this page | View other revisions | View current revision
Edited September 28, 2006 1:17 EST by Simonton (diff)
Search: