Index: /java/ecj/cecj/app/BoardGameProblem.java
===================================================================
--- /java/ecj/cecj/app/BoardGameProblem.java	(revision 44)
+++ /java/ecj/cecj/app/BoardGameProblem.java	(revision 44)
@@ -0,0 +1,82 @@
+package cecj.app;
+
+import cecj.app.othello.OthelloBoard;
+import cecj.app.othello.OthelloGame;
+import cecj.app.othello.OthelloPlayer;
+import cecj.interaction.InteractionResult;
+import cecj.interaction.WinDrawLossResult;
+import cecj.interaction.WinDrawLossResult.Result;
+import cecj.problems.SymmetricTestBasedProblem;
+import cecj.utils.Pair;
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+import ec.vector.DoubleVectorIndividual;
+import games.Player;
+import games.scenarios.GameScenario;
+import games.scenarios.RandomizedTwoPlayersGameScenario;
+import games.scenarios.SimpleTwoPlayersGameScenario;
+
+public class BoardGameProblem extends SymmetricTestBasedProblem {
+
+	private static final int WPC_LENGTH = 64;
+	private static final String P_RANDOMNESS = "randomness";
+
+	private double randomness;
+	private boolean randomizedPlay;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+
+		Parameter randomnessParam = base.push(P_RANDOMNESS);
+		if (state.parameters.exists(randomnessParam)) {
+			randomness = state.parameters.getDoubleWithDefault(randomnessParam, null, 0);
+			randomizedPlay = true;
+		} else {
+			randomizedPlay = false;
+		}
+	}
+
+	@Override
+	public Pair<? extends InteractionResult> test(EvolutionState state, Individual candidate,
+			Individual test) {
+		if (!(candidate instanceof DoubleVectorIndividual)
+				|| !(test instanceof DoubleVectorIndividual)) {
+			state.output.error("Othello players should be represented by floats vectors\n");
+		}
+
+		double[] wpc1 = ((DoubleVectorIndividual) candidate).genome;
+		double[] wpc2 = ((DoubleVectorIndividual) test).genome;
+
+		if (wpc1.length != WPC_LENGTH || wpc2.length != WPC_LENGTH) {
+			state.output.error("Players WPC vectors length should be 64\n");
+		}
+
+		// TODO: should the game be repeated?
+		OthelloPlayer player1 = new OthelloPlayer(wpc1);
+		OthelloPlayer player2 = new OthelloPlayer(wpc2);
+		OthelloGame game = new OthelloGame(new OthelloBoard());
+
+		GameScenario scenario;
+		if (randomizedPlay) {
+			scenario = new RandomizedTwoPlayersGameScenario(state.random[0], new Player[] {
+					player1, player2 }, new double[] { randomness, randomness });
+		} else {
+			scenario = new SimpleTwoPlayersGameScenario(new Player[] { player1, player2 });
+		}
+
+		int result = scenario.play(game);
+		if (result > 0) {
+			return new Pair<WinDrawLossResult>(new WinDrawLossResult(Result.WIN),
+					new WinDrawLossResult(Result.LOSS));
+		} else if (result < 0) {
+			return new Pair<WinDrawLossResult>(new WinDrawLossResult(Result.LOSS),
+					new WinDrawLossResult(Result.WIN));
+		} else {
+			return new Pair<WinDrawLossResult>(new WinDrawLossResult(Result.DRAW),
+					new WinDrawLossResult(Result.DRAW));
+		}
+	}
+
+}
Index: /java/ecj/cecj/app/go/Go.java
===================================================================
--- /java/ecj/cecj/app/go/Go.java	(revision 44)
+++ /java/ecj/cecj/app/go/Go.java	(revision 44)
@@ -0,0 +1,81 @@
+package cecj.app.go;
+
+import cecj.app.othello.OthelloBoard;
+import cecj.app.othello.OthelloGame;
+import cecj.app.othello.OthelloPlayer;
+import cecj.interaction.InteractionResult;
+import cecj.interaction.WinDrawLossResult;
+import cecj.interaction.WinDrawLossResult.Result;
+import cecj.problems.SymmetricTestBasedProblem;
+import cecj.utils.Pair;
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+import ec.vector.DoubleVectorIndividual;
+import games.Player;
+import games.scenarios.GameScenario;
+import games.scenarios.RandomizedTwoPlayersGameScenario;
+import games.scenarios.SimpleTwoPlayersGameScenario;
+
+public class Go extends SymmetricTestBasedProblem {
+
+	private static final int WPC_LENGTH = 25;
+	private static final String P_RANDOMNESS = "randomness";
+
+	private double randomness;
+	private boolean randomizedPlay;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+
+		Parameter randomnessParam = base.push(P_RANDOMNESS);
+		if (state.parameters.exists(randomnessParam)) {
+			randomness = state.parameters.getDoubleWithDefault(randomnessParam, null, 0);
+			randomizedPlay = true;
+		} else {
+			randomizedPlay = false;
+		}
+	}
+
+	@Override
+	public Pair<? extends InteractionResult> test(EvolutionState state, Individual candidate,
+			Individual test) {
+		if (!(candidate instanceof DoubleVectorIndividual)
+				|| !(test instanceof DoubleVectorIndividual)) {
+			state.output.error("Othello players should be represented by floats vectors\n");
+		}
+		
+		double[] wpc1 = ((DoubleVectorIndividual) candidate).genome;
+		double[] wpc2 = ((DoubleVectorIndividual) test).genome;
+		
+		if (wpc1.length != WPC_LENGTH || wpc2.length != WPC_LENGTH) {
+			state.output.error("Players WPC vectors length should be 64\n");
+		}
+
+	    GoPlayer player1 = new GoPlayer(wpc1);
+		GoPlayer player2 = new GoPlayer(wpc2);
+		GoGame game = new GoGame(new GoBoard());
+
+		GameScenario scenario;
+		if (randomizedPlay) {
+			scenario = new RandomizedTwoPlayersGameScenario(state.random[0], new Player[] {
+					player1, player2 }, new double[] { randomness, randomness });
+		} else {
+			scenario = new SimpleTwoPlayersGameScenario(new Player[] { player1, player2 });
+		}
+
+		int result = scenario.play(game);
+		if (result > 0) {
+			return new Pair<WinDrawLossResult>(new WinDrawLossResult(Result.WIN),
+					new WinDrawLossResult(Result.LOSS));
+		} else if (result < 0) {
+			return new Pair<WinDrawLossResult>(new WinDrawLossResult(Result.LOSS),
+					new WinDrawLossResult(Result.WIN));
+		} else {
+			return new Pair<WinDrawLossResult>(new WinDrawLossResult(Result.DRAW),
+					new WinDrawLossResult(Result.DRAW));
+		}
+	}
+
+}
Index: /java/ecj/cecj/app/go/GoBoard.java
===================================================================
--- /java/ecj/cecj/app/go/GoBoard.java	(revision 44)
+++ /java/ecj/cecj/app/go/GoBoard.java	(revision 44)
@@ -0,0 +1,69 @@
+package cecj.app.go;
+
+import cecj.app.othello.OthelloBoard;
+import games.Board;
+import games.GameMove;
+import games.Player;
+
+public class GoBoard implements Board {
+	
+	private static final int BOARD_SIZE = 8;
+	private static final int BOARD_MARGIN = 2;
+	
+	private int board[][];
+	
+	public int countPieces(int i) {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
+	public double evaluate(Player player) {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
+	public int getPiece(int row, int col) {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
+	public int getPiece(int row, int col, int dir, int dist) {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
+	public GameMove getShiftedMove(int row, int col, int dir, int dist) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public int getValueAt(int row, int col) {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
+	public boolean isEmpty(int row, int col) {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+	public void setPiece(int row, int col, int dir, int dist, int currentPlayer) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public GoBoard clone() {
+		GoBoard clone = new GoBoard();
+		for (int row = 1; row <= BOARD_SIZE; row++) {
+			for (int col = 1; col <= BOARD_SIZE; col++) {
+				clone.board[row][col] = board[row][col];
+			}
+		}
+		return clone;
+	}
+
+	public static int size() {
+		return BOARD_SIZE;
+	}
+}
Index: /java/ecj/cecj/app/go/GoGame.java
===================================================================
--- /java/ecj/cecj/app/go/GoGame.java	(revision 44)
+++ /java/ecj/cecj/app/go/GoGame.java	(revision 44)
@@ -0,0 +1,61 @@
+package cecj.app.go;
+
+import java.util.List;
+
+import games.Board;
+import games.BoardGame;
+import games.GameMove;
+import games.Player;
+
+public class GoGame implements BoardGame {
+
+	public GoGame(GoBoard board) {
+		
+	}
+	
+	public boolean endOfGame() {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+	public double evalMove(Player player, GameMove move) {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
+	public List<? extends GameMove> findMoves() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public Board getBoard() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public int getCurrentPlayer() {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
+	public int getOutcome() {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
+	public void makeMove(GameMove move) {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void reset() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void switchPlayer() {
+		// TODO Auto-generated method stub
+
+	}
+
+}
Index: /java/ecj/cecj/app/go/GoPlayer.java
===================================================================
--- /java/ecj/cecj/app/go/GoPlayer.java	(revision 44)
+++ /java/ecj/cecj/app/go/GoPlayer.java	(revision 44)
@@ -0,0 +1,49 @@
+package cecj.app.go;
+
+import java.util.Arrays;
+
+import cecj.app.othello.OthelloBoard;
+import ec.util.MersenneTwisterFast;
+import games.Player;
+
+public class GoPlayer implements Player {
+
+	private static final int WPC_LENGTH = 25;
+
+	private double[] wpc;
+
+	public GoPlayer() {
+		this.wpc = new double[WPC_LENGTH];
+	}
+	
+	public GoPlayer(double[] wpc) {
+		this.wpc = wpc;
+	}
+
+	public double getValue(int row, int col) {
+		return wpc[(row - 1) * GoBoard.size() + (col - 1)];
+	}
+	
+	public double[] getWPC() {
+		return wpc;
+	}
+
+	public void setValue(int row, int col, double value) {
+		wpc[(row - 1) * GoBoard.size() + (col - 1)] = value; 
+	}
+	
+	@Override
+	public String toString() {
+		return Arrays.toString(wpc);
+	}
+	
+	public void randomize(MersenneTwisterFast random, double range) {
+		for (int i = 0; i < WPC_LENGTH; i++) {
+			wpc[i] = random.nextDouble() * range;
+			if (random.nextBoolean()) {
+				wpc[i] *= -1;
+			}
+		}
+	}
+
+}
Index: /java/ecj/cecj/app/numbers_game/CompareOnAllGame.java
===================================================================
--- /java/ecj/cecj/app/numbers_game/CompareOnAllGame.java	(revision 44)
+++ /java/ecj/cecj/app/numbers_game/CompareOnAllGame.java	(revision 44)
@@ -0,0 +1,26 @@
+package cecj.app.numbers_game;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import cecj.interaction.InteractionResult;
+import cecj.interaction.RealValuedResult;
+import cecj.utils.Pair;
+
+
+public class CompareOnAllGame extends MultiDimensionalNumbersGame {
+
+	@Override
+	protected Pair<? extends InteractionResult> compareDimensionsVectors(
+			List<BigInteger> candidateVector, List<BigInteger> testVector) {
+
+		for (int dim = 0; dim < candidateVector.size(); dim++) {
+			if (candidateVector.get(dim).compareTo(testVector.get(dim)) < 0) {
+				return new Pair<RealValuedResult>(new RealValuedResult(-1), new RealValuedResult(1));
+			}
+		}
+
+		return new Pair<RealValuedResult>(new RealValuedResult(1), new RealValuedResult(-1));
+	}
+
+}
Index: /java/ecj/cecj/app/numbers_game/CompareOnOneGame.java
===================================================================
--- /java/ecj/cecj/app/numbers_game/CompareOnOneGame.java	(revision 44)
+++ /java/ecj/cecj/app/numbers_game/CompareOnOneGame.java	(revision 44)
@@ -0,0 +1,32 @@
+package cecj.app.numbers_game;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import cecj.interaction.InteractionResult;
+import cecj.interaction.RealValuedResult;
+import cecj.utils.Pair;
+
+
+public class CompareOnOneGame extends MultiDimensionalNumbersGame {
+
+	@Override
+	protected Pair<? extends InteractionResult> compareDimensionsVectors(
+			List<BigInteger> candidateVector, List<BigInteger> testVector) {
+
+		int comparisonDimension = 0;
+		BigInteger maxDimensionValue = testVector.get(0);
+		for (int dim = 1; dim < testVector.size(); dim++) {
+			if (testVector.get(dim).compareTo(maxDimensionValue) > 0) {
+				maxDimensionValue = testVector.get(dim);
+				comparisonDimension = dim;
+			}
+		}
+
+		if (candidateVector.get(comparisonDimension).compareTo(testVector.get(comparisonDimension)) >= 0) {
+			return new Pair<RealValuedResult>(new RealValuedResult(1), new RealValuedResult(-1));
+		} else {
+			return new Pair<RealValuedResult>(new RealValuedResult(-1), new RealValuedResult(1));
+		}
+	}
+}
Index: /java/ecj/cecj/app/numbers_game/MultiDimensionalNumbersGame.java
===================================================================
--- /java/ecj/cecj/app/numbers_game/MultiDimensionalNumbersGame.java	(revision 44)
+++ /java/ecj/cecj/app/numbers_game/MultiDimensionalNumbersGame.java	(revision 44)
@@ -0,0 +1,118 @@
+package cecj.app.numbers_game;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.List;
+
+import cecj.interaction.InteractionResult;
+import cecj.problems.SymmetricTestBasedProblem;
+import cecj.statistics.ObjectiveFitnessCalculator;
+import cecj.utils.Pair;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+import ec.vector.BitVectorIndividual;
+
+public abstract class MultiDimensionalNumbersGame extends SymmetricTestBasedProblem implements
+		ObjectiveFitnessCalculator {
+
+	private static final String P_DIMENSIONS = "dimensions";
+	private static final String P_DIM_SIZE = "dimension-size";
+
+	private int numDimensions;
+	private int dimensionSize;
+	private int expectedGenomeLength;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+		
+		Parameter numDimensionsParam = base.push(P_DIMENSIONS);
+		numDimensions = state.parameters.getInt(numDimensionsParam, null, 1);
+		if (numDimensions <= 0) {
+			state.output
+				.fatal("Multi Dimensional Numbers Game dimensions must be specified and >= 0\n", numDimensionsParam);
+		}
+
+		Parameter dimensionSizeParam = base.push(P_DIM_SIZE);
+		dimensionSize = state.parameters.getInt(dimensionSizeParam, null, 1);
+		if (dimensionSize <= 0) {
+			state.output
+				.fatal("Multi Dimensional Numbers Game dimension size must be specified and >= 0\n", dimensionSizeParam);
+		}
+
+		expectedGenomeLength = numDimensions * dimensionSize;
+	}
+
+	@Override
+	public Pair<? extends InteractionResult> test(EvolutionState state, Individual candidate,
+			Individual test) {
+		if (!(candidate instanceof BitVectorIndividual) || !(test instanceof BitVectorIndividual)) {
+			state.output
+				.error("NumbersGame player's individual should be represented by bit vector\n");
+		}
+
+		BitVectorIndividual bitCandidate = (BitVectorIndividual) candidate;
+		BitVectorIndividual bitTest = (BitVectorIndividual) test;
+
+		if (bitCandidate.genomeLength() != bitTest.genomeLength()) {
+			state.output.error("NumbersGame players' bit vectors should be equal length\n");
+		}
+
+		if (bitCandidate.genomeLength() != expectedGenomeLength) {
+			state.output
+				.error("NumbersGame player's bit vector length must be equal to product of dimensions number and dimension size\n");
+		}
+
+		List<BigInteger> candidateVector = getIntegerVector(bitCandidate.genome);
+		List<BigInteger> testVector = getIntegerVector(bitTest.genome);
+
+		return compareDimensionsVectors(candidateVector, testVector);
+	}
+
+	/**
+	 * Returns objective fitness normalized to [0, 1] interval;
+	 */
+	public float calculateObjectiveFitness(EvolutionState state, Individual ind) {
+		if (!(ind instanceof BitVectorIndividual)) {
+			state.output.error("Competitor individuals should be represented by bit vectors\n");
+		}
+		BitVectorIndividual bitIndividual = (BitVectorIndividual) ind;
+
+		BigDecimal dimensionMaxValue = new BigDecimal(2).pow(dimensionSize)
+			.subtract(BigDecimal.ONE);
+		BigDecimal sumMaxValue = dimensionMaxValue.multiply(new BigDecimal(numDimensions));
+
+		List<BigInteger> dimensionVector = getIntegerVector(bitIndividual.genome);
+		BigDecimal sum = BigDecimal.ZERO;
+		for (BigInteger dimension : dimensionVector) {
+			sum = sum.add(new BigDecimal(dimension));
+		}
+
+		return sum.divide(sumMaxValue, 10, RoundingMode.DOWN).floatValue();
+	}
+
+	private List<BigInteger> getIntegerVector(boolean[] genome) {
+		List<BigInteger> result = new ArrayList<BigInteger>();
+		BigInteger bigTwo = new BigDecimal(2).toBigInteger();
+
+		for (int dim = 0; dim < numDimensions; dim++) {
+			BigInteger dimValue = BigInteger.ZERO;
+			for (int i = 0; i < dimensionSize; i++) {
+				dimValue = dimValue.multiply(bigTwo);
+				if (genome[(dim * dimensionSize) + i]) {
+					dimValue = dimValue.add(BigInteger.ONE);
+				}
+			}
+			result.add(dimValue);
+		}
+
+		return result;
+	}
+
+	protected abstract Pair<? extends InteractionResult> compareDimensionsVectors(
+			List<BigInteger> candidateVector, List<BigInteger> testVector);
+}
Index: /java/ecj/cecj/app/numbers_game/MultiDimensionalNumbersGame1.java
===================================================================
--- /java/ecj/cecj/app/numbers_game/MultiDimensionalNumbersGame1.java	(revision 44)
+++ /java/ecj/cecj/app/numbers_game/MultiDimensionalNumbersGame1.java	(revision 44)
@@ -0,0 +1,33 @@
+package cecj.app.numbers_game;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import cecj.interaction.InteractionResult;
+import cecj.interaction.RealValuedResult;
+import cecj.utils.Pair;
+
+
+public class MultiDimensionalNumbersGame1 extends MultiDimensionalNumbersGame {
+
+	@Override
+	protected Pair<? extends InteractionResult> compareDimensionsVectors(
+			List<BigInteger> candidateVector, List<BigInteger> testVector) {
+
+		int comparisonDimension = 0;
+		BigInteger maxDiffOnDimension = candidateVector.get(0).subtract(testVector.get(0)).abs();
+		for (int dim = 1; dim < candidateVector.size(); dim++) {
+			BigInteger diff = candidateVector.get(dim).subtract(testVector.get(dim)).abs();
+			if (diff.compareTo(maxDiffOnDimension) > 0) {
+				maxDiffOnDimension = diff;
+				comparisonDimension = dim;
+			}
+		}
+
+		if (candidateVector.get(comparisonDimension).compareTo(testVector.get(comparisonDimension)) > 0) {
+			return new Pair<RealValuedResult>(new RealValuedResult(1), new RealValuedResult(0));
+		} else {
+			return new Pair<RealValuedResult>(new RealValuedResult(0), new RealValuedResult(1));
+		}
+	}
+}
Index: /java/ecj/cecj/app/numbers_game/MultiDimensionalNumbersGame2.java
===================================================================
--- /java/ecj/cecj/app/numbers_game/MultiDimensionalNumbersGame2.java	(revision 44)
+++ /java/ecj/cecj/app/numbers_game/MultiDimensionalNumbersGame2.java	(revision 44)
@@ -0,0 +1,33 @@
+package cecj.app.numbers_game;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import cecj.interaction.InteractionResult;
+import cecj.interaction.RealValuedResult;
+import cecj.utils.Pair;
+
+
+public class MultiDimensionalNumbersGame2 extends MultiDimensionalNumbersGame {
+
+	@Override
+	protected Pair<? extends InteractionResult> compareDimensionsVectors(
+			List<BigInteger> candidateVector, List<BigInteger> testVector) {
+
+		int comparisonDimension = 0;
+		BigInteger minDiffOnDimension = candidateVector.get(0).subtract(testVector.get(0)).abs();
+		for (int dim = 1; dim < candidateVector.size(); dim++) {
+			BigInteger diff = candidateVector.get(dim).subtract(testVector.get(dim)).abs();
+			if (diff.compareTo(minDiffOnDimension) < 0) {
+				minDiffOnDimension = diff;
+				comparisonDimension = dim;
+			}
+		}
+
+		if (candidateVector.get(comparisonDimension).compareTo(testVector.get(comparisonDimension)) > 0) {
+			return new Pair<RealValuedResult>(new RealValuedResult(1), new RealValuedResult(0));
+		} else {
+			return new Pair<RealValuedResult>(new RealValuedResult(0), new RealValuedResult(1));
+		}
+	}
+}
Index: /java/ecj/cecj/app/numbers_game/SingleDimensionalNumbersGame.java
===================================================================
--- /java/ecj/cecj/app/numbers_game/SingleDimensionalNumbersGame.java	(revision 44)
+++ /java/ecj/cecj/app/numbers_game/SingleDimensionalNumbersGame.java	(revision 44)
@@ -0,0 +1,83 @@
+package cecj.app.numbers_game;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+import cecj.interaction.InteractionResult;
+import cecj.interaction.RealValuedResult;
+import cecj.problems.SymmetricTestBasedProblem;
+import cecj.statistics.ObjectiveFitnessCalculator;
+import cecj.utils.Pair;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.vector.BitVectorIndividual;
+
+public class SingleDimensionalNumbersGame extends SymmetricTestBasedProblem implements ObjectiveFitnessCalculator {
+
+	@Override
+	public Pair<? extends InteractionResult> test(EvolutionState state, Individual candidate,
+			Individual test) {
+		if (!(candidate instanceof BitVectorIndividual) || !(test instanceof BitVectorIndividual)) {
+			state.output.error("Competitor individuals should be represented by bit vectors\n");
+		}
+
+		BitVectorIndividual bitCandidate = (BitVectorIndividual) candidate;
+		BitVectorIndividual bitTest = (BitVectorIndividual) test;
+
+		if (bitCandidate.genomeLength() != bitTest.genomeLength()) {
+			state.output.error("Competitors' bit vectors should be equal length\n");
+		}
+
+		for (int i = 0; i < bitCandidate.genomeLength(); i++) {
+			if (bitCandidate.genome[i] != bitTest.genome[i]) {
+				if (bitCandidate.genome[i]) {
+					return new Pair<RealValuedResult>(new RealValuedResult(1),
+						new RealValuedResult(0));
+				} else {
+					return new Pair<RealValuedResult>(new RealValuedResult(0),
+						new RealValuedResult(1));
+				}
+			}
+		}
+
+		return new Pair<RealValuedResult>(new RealValuedResult(0), new RealValuedResult(0));
+	}
+
+	public float calculateObjectiveFitness(EvolutionState state, Individual ind) {
+		if (!(ind instanceof BitVectorIndividual)) {
+			state.output.error("Competitor individuals should be represented by bit vectors\n");
+		}
+		BitVectorIndividual bitIndividual = (BitVectorIndividual) ind;
+
+		BigDecimal two = new BigDecimal(2);
+		BigDecimal maxValue = two.pow(bitIndividual.genome.length).subtract(BigDecimal.ONE);
+
+		BigDecimal result = BigDecimal.ZERO;
+		for (int i = 0; i < bitIndividual.genomeLength(); i++) {
+			result = result.multiply(two);
+			if (bitIndividual.genome[i]) {
+				result = result.add(BigDecimal.ONE);
+			}
+		}
+
+		return result.divide(maxValue, 10, RoundingMode.DOWN).floatValue();
+	}
+
+	@Deprecated
+	public float calculateLongObjectiveFitness(EvolutionState state, Individual ind) {
+		if (!(ind instanceof BitVectorIndividual)) {
+			state.output.error("Competitor individuals should be represented by bit vectors\n");
+		}
+
+		BitVectorIndividual bitIndividual = (BitVectorIndividual) ind;
+		long result = 0;
+		for (int i = 0; i < bitIndividual.genomeLength(); i++) {
+			result *= 2;
+			if (bitIndividual.genome[i]) {
+				result++;
+			}
+		}
+		return result;
+	}
+}
Index: /java/ecj/cecj/app/numbers_game/singlePopArchivingSingleDimNumbersGame.params
===================================================================
--- /java/ecj/cecj/app/numbers_game/singlePopArchivingSingleDimNumbersGame.params	(revision 44)
+++ /java/ecj/cecj/app/numbers_game/singlePopArchivingSingleDimNumbersGame.params	(revision 44)
@@ -0,0 +1,61 @@
+verbosity	= 0
+
+breedthreads	= 1
+evalthreads		= 1
+seed.0			= 4357
+
+pop			= ec.Population
+state		= ec.simple.SimpleEvolutionState
+init		= ec.simple.SimpleInitializer
+finish		= ec.simple.SimpleFinisher
+breed		= ec.simple.SimpleBreeder
+stat		= ec.simple.SimpleStatistics
+exch		= ec.simple.SimpleExchanger
+eval		= coevolution.eval.ArchivingCoevolutionaryEvaluator
+
+generations				= 50
+checkpoint				= false
+prefix					= ec
+checkpoint-modulo		= 1
+
+pop.subpops						= 1
+pop.subpop.0					= coevolution.archive.ArchivingSubpopulation
+pop.subpop.0.size 				= 5
+pop.subpop.0.duplicate-retries 	= 0
+
+pop.subpop.0.species 				= ec.vector.VectorSpecies
+pop.subpop.0.species.ind			= ec.vector.BitVectorIndividual
+pop.subpop.0.species.fitness 		= ec.simple.SimpleFitness
+pop.subpop.0.species.genome-size	= 8
+pop.subpop.0.species.crossover-type	= one
+pop.subpop.0.species.mutation-prob	= 0.1
+
+pop.subpop.0.species.pipe							= ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0					= ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.1			= ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1.size 	= 2
+
+pop.subpop.0.species.pipe.source.0.source.0					= ec.select.MultiSelection
+pop.subpop.0.species.pipe.source.0.source.0.num-selects		= 2
+pop.subpop.0.species.pipe.source.0.source.0.select.0		= coevolution.archive.ArchiveRandomSelection
+pop.subpop.0.species.pipe.source.0.source.0.select.0.prob	= 0.5
+pop.subpop.0.species.pipe.source.0.source.0.select.0.size	= 5
+pop.subpop.0.species.pipe.source.0.source.0.select.1		= ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.0.select.1.size 	= 2
+pop.subpop.0.species.pipe.source.0.source.0.select.1.prob 	= 0.5
+
+eval.archive										= coevolution.archive.BestOfGenerationArchive
+eval.problem										= coevolution.app.numbers_game.SingleDimensionalNumbersGame
+eval.statistics										= coevolution.statistics.SimpleCoevolutionaryStatistics
+eval.interaction-scheme								= coevolution.interaction.IntraPopulationInteractionScheme
+eval.subpop.0.sampling-method						= coevolution.sampling.AllSamplingMethod
+eval.subpop.0.fitness-method						= coevolution.fitness.SimpleSumFitness
+eval.subpop.0.archive-sampling-method				= coevolution.sampling.AllSamplingMethod
+
+stat.file		= $out.stat
+stat.num-children 			= 1
+stat.child.0 				= coevolution.statistics.AverageObjectiveFitnessChartStatistics
+stat.child.0.fitness-calc 	= coevolution.app.numbers_game.SingleDimensionalNumbersGame 
+stat.child.0.title 			= Average performance
+stat.child.0.x-axis-label 	= generation
+stat.child.0.y-axis-label 	= fitness
Index: /java/ecj/cecj/app/numbers_game/singlePopSingleDimNumbersGame.params
===================================================================
--- /java/ecj/cecj/app/numbers_game/singlePopSingleDimNumbersGame.params	(revision 44)
+++ /java/ecj/cecj/app/numbers_game/singlePopSingleDimNumbersGame.params	(revision 44)
@@ -0,0 +1,58 @@
+verbosity	= 0
+
+breedthreads	= 1
+evalthreads		= 1
+seed.0			= 4357
+
+pop			= ec.Population
+state		= ec.simple.SimpleEvolutionState
+init		= ec.simple.SimpleInitializer
+finish		= ec.simple.SimpleFinisher
+breed		= ec.simple.SimpleBreeder
+stat		= ec.simple.SimpleStatistics
+exch		= ec.simple.SimpleExchanger
+eval		= coevolution.eval.SimpleCoevolutionaryEvaluator
+
+generations				= 50
+quit-on-run-complete	= true
+checkpoint				= false
+prefix					= ec
+checkpoint-modulo		= 1
+
+stat.file		= $out.stat
+
+pop.subpops			= 1
+pop.subpop.0		= ec.Subpopulation
+
+pop.subpop.0.size 				= 5
+pop.subpop.0.duplicate-retries 	= 0
+pop.subpop.0.species 			= ec.vector.VectorSpecies
+
+pop.subpop.0.species.fitness 		= ec.simple.SimpleFitness
+pop.subpop.0.species.ind			= ec.vector.BitVectorIndividual
+
+pop.subpop.0.species.genome-size	= 8
+pop.subpop.0.species.crossover-type	= one
+pop.subpop.0.species.crossover-prob	= 0.8
+pop.subpop.0.species.mutation-prob	= 0.1
+
+pop.subpop.0.species.pipe					= ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0			= ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0	= ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1	= ec.select.TournamentSelection
+
+select.tournament.size	= 2
+breed.elites.0 			= 1
+
+eval.problem					= coevolution.problems.SingleDimensionalNumbersGame
+eval.interaction-scheme			= coevolution.interaction.IntraPopulationInteractionScheme
+eval.subpop.0.sampling-method	= coevolution.sampling.AllSamplingMethod
+eval.subpop.0.fitness-method	= coevolution.fitness.SimpleSumFitness
+
+stat 						= ec.simple.SimpleShortStatistics
+stat.num-children 			= 1
+stat.child.0 				= coevolution.statistics.AverageObjectiveFitnessChartStatistics
+stat.child.0.fitness-calc 	= coevolution.problems.SingleDimensionalNumbersGame 
+stat.child.0.title 			= Average performance
+stat.child.0.x-axis-label 	= generation
+stat.child.0.y-axis-label 	= fitness
Index: /java/ecj/cecj/app/numbers_game/tournamentSingleDimNumbersGame.params
===================================================================
--- /java/ecj/cecj/app/numbers_game/tournamentSingleDimNumbersGame.params	(revision 44)
+++ /java/ecj/cecj/app/numbers_game/tournamentSingleDimNumbersGame.params	(revision 44)
@@ -0,0 +1,50 @@
+verbosity	= 0
+
+breedthreads	= 1
+evalthreads	= 1
+seed.0		= 4357
+
+pop			= ec.Population
+state		= ec.simple.SimpleEvolutionState
+init		= ec.simple.SimpleInitializer
+finish		= ec.simple.SimpleFinisher
+breed		= ec.simple.SimpleBreeder
+stat 		= ec.simple.SimpleShortStatistics
+exch		= ec.simple.SimpleExchanger
+eval		= coevolution.eval.TournamentCoevolutionaryEvaluator
+
+generations				= 500
+checkpoint				= false
+prefix					= ec
+checkpoint-modulo		= 1
+
+pop.subpops						= 1
+pop.subpop.0					= ec.Subpopulation
+pop.subpop.0.size 				= 25
+pop.subpop.0.duplicate-retries 	= 0
+
+pop.subpop.0.species 						= ec.vector.VectorSpecies
+pop.subpop.0.species.ind					= ec.vector.BitVectorIndividual
+pop.subpop.0.species.fitness 				= ec.simple.SimpleFitness
+pop.subpop.0.species.genome-size			= 100
+pop.subpop.0.species.crossover-type			= one
+pop.subpop.0.species.mutation-prob			= 0.05
+
+pop.subpop.0.species.pipe					= ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0			= ec.select.FitProportionateSelection
+pop.subpop.0.species.pipe.source.1			= ec.select.FitProportionateSelection
+
+eval.problem		= coevolution.app.numbers_game.SingleDimensionalNumbersGame
+
+stat.file					= $out.stat
+stat.num-children 			= 2
+stat.child.0 				= coevolution.statistics.AverageObjectiveFitnessChartStatistics
+stat.child.0.title 			= Average performance
+stat.child.0.x-axis-label 	= generation
+stat.child.0.y-axis-label 	= fitness
+stat.child.0.fitness-calc 	= coevolution.app.numbers_game.SingleDimensionalNumbersGame 
+stat.child.1 				= coevolution.statistics.AverageSubjectiveFitnessChartStatistics
+stat.child.1.title 			= Average subjective performance
+stat.child.1.x-axis-label 	= generation
+stat.child.1.y-axis-label 	= fitness
+stat.child.1.fitness-calc 	= coevolution.app.numbers_game.SingleDimensionalNumbersGame 
Index: /java/ecj/cecj/app/numbers_game/twoPopMultiDimNumbersGame.params
===================================================================
--- /java/ecj/cecj/app/numbers_game/twoPopMultiDimNumbersGame.params	(revision 44)
+++ /java/ecj/cecj/app/numbers_game/twoPopMultiDimNumbersGame.params	(revision 44)
@@ -0,0 +1,75 @@
+verbosity	= 0
+
+breedthreads	= 1
+evalthreads		= 1
+seed.0			= 4357
+
+pop			= ec.Population
+state		= ec.simple.SimpleEvolutionState
+init		= ec.simple.SimpleInitializer
+finish		= ec.simple.SimpleFinisher
+breed		= ec.simple.SimpleBreeder
+stat 		= ec.simple.SimpleShortStatistics
+exch		= ec.simple.SimpleExchanger
+eval		= coevolution.eval.SimpleCoevolutionaryEvaluator
+
+generations				= 500
+checkpoint				= false
+prefix					= ec
+checkpoint-modulo		= 1
+
+pop.subpops			= 2
+pop.subpop.0		= ec.Subpopulation
+pop.subpop.1		= ec.Subpopulation
+
+pop.subpop.0.size 				= 25
+pop.subpop.1.size 				= 25
+pop.subpop.0.duplicate-retries 	= 0
+pop.subpop.1.duplicate-retries 	= 0
+
+pop.subpop.0.species 				= ec.vector.VectorSpecies
+pop.subpop.1.species 				= ec.vector.VectorSpecies
+pop.subpop.0.species.fitness 		= ec.simple.SimpleFitness
+pop.subpop.1.species.fitness 		= ec.simple.SimpleFitness
+pop.subpop.0.species.ind			= ec.vector.BitVectorIndividual
+pop.subpop.1.species.ind			= ec.vector.BitVectorIndividual
+
+pop.subpop.0.species.genome-size	= 100
+pop.subpop.1.species.genome-size	= 100
+pop.subpop.0.species.crossover-type	= one
+pop.subpop.1.species.crossover-type	= one
+pop.subpop.0.species.mutation-prob	= 0.05
+pop.subpop.1.species.mutation-prob	= 0.05
+
+pop.subpop.0.species.pipe			= ec.vector.breed.VectorMutationPipeline
+pop.subpop.1.species.pipe			= ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0	= ec.select.FitProportionateSelection
+pop.subpop.1.species.pipe.source.0	= ec.select.FitProportionateSelection
+
+eval.problem								= coevolution.app.numbers_game.MultiDimensionalNumbersGame2
+eval.problem.dimensions						= 10
+eval.problem.dimension-size					= 10
+eval.interaction-scheme						= coevolution.interaction.InterPopulationInteractionScheme
+eval.subpop.0.sampling-method				= coevolution.sampling.RandomSamplingMethod
+eval.subpop.0.sampling-method.sample-size	= 15
+eval.subpop.0.fitness-method				= coevolution.fitness.SimpleSumFitness
+eval.subpop.1.sampling-method				= coevolution.sampling.RandomSamplingMethod
+eval.subpop.1.sampling-method.sample-size	= 15
+eval.subpop.1.fitness-method				= coevolution.fitness.SimpleSumFitness
+
+stat.file									= $out.stat
+stat.num-children 							= 2
+stat.child.0 								= coevolution.statistics.AverageObjectiveFitnessChartStatistics
+stat.child.0.title 							= Average performance
+stat.child.0.x-axis-label 					= generation
+stat.child.0.y-axis-label 					= fitness
+stat.child.0.fitness-calc 					= coevolution.app.numbers_game.MultiDimensionalNumbersGame2
+stat.child.0.fitness-calc.dimensions 		= 10
+stat.child.0.fitness-calc.dimension-size 	= 10
+stat.child.1 								= coevolution.statistics.AverageSubjectiveFitnessChartStatistics
+stat.child.1.title 							= Average subjective performance
+stat.child.1.x-axis-label 					= generation
+stat.child.1.y-axis-label 					= fitness
+stat.child.1.fitness-calc 					= coevolution.app.numbers_game.MultiDimensionalNumbersGame2 
+stat.child.1.fitness-calc.dimensions 		= 10
+stat.child.1.fitness-calc.dimension-size 	= 10
Index: /java/ecj/cecj/app/numbers_game/twoPopSingleDimNumbersGame.params
===================================================================
--- /java/ecj/cecj/app/numbers_game/twoPopSingleDimNumbersGame.params	(revision 44)
+++ /java/ecj/cecj/app/numbers_game/twoPopSingleDimNumbersGame.params	(revision 44)
@@ -0,0 +1,67 @@
+verbosity	= 0
+
+breedthreads	= 1
+evalthreads		= 1
+seed.0			= 4357
+
+pop			= ec.Population
+state		= ec.simple.SimpleEvolutionState
+init		= ec.simple.SimpleInitializer
+finish		= ec.simple.SimpleFinisher
+breed		= ec.simple.SimpleBreeder
+stat 		= ec.simple.SimpleShortStatistics
+exch		= ec.simple.SimpleExchanger
+eval		= coevolution.eval.SimpleCoevolutionaryEvaluator
+
+generations				= 500
+checkpoint				= false
+prefix					= ec
+checkpoint-modulo		= 1
+
+pop.subpops			= 2
+pop.subpop.0		= ec.Subpopulation
+pop.subpop.1		= ec.Subpopulation
+
+pop.subpop.0.size 				= 25
+pop.subpop.1.size 				= 25
+pop.subpop.0.duplicate-retries 	= 0
+pop.subpop.1.duplicate-retries 	= 0
+
+pop.subpop.0.species 				= ec.vector.VectorSpecies
+pop.subpop.1.species 				= ec.vector.VectorSpecies
+pop.subpop.0.species.fitness 		= ec.simple.SimpleFitness
+pop.subpop.1.species.fitness 		= ec.simple.SimpleFitness
+pop.subpop.0.species.ind			= ec.vector.BitVectorIndividual
+pop.subpop.1.species.ind			= ec.vector.BitVectorIndividual
+
+pop.subpop.0.species.genome-size	= 100
+pop.subpop.1.species.genome-size	= 100
+pop.subpop.0.species.crossover-type	= one
+pop.subpop.1.species.crossover-type	= one
+pop.subpop.0.species.mutation-prob	= 0.05
+pop.subpop.1.species.mutation-prob	= 0.05
+
+pop.subpop.0.species.pipe			= ec.vector.breed.VectorMutationPipeline
+pop.subpop.1.species.pipe			= ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0	= ec.select.FitProportionateSelection
+pop.subpop.1.species.pipe.source.0	= ec.select.FitProportionateSelection
+
+eval.problem					= coevolution.app.numbers_game.SingleDimensionalNumbersGame
+eval.interaction-scheme			= coevolution.interaction.InterPopulationInteractionScheme
+eval.subpop.0.sampling-method	= coevolution.sampling.AllSamplingMethod
+eval.subpop.0.fitness-method	= coevolution.fitness.SimpleSumFitness
+eval.subpop.1.sampling-method	= coevolution.sampling.AllSamplingMethod
+eval.subpop.1.fitness-method	= coevolution.fitness.SimpleSumFitness
+
+stat.file					= $out.stat
+stat.num-children 			= 2
+stat.child.0 				= coevolution.statistics.AverageObjectiveFitnessChartStatistics
+stat.child.0.title 			= Average performance
+stat.child.0.x-axis-label 	= generation
+stat.child.0.y-axis-label 	= fitness
+stat.child.0.fitness-calc 	= coevolution.app.numbers_game.SingleDimensionalNumbersGame 
+stat.child.1 				= coevolution.statistics.AverageSubjectiveFitnessChartStatistics
+stat.child.1.title 			= Average subjective performance
+stat.child.1.x-axis-label 	= generation
+stat.child.1.y-axis-label 	= fitness
+stat.child.1.fitness-calc 	= coevolution.app.numbers_game.SingleDimensionalNumbersGame 
Index: /java/ecj/cecj/app/numbers_game/twoPopSingleDimNumbersGameRandomSampling.params
===================================================================
--- /java/ecj/cecj/app/numbers_game/twoPopSingleDimNumbersGameRandomSampling.params	(revision 44)
+++ /java/ecj/cecj/app/numbers_game/twoPopSingleDimNumbersGameRandomSampling.params	(revision 44)
@@ -0,0 +1,69 @@
+verbosity	= 0
+
+breedthreads	= 1
+evalthreads		= 1
+seed.0			= 4357
+
+pop			= ec.Population
+state		= ec.simple.SimpleEvolutionState
+init		= ec.simple.SimpleInitializer
+finish		= ec.simple.SimpleFinisher
+breed		= ec.simple.SimpleBreeder
+stat 		= ec.simple.SimpleShortStatistics
+exch		= ec.simple.SimpleExchanger
+eval		= coevolution.eval.SimpleCoevolutionaryEvaluator
+
+generations				= 50
+checkpoint				= false
+prefix					= ec
+checkpoint-modulo		= 1
+
+pop.subpops			= 2
+pop.subpop.0		= ec.Subpopulation
+pop.subpop.1		= ec.Subpopulation
+
+pop.subpop.0.size 				= 5
+pop.subpop.1.size 				= 5
+pop.subpop.0.duplicate-retries 	= 0
+pop.subpop.1.duplicate-retries 	= 0
+
+pop.subpop.0.species 				= ec.vector.VectorSpecies
+pop.subpop.1.species 				= ec.vector.VectorSpecies
+pop.subpop.0.species.fitness 		= ec.simple.SimpleFitness
+pop.subpop.1.species.fitness 		= ec.simple.SimpleFitness
+pop.subpop.0.species.ind			= ec.vector.BitVectorIndividual
+pop.subpop.1.species.ind			= ec.vector.BitVectorIndividual
+
+pop.subpop.0.species.genome-size	= 10
+pop.subpop.1.species.genome-size	= 10
+pop.subpop.0.species.crossover-type	= one
+pop.subpop.1.species.crossover-type	= one
+pop.subpop.0.species.mutation-prob	= 0.05
+pop.subpop.1.species.mutation-prob	= 0.05
+
+pop.subpop.0.species.pipe			= ec.vector.breed.VectorMutationPipeline
+pop.subpop.1.species.pipe			= ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0	= ec.select.FitProportionateSelection
+pop.subpop.1.species.pipe.source.0	= ec.select.FitProportionateSelection
+
+eval.problem								= coevolution.app.numbers_game.SingleDimensionalNumbersGame
+eval.interaction-scheme						= coevolution.interaction.InterPopulationInteractionScheme
+eval.subpop.0.sampling-method				= coevolution.sampling.RandomSamplingMethod
+eval.subpop.0.sampling-method.sample-size 	= 1
+eval.subpop.0.fitness-method				= coevolution.fitness.SimpleSumFitness
+eval.subpop.1.sampling-method				= coevolution.sampling.RandomSamplingMethod
+eval.subpop.1.sampling-method.sample-size 	= 1
+eval.subpop.1.fitness-method				= coevolution.fitness.SimpleSumFitness
+
+stat.file					= $out.stat
+stat.num-children 			= 2
+stat.child.0 				= coevolution.statistics.AverageObjectiveFitnessChartStatistics
+stat.child.0.title 			= Average performance
+stat.child.0.x-axis-label 	= generation
+stat.child.0.y-axis-label 	= fitness
+stat.child.0.fitness-calc 	= coevolution.app.numbers_game.SingleDimensionalNumbersGame 
+stat.child.1 				= coevolution.statistics.AverageSubjectiveFitnessChartStatistics
+stat.child.1.title 			= Average subjective performance
+stat.child.1.x-axis-label 	= generation
+stat.child.1.y-axis-label 	= fitness
+stat.child.1.fitness-calc 	= coevolution.app.numbers_game.SingleDimensionalNumbersGame 
Index: /java/ecj/cecj/app/othello/Othello.java
===================================================================
--- /java/ecj/cecj/app/othello/Othello.java	(revision 44)
+++ /java/ecj/cecj/app/othello/Othello.java	(revision 44)
@@ -0,0 +1,77 @@
+package cecj.app.othello;
+
+import cecj.interaction.InteractionResult;
+import cecj.interaction.WinDrawLossResult;
+import cecj.interaction.WinDrawLossResult.Result;
+import cecj.problems.SymmetricTestBasedProblem;
+import cecj.utils.Pair;
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+import ec.vector.DoubleVectorIndividual;
+import games.Player;
+import games.scenarios.GameScenario;
+import games.scenarios.RandomizedTwoPlayersGameScenario;
+import games.scenarios.SimpleTwoPlayersGameScenario;
+
+public class Othello extends SymmetricTestBasedProblem {
+
+	private static final int WPC_LENGTH = 64;
+	private static final String P_RANDOMNESS = "randomness";
+
+	private double randomness;
+	private boolean randomizedPlay;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+
+		Parameter randomnessParam = base.push(P_RANDOMNESS);
+		if (state.parameters.exists(randomnessParam)) {
+			randomness = state.parameters.getDoubleWithDefault(randomnessParam, null, 0);
+			randomizedPlay = true;
+		} else {
+			randomizedPlay = false;
+		}
+	}
+
+	@Override
+	public Pair<? extends InteractionResult> test(EvolutionState state, Individual candidate,
+			Individual test) {
+		if (!(candidate instanceof DoubleVectorIndividual)
+				|| !(test instanceof DoubleVectorIndividual)) {
+			state.output.error("Othello players should be represented by floats vectors\n");
+		}
+
+		double[] wpc1 = ((DoubleVectorIndividual) candidate).genome;
+		double[] wpc2 = ((DoubleVectorIndividual) test).genome;
+
+		if (wpc1.length != WPC_LENGTH || wpc2.length != WPC_LENGTH) {
+			state.output.error("Players WPC vectors length should be 64\n");
+		}
+
+		OthelloPlayer player1 = new OthelloPlayer(wpc1);
+		OthelloPlayer player2 = new OthelloPlayer(wpc2);
+		OthelloGame game = new OthelloGame(new OthelloBoard());
+
+		GameScenario scenario;
+		if (randomizedPlay) {
+			scenario = new RandomizedTwoPlayersGameScenario(state.random[0], new Player[] {
+					player1, player2 }, new double[] { randomness, randomness });
+		} else {
+			scenario = new SimpleTwoPlayersGameScenario(new Player[] { player1, player2 });
+		}
+
+		int result = scenario.play(game);
+		if (result > 0) {
+			return new Pair<WinDrawLossResult>(new WinDrawLossResult(Result.WIN),
+					new WinDrawLossResult(Result.LOSS));
+		} else if (result < 0) {
+			return new Pair<WinDrawLossResult>(new WinDrawLossResult(Result.LOSS),
+					new WinDrawLossResult(Result.WIN));
+		} else {
+			return new Pair<WinDrawLossResult>(new WinDrawLossResult(Result.DRAW),
+					new WinDrawLossResult(Result.DRAW));
+		}
+	}
+}
Index: /java/ecj/cecj/app/othello/OthelloBestEvolvedPlayer.java
===================================================================
--- /java/ecj/cecj/app/othello/OthelloBestEvolvedPlayer.java	(revision 44)
+++ /java/ecj/cecj/app/othello/OthelloBestEvolvedPlayer.java	(revision 44)
@@ -0,0 +1,20 @@
+package cecj.app.othello;
+
+public class OthelloBestEvolvedPlayer extends OthelloPlayerFitnessCalculator {
+
+	double[] wpc = { 4.622507f, -1.477853f, 1.409644f, -0.066975f, -0.305214f, 1.633019f,
+			-1.050899f, 4.365550f, -1.329145f, -2.245663f, -1.060633f, -0.541089f, -0.332716f,
+			-0.475830f, -2.274535f, -0.032595f, 2.681550f, -0.906628f, 0.229372f, 0.059260f,
+			-0.150415f, 0.321982f, -1.145060f, 2.986767f, -0.746066f, -0.317389f, 0.140040f,
+			-0.045266f, 0.236595f, 0.158543f, -0.720833f, -0.131124f, -0.305566f, -0.328398f,
+			0.073872f, -0.131472f, -0.172101f, 0.016603f, -0.511448f, -0.264125f, 2.777411f,
+			-0.769551f, 0.676483f, 0.282190f, 0.007184f, 0.269876f, -1.408169f, 2.396238f,
+			-1.566175f, -3.049899f, -0.637408f, -0.077690f, -0.648382f, -0.911066f, -3.329772f,
+			-0.870962f, 5.046583f, -1.468806f, 1.545046f, -0.031175f, 0.263998f, 2.063148f,
+			-0.148002f, 5.781035f };
+
+	@Override
+	protected OthelloPlayer getPlayer() {
+		return new OthelloPlayer(wpc);
+	}
+}
Index: /java/ecj/cecj/app/othello/OthelloBoard.java
===================================================================
--- /java/ecj/cecj/app/othello/OthelloBoard.java	(revision 44)
+++ /java/ecj/cecj/app/othello/OthelloBoard.java	(revision 44)
@@ -0,0 +1,135 @@
+package cecj.app.othello;
+
+import java.util.Arrays;
+import games.Board;
+import games.Player;
+
+public class OthelloBoard implements Board {
+	private static final int BOARD_SIZE = 8;
+	private static final int BOARD_MARGIN = 2;
+	
+	private static final int EMPTY = -1;
+	
+	public static final int BLACK = 0;
+	public static final int WHITE = 1;
+	
+	public static final int NUM_DIRECTIONS = 8;
+	public static final int ROW_DIR[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
+	public static final int COL_DIR[] = { -1, 0, 1, -1, 1, -1, 0, 1 };
+
+	private int board[][];
+
+	public OthelloBoard() {
+		board = new int[BOARD_SIZE + BOARD_MARGIN][BOARD_SIZE + BOARD_MARGIN];
+		reset();
+	}
+
+	private void initBoard() {
+		setPiece(4, 4, WHITE);
+		setPiece(4, 5, BLACK);
+		setPiece(5, 4, BLACK);
+		setPiece(5, 5, WHITE);
+	}
+
+	public int countPieces(int player) {
+		int count = 0;
+		for (int row = 1; row <= BOARD_SIZE; row++) {
+			for (int col = 1; col <= BOARD_SIZE; col++) {
+				if (getPiece(row, col) == player) {
+					count++;
+				}
+			}
+		}
+		return count;
+	}
+
+	public static int size() {
+		return BOARD_SIZE;
+	}
+
+	public int getPiece(int row, int col) {
+		return board[row][col];
+	}
+
+	public void setPiece(int row, int col, int player) {
+		board[row][col] = player;
+	}
+
+	public boolean isEmpty(int row, int col) {
+		return (getPiece(row, col) == EMPTY);
+	}
+
+	public int getPiece(int row, int col, int dir, int dist) {
+		return getPiece(row + dist * ROW_DIR[dir], col + dist * COL_DIR[dir]);
+	}
+
+	public void setPiece(int row, int col, int dir, int dist, int player) {
+		setPiece(row + dist * ROW_DIR[dir], col + dist * COL_DIR[dir], player);
+	}
+	
+	public OthelloMove getShiftedMove(int row, int col, int dir, int dist) {
+		return new OthelloMove(row + dist * ROW_DIR[dir], col + dist * COL_DIR[dir]);
+	}
+	
+	@Override
+	public String toString() {
+		StringBuilder builder = new StringBuilder();
+		builder.append("    ");
+		for (int i = 1; i <= BOARD_SIZE; i++) {
+			builder.append(i + " ");
+		}
+		builder.append("\n");
+		
+		for (int i = 0; i < BOARD_SIZE + BOARD_MARGIN; i++) {
+			if (i > 0 && i <= BOARD_SIZE) {
+				builder.append(i + " ");
+			} else {
+				builder.append("  ");				
+			}
+			for (int j = 0; j < BOARD_SIZE + BOARD_MARGIN; j++) {
+				builder.append(((board[i][j] == -1) ? "-" : board[i][j]) + " ");
+			}
+			builder.append("\n");
+		}
+		return builder.toString();
+	}
+
+	public void reset() {
+		for (int row = 0; row < board.length; row++) {
+			Arrays.fill(board[row], EMPTY);
+		}
+
+		initBoard();		
+	}
+	
+	@Override
+	public OthelloBoard clone() {
+		OthelloBoard clone = new OthelloBoard();
+		for (int row = 1; row <= BOARD_SIZE; row++) {
+			for (int col = 1; col <= BOARD_SIZE; col++) {
+				clone.board[row][col] = board[row][col];
+			}
+		}
+		return clone;
+	}
+	
+	public double evaluate(Player player) {
+		double result = 0;
+		for (int row = 1; row <= BOARD_SIZE; row++) {
+			for (int col = 1; col <= BOARD_SIZE; col++) {
+				result += getValueAt(row, col) * player.getValue(row, col);
+			}
+		}
+		return result;
+	}
+	
+	public int getValueAt(int row, int col) {
+		if (board[row][col] == OthelloBoard.BLACK) {
+			return 1;
+		} else if (board[row][col] == OthelloBoard.WHITE) {
+			return -1;
+		} else {
+			return 0;
+		}
+	}
+}
Index: /java/ecj/cecj/app/othello/OthelloGame.java
===================================================================
--- /java/ecj/cecj/app/othello/OthelloGame.java	(revision 44)
+++ /java/ecj/cecj/app/othello/OthelloGame.java	(revision 44)
@@ -0,0 +1,119 @@
+package cecj.app.othello;
+
+import games.Board;
+import games.BoardGame;
+import games.GameMove;
+import games.Player;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class OthelloGame implements BoardGame {
+
+	private static final int NUM_PLAYERS = 2;
+
+	private int currentPlayer;
+	private OthelloBoard board;
+
+	public OthelloGame(OthelloBoard board) {
+		this.board = board;
+	}
+
+	public boolean endOfGame() {
+		for (int row = 1; row <= OthelloBoard.size(); row++) {
+			for (int col = 1; col <= OthelloBoard.size(); col++) {
+				if (canPlace(row, col, currentPlayer)
+						|| canPlace(row, col, getOpponent(currentPlayer))) {
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+
+	public double evalMove(Player player, GameMove move) {
+		List<Integer> directions = findDirections(move.getRow(), move.getCol(), currentPlayer);
+
+		float result = 0;
+		for (int dir : directions) {
+			int dist = 1;
+			while (board.getPiece(move.getRow(), move.getCol(), dir, dist) == getOpponent(currentPlayer)) {
+				GameMove shifted = board.getShiftedMove(move.getRow(), move.getCol(), dir, dist);
+				result += 2 * player.getValue(shifted.getRow(), shifted.getCol());
+				dist++;
+			}
+		}
+
+		return result + player.getValue(move.getRow(), move.getCol());
+	}
+
+	public List<? extends GameMove> findMoves() {
+		List<OthelloMove> moves = new ArrayList<OthelloMove>();
+		for (int row = 1; row <= OthelloBoard.size(); row++) {
+			for (int col = 1; col <= OthelloBoard.size(); col++) {
+				if (canPlace(row, col, currentPlayer)) {
+					moves.add(new OthelloMove(row, col));
+				}
+			}
+		}
+		return moves;
+	}
+
+	public void makeMove(GameMove move) {
+		List<Integer> directions = findDirections(move.getRow(), move.getCol(), currentPlayer);
+		for (int dir : directions) {
+			int dist = 1;
+			board.setPiece(move.getRow(), move.getCol(), currentPlayer);
+			while (board.getPiece(move.getRow(), move.getCol(), dir, dist) == getOpponent(currentPlayer)) {
+				board.setPiece(move.getRow(), move.getCol(), dir, dist, currentPlayer);
+				dist++;
+			}
+		}
+	}
+
+	List<Integer> findDirections(int row, int col, int player) {
+		List<Integer> directions = new ArrayList<Integer>();
+
+		if (board.isEmpty(row, col)) {
+			for (int dir = 0; dir < OthelloBoard.NUM_DIRECTIONS; dir++) {
+				int dist = 1;
+				while (board.getPiece(row, col, dir, dist) == getOpponent(player)) {
+					dist++;
+				}
+				if (dist > 1 && board.getPiece(row, col, dir, dist) == player) {
+					directions.add(dir);
+				}
+			}
+		}
+		return directions;
+	}
+
+	boolean canPlace(int row, int col, int curPlayer) {
+		return (!findDirections(row, col, curPlayer).isEmpty());
+	}
+
+	int getOpponent(int player) {
+		return ((player + 1) % NUM_PLAYERS);
+	}
+
+	public void switchPlayer() {
+		currentPlayer = getOpponent(currentPlayer);
+	}
+
+	public int getCurrentPlayer() {
+		return currentPlayer;
+	}
+	
+	public int getOutcome() {
+		return (board.countPieces(0) - board.countPieces(1));
+	}
+
+	public void reset() {
+		board.reset();
+		currentPlayer = 0;
+	}
+
+	public Board getBoard() {
+		return board;
+	}
+}
Index: /java/ecj/cecj/app/othello/OthelloHeuristicPlayer.java
===================================================================
--- /java/ecj/cecj/app/othello/OthelloHeuristicPlayer.java	(revision 44)
+++ /java/ecj/cecj/app/othello/OthelloHeuristicPlayer.java	(revision 44)
@@ -0,0 +1,16 @@
+package cecj.app.othello;
+
+public class OthelloHeuristicPlayer extends OthelloPlayerFitnessCalculator {
+
+	double[] wpc = { 1.00f, -0.25f, 0.10f, 0.05f, 0.05f, 0.10f, -0.25f, 1.00f, -0.25f, -0.25f,
+			0.01f, 0.01f, 0.01f, 0.01f, -0.25f, -0.25f, 0.10f, 0.01f, 0.05f, 0.02f, 0.02f, 0.05f,
+			0.01f, 0.10f, 0.05f, 0.01f, 0.02f, 0.01f, 0.01f, 0.02f, 0.01f, 0.05f, 0.05f, 0.01f,
+			0.02f, 0.01f, 0.01f, 0.02f, 0.01f, 0.05f, 0.10f, 0.01f, 0.05f, 0.02f, 0.02f, 0.05f,
+			0.01f, 0.10f, -0.25f, -0.25f, 0.01f, 0.01f, 0.01f, 0.01f, -0.25f, -0.25f, 1.00f,
+			-0.25f, 0.10f, 0.05f, 0.05f, 0.10f, -0.25f, 1.00f };
+
+	@Override
+	protected OthelloPlayer getPlayer() {
+		return new OthelloPlayer(wpc);
+	}
+}
Index: /java/ecj/cecj/app/othello/OthelloMove.java
===================================================================
--- /java/ecj/cecj/app/othello/OthelloMove.java	(revision 44)
+++ /java/ecj/cecj/app/othello/OthelloMove.java	(revision 44)
@@ -0,0 +1,34 @@
+package cecj.app.othello;
+
+import games.GameMove;
+
+public class OthelloMove implements GameMove {
+	private int row;
+	private int col;
+
+	public OthelloMove(int row, int col) {
+		this.row = row;
+		this.col = col;
+	}
+
+	public int getRow() {
+		return row;
+	}
+
+	public int getCol() {
+		return col;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (!(obj instanceof OthelloMove))
+			return false;
+		OthelloMove move = (OthelloMove) obj;
+		return (this.row == move.row && this.col == move.col);
+	}
+	
+	@Override
+	public String toString() {
+		return "(" + row + ", " + col + ")";
+	}
+}
Index: /java/ecj/cecj/app/othello/OthelloPlayer.java
===================================================================
--- /java/ecj/cecj/app/othello/OthelloPlayer.java	(revision 44)
+++ /java/ecj/cecj/app/othello/OthelloPlayer.java	(revision 44)
@@ -0,0 +1,47 @@
+package cecj.app.othello;
+
+import java.util.Arrays;
+
+import ec.util.MersenneTwisterFast;
+
+import games.Player;
+
+public class OthelloPlayer implements Player {
+	private static final int WPC_LENGTH = 64;
+
+	private double[] wpc;
+
+	public OthelloPlayer() {
+		this.wpc = new double[WPC_LENGTH];
+	}
+	
+	public OthelloPlayer(double[] wpc) {
+		this.wpc = wpc;
+	}
+
+	public double getValue(int row, int col) {
+		return wpc[(row - 1) * OthelloBoard.size() + (col - 1)];
+	}
+	
+	public double[] getWPC() {
+		return wpc;
+	}
+
+	public void setValue(int row, int col, double value) {
+		wpc[(row - 1) * OthelloBoard.size() + (col - 1)] = value; 
+	}
+	
+	@Override
+	public String toString() {
+		return Arrays.toString(wpc);
+	}
+	
+	public void randomize(MersenneTwisterFast random, double range) {
+		for (int i = 0; i < WPC_LENGTH; i++) {
+			wpc[i] = random.nextDouble() * range;
+			if (random.nextBoolean()) {
+				wpc[i] *= -1;
+			}
+		}
+	}
+}
Index: /java/ecj/cecj/app/othello/OthelloPlayerFitnessCalculator.java
===================================================================
--- /java/ecj/cecj/app/othello/OthelloPlayerFitnessCalculator.java	(revision 44)
+++ /java/ecj/cecj/app/othello/OthelloPlayerFitnessCalculator.java	(revision 44)
@@ -0,0 +1,80 @@
+package cecj.app.othello;
+
+import cecj.statistics.ObjectiveFitnessCalculator;
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+import ec.vector.DoubleVectorIndividual;
+import games.BoardGame;
+import games.Player;
+import games.scenarios.GameScenario;
+import games.scenarios.RandomizedTwoPlayersGameScenario;
+
+public abstract class OthelloPlayerFitnessCalculator implements ObjectiveFitnessCalculator {
+
+	protected static final int WPC_LENGTH = 64;
+	
+	protected static final String P_EVALUATOR_RANDOMNESS = "evaluator-randomness";
+	protected static final String P_EVALUATED_RANDOMNESS = "evaluated-randomness";
+
+	private static final String P_PLAY_BOTH = "play-both";
+	private static final String P_REPEATS = "repeats";
+
+	protected double evaluatedRandomness;
+	protected double evaluatorRandomness;
+	private boolean playBoth;
+	private int repeats;
+
+	public void setup(EvolutionState state, Parameter base) {
+		Parameter randomnessParam = base.push(P_EVALUATED_RANDOMNESS);
+		evaluatedRandomness = state.parameters.getDoubleWithDefault(randomnessParam, null, 0);
+
+		randomnessParam = base.push(P_EVALUATOR_RANDOMNESS);
+		evaluatorRandomness = state.parameters.getDoubleWithDefault(randomnessParam, null, 0);
+
+		Parameter repetitionsParam = base.push(P_REPEATS);
+		repeats = state.parameters.getIntWithDefault(repetitionsParam, null, 1);
+
+		Parameter playBothParam = base.push(P_PLAY_BOTH);
+		playBoth = state.parameters.getBoolean(playBothParam, null, false);
+	}
+
+	public float calculateObjectiveFitness(EvolutionState state, Individual ind) {
+		if (!(ind instanceof DoubleVectorIndividual)) {
+			state.output.error("Othello players should be represented by floats vectors\n");
+		}
+
+		double[] wpc1 = ((DoubleVectorIndividual) ind).genome;
+
+		if (wpc1.length != WPC_LENGTH) {
+			state.output.error("Players WPC vectors length should be 64\n");
+		}
+
+		Player player1 = new OthelloPlayer(wpc1);
+		Player player2 = getPlayer();
+		BoardGame game = new OthelloGame(new OthelloBoard());
+
+		GameScenario scenario1 = new RandomizedTwoPlayersGameScenario(state.random[0], new Player[] { player1,
+				player2 }, new double[] { evaluatedRandomness, evaluatorRandomness });
+		GameScenario scenario2 = new RandomizedTwoPlayersGameScenario(state.random[0], new Player[] { player2,
+				player1 }, new double[] { evaluatorRandomness, evaluatedRandomness });
+
+		float sum = 0;
+		for (int r = 0; r < repeats; r++) {
+			game.reset();
+			sum += ((scenario1.play(game) > 0) ? 1 : 0);
+			if (playBoth) {
+				game.reset();
+				sum += ((scenario2.play(game) < 0) ? 1 : 0);
+			}
+		}
+
+		if (playBoth) {
+			return sum / (repeats * 2);
+		} else {
+			return sum / repeats;
+		}
+	}
+
+	protected abstract OthelloPlayer getPlayer();
+}
Index: /java/ecj/cecj/app/othello/OthelloRandomPlayer1.java
===================================================================
--- /java/ecj/cecj/app/othello/OthelloRandomPlayer1.java	(revision 44)
+++ /java/ecj/cecj/app/othello/OthelloRandomPlayer1.java	(revision 44)
@@ -0,0 +1,24 @@
+package cecj.app.othello;
+
+import java.util.Random;
+
+public class OthelloRandomPlayer1 extends OthelloPlayerFitnessCalculator {
+
+	private static final float WPC_POSITION_RANGE = 5;	
+	
+	@Override
+	protected OthelloPlayer getPlayer() {
+		double[] wpc = new double[WPC_LENGTH];
+		Random r = new Random(System.currentTimeMillis());
+		
+		for (int i = 0; i < WPC_LENGTH; i++) {
+			wpc[i] = r.nextDouble() * WPC_POSITION_RANGE;
+			if (r.nextBoolean()) {
+				wpc[i] *= -1;
+			}
+		}
+		
+		return new OthelloPlayer(wpc);
+	}
+
+}
Index: /java/ecj/cecj/app/othello/OthelloRandomPlayer2.java
===================================================================
--- /java/ecj/cecj/app/othello/OthelloRandomPlayer2.java	(revision 44)
+++ /java/ecj/cecj/app/othello/OthelloRandomPlayer2.java	(revision 44)
@@ -0,0 +1,19 @@
+package cecj.app.othello;
+
+import ec.util.Parameter;
+
+import ec.EvolutionState;
+
+public class OthelloRandomPlayer2 extends OthelloPlayerFitnessCalculator {
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+		evaluatorRandomness = 1;
+	}
+	
+	@Override
+	protected OthelloPlayer getPlayer() {
+		return new OthelloPlayer(new double[WPC_LENGTH]);
+	}
+}
Index: /java/ecj/cecj/app/othello/OthelloTDL.java
===================================================================
--- /java/ecj/cecj/app/othello/OthelloTDL.java	(revision 44)
+++ /java/ecj/cecj/app/othello/OthelloTDL.java	(revision 44)
@@ -0,0 +1,110 @@
+package cecj.app.othello;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Population;
+import ec.Statistics;
+import ec.Subpopulation;
+import ec.simple.SimpleEvolutionState;
+import ec.simple.SimpleFitness;
+import ec.util.MersenneTwisterFast;
+import ec.util.Output;
+import ec.util.Parameter;
+import ec.util.ParameterDatabase;
+import ec.vector.DoubleVectorIndividual;
+import games.BoardGame;
+import games.scenarios.SelfPlayTDLScenario;
+
+public class OthelloTDL {
+
+	private static final String P_TDL = "tdl";
+
+	private static final String P_STAT = "stat";
+	private static final String P_SEED = "seed";
+	private static final String P_VERBOSITY = "verbosity";
+
+	private static final String P_RANDOMNESS = "randomness";
+	private static final String P_LEARNING_RATE = "learning-rate";
+
+	private static final String P_GAMES = "games";
+
+	public static void main(String[] args) {
+		ParameterDatabase parameters = ec.Evolve.loadParameterDatabase(args);
+
+		Parameter verbosityParam = new Parameter(P_VERBOSITY);
+		int verbosity = parameters.getInt(verbosityParam, null, 0);
+		if (verbosity < 0) {
+			Output.initialError("Verbosity should be an integer >= 0.\n", verbosityParam);
+		}
+
+		Output output = new Output(true, verbosity);
+		output.addLog(ec.util.Log.D_STDOUT, Output.V_VERBOSE, false);
+		output.addLog(ec.util.Log.D_STDERR, Output.V_VERBOSE, true);
+
+		int time = (int) (System.currentTimeMillis());
+		Parameter seedParam = new Parameter(P_SEED);
+		int seed = ec.Evolve.determineSeed(output, parameters, seedParam, time, 0, false);
+		MersenneTwisterFast random = new MersenneTwisterFast(seed);
+
+		EvolutionState state = new SimpleEvolutionState();
+		state.parameters = parameters;
+		state.random = new MersenneTwisterFast[] { random };
+		state.output = output;
+		
+		state.generation = 0;
+		state.population = new Population();
+		state.population.subpops = new Subpopulation[1];
+		state.population.subpops[0] = new Subpopulation();
+		state.population.subpops[0].individuals = new Individual[1];
+
+		OthelloPlayer player = new OthelloPlayer();
+		DoubleVectorIndividual ind = new DoubleVectorIndividual();
+		ind.genome = player.getWPC();
+		ind.fitness = new SimpleFitness();
+		state.population.subpops[0].individuals[0] = ind;
+	
+		new OthelloTDL(state).run(player);
+	}
+
+	private Statistics stat;
+	private EvolutionState state;
+	private MersenneTwisterFast random;
+
+	private int numGames;
+	private double randomness;
+	private double learningRate;
+
+	public OthelloTDL(EvolutionState state) {
+		this.state = state;
+		this.random = state.random[0];
+
+		Parameter base = new Parameter(P_TDL);
+		Parameter randomnessParam = base.push(P_RANDOMNESS);
+		randomness = state.parameters.getDoubleWithDefault(randomnessParam, null, 0.1);
+
+		Parameter learningRateParam = base.push(P_LEARNING_RATE);
+		learningRate = state.parameters.getDoubleWithDefault(learningRateParam, null, 0.01);
+
+		Parameter numGamesParam = base.push(P_GAMES);
+		numGames = state.parameters.getIntWithDefault(numGamesParam, null, 1000000);
+		state.numGenerations = numGames;
+		
+		Parameter statParam = base.push(P_STAT);
+		stat = (Statistics) state.parameters.getInstanceForParameterEq(statParam, null,
+																		Statistics.class);
+		stat.setup(state, statParam);
+	}
+
+	public void run(OthelloPlayer player) {
+		BoardGame othelloGame = new OthelloGame(new OthelloBoard());
+		SelfPlayTDLScenario scenario = new SelfPlayTDLScenario(random, player, randomness,
+			learningRate);
+		
+		for (int game = 0; game < numGames; game++) {
+			stat.postEvaluationStatistics(state);
+			othelloGame.reset();
+			scenario.play(othelloGame);
+			state.generation++;
+		}
+	}
+}
Index: /java/ecj/cecj/app/othello/OthelloTDLImprover.java
===================================================================
--- /java/ecj/cecj/app/othello/OthelloTDLImprover.java	(revision 44)
+++ /java/ecj/cecj/app/othello/OthelloTDLImprover.java	(revision 44)
@@ -0,0 +1,66 @@
+package cecj.app.othello;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+import ec.vector.DoubleVectorIndividual;
+import games.BoardGame;
+import games.Player;
+import cecj.eval.TDLImprover;
+import games.scenarios.SelfPlayTDLScenario;
+
+public class OthelloTDLImprover implements TDLImprover {
+
+	private static final int WPC_LENGTH = 64;
+
+	private static final String P_REPEATS = "repeats";
+	private static final String P_RANDOMNESS = "randomness";
+	private static final String P_LEARNING_RATE = "learning-rate";
+
+	private int repeats;
+	private double randomness;
+	private double learningRate;
+
+	public void setup(EvolutionState state, Parameter base) {
+		Parameter randomnessParam = base.push(P_RANDOMNESS);
+		randomness = state.parameters.getDoubleWithDefault(randomnessParam, null, 0.1);
+
+		Parameter learningRateParam = base.push(P_LEARNING_RATE);
+		learningRate = state.parameters.getDoubleWithDefault(learningRateParam, null, 0.01);
+
+		Parameter repeatsParam = base.push(P_REPEATS);
+		repeats = state.parameters.getIntWithDefault(repeatsParam, null, 10);
+	}
+
+	public void improve(EvolutionState state, Individual ind) {
+		Player player = new OthelloPlayer(getWPC(state, ind));
+		BoardGame game = new OthelloGame(new OthelloBoard());
+		SelfPlayTDLScenario selfPlayScenario = new SelfPlayTDLScenario(state.random[0], player,
+			randomness, learningRate);
+
+		for (int r = 0; r < repeats; r++) {
+			game.reset();
+			selfPlayScenario.play(game);
+		}
+	}
+
+	public void prepareForImproving(EvolutionState state, Individual ind) {
+		double[] wpc = getWPC(state, ind);
+		for (int i = 0; i < WPC_LENGTH; i++) {
+			wpc[i] = 0.0;
+		}
+	}
+
+	private double[] getWPC(EvolutionState state, Individual ind) {
+		if (!(ind instanceof DoubleVectorIndividual)) {
+			state.output.error("Othello players should be represented by floats vectors\n");
+		}
+
+		double[] wpc = ((DoubleVectorIndividual) ind).genome;
+		if (wpc.length != WPC_LENGTH) {
+			state.output.error("Players WPC vectors length should be 64\n");
+		}
+
+		return wpc;
+	}
+}
Index: /java/ecj/cecj/app/othello/othelloSinglePopCoevolution.params
===================================================================
--- /java/ecj/cecj/app/othello/othelloSinglePopCoevolution.params	(revision 44)
+++ /java/ecj/cecj/app/othello/othelloSinglePopCoevolution.params	(revision 44)
@@ -0,0 +1,61 @@
+verbosity	= 0
+
+breedthreads	= 1
+evalthreads	= 1
+seed.0		= 4357
+
+pop			= ec.Population
+state		= ec.simple.SimpleEvolutionState
+init		= ec.simple.SimpleInitializer
+finish		= ec.simple.SimpleFinisher
+breed		= ec.simple.SimpleBreeder
+stat 		= ec.simple.SimpleStatistics
+exch		= ec.simple.SimpleExchanger
+eval		= coevolution.eval.ArchivingCoevolutionaryEvaluator
+
+generations				= 5000
+checkpoint				= false
+prefix					= ec
+checkpoint-modulo		= 1
+
+pop.subpops						= 1
+pop.subpop.0					= ec.Subpopulation
+pop.subpop.0.size 				= 5
+pop.subpop.0.duplicate-retries 	= 0
+
+pop.subpop.0.species 						= ec.vector.FloatVectorSpecies
+pop.subpop.0.species.ind					= ec.vector.DoubleVectorIndividual
+pop.subpop.0.species.fitness 				= ec.simple.SimpleFitness
+pop.subpop.0.species.genome-size			= 64
+pop.subpop.0.species.min-gene				= -5
+pop.subpop.0.species.max-gene				= 5
+pop.subpop.0.species.crossover-type			= one
+pop.subpop.0.species.mutation-prob			= 0.05
+pop.subpop.0.speciec.mutation-type			= gauss
+pop.subpop.0.species.mutation-stdev			= 0.25
+
+pop.subpop.0.species.pipe							= ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0					= ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0			= ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1			= ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.0.size 	= 3
+pop.subpop.0.species.pipe.source.0.source.1.size 	= 3
+
+eval.problem 							= coevolution.app.othello.Othello
+eval.statistics							= coevolution.statistics.SimpleCoevolutionaryStatistics
+eval.interaction-scheme					= coevolution.interaction.IntraPopulationInteractionScheme
+eval.subpop.0.sampling-method			= coevolution.sampling.AllSamplingMethod
+eval.subpop.0.fitness-method			= coevolution.fitness.SimpleSumFitness
+
+stat.file					= $out.stat
+stat.num-children 			= 1
+stat.child.0 				= coevolution.statistics.AverageObjectiveFitnessStatistics
+stat.child.0.fitness-file	= $fitness.stat
+stat.child.0.title 			= Average performance
+stat.child.0.x-axis-label 	= generation
+stat.child.0.y-axis-label 	= fitness
+
+stat.child.0.fitness-calc 						= coevolution.app.othello.OthelloRandomPlayer2 
+stat.child.0.fitness-calc.play-both 			= true
+stat.child.0.fitness-calc.repeats	 			= 100
+stat.child.0.fitness-calc.evaluated-randomness 	= 0.1
Index: /java/ecj/cecj/app/othello/othelloTDLImprovingCoevolution.params
===================================================================
--- /java/ecj/cecj/app/othello/othelloTDLImprovingCoevolution.params	(revision 44)
+++ /java/ecj/cecj/app/othello/othelloTDLImprovingCoevolution.params	(revision 44)
@@ -0,0 +1,66 @@
+verbosity	= 0
+
+breedthreads	= 1
+evalthreads		= 1
+seed.0				= 1987
+
+pop				= ec.Population
+state			= ec.simple.SimpleEvolutionState
+init			= ec.simple.SimpleInitializer
+finish			= ec.simple.SimpleFinisher
+breed			= ec.simple.SimpleBreeder
+stat 			= ec.simple.SimpleStatistics
+exch			= ec.simple.SimpleExchanger
+eval			= coevolution.eval.TDLImprovingEvaluator
+
+generations				= 5000
+checkpoint				= false
+prefix					= ec
+checkpoint-modulo		= 1
+
+pop.subpops						= 1
+pop.subpop.0					= ec.Subpopulation
+pop.subpop.0.size 				= 1
+pop.subpop.0.duplicate-retries 	= 0
+
+pop.subpop.0.species 									= ec.vector.FloatVectorSpecies
+pop.subpop.0.species.ind								= ec.vector.DoubleVectorIndividual
+pop.subpop.0.species.fitness 							= ec.simple.SimpleFitness
+pop.subpop.0.species.genome-size						= 64
+pop.subpop.0.species.min-gene							= -5
+pop.subpop.0.species.max-gene							= 5
+pop.subpop.0.species.crossover-type						= one
+pop.subpop.0.species.mutation-prob						= 0.00
+pop.subpop.0.species.mutation-type						= reset
+pop.subpop.0.species.mutation-stdev						= 0.25
+
+pop.subpop.0.species.pipe								= ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0						= ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.1				= ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1.size 		= 2
+pop.subpop.0.species.pipe.source.0.source.0				= ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.0.size 		= 2
+
+eval.problem											= coevolution.app.othello.Othello
+eval.inner-evaluator									= coevolution.eval.SimpleCoevolutionaryEvaluator
+eval.inner-evaluator.problem							= coevolution.app.othello.Othello
+eval.inner-evaluator.interaction-scheme					= coevolution.interaction.IntraPopulationInteractionScheme
+eval.inner-evaluator.subpop.0.sampling-method			= coevolution.sampling.AllSamplingMethod
+eval.inner-evaluator.subpop.0.fitness-method			= coevolution.fitness.SimpleSumFitness
+
+eval.tdl-improver								= coevolution.app.othello.OthelloTDLImprover
+eval.tdl-improver.repeats 						= 100
+eval.tdl-improver.randomness 					= 0.1
+eval.tdl-improver.learning-rate 				= 0.01
+
+stat.file										= $out.stat
+stat.num-children 								= 1
+stat.child.0 									= coevolution.statistics.AverageObjectiveFitnessChartStatistics
+stat.child.0.title 								= Average performance
+stat.child.0.x-axis-label 						= generation
+stat.child.0.y-axis-label 						= fitness
+
+stat.child.0.fitness-calc 						= coevolution.app.othello.OthelloRandomPlayer2 
+stat.child.0.fitness-calc.play-both 			= true
+stat.child.0.fitness-calc.repeats				= 50
+stat.child.0.fitness-calc.evaluated-randomness	= 0.1
Index: /java/ecj/cecj/archive/ArchiveRandomSelection.java
===================================================================
--- /java/ecj/cecj/archive/ArchiveRandomSelection.java	(revision 44)
+++ /java/ecj/cecj/archive/ArchiveRandomSelection.java	(revision 44)
@@ -0,0 +1,77 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.archive;
+
+import java.util.List;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.SelectionMethod;
+import ec.select.SelectDefaults;
+import ec.util.Parameter;
+
+public class ArchiveRandomSelection extends SelectionMethod {
+
+	/** default base */
+	private static final String P_ARCHIVAL_RANDOM = "archival-random";
+
+	private static final String P_SIZE = "size";
+	private static final int ENTIRE_ARCHIVE = -1;
+
+	private int size;
+
+	public Parameter defaultBase() {
+		return SelectDefaults.base().push(P_ARCHIVAL_RANDOM);
+	}
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+		
+		Parameter sizeParam = base.push(P_SIZE);
+		size = state.parameters.getIntWithDefault(sizeParam, null, ENTIRE_ARCHIVE);
+	}
+
+	@Override
+	public int produce(int subpopulation, EvolutionState state, int thread) {
+		throw new UnsupportedOperationException(
+			"Archival selection methods do not support supopulation index-based produce method.");
+	}
+
+	@Override
+	public int produce(int min, int max, int start, int subpop, Individual[] inds,
+			EvolutionState state, int thread) {
+		int n = 1;
+		if (n > max)
+			n = max;
+		if (n < min)
+			n = min;
+
+		List<Individual> archive = ((ArchivingSubpopulation) state.population.subpops[subpop])
+			.getArchivalIndividuals();
+		List<Individual> popInds = ((ArchivingSubpopulation) state.population.subpops[subpop])
+			.getIndividuals();
+
+		if (!archive.isEmpty()) {
+			for (int q = 0; q < n; q++) {
+				int selected;
+				if (size <= 0) {
+					selected = state.random[thread].nextInt(archive.size());
+				} else {
+					selected = archive.size() - state.random[thread].nextInt(size) - 1;
+					selected = Math.max(selected, 0);
+				}
+				inds[start + q] = archive.get(selected);
+			}
+		} else {
+			for (int q = 0; q < n; q++) {
+				inds[start + q] = popInds.get(state.random[thread].nextInt(popInds.size()));
+			}
+		}
+
+		return n;
+	}
+}
Index: /java/ecj/cecj/archive/ArchivingSubpopulation.java
===================================================================
--- /java/ecj/cecj/archive/ArchivingSubpopulation.java	(revision 44)
+++ /java/ecj/cecj/archive/ArchivingSubpopulation.java	(revision 44)
@@ -0,0 +1,57 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.archive;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import ec.EvolutionState;
+import ec.Group;
+import ec.Individual;
+import ec.Subpopulation;
+import ec.util.Parameter;
+
+/**
+ * 
+ * @author Marcin Szubert
+ *
+ */
+public class ArchivingSubpopulation extends Subpopulation {
+
+	private List<Individual> archiveIndividuals;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+		archiveIndividuals = new ArrayList<Individual>();
+	}
+
+	@Override
+	public Group emptyClone() {
+		ArchivingSubpopulation subpopulation = (ArchivingSubpopulation) super.emptyClone();
+		subpopulation.archiveIndividuals = archiveIndividuals;
+		return subpopulation;
+	}
+
+	/**
+	 * Returns the list of archival individuals.
+	 * 
+	 * @return the list of archival individuals
+	 */
+	public List<Individual> getArchivalIndividuals() {
+		return archiveIndividuals;
+	}
+
+	/**
+	 * Returns the list of population individuals.
+	 * 
+	 * @return the list of population individuals
+	 */
+	public List<Individual> getIndividuals() {
+		return Arrays.asList(individuals);
+	}
+}
Index: /java/ecj/cecj/archive/BestOfGenerationArchive.java
===================================================================
--- /java/ecj/cecj/archive/BestOfGenerationArchive.java	(revision 44)
+++ /java/ecj/cecj/archive/BestOfGenerationArchive.java	(revision 44)
@@ -0,0 +1,78 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.archive;
+
+import java.util.List;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+/**
+ * Represents the simplest archive type which just finds the best individual from the submitted
+ * population and appends it to the list of individuals found in previous generations. Note that, by
+ * default, the archive size is unbounded and grows steadily over time because no archival
+ * individuals are removed. By setting the <code>archive-size</code> parameter value to <i>x</i>,
+ * only the best competitors from last <i>x</i> generations are maintained.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public class BestOfGenerationArchive extends CoevolutionaryArchive {
+
+	private static final int UNBOUNDED_ARCHIVE_SIZE = -1;
+
+	private static final String P_ARCHIVE_SIZE = "size";
+	private static final String P_SUBPOP = "subpop";
+
+	private int[] archiveSize;
+	private int[] currentArchivePosition;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+
+		currentArchivePosition = new int[numSubpopulations];
+		archiveSize = new int[numSubpopulations];
+
+		for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+			Parameter archiveSizeParameter = base.push(P_SUBPOP).push("" + subpop).push(
+					P_ARCHIVE_SIZE);
+			archiveSize[subpop] = state.parameters.getIntWithDefault(archiveSizeParameter, null,
+					UNBOUNDED_ARCHIVE_SIZE);
+			if (archiveSize[subpop] <= 0 && archiveSize[subpop] != UNBOUNDED_ARCHIVE_SIZE) {
+				state.output.fatal("Archive size must be > 0.\n", archiveSizeParameter);
+			}
+		}
+	}
+
+	@Override
+	public void submit(EvolutionState state) {
+		for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+			Individual bestOfGeneration = findBestIndividual(getIndividuals(state, subpop));
+			List<Individual> archive = getArchive(state, subpop);
+
+			if ((archiveSize[subpop] == UNBOUNDED_ARCHIVE_SIZE)
+					|| (archive.size() < archiveSize[subpop])) {
+				archive.add(bestOfGeneration);
+			} else {
+				archive.set(currentArchivePosition[subpop], bestOfGeneration);
+				currentArchivePosition[subpop]++;
+				currentArchivePosition[subpop] %= archiveSize[subpop];
+			}
+		}
+	}
+
+	private Individual findBestIndividual(List<Individual> inds) {
+		Individual result = inds.get(0);
+		for (Individual ind : inds) {
+			if (ind.fitness.betterThan(result.fitness)) {
+				result = ind;
+			}
+		}
+		return result;
+	}
+}
Index: /java/ecj/cecj/archive/CandidateTestArchive.java
===================================================================
--- /java/ecj/cecj/archive/CandidateTestArchive.java	(revision 44)
+++ /java/ecj/cecj/archive/CandidateTestArchive.java	(revision 44)
@@ -0,0 +1,88 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.archive;
+
+import java.util.List;
+
+import cecj.eval.ArchivingCoevolutionaryEvaluator;
+import cecj.interaction.LearnerTeacherInteractionScheme;
+import cecj.interaction.LearnerTeacherInteractionScheme.Role;
+import cecj.problems.TestBasedProblem;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+/**
+ * Represents archive dedicated for learner-teacher coevolution, where two distinct roles can be
+ * distinguished. The first one (leaner) represents candidate solution to the problem and it is
+ * rewarded for performing well on tests which are representatives of the second role (teacher).
+ * 
+ * It requires <code>LearnerTeacherInteractionScheme</code> and <code>TestBasedProblem</code>
+ * definition.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public abstract class CandidateTestArchive extends CoevolutionaryArchive {
+
+	/**
+	 * The interaction scheme between coevolving populations.
+	 */
+	protected LearnerTeacherInteractionScheme interactionScheme;
+
+	/**
+	 * Problem which determines the interaction form between candidates and tests.
+	 */
+	protected TestBasedProblem problem;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+
+		ArchivingCoevolutionaryEvaluator e = (ArchivingCoevolutionaryEvaluator) state.evaluator;
+		if (!(e.getInteractionScheme() instanceof LearnerTeacherInteractionScheme)) {
+			state.output
+					.fatal("This archive can be used only with learner-teacher interaction scheme.\n");
+		}
+		interactionScheme = (LearnerTeacherInteractionScheme) e.getInteractionScheme();
+		problem = e.getProblem();
+	}
+
+	@Override
+	public void submit(EvolutionState state) {
+		List<Integer> candidatePops = interactionScheme.getSubpopulationIndices(Role.LEARNER);
+		List<Integer> testPops = interactionScheme.getSubpopulationIndices(Role.TEACHER);
+		for (int candidatePop : candidatePops) {
+			List<Individual> cArchive = getArchive(state, candidatePop);
+			List<Individual> candidates = getIndividuals(state, candidatePop);
+			for (int testPop : testPops) {
+				List<Individual> tArchive = getArchive(state, testPop);
+				List<Individual> tests = getIndividuals(state, testPop);
+				submit(state, candidates, cArchive, tests, tArchive);
+			}
+		}
+	}
+
+	/**
+	 * Submits new candidates and tests to the archives. The role of the archive is to determine
+	 * which individuals of both roles are useful and should be kept in the archive. It is possible
+	 * also to remove some existing individual because new one is strictly better.
+	 * 
+	 * @param state
+	 *            the current evolution state
+	 * @param candidates
+	 *            the list of newly generated candidate solutions
+	 * @param cArchive
+	 *            the list of archival candidate solutions
+	 * @param tests
+	 *            the list of newly generated tests
+	 * @param tArchive
+	 *            the list of archival tests
+	 */
+	protected abstract void submit(EvolutionState state, List<Individual> candidates,
+			List<Individual> cArchive, List<Individual> tests, List<Individual> tArchive);
+}
Index: /java/ecj/cecj/archive/CoevolutionaryArchive.java
===================================================================
--- /java/ecj/cecj/archive/CoevolutionaryArchive.java	(revision 44)
+++ /java/ecj/cecj/archive/CoevolutionaryArchive.java	(revision 44)
@@ -0,0 +1,104 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.archive;
+
+import java.util.List;
+
+import cecj.eval.ArchivingCoevolutionaryEvaluator;
+import cecj.eval.TDLImprovingEvaluator;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Setup;
+import ec.util.Parameter;
+
+/**
+ * The abstract class representing any archive used with coevolutionary algorithm. Archive
+ * mechanisms play 3 important roles during the course of evolution:
+ * 
+ * <ul>
+ * <li>
+ * provide genetic material for future generations - archival individual can be chosen as parents of
+ * future generations; this feature is implemented by coevolutionary breeding pipelines</li>
+ * <li>
+ * improve fitness evaluation of individuals in the population - they can interact with individuals
+ * sampled from the archive; this feature is implemented in <code>ArchivingEvaluator</code></li>
+ * <li>
+ * approximate desired solution concept - while population performs exploration of solution space,
+ * archive is aimed at storing the most promising individuals with respect to implemented solution
+ * concept; this feature is implemented by this class and its subclasses.</li>
+ * </ul>
+ * 
+ * Archives are incorporated into <code>ArchivingSubpopulation</code> objects and there are stored
+ * archival individuals of the same species as the original population. In subclasses of
+ * <code>CoevolutionaryArchive</code> only the method specifying how archives should be updated is
+ * defined.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public abstract class CoevolutionaryArchive implements Setup {
+
+	private static final String P_POP = "pop";
+	private static final String P_SIZE = "subpops";
+
+	/**
+	 * Number of coevolving populations.
+	 */
+	protected int numSubpopulations;
+
+	/**
+	 * Checks if <code>ArchivingCoevolutionaryEvaluator</code> is used and reads the number of
+	 * populations from the configuration.
+	 */
+	public void setup(EvolutionState state, Parameter base) {
+		if (!(state.evaluator instanceof ArchivingCoevolutionaryEvaluator)
+				&& !(state.evaluator instanceof TDLImprovingEvaluator)) {
+			state.output.fatal("This archive can be used only with ArchivingEvaluator.\n");
+		}
+
+		Parameter popSizeParameter = new Parameter(P_POP).push(P_SIZE);
+		numSubpopulations = state.parameters.getInt(popSizeParameter, null, 0);
+	}
+
+	/**
+	 * Gets the list of archival individuals from given subpopulation.
+	 * 
+	 * @param state
+	 *            the current evolution state
+	 * @param subpop
+	 *            the index of subpopulation
+	 * @return the list of archival individuals of the subpopulation
+	 */
+	protected List<Individual> getArchive(EvolutionState state, int subpop) {
+		ArchivingSubpopulation subpopulation = (ArchivingSubpopulation) state.population.subpops[subpop];
+		return subpopulation.getArchivalIndividuals();
+	}
+
+	/**
+	 * Gets the list of individuals from given subpopulation.
+	 * 
+	 * @param state
+	 *            the current evolution state
+	 * @param subpop
+	 *            the index of subpopulation
+	 * @return the list of current individuals in the subpopulation
+	 */
+	protected List<Individual> getIndividuals(EvolutionState state, int subpop) {
+		ArchivingSubpopulation subpopulation = (ArchivingSubpopulation) state.population.subpops[subpop];
+		return subpopulation.getIndividuals();
+	}
+
+	/**
+	 * The main method of this class which is responsible by updating individuals in all archives
+	 * basing on the current evolution state, specifically on new individuals in populations
+	 * generated by coevolution process.
+	 * 
+	 * @param state
+	 *            the current evolution state
+	 */
+	public abstract void submit(EvolutionState state);
+}
Index: /java/ecj/cecj/archive/IPCArchive.java
===================================================================
--- /java/ecj/cecj/archive/IPCArchive.java	(revision 44)
+++ /java/ecj/cecj/archive/IPCArchive.java	(revision 44)
@@ -0,0 +1,60 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.archive;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ec.EvolutionState;
+import ec.Individual;
+
+/**
+ * Incremental Pareto-Coevolution Archive.
+ * 
+ * For each of the submitted candidates it is checked if any useful test exists in the archive or
+ * currently submitted population, that proves the candidate is non-dominated. If such test is
+ * found, the considered individual is added to the archive while all individuals that it dominates
+ * are removed.
+ * 
+ * The implementation relies heavily on the methods provided by the superclass Ð
+ * <code>PareroCoevolutionArchive</code>.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public class IPCArchive extends ParetoCoevolutionArchive {
+
+	@Override
+	protected void submit(EvolutionState state, List<Individual> candidates,
+			List<Individual> cArchive, List<Individual> tests, List<Individual> tArchive) {
+		List<Individual> testsCopy = new ArrayList<Individual>(tests);
+		List<Individual> usefulTests;
+
+		/*
+		 * Is is a right sequence of operations? Dominated candidates are eliminated before new
+		 * tests are added to the test archive. New tests can make yet another candidate dominated..
+		 */
+		for (Individual candidate : candidates) {
+			if (isUseful(state, candidate, cArchive, tArchive, testsCopy)) {
+				usefulTests = findUsefulTests(state, candidate, cArchive, tArchive, testsCopy);
+				eliminateDominatedCandidates(state, candidate, cArchive, tArchive);
+
+				cArchive.add(candidate);
+				tArchive.addAll(usefulTests);
+				testsCopy.removeAll(usefulTests);
+			}
+		}
+	}
+
+	private void eliminateDominatedCandidates(EvolutionState state, Individual candidate,
+			List<Individual> candidateArchive, List<Individual> testArchive) {
+		for (int c = candidateArchive.size() - 1; c >= 0; c--) {
+			if (dominates(state, candidate, candidateArchive.get(c), testArchive)) {
+				candidateArchive.remove(c);
+			}
+		}
+	}
+}
Index: /java/ecj/cecj/archive/LAPCArchive.java
===================================================================
--- /java/ecj/cecj/archive/LAPCArchive.java	(revision 44)
+++ /java/ecj/cecj/archive/LAPCArchive.java	(revision 44)
@@ -0,0 +1,128 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.archive;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+/**
+ * Layered Pareto-Coevolution Archive.
+ * 
+ * This archive is a modified version of the IPCA archive. While the original one can grow
+ * indefinitely (tests are never removed from the archive), this type of archive limits the maximum
+ * number of stored individuals. However, this goal is achieved for the price of reducing the
+ * reliability of the algorithm. After appending non-dominated candidate solutions and useful tests
+ * to appropriate archives, <code>maintainLayers</code> and <code>updateTestArchive</code> methods
+ * are invoked in order to decrease the amount of used memory. The first one checks which candidate
+ * solutions belong to the first <code>num-layers</code> Pareto layers and keeps them in the
+ * archive. The second retains only these tests which make distinctions between neighboring layers.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public class LAPCArchive extends ParetoCoevolutionArchive {
+
+	private static final String P_NUM_LAYERS = "num-layers";
+
+	private int numLayers;
+
+	private List<List<Individual>> layers;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+
+		Parameter numLayersParameter = base.push(P_NUM_LAYERS);
+		numLayers = state.parameters.getInt(numLayersParameter, null, 1);
+		if (numLayers <= 0) {
+			state.output.fatal("Number of LAPCA layers must be > 0.\n");
+		}
+
+		layers = new ArrayList<List<Individual>>(numLayers);
+	}
+
+	/*
+	 * It is implemented in a IPCA-like way. Another method is to extend both existing archives by
+	 * new individuals, then find first n layers of candidates with respect to all tests in the
+	 * archive and in the population and finally select necessary tests making distinctions between
+	 * layers.
+	 */
+	@Override
+	protected void submit(EvolutionState state, List<Individual> candidates,
+			List<Individual> cArchive, List<Individual> tests, List<Individual> tArchive) {
+		List<Individual> testsCopy = new ArrayList<Individual>(tests);
+		List<Individual> usefulTests;
+
+		for (Individual candidate : candidates) {
+			if (isUseful(state, candidate, cArchive, tArchive, testsCopy)) {
+				usefulTests = findUsefulTests(state, candidate, cArchive, tArchive, testsCopy);
+
+				cArchive.add(candidate);
+				tArchive.addAll(usefulTests);
+				testsCopy.removeAll(usefulTests);
+			}
+		}
+
+		maintainLayers(state, cArchive, tArchive);
+		updateTestArchive(state, tArchive);
+	}
+
+	private void updateTestArchive(EvolutionState state, List<Individual> tArchive) {
+		Set<Individual> tset = new HashSet<Individual>();
+		tset.addAll(findDistinguishingTests(state, layers.get(0), layers.get(0), tArchive));
+		for (int l = 1; l < numLayers; l++) {
+			tset.addAll(findDistinguishingTests(state, layers.get(l - 1), layers.get(l), tArchive));
+		}
+
+		tArchive.clear();
+		tArchive.addAll(tset);
+	}
+
+	private List<Individual> findDistinguishingTests(EvolutionState state, List<Individual> layer1,
+			List<Individual> layer2, List<Individual> tests) {
+		List<Individual> distinguishingTests = new ArrayList<Individual>();
+		for (Individual candidate1 : layer1) {
+			for (Individual candidate2 : layer2) {
+				if (candidate1.equals(candidate2))
+					continue;
+				Individual test = findUsefulTest(state, candidate1, candidate2, tests);
+				if ((test != null) && (!distinguishingTests.contains(test))) {
+					distinguishingTests.add(test);
+				}
+			}
+		}
+		return distinguishingTests;
+	}
+
+	private void maintainLayers(EvolutionState state, List<Individual> cArchive,
+			List<Individual> tArchive) {
+		List<Individual> cArchiveCopy = new ArrayList<Individual>(cArchive);
+		for (int layer = 0; layer < numLayers; layer++) {
+			List<Individual> frontPareto = findNonDominatedCandidates(state, cArchiveCopy, tArchive);
+			layers.set(layer, frontPareto);
+			cArchiveCopy.removeAll(frontPareto);
+		}
+		cArchive.removeAll(cArchiveCopy);
+	}
+
+	private List<Individual> findNonDominatedCandidates(EvolutionState state,
+			List<Individual> cArchive, List<Individual> tArchive) {
+		List<Individual> result = new ArrayList<Individual>();
+		for (Individual candidate : cArchive) {
+			if (!isDominated(state, candidate, cArchive, tArchive)) {
+				result.add(candidate);
+			}
+		}
+		return result;
+	}
+
+}
Index: /java/ecj/cecj/archive/MaxSolveArchive.java
===================================================================
--- /java/ecj/cecj/archive/MaxSolveArchive.java	(revision 44)
+++ /java/ecj/cecj/archive/MaxSolveArchive.java	(revision 44)
@@ -0,0 +1,175 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.archive;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import cecj.interaction.InteractionResult;
+import cecj.utils.EquivalenceComparator;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+/**
+ * The simplest type of candidate-test archive.
+ * 
+ * During the first step of the <code>submit</code> method, new candidates and tests are added to
+ * corresponding archives; then duplicate candidate solutions are eliminated (two individuals are
+ * considered equal if for each test in the archive they have identical outcomes). After sorting
+ * candidates by number of solved tests, the best <code>archive-size</code> individuals are kept in
+ * the archive. The last step is elimination of unsolved and duplicated (with respect to the
+ * outcomes against archival candidates) tests.
+ * 
+ * Since duplicates removal is a common task, a purpose-built <code>EquivalenceComparator</code>
+ * interface is used for defining custom equivalence criteria.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public class MaxSolveArchive extends CandidateTestArchive {
+
+	private static final String P_ARCHIVE_SIZE = "archive-size";
+
+	private int archiveSize;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+
+		Parameter archiveSizeParameter = base.push(P_ARCHIVE_SIZE);
+		archiveSize = state.parameters.getInt(archiveSizeParameter, null, 1);
+		if (archiveSize <= 0) {
+			state.output.fatal("Archive size must be > 0\n");
+		}
+	}
+
+	@Override
+	protected void submit(EvolutionState state, List<Individual> candidates,
+			List<Individual> cArchive, List<Individual> tests, List<Individual> tArchive) {
+		cArchive.addAll(candidates);
+		tArchive.addAll(tests);
+
+		eliminateDuplicates(cArchive, new CandidateEquivalenceComparator(state, tArchive));
+		Map<Individual, Integer> numSolved = countSolved(state, cArchive, tArchive);
+		Collections.sort(cArchive, new NumberSolvedComparator(numSolved));
+
+		if (cArchive.size() > archiveSize) {
+			cArchive.subList(archiveSize, cArchive.size()).clear();
+		}
+
+		eliminateUnsolvedTests(state, cArchive, tArchive);
+		eliminateDuplicates(tArchive, new TestEquivalenceComparator(state, cArchive));
+	}
+
+	private void eliminateDuplicates(List<Individual> archive,
+			EquivalenceComparator<Individual> comparator) {
+		for (int ind1 = 0; ind1 < archive.size(); ind1++) {
+			for (int ind2 = archive.size(); ind2 > ind1; ind2--) {
+				if (comparator.equal(archive.get(ind1), archive.get(ind2))) {
+					archive.remove(ind2);
+				}
+			}
+		}
+	}
+
+	private void eliminateUnsolvedTests(EvolutionState state, List<Individual> cArchive,
+			List<Individual> tArchive) {
+		for (int test = 0; test < tArchive.size(); test++) {
+			if (!isSolved(state, tArchive.get(test), cArchive)) {
+				tArchive.remove(test);
+			}
+		}
+	}
+
+	private boolean isSolved(EvolutionState state, Individual test, List<Individual> candidates) {
+		for (Individual candidate : candidates) {
+			if (problem.solves(state, candidate, test)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private Map<Individual, Integer> countSolved(EvolutionState state, List<Individual> candidates,
+			List<Individual> tests) {
+		Map<Individual, Integer> result = new HashMap<Individual, Integer>();
+		for (Individual candidate : candidates) {
+			int countTest = 0;
+			for (Individual test : tests) {
+				if (problem.solves(state, candidate, test)) {
+					countTest++;
+				}
+			}
+			result.put(candidate, countTest);
+		}
+		return result;
+	}
+
+	private class NumberSolvedComparator implements Comparator<Individual> {
+		private Map<Individual, Integer> solved;
+
+		public NumberSolvedComparator(Map<Individual, Integer> solved) {
+			this.solved = solved;
+		}
+
+		public int compare(Individual o1, Individual o2) {
+			if (solved.get(o1) > solved.get(o2)) {
+				return -1;
+			} else if (solved.get(o1) > solved.get(o2)) {
+				return 1;
+			} else {
+				return 0;
+			}
+		}
+	}
+
+	private class CandidateEquivalenceComparator implements EquivalenceComparator<Individual> {
+		private EvolutionState state;
+		private List<Individual> tests;
+
+		public CandidateEquivalenceComparator(EvolutionState state, List<Individual> tests) {
+			this.state = state;
+			this.tests = tests;
+		}
+
+		public boolean equal(Individual o1, Individual o2) {
+			for (Individual test : tests) {
+				InteractionResult result1 = problem.test(state, o1, test).first;
+				InteractionResult result2 = problem.test(state, o2, test).first;
+				if (!result1.equals(result2)) {
+					return false;
+				}
+			}
+			return false;
+		}
+	}
+
+	private class TestEquivalenceComparator implements EquivalenceComparator<Individual> {
+		private EvolutionState state;
+		private List<Individual> candidates;
+
+		public TestEquivalenceComparator(EvolutionState state, List<Individual> candidates) {
+			this.state = state;
+			this.candidates = candidates;
+		}
+
+		public boolean equal(Individual o1, Individual o2) {
+			for (Individual candidate : candidates) {
+				InteractionResult result1 = problem.test(state, candidate, o2).second;
+				InteractionResult result2 = problem.test(state, candidate, o2).second;
+				if (!result1.equals(result2)) {
+					return false;
+				}
+			}
+			return false;
+		}
+	}
+}
Index: /java/ecj/cecj/archive/ParetoCoevolutionArchive.java
===================================================================
--- /java/ecj/cecj/archive/ParetoCoevolutionArchive.java	(revision 44)
+++ /java/ecj/cecj/archive/ParetoCoevolutionArchive.java	(revision 44)
@@ -0,0 +1,231 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.archive;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import cecj.interaction.InteractionResult;
+
+import ec.EvolutionState;
+import ec.Individual;
+
+/**
+ * Represents the archive for Pareto-Coevolution paradigm where each test is viewed as an objective
+ * in the sense of Multi-Objective Optimization.
+ * 
+ * This class provides methods for comparing individuals on the basis of their interactions outcomes
+ * considered in the context of Pareto dominance relation (methods: <code>dominates</code>,
+ * <code>isDominated</code>). According to the results of these comparisons a test can be found
+ * useful if it proves that a particular candidate solution is not dominated by any other individual
+ * in the archive. Such usefulness can be verified using the methods of this class (
+ * <code>isUseful</code>, <code>findUsefulTest</code>). It provides methods for comparing
+ * individuals on the basis of their interaction results.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public abstract class ParetoCoevolutionArchive extends CandidateTestArchive {
+
+	/**
+	 * Tries to find a test for which <code>candidate1</code> has better outcome than
+	 * <code>candidate2<code>. It is needed for <code>candidate1</code> to be non-dominated and thus
+	 * useful to be stored in the archive. If the test is found it makes distinction between
+	 * candidates.
+	 * 
+	 * @param state
+	 *            the current evolution state
+	 * @param candidate1
+	 *            the candidate which should appear to be better at some test
+	 * @param candidate2
+	 *            the reference candidate solution which is checked for dominating the candidate1
+	 * @param tests
+	 *            the list of test to be searched
+	 * @return <code>null</code> if there is no such test
+	 */
+	protected Individual findUsefulTest(EvolutionState state, Individual candidate1,
+			Individual candidate2, List<Individual> tests) {
+		for (Individual test : tests) {
+			InteractionResult result1 = problem.test(state, candidate1, test).first;
+			InteractionResult result2 = problem.test(state, candidate2, test).first;
+			if (result1.betterThan(result2)) {
+				return test;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Checks if <code>candidate1</code> Pareto-dominates <code>candidate2</code> or both candidates
+	 * are equal with respect to <code>tests</code>. One candidate is Pareto-dominated if it has
+	 * better or equal outcomes for all <code>tests</code> and for at least one - strictly better.
+	 * 
+	 * @param state
+	 *            the current evolution state
+	 * @param candidate1
+	 *            the candidate solution which is checked for dominating the other candidate
+	 * @param candidate2
+	 *            the candidate solutions which is checked for being dominated
+	 * @param tests
+	 *            the set of tests with respect to which dominance is checked
+	 * @return <code>true</code> if <code>candidate1</code> dominates <code>candidate2</code> or
+	 *         they are equal with respect to <code>tests</code>, <code>false</code> otherwise
+	 */
+	protected boolean dominatesOrEqual(EvolutionState state, Individual candidate1,
+			Individual candidate2, List<Individual> tests) {
+		return (findUsefulTest(state, candidate2, candidate1, tests) == null);
+	}
+
+	/**
+	 * Checks if <code>candidate1</code> Pareto-dominates <code>candidate2</code> with respect to
+	 * <code>tests</code>. One candidate is Pareto-dominated if it has better or equal outcomes for
+	 * all <code>tests</code> and for at least one - strictly better.
+	 * 
+	 * @param state
+	 *            the current evolution state
+	 * @param candidate1
+	 *            the candidate solution which is checked for dominating the other candidate
+	 * @param candidate2
+	 *            the candidate solutions which is checked for being dominated
+	 * @param tests
+	 *            the set of tests with respect to which dominance is checked
+	 * @return <code>true</code> if <code>candidate1</code> dominates <code>candidate2</code> with
+	 *         respect to <code>tests</code>, <code>false</code> otherwise
+	 */
+	protected boolean dominates(EvolutionState state, Individual candidate1, Individual candidate2,
+			List<Individual> tests) {
+		if ((findUsefulTest(state, candidate2, candidate1, tests) == null)
+				&& (findUsefulTest(state, candidate1, candidate2, tests) != null)) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	/**
+	 * Verifies if <code>candidate</code> is dominated by any candidate solution present in
+	 * <code>cArchive</code> with respect to tests in <code>tArchive</code> or if another solution
+	 * has equivalent outcomes for all tests in <code>tArchive</code>.
+	 * 
+	 * If the archive contains a <code>candidate</code>, the outcome is <code>true</code>.
+	 * 
+	 * @param state
+	 *            the current evolution state
+	 * @param candidate
+	 *            the candidate which is checked for being dominated; it should not be in the
+	 *            archive
+	 * @param cArchive
+	 *            the archive of candidate solutions
+	 * @param tArchive
+	 *            the archive of tests
+	 * @return <code>true</code> if <code>candidate</code> is dominated by or equal to another
+	 *         solution in the archive
+	 */
+	protected boolean isDominatedOrEqual(EvolutionState state, Individual candidate,
+			List<Individual> cArchive, List<Individual> tArchive) {
+		for (Individual otherCandidate : cArchive) {
+			if (dominatesOrEqual(state, otherCandidate, candidate, tArchive)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Verifies if <code>candidate</code> is dominated by any candidate solution present in
+	 * <code>cArchive</code> with respect to tests in <code>tArchive</code>.
+	 * 
+	 * @param state
+	 *            the current evolution state
+	 * @param candidate
+	 *            the candidate which is checked for being dominated
+	 * @param cArchive
+	 *            the archive of candidate solutions
+	 * @param tArchive
+	 *            the archive of tests
+	 * @return <code>true</code> if <code>candidate</code> is dominated by any solution in the
+	 *         archive
+	 */
+	protected boolean isDominated(EvolutionState state, Individual candidate,
+			List<Individual> cArchive, List<Individual> tArchive) {
+		for (Individual otherCandidate : cArchive) {
+			if (dominates(state, otherCandidate, candidate, tArchive)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Checks if <code>newCandidate</code> is useful with respect to current archives of candidates
+	 * and tests and new population of generated tests. A candidate solutions is considered
+	 * <i>useful</i> if it is non-dominated and no solution is already present with identical
+	 * outcomes for all tests.
+	 * 
+	 * @param state
+	 *            the current evolution state
+	 * @param newCandidate
+	 *            the candidate whose usefulness is verified
+	 * @param cArchive
+	 *            the archive of candidate solutions
+	 * @param tArchive
+	 *            the archive of tests
+	 * @param newTests
+	 *            the population of new tests
+	 * @return <code>true</code> if <code>newCandidate</code> is <i>useful</i> and should be
+	 *         included in the archive.
+	 */
+	protected boolean isUseful(EvolutionState state, Individual newCandidate,
+			List<Individual> cArchive, List<Individual> tArchive, List<Individual> newTests) {
+		if (isDominatedOrEqual(state, newCandidate, cArchive, tArchive)
+				&& isDominatedOrEqual(state, newCandidate, cArchive, newTests)) {
+			return false;
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 * Finds tests which are needed to prove usefulness of given <code>newCandidate</code>. These
+	 * tests should make distinctions between existing solutions in the <code>cArchive</code> and
+	 * the new one. If the <code>newCandidate</code> solution is non-dominated without adding any of
+	 * <code>newTests</code> to the test archive, the returned list is empty.
+	 * 
+	 * @param state
+	 *            the current evolution state
+	 * @param newCandidate
+	 *            the candidate solution whose non-dominated status is to be guaranteed
+	 * @param cArchive
+	 *            the archive of candidate solutions
+	 * @param tArchive
+	 *            the archive of tests
+	 * @param newTests
+	 *            the population of new tests
+	 * @return the list of test individuals from <code>newTests</code> which should be added to the
+	 *         <code>tArchive</code> to make <code>newCandidate</code> non-dominated. If even adding
+	 *         all test is not sufficient, <code>null</code> is returned.
+	 */
+	protected List<Individual> findUsefulTests(EvolutionState state, Individual newCandidate,
+			List<Individual> cArchive, List<Individual> tArchive, List<Individual> newTests) {
+		List<Individual> selected = new ArrayList<Individual>();
+		List<Individual> rest = new ArrayList<Individual>(newTests);
+
+		for (Individual candidate : cArchive) {
+			if (dominatesOrEqual(state, candidate, newCandidate, tArchive)
+					&& dominatesOrEqual(state, candidate, newCandidate, selected)) {
+				Individual test = findUsefulTest(state, newCandidate, candidate, rest);
+				if (test == null) {
+					return null;
+				} else {
+					selected.add(test);
+					rest.remove(test);
+				}
+			}
+		}
+
+		return selected;
+	}
+}
Index: /java/ecj/cecj/eval/ArchivingCoevolutionaryEvaluator.java
===================================================================
--- /java/ecj/cecj/eval/ArchivingCoevolutionaryEvaluator.java	(revision 44)
+++ /java/ecj/cecj/eval/ArchivingCoevolutionaryEvaluator.java	(revision 44)
@@ -0,0 +1,115 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.eval;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import cecj.archive.ArchivingSubpopulation;
+import cecj.archive.CoevolutionaryArchive;
+import cecj.interaction.InteractionResult;
+import cecj.sampling.SamplingMethod;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+/**
+ * Extends the simple evaluation process with an archiving mechanism.
+ * 
+ * The evaluation procedure is realized in the following manner. Firstly, after taking simple
+ * evaluation steps as in the superclass, additional opponents are selected among archival
+ * individuals (an archive is maintained for each subpopulation). Outcomes of the interactions with
+ * such opponents are added to results obtained by the superclass and aggregated together.
+ * Eventually, subpopulation individuals are submitted to the archive which decides if any of them
+ * is worth keeping. While interaction scheme and fitness aggregation method are inherited from the
+ * <code>SimpleCoevolutionaryEvaluator</code>, archival sampling methods must be defined separately
+ * for each of the archives.
+ * 
+ * Often, opponents sampled from the population are less competent than these from the archive; to
+ * address this issue, additional parameters were created that specify the relative importance of
+ * opponents from both sources - <code>archive-inds-weight</code> and <code>pop-inds-weight</code>.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public class ArchivingCoevolutionaryEvaluator extends SimpleCoevolutionaryEvaluator {
+
+	private static final String P_ARCHIVE = "archive";
+	private static final String P_ARCHIVE_INDS_WEIGHT = "archive-inds-weight";
+	private static final String P_ARCHIVE_SAMPLING_METHOD = "archive-sampling-method";
+
+	private CoevolutionaryArchive archive;
+
+	private List<List<Individual>> archiveOpponents;
+
+	private SamplingMethod[] archiveSamplingMethod;
+
+	private int archiveIndsWeight;
+
+	@Override
+	public void setup(final EvolutionState state, final Parameter base) {
+		super.setup(state, base);
+
+		Parameter archiveParam = base.push(P_ARCHIVE);
+		archive = (CoevolutionaryArchive) (state.parameters.getInstanceForParameter(archiveParam,
+				null, CoevolutionaryArchive.class));
+		archive.setup(state, base.push(P_ARCHIVE));
+
+		Parameter archiveIndsWeightParam = base.push(P_ARCHIVE_INDS_WEIGHT);
+		archiveIndsWeight = state.parameters.getIntWithDefault(archiveIndsWeightParam, null, 1);
+
+		archiveOpponents = new ArrayList<List<Individual>>(numSubpopulations);
+		archiveSamplingMethod = new SamplingMethod[numSubpopulations];
+
+		for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+			archiveOpponents.add(new ArrayList<Individual>());
+			setupArchivingSubpopulation(state, base, subpop);
+		}
+	}
+
+	private void setupArchivingSubpopulation(EvolutionState state, Parameter base, int subpop) {
+		Parameter samplingMethodParam = base.push(P_SUBPOP).push("" + subpop).push(
+				P_ARCHIVE_SAMPLING_METHOD);
+		archiveSamplingMethod[subpop] = (SamplingMethod) (state.parameters.getInstanceForParameter(
+				samplingMethodParam, null, SamplingMethod.class));
+		archiveSamplingMethod[subpop].setup(state, samplingMethodParam);
+	}
+
+	@Override
+	public void evaluatePopulation(EvolutionState state) {
+		if (!(state.population.subpops[0] instanceof ArchivingSubpopulation)) {
+			state.output.fatal("Archiving evaluator requires archiving subpopulation");
+		}
+
+		super.evaluatePopulation(state);
+
+		for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+			archiveOpponents.set(subpop, findOpponentsFromArchive(state, subpop));
+		}
+
+		for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+			List<List<InteractionResult>> subpopulationResults = interactionScheme
+					.performInteractions(state, subpop, archiveOpponents);
+
+			fitnessAggregateMethod[subpop].addToAggregate(state, subpop, subpopulationResults,
+					archiveIndsWeight);
+			fitnessAggregateMethod[subpop].assignFitness(state, subpop);
+
+			if (statistics != null) {
+				statistics.printInteractionResults(state, subpopulationResults, subpop);
+			}
+		}
+
+		archive.submit(state);
+	}
+
+	private List<Individual> findOpponentsFromArchive(EvolutionState state, int subpop) {
+		List<Individual> archivalInds = ((ArchivingSubpopulation) state.population.subpops[subpop])
+				.getArchivalIndividuals();
+		return archiveSamplingMethod[subpop].sample(state, archivalInds);
+	}
+}
Index: /java/ecj/cecj/eval/CoevolutionaryEvaluator.java
===================================================================
--- /java/ecj/cecj/eval/CoevolutionaryEvaluator.java	(revision 44)
+++ /java/ecj/cecj/eval/CoevolutionaryEvaluator.java	(revision 44)
@@ -0,0 +1,62 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.eval;
+
+import cecj.problems.CoevolutionaryProblem;
+import cecj.problems.TestBasedProblem;
+import ec.Evaluator;
+import ec.EvolutionState;
+import ec.util.Parameter;
+
+/**
+ * The base class for all coevolutionary evaluators.
+ * 
+ * This class is responsible for verifying if problem and population are consistent with the idea of
+ * coevolution.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public abstract class CoevolutionaryEvaluator extends Evaluator {
+
+	private static final String P_POP = "pop";
+	private static final String P_SIZE = "subpops";
+
+	/**
+	 * Number of subpopulations.
+	 */
+	protected int numSubpopulations;
+
+	@Override
+	public void setup(final EvolutionState state, final Parameter base) {
+		super.setup(state, base);
+
+		if (!(p_problem instanceof CoevolutionaryProblem)) {
+			state.output
+					.fatal("Coevolutionary evaluator is dedicated to coevolutionary problems\n");
+		}
+
+		Parameter popSizeParameter = new Parameter(P_POP).push(P_SIZE);
+		numSubpopulations = state.parameters.getInt(popSizeParameter, null, 0);
+		if (numSubpopulations <= 0) {
+			state.output.fatal("Population size must be > 0.\n", popSizeParameter);
+		}
+	}
+
+	@Override
+	public boolean runComplete(EvolutionState state) {
+		return false;
+	}
+
+	/**
+	 * Returns a problem that forms a base of evaluation of the individuals.
+	 * 
+	 * @return the instance of test-based problem used by this evaluator
+	 */
+	public TestBasedProblem getProblem() {
+		return (TestBasedProblem) p_problem;
+	}
+}
Index: /java/ecj/cecj/eval/SimpleCoevolutionaryEvaluator.java
===================================================================
--- /java/ecj/cecj/eval/SimpleCoevolutionaryEvaluator.java	(revision 44)
+++ /java/ecj/cecj/eval/SimpleCoevolutionaryEvaluator.java	(revision 44)
@@ -0,0 +1,178 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+*/
+
+package cecj.eval;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import cecj.fitness.FitnessAggregateMethod;
+import cecj.interaction.InteractionResult;
+import cecj.interaction.InteractionScheme;
+import cecj.sampling.SamplingMethod;
+import cecj.statistics.CoevolutionaryStatistics;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+/**
+ * 
+ * Simple coevolutionary evaluator without any additional mechanisms.
+ * 
+ * This is the simplest implementation of conventional coevolutionary evaluation where interactions
+ * between individuals can be performed in an arbitrary order. However, the character and the scope
+ * of interactions can be different Ð it is defined by instantiating appropriate
+ * <code>InteractionScheme</code> subclass. The evaluation proceeds as follows. First of all, a
+ * reference set of opponent individuals is selected from each subpopulation. This task is handled
+ * by a <code>SamplingMethod</code> realization. Distinct sampling methods can be used by different
+ * subpopulations. Next, each subpopulation individuals are confronted with previously selected
+ * opponents from subpopulations pointed by the concrete <code>InteractionScheme</code> class.
+ * Finally, <code>FitnessAggregateMethod</code> is responsible for aggregating outcomes of these
+ * confrontations into a single fitness measure which is used later during selection stage of the
+ * evolutionary process. It evaluates individuals according to the outcomes of its interactions with
+ * other individuals. Interactions are not restricted to intraspecific or interspecific type, i.e.
+ * opponents can be chosen from the same population or any other coevolving population.
+ * 
+ * In contrast to <code>TournamentCoevolutionaryEvaluator</code> all interactions can be simulated
+ * in any order. There are no sequential dependencies between interactions.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public class SimpleCoevolutionaryEvaluator extends CoevolutionaryEvaluator {
+
+	protected static final String P_SUBPOP = "subpop";
+	private static final String P_STATISTICS = "statistics";
+	private static final String P_FITNESS_METHOD = "fitness-method";
+	private static final String P_POP_INDS_WEIGHT = "pop-inds-weight";
+	private static final String P_SAMPLING_METHOD = "sampling-method";
+	private static final String P_INTERACTION_SCHEME = "interaction-scheme";
+
+	/**
+	 * Tests used to interact with candidate solutions.
+	 */
+	protected List<List<Individual>> opponents;
+
+	/**
+	 * Methods of sampling the opponents from particular populations.
+	 */
+	protected SamplingMethod[] samplingMethod;
+
+	/**
+	 * The Method of aggregating multiple interaction outcomes into single value.
+	 */
+	protected FitnessAggregateMethod[] fitnessAggregateMethod;
+
+	/**
+	 * Specifies how interactions between populations look like.
+	 */
+	protected InteractionScheme interactionScheme;
+
+	/**
+	 * Gathers statistics about evaluation stage.
+	 */
+	protected CoevolutionaryStatistics statistics;
+
+	/**
+	 * Indicates how important are population opponents with respect to potential archival
+	 * opponents.
+	 */
+	private int popIndsWeight;
+
+	@Override
+	public void setup(final EvolutionState state, final Parameter base) {
+		super.setup(state, base);
+
+		Parameter interactionSchemeParam = base.push(P_INTERACTION_SCHEME);
+		interactionScheme = (InteractionScheme) (state.parameters.getInstanceForParameter(
+				interactionSchemeParam, null, InteractionScheme.class));
+		interactionScheme.setup(state, interactionSchemeParam);
+
+		Parameter popIndsWeightParam = base.push(P_POP_INDS_WEIGHT);
+		popIndsWeight = state.parameters.getIntWithDefault(popIndsWeightParam, null, 1);
+
+		Parameter statisticsParam = base.push(P_STATISTICS);
+		if (state.parameters.exists(statisticsParam)) {
+			statistics = (CoevolutionaryStatistics) (state.parameters.getInstanceForParameter(
+					statisticsParam, null, CoevolutionaryStatistics.class));
+			statistics.setup(state, statisticsParam);
+		}
+
+		opponents = new ArrayList<List<Individual>>(numSubpopulations);
+		samplingMethod = new SamplingMethod[numSubpopulations];
+		fitnessAggregateMethod = new FitnessAggregateMethod[numSubpopulations];
+
+		for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+			opponents.add(new ArrayList<Individual>());
+			setupSubpopulation(state, base, subpop);
+		}
+	}
+
+	/**
+	 * Sets up fitness aggregate methods and sampling method for the given subpopulation.
+	 * 
+	 * @param state
+	 *            the current evolutionary state
+	 * @param base
+	 *            the base parameter
+	 * @param subpop
+	 *            the subpopulation index
+	 */
+	private void setupSubpopulation(EvolutionState state, Parameter base, int subpop) {
+		Parameter samplingMethodParam = base.push(P_SUBPOP).push("" + subpop).push(
+				P_SAMPLING_METHOD);
+		samplingMethod[subpop] = (SamplingMethod) (state.parameters.getInstanceForParameter(
+				samplingMethodParam, null, SamplingMethod.class));
+		samplingMethod[subpop].setup(state, samplingMethodParam);
+
+		Parameter fitnessMethodParam = base.push(P_SUBPOP).push("" + subpop).push(P_FITNESS_METHOD);
+		fitnessAggregateMethod[subpop] = (FitnessAggregateMethod) (state.parameters
+				.getInstanceForParameter(fitnessMethodParam, null, FitnessAggregateMethod.class));
+	}
+
+	@Override
+	public void evaluatePopulation(EvolutionState state) {
+		for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+			opponents.set(subpop, findOpponentsFromSubpopulation(state, subpop));
+		}
+
+		for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+			List<List<InteractionResult>> subpopulationResults = interactionScheme
+					.performInteractions(state, subpop, opponents);
+
+			fitnessAggregateMethod[subpop].prepareToAggregate(state, subpop);
+			fitnessAggregateMethod[subpop].addToAggregate(state, subpop, subpopulationResults,
+					popIndsWeight);
+			fitnessAggregateMethod[subpop].assignFitness(state, subpop);
+
+			if (statistics != null) {
+				statistics.printInteractionResults(state, subpopulationResults, subpop);
+			}
+		}
+	}
+
+	/**
+	 * Samples subpopulation to choose a reference set of individuals. Other individuals can be
+	 * evaluated on the basis of interactions with this reference set. It may happen that
+	 * individuals from the same subpopulation are tested int this way - it depends on
+	 * 
+	 * @param subpop
+	 *            the index of subpopulation
+	 * @return a list of individuals sampled from the given subpopulation
+	 */
+	private List<Individual> findOpponentsFromSubpopulation(EvolutionState state, int subpop) {
+		return samplingMethod[subpop].sample(state, state.population.subpops[subpop].individuals);
+	}
+
+	/**
+	 * Returns the interaction scheme used during the evaluation.
+	 * 
+	 * @return the interaction scheme used by this evaluator
+	 */
+	public InteractionScheme getInteractionScheme() {
+		return interactionScheme;
+	}
+}
Index: /java/ecj/cecj/eval/TDLImprover.java
===================================================================
--- /java/ecj/cecj/eval/TDLImprover.java	(revision 44)
+++ /java/ecj/cecj/eval/TDLImprover.java	(revision 44)
@@ -0,0 +1,40 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.eval;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Setup;
+
+/**
+ * Represents temporal difference learning (TDL) algorithm which is applied to population
+ * individuals to improve them between subsequent evolutionary generations.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public interface TDLImprover extends Setup {
+
+	/**
+	 * Prepares an individual for being improved by TDL algorithm.
+	 * 
+	 * @param state
+	 *            current evolutionary state
+	 * @param ind
+	 *            individual to be prepared
+	 */
+	public void prepareForImproving(EvolutionState state, Individual ind);
+
+	/**
+	 * Applies TDL algorithm to the given individual to improve its fitness
+	 * 
+	 * @param state
+	 *            current evolutionary state
+	 * @param ind
+	 *            an individual to be improved
+	 */
+	public void improve(EvolutionState state, Individual ind);
+}
Index: /java/ecj/cecj/eval/TDLImprovingEvaluator.java
===================================================================
--- /java/ecj/cecj/eval/TDLImprovingEvaluator.java	(revision 44)
+++ /java/ecj/cecj/eval/TDLImprovingEvaluator.java	(revision 44)
@@ -0,0 +1,83 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.eval;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+/**
+ * Wrapper for <code>CoevolutionaryEvaluator</code> performing an additional learning phase before
+ * actual evaluation.
+ * 
+ * The only role of this class is improving each individual of the population by running a specific
+ * temporal difference learning (TDL) algorithm before the evaluation. Since the exact
+ * implementation of this algorithm depends on the problem, evaluator delegates the learning task to
+ * the provided <code>TDLImprover</code> interface realization. At the beginning of evolutionary
+ * process individuals may require some preparation for running TDL. For this reason, appropriate
+ * interface methods are invoked before the first evaluation. Clearly, not every problem can be
+ * approached by reinforcement learning paradigm so this class has also a limited scope of
+ * applicability.
+ * 
+ * Note that this evaluator realizes the Coevolutionary Reinforcement Learning idea.
+ * 
+ * @author Marcin Szubert
+ * @see TDLImprover
+ * 
+ */
+public class TDLImprovingEvaluator extends CoevolutionaryEvaluator {
+
+	private static final String P_INNER_EVALUATOR = "inner-evaluator";
+	private static final String P_TDL_IMPROVER = "tdl-improver";
+	private static final String P_TDL_FREQUENCY = "tdl-frequency";
+
+	private CoevolutionaryEvaluator innerEvaluator;
+	private TDLImprover temporalDifferenceImprover;
+	private boolean firstEvaluation = true;
+	private int tdlFrequency;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+
+		Parameter innerEvaluatorParam = base.push(P_INNER_EVALUATOR);
+		innerEvaluator = (CoevolutionaryEvaluator) (state.parameters.getInstanceForParameter(
+				innerEvaluatorParam, null, CoevolutionaryEvaluator.class));
+		innerEvaluator.setup(state, innerEvaluatorParam);
+
+		Parameter tdlImproverParam = base.push(P_TDL_IMPROVER);
+		temporalDifferenceImprover = (TDLImprover) (state.parameters.getInstanceForParameter(
+				tdlImproverParam, null, TDLImprover.class));
+		temporalDifferenceImprover.setup(state, tdlImproverParam);
+
+		Parameter tdlImprovingFrequency = base.push(P_TDL_FREQUENCY);
+		tdlFrequency = state.parameters.getIntWithDefault(tdlImprovingFrequency, null, 1);
+	}
+
+	@Override
+	public void evaluatePopulation(EvolutionState state) {
+		if (firstEvaluation) {
+			for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+				Individual[] inds = state.population.subpops[subpop].individuals;
+				for (Individual ind : inds) {
+					temporalDifferenceImprover.prepareForImproving(state, ind);
+				}
+			}
+			firstEvaluation = false;
+		}
+
+		if ((state.generation % tdlFrequency) == 0) {
+			for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+				Individual[] inds = state.population.subpops[subpop].individuals;
+				for (Individual ind : inds) {
+					temporalDifferenceImprover.improve(state, ind);
+				}
+			}
+		}
+
+		innerEvaluator.evaluatePopulation(state);
+	}
+}
Index: /java/ecj/cecj/eval/TournamentCoevolutionaryEvaluator.java
===================================================================
--- /java/ecj/cecj/eval/TournamentCoevolutionaryEvaluator.java	(revision 44)
+++ /java/ecj/cecj/eval/TournamentCoevolutionaryEvaluator.java	(revision 44)
@@ -0,0 +1,228 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+*/
+
+package cecj.eval;
+
+import cecj.interaction.InteractionResult;
+import cecj.problems.SymmetricCompetitionProblem;
+import ec.EvolutionState;
+import ec.Individual;
+import ec.simple.SimpleFitness;
+import ec.util.Parameter;
+
+/**
+ * Single elimination tournament competitive evaluator. It is different from the other
+ * coevolutionary evaluators because interactions between individuals must be simulated in strict
+ * order. It depends on the outcome of previous interaction if the individual can compete further.
+ * 
+ * Assumes that individuals use <code>SimpleFitness</code>. The fitness assigned by this method is
+ * equal to the height of the tournament subtree that particular individual has traversed - the
+ * number of games won. To reduce the inherent noise of the tournament evaluation scheme, a few
+ * rounds can be played. The number of rounds is specified by a <code>repeats</code> parameter which
+ * is equal to 1 by default. This evaluator can be used if problem being solved implements
+ * <code>SymmetricCompetitionProblem</code> interface.
+ * 
+ * Since it would be hard to extend this evaluator with generic archiving or fitness sharing, only
+ * the simplest settings are available.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public class TournamentCoevolutionaryEvaluator extends CoevolutionaryEvaluator {
+
+	private static final String P_REPEATS = "repeats";
+
+	/**
+	 * Specifies how many times the tournament should be repeated during single evaluation process.
+	 * More repeats can reduce the noise of this evaluation scheme.
+	 */
+	private int tournamentRepeats;
+
+	private SymmetricCompetitionProblem problem;
+
+	/**
+	 * Represents competing individuals.
+	 */
+	private Individual[] competitors;
+
+	/**
+	 * Number of competitors - size of the particular subpopulation.
+	 */
+	private int numCompetitors;
+
+	/**
+	 * Points gathered during the course of competition.
+	 */
+	private int[] points;
+
+	/**
+	 * An array used as a tournament tree representation. It stores indices of competing
+	 * individuals. Neighboring indices compete with each other in certain round.
+	 */
+	private int[] competition;
+
+	/**
+	 * Stores active competitors ready to be divided into pairs.
+	 */
+	private int[] activeCompetitors;
+
+	/**
+	 * Indicates if particular competitor is still in game.
+	 */
+	private boolean[] active;
+
+	@Override
+	public void setup(final EvolutionState state, final Parameter base) {
+		super.setup(state, base);
+
+		if (!(p_problem instanceof SymmetricCompetitionProblem)) {
+			state.output.fatal("Tournament evaluator can be used only with symmetric problems");
+		} else {
+			problem = (SymmetricCompetitionProblem) p_problem;
+		}
+
+		Parameter repeatsParameter = base.push(P_REPEATS);
+		tournamentRepeats = state.parameters.getIntWithDefault(repeatsParameter, null, 1);
+		if (tournamentRepeats <= 0) {
+			state.output.fatal("Tournament repeats parameter can not be negative.",
+					repeatsParameter);
+		}
+	}
+
+	@Override
+	public void evaluatePopulation(EvolutionState state) {
+		for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+			prepareTournament(state, subpop);
+			for (int r = 0; r < tournamentRepeats; r++) {
+				makeTournament(state);
+			}
+			assignFitness(state);
+		}
+	}
+
+	/**
+	 * Initializes structures used in the tournament series.
+	 * 
+	 * @param state
+	 *            current evolutionary state
+	 * @param subpop
+	 *            index of subpopulation
+	 */
+	private void prepareTournament(EvolutionState state, int subpop) {
+		competitors = state.population.subpops[subpop].individuals;
+		numCompetitors = competitors.length;
+
+		points = new int[numCompetitors];
+		active = new boolean[numCompetitors];
+		competition = new int[numCompetitors];
+		activeCompetitors = new int[numCompetitors];
+	}
+
+	/**
+	 * Plays a single tournament between earlier selected competitors from particular subpopulation.
+	 * Each tournament consists of a sequence of rounds. In each round number of active competitors
+	 * is reduced by half according to the results of their games (approximately - if at the start
+	 * of the round number of players is odd, one player is given a "bye" and advances to the next
+	 * round directly). At the beginning of each round there is a drawing which assigns competitors
+	 * in pairs.
+	 * 
+	 * @param state
+	 *            current evolutionary state
+	 */
+	private void makeTournament(EvolutionState state) {
+		int numActiveCompetitors;
+		for (int c = 0; c < numCompetitors; c++) {
+			active[c] = true;
+		}
+
+		while ((numActiveCompetitors = findActiveCompetitors()) > 1) {
+			shuffleCompetitors(state, numActiveCompetitors);
+			playTournamentRound(state, numActiveCompetitors);
+		}
+	}
+
+	/**
+	 * Assigns fitness value to each competing individual according to overall points which it has
+	 * gathered during the series of tournaments.
+	 * 
+	 * @param state
+	 *            current evolutionary state
+	 */
+	private void assignFitness(EvolutionState state) {
+		for (int c = 0; c < numCompetitors; c++) {
+			Individual competitor = competitors[c];
+			((SimpleFitness) competitor.fitness).setFitness(state, points[c], false);
+		}
+	}
+
+	/**
+	 * Finds still active competitors according to <code>active</code> array. Found competitor
+	 * indices are stored in <code>activeCompetitors</code> array and their number is returned.
+	 * 
+	 * @return number of still active competitors
+	 */
+	private int findActiveCompetitors() {
+		int leftCompetitors = 0;
+		for (int c = 0; c < numCompetitors; c++) {
+			if (active[c]) {
+				activeCompetitors[leftCompetitors++] = c;
+			}
+		}
+		return leftCompetitors;
+	}
+
+	/**
+	 * Randomly shuffles competitors indices taken from <
+	 * 
+	 * @param state
+	 *            current evolutionary state
+	 * @param count
+	 *            the number of shuffled competitors
+	 */
+	private void shuffleCompetitors(EvolutionState state, int count) {
+		int left = count;
+		for (int i = 0; i < count; i++) {
+			int rand = state.random[0].nextInt(left);
+			competition[i] = activeCompetitors[rand];
+			activeCompetitors[rand] = activeCompetitors[--left];
+		}
+	}
+
+	/**
+	 * Arranges a competition between neighbors in <code>competition</code> array.
+	 * 
+	 * @param state
+	 *            current evolutionary state
+	 * @param numLeftCompetitors
+	 *            the number of competitors left
+	 */
+	private void playTournamentRound(EvolutionState state, int numLeftCompetitors) {
+		for (int i = 0; i + 1 < numLeftCompetitors; i += 2) {
+			Individual c1 = competitors[competition[i]];
+			Individual c2 = competitors[competition[i + 1]];
+
+			// TODO: consider if it is needed to call compete method twice
+			// maybe it should use internal individual's fitness or return both
+			// results at once?
+			InteractionResult score1 = problem.compete(state, c1, c2).first;
+			InteractionResult score2 = problem.compete(state, c2, c1).first;
+
+			if (score1.betterThan(score2)) {
+				points[competition[i]]++;
+				active[competition[i + 1]] = false;
+			} else {
+				points[competition[i + 1]]++;
+				active[competition[i]] = false;
+			}
+		}
+
+		// TODO: in case of odd number of competitors, should the one given a
+		// "bye" achieve a point
+		// in this round?
+		if (numLeftCompetitors % 2 != 0) {
+			points[competition[numLeftCompetitors - 1]]++;
+		}
+	}
+}
Index: /java/ecj/cecj/fitness/CompetitiveFitnessSharing.java
===================================================================
--- /java/ecj/cecj/fitness/CompetitiveFitnessSharing.java	(revision 44)
+++ /java/ecj/cecj/fitness/CompetitiveFitnessSharing.java	(revision 44)
@@ -0,0 +1,60 @@
+package cecj.fitness;
+
+import java.util.Arrays;
+import java.util.List;
+
+import cecj.interaction.InteractionResult;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.simple.SimpleFitness;
+
+public class CompetitiveFitnessSharing implements FitnessAggregateMethod {
+
+	private float[] fitnesses;
+
+	public void prepareToAggregate(EvolutionState state, int subpop) {
+		fitnesses = new float[state.population.subpops[subpop].individuals.length];
+		Arrays.fill(fitnesses, 0.0f);
+	}
+	
+	public void addToAggregate(EvolutionState state, int subpop,
+			List<List<InteractionResult>> results, int weight) {
+
+		Individual[] inds = state.population.subpops[subpop].individuals;
+		if (results.size() != inds.length) {
+			throw new IllegalArgumentException(
+				"Results list's size must be equal to subpopulation size.");
+		}
+
+		int numOpponents = results.get(0).size();
+		float[] opponentSum = new float[numOpponents];
+		for (int opponent = 0; opponent < numOpponents; opponent++) {
+			for (int ind = 0; ind < inds.length; ind++) {
+				opponentSum[opponent] += results.get(ind).get(opponent).getNumericValue();
+			}
+		}
+
+		for (int ind = 0; ind < inds.length; ind++) {
+			float indFitness = 0;
+			for (int opponent = 0; opponent < numOpponents; opponent++) {
+				if (opponentSum[opponent] == 0) {
+					continue;
+				}
+				
+				indFitness += results.get(ind).get(opponent).getNumericValue()
+						/ opponentSum[opponent];
+			}
+
+			fitnesses[ind] += indFitness * weight;
+			((SimpleFitness) (inds[ind].fitness)).setFitness(state, indFitness, false);
+		}
+	}
+	
+	public void assignFitness(EvolutionState state, int subpop) {
+		Individual[] inds = state.population.subpops[subpop].individuals;
+		for (int ind = 0; ind < inds.length; ind++) {
+			((SimpleFitness) inds[ind].fitness).setFitness(state, fitnesses[ind], false);
+		}
+	}
+}
Index: /java/ecj/cecj/fitness/FitnessAggregateMethod.java
===================================================================
--- /java/ecj/cecj/fitness/FitnessAggregateMethod.java	(revision 44)
+++ /java/ecj/cecj/fitness/FitnessAggregateMethod.java	(revision 44)
@@ -0,0 +1,26 @@
+package cecj.fitness;
+
+import java.util.List;
+
+import cecj.interaction.InteractionResult;
+
+import ec.EvolutionState;
+
+/**
+ * A method of aggregating individuals' interactions results.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public interface FitnessAggregateMethod {
+
+	public void prepareToAggregate(EvolutionState state, int subpop);
+
+	public void addToAggregate(EvolutionState state, int subpop,
+			List<List<InteractionResult>> subpopulationResults, int weight);
+
+	/**
+	 * Assigns fitness to all individuals in the population according to their interaction outcomes.
+	 */
+	public void assignFitness(EvolutionState state, int subpop);
+}
Index: /java/ecj/cecj/fitness/SimpleSumFitness.java
===================================================================
--- /java/ecj/cecj/fitness/SimpleSumFitness.java	(revision 44)
+++ /java/ecj/cecj/fitness/SimpleSumFitness.java	(revision 44)
@@ -0,0 +1,45 @@
+package cecj.fitness;
+
+import java.util.Arrays;
+import java.util.List;
+
+import cecj.interaction.InteractionResult;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.simple.SimpleFitness;
+
+public class SimpleSumFitness implements FitnessAggregateMethod {
+
+	private float[] fitnesses;
+
+	public void prepareToAggregate(EvolutionState state, int subpop) {
+		fitnesses = new float[state.population.subpops[subpop].individuals.length];
+		Arrays.fill(fitnesses, 0.0f);
+	}
+
+	public void addToAggregate(EvolutionState state, int subpop,
+			List<List<InteractionResult>> subpopulationResults, int weight) {
+
+		Individual[] inds = state.population.subpops[subpop].individuals;
+		if (subpopulationResults.size() != inds.length) {
+			throw new IllegalArgumentException(
+				"Results list's size must be equal to subpopulation size.");
+		}
+
+		for (int ind = 0; ind < inds.length; ind++) {
+			float fitness = 0;
+			for (InteractionResult result : subpopulationResults.get(ind)) {
+				fitness += result.getNumericValue();
+			}
+			fitnesses[ind] += fitness * weight;
+		}
+	}
+
+	public void assignFitness(EvolutionState state, int subpop) {
+		Individual[] inds = state.population.subpops[subpop].individuals;
+		for (int ind = 0; ind < inds.length; ind++) {
+			((SimpleFitness) inds[ind].fitness).setFitness(state, fitnesses[ind], false);
+		}
+	}
+}
Index: /java/ecj/cecj/interaction/InterPopulationInteractionScheme.java
===================================================================
--- /java/ecj/cecj/interaction/InterPopulationInteractionScheme.java	(revision 44)
+++ /java/ecj/cecj/interaction/InterPopulationInteractionScheme.java	(revision 44)
@@ -0,0 +1,62 @@
+package cecj.interaction;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import cecj.problems.SymmetricCompetitionProblem;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+public class InterPopulationInteractionScheme implements InteractionScheme {
+
+	private static final String P_POP = "pop";
+	private static final String P_SIZE = "subpops";
+
+	/**
+	 * Number of subpopulations.
+	 */
+	private int numSubpopulations;
+
+	private SymmetricCompetitionProblem problem;
+
+	public void setup(EvolutionState state, Parameter base) {
+		if (!(state.evaluator.p_problem instanceof SymmetricCompetitionProblem)) {
+			state.output.fatal("Intrapopulation interactions need symmetric problem definition\n");
+		} else {
+			problem = (SymmetricCompetitionProblem) state.evaluator.p_problem;
+		}
+
+		Parameter popSizeParameter = new Parameter(P_POP).push(P_SIZE);
+		numSubpopulations = state.parameters.getInt(popSizeParameter, null, 0);
+		if (numSubpopulations <= 0) {
+			state.output.fatal("Population size must be > 0.\n", popSizeParameter);
+		}
+	}
+
+	public List<List<InteractionResult>> performInteractions(EvolutionState state, int subpop,
+			List<List<Individual>> opponents) {
+		List<List<InteractionResult>> subpopulationResults = new ArrayList<List<InteractionResult>>();
+		Individual[] competitors = state.population.subpops[subpop].individuals;
+
+		for (Individual competitor : competitors) {
+			List<InteractionResult> results = new ArrayList<InteractionResult>();
+
+			for (int subpop2 = 0; subpop2 < numSubpopulations; subpop2++) {
+				if (subpop2 == subpop) {
+					continue;
+				}
+
+				List<Individual> curOpponents = opponents.get(subpop2);
+				for (Individual opponent : curOpponents) {
+					results.add(problem.compete(state, competitor, opponent).first);
+				}
+			}
+
+			subpopulationResults.add(results);
+		}
+
+		return subpopulationResults;
+	}
+}
Index: /java/ecj/cecj/interaction/InteractionResult.java
===================================================================
--- /java/ecj/cecj/interaction/InteractionResult.java	(revision 44)
+++ /java/ecj/cecj/interaction/InteractionResult.java	(revision 44)
@@ -0,0 +1,8 @@
+package cecj.interaction;
+
+public interface InteractionResult {
+	
+	public boolean betterThan(InteractionResult other);
+	
+	public float getNumericValue();
+}
Index: /java/ecj/cecj/interaction/InteractionScheme.java
===================================================================
--- /java/ecj/cecj/interaction/InteractionScheme.java	(revision 44)
+++ /java/ecj/cecj/interaction/InteractionScheme.java	(revision 44)
@@ -0,0 +1,23 @@
+package cecj.interaction;
+
+import java.util.List;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Setup;
+
+/**
+ * Interface representing an abstract scheme of interactions between individuals.
+ * 
+ * Its implementations should read population roles in interactions and depending on their roles
+ * assign given interaction sequence. Moreover it is the only entity conscious of what method of
+ * problem definition must be called to properly evaluate interacting individuals.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public interface InteractionScheme extends Setup {
+
+	public List<List<InteractionResult>> performInteractions(EvolutionState state, int subpop,
+			List<List<Individual>> opponents);
+}
Index: /java/ecj/cecj/interaction/IntraPopulationInteractionScheme.java
===================================================================
--- /java/ecj/cecj/interaction/IntraPopulationInteractionScheme.java	(revision 44)
+++ /java/ecj/cecj/interaction/IntraPopulationInteractionScheme.java	(revision 44)
@@ -0,0 +1,48 @@
+package cecj.interaction;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import cecj.problems.SymmetricCompetitionProblem;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+/**
+ * 
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public class IntraPopulationInteractionScheme implements InteractionScheme {
+
+	private SymmetricCompetitionProblem problem;
+
+	public void setup(EvolutionState state, Parameter base) {
+		if (!(state.evaluator.p_problem instanceof SymmetricCompetitionProblem)) {
+			state.output.fatal("Intrapopulation interactions need symmetric problem definition\n");
+		} else {
+			problem = (SymmetricCompetitionProblem) state.evaluator.p_problem;
+		}
+	}
+
+	public List<List<InteractionResult>> performInteractions(EvolutionState state, int subpop,
+			List<List<Individual>> opponents) {
+
+		List<List<InteractionResult>> subpopulationResults = new ArrayList<List<InteractionResult>>();
+		Individual[] competitors = state.population.subpops[subpop].individuals;
+		List<Individual> curOpponents = opponents.get(subpop);
+
+		for (Individual competitor : competitors) {
+			List<InteractionResult> results = new ArrayList<InteractionResult>();
+			for (Individual opponent : curOpponents) {
+				results.add(problem.compete(state, competitor, opponent).first);
+				results.add(problem.compete(state, opponent, competitor).second);
+			}
+			subpopulationResults.add(results);
+		}
+
+		return subpopulationResults;
+	}
+}
Index: /java/ecj/cecj/interaction/LearnerTeacherInteractionScheme.java
===================================================================
--- /java/ecj/cecj/interaction/LearnerTeacherInteractionScheme.java	(revision 44)
+++ /java/ecj/cecj/interaction/LearnerTeacherInteractionScheme.java	(revision 44)
@@ -0,0 +1,102 @@
+package cecj.interaction;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import cecj.problems.TestBasedProblem;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+/**
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public class LearnerTeacherInteractionScheme implements InteractionScheme {
+
+	private static final String P_POP = "pop";
+	private static final String P_ROLE = "role";
+	private static final String P_SIZE = "subpops";
+	private static final String P_SUBPOP = "subpop";
+
+	/**
+	 * Number of subpopulations.
+	 */
+	private int numSubpopulations;
+
+	private TestBasedProblem problem;
+
+	public enum Role {
+		LEARNER, TEACHER
+	}
+
+	private Role[] subpopulationRoles;
+
+	public void setup(EvolutionState state, Parameter base) {
+		if (!(state.evaluator.p_problem instanceof TestBasedProblem)) {
+			state.output.fatal("Learner-teacher interactions need asymmetric problem definition\n");
+		} else {
+			problem = (TestBasedProblem) state.evaluator.p_problem;
+		}
+
+		Parameter popSizeParameter = new Parameter(P_POP).push(P_SIZE);
+		numSubpopulations = state.parameters.getInt(popSizeParameter, null, 0);
+		if (numSubpopulations <= 0) {
+			state.output.fatal("Population size must be > 0.\n", popSizeParameter);
+		}
+
+		for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+			Parameter subpopRoleParam = base.push(P_SUBPOP).push("" + subpop).push(P_ROLE);
+			String role = state.parameters.getString(subpopRoleParam, null);
+			if (role == null) {
+				state.output.fatal("Subpopulation role must be specified for the learner-teacher "
+						+ "interactions scheme\n", subpopRoleParam);
+			} else {
+				try {
+					subpopulationRoles[subpop] = Enum.valueOf(Role.class, role.toUpperCase());
+				} catch (IllegalArgumentException ex) {
+					state.output.fatal("Subpopulation role " + role
+							+ " does not exist in the learner-teacher interactions scheme");
+				}
+			}
+		}
+	}
+
+	public List<List<InteractionResult>> performInteractions(EvolutionState state, int subpop,
+			List<List<Individual>> opponents) {
+
+		List<List<InteractionResult>> subpopulationResults = new ArrayList<List<InteractionResult>>();
+		Individual[] inds = state.population.subpops[subpop].individuals;
+
+		for (Individual ind : inds) {
+			List<InteractionResult> results = new ArrayList<InteractionResult>();
+			for (int subpop2 = 0; subpop2 < numSubpopulations; subpop2++) {
+				if (subpopulationRoles[subpop2] != subpopulationRoles[subpop]) {
+					List<Individual> curOpponents = opponents.get(subpop2);
+					for (Individual opponent : curOpponents) {
+						if (subpopulationRoles[subpop] == Role.LEARNER) {
+							results.add(problem.test(state, ind, opponent).first);
+						} else {
+							results.add(problem.test(state, opponent, ind).second);
+						}
+					}
+				}
+			}
+			subpopulationResults.add(results);
+		}
+
+		return subpopulationResults;
+	}
+
+	public List<Integer> getSubpopulationIndices(Role role) {
+		List<Integer> result = new ArrayList<Integer>();
+		for (int subpop = 0; subpop < numSubpopulations; subpop++) {
+			if (subpopulationRoles[subpop] == role) {
+				result.add(subpop);
+			}
+		}
+		return result;
+	}
+}
Index: /java/ecj/cecj/interaction/RealValuedResult.java
===================================================================
--- /java/ecj/cecj/interaction/RealValuedResult.java	(revision 44)
+++ /java/ecj/cecj/interaction/RealValuedResult.java	(revision 44)
@@ -0,0 +1,43 @@
+package cecj.interaction;
+
+/**
+ * Immutable class representing real-valued interaction results.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public class RealValuedResult implements InteractionResult {
+
+	private float value;
+
+	public RealValuedResult(float value) {
+		this.value = value;
+	}
+
+	public boolean betterThan(InteractionResult other) {
+		if (!(other instanceof RealValuedResult)) {
+			throw new IllegalArgumentException(
+				"Interaction result comparison must be done within the same type of results.");
+		} else {
+			return (this.value > ((RealValuedResult) other).value);
+		}
+	}
+
+	public float getNumericValue() {
+		return value;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (!(obj instanceof RealValuedResult)) {
+			return false;
+		}
+
+		return (((RealValuedResult) obj).value == this.value);
+	}
+	
+	@Override
+	public String toString() {
+		return Float.toString(value);
+	}
+}
Index: /java/ecj/cecj/interaction/WinDrawLossResult.java
===================================================================
--- /java/ecj/cecj/interaction/WinDrawLossResult.java	(revision 44)
+++ /java/ecj/cecj/interaction/WinDrawLossResult.java	(revision 44)
@@ -0,0 +1,38 @@
+package cecj.interaction;
+
+public class WinDrawLossResult implements InteractionResult {
+
+	public enum Result {
+		LOSS, DRAW, WIN
+	}
+
+	private Result result;
+
+	public WinDrawLossResult(Result result) {
+		this.result = result;
+	}
+
+	public boolean betterThan(InteractionResult other) {
+		if (!(other instanceof WinDrawLossResult)) {
+			throw new IllegalArgumentException(
+				"Interaction result comparison must be done within the same type of results.");
+		} else {
+			return (this.result.ordinal() > ((WinDrawLossResult) other).result.ordinal());
+		}
+	}
+
+	public float getNumericValue() {
+		if (result == Result.LOSS) {
+			return 0;
+		} else if (result == Result.DRAW) {
+			return 1;
+		} else {
+			return 3;
+		}
+	}
+
+	@Override
+	public String toString() {
+		return result.name().charAt(0) + "";
+	}
+}
Index: /java/ecj/cecj/problems/CoevolutionaryProblem.java
===================================================================
--- /java/ecj/cecj/problems/CoevolutionaryProblem.java	(revision 44)
+++ /java/ecj/cecj/problems/CoevolutionaryProblem.java	(revision 44)
@@ -0,0 +1,12 @@
+package cecj.problems;
+
+/**
+ * 
+ * The marker interface for all the coevolutionary problems.
+ * 
+ * @author Marcin Szubert
+ *
+ */
+public interface CoevolutionaryProblem {
+
+}
Index: /java/ecj/cecj/problems/SymmetricCompetitionProblem.java
===================================================================
--- /java/ecj/cecj/problems/SymmetricCompetitionProblem.java	(revision 44)
+++ /java/ecj/cecj/problems/SymmetricCompetitionProblem.java	(revision 44)
@@ -0,0 +1,25 @@
+package cecj.problems;
+
+import cecj.interaction.InteractionResult;
+import cecj.utils.Pair;
+import ec.EvolutionState;
+import ec.Individual;
+
+/**
+ * Problem is symmetric if sets of possible behaviours of both competitors are identical. It does
+ * not mean that the game is symmetric itself in game-theoretic meaning ( )
+ * 
+ * @author Marcin Szubert
+ */
+public interface SymmetricCompetitionProblem extends CoevolutionaryProblem {
+
+	/**
+	 * 
+	 * @param state
+	 * @param competitor1
+	 * @param competitor2
+	 * @return
+	 */
+	public Pair<? extends InteractionResult> compete(EvolutionState state, Individual competitor1,
+			Individual competitor2);
+}
Index: /java/ecj/cecj/problems/SymmetricTestBasedProblem.java
===================================================================
--- /java/ecj/cecj/problems/SymmetricTestBasedProblem.java	(revision 44)
+++ /java/ecj/cecj/problems/SymmetricTestBasedProblem.java	(revision 44)
@@ -0,0 +1,15 @@
+package cecj.problems;
+
+import cecj.interaction.InteractionResult;
+import cecj.utils.Pair;
+import ec.EvolutionState;
+import ec.Individual;
+
+public abstract class SymmetricTestBasedProblem extends TestBasedProblem implements
+		SymmetricCompetitionProblem {
+
+	public Pair<? extends InteractionResult> compete(EvolutionState state, Individual competitor1,
+			Individual competitor2) {
+		return test(state, competitor1, competitor2);
+	}
+}
Index: /java/ecj/cecj/problems/SymmetricTestBasedProblemCachingDecorator.java
===================================================================
--- /java/ecj/cecj/problems/SymmetricTestBasedProblemCachingDecorator.java	(revision 44)
+++ /java/ecj/cecj/problems/SymmetricTestBasedProblemCachingDecorator.java	(revision 44)
@@ -0,0 +1,16 @@
+package cecj.problems;
+
+import cecj.interaction.InteractionResult;
+import cecj.utils.Pair;
+import ec.EvolutionState;
+import ec.Individual;
+
+public class SymmetricTestBasedProblemCachingDecorator extends TestBasedProblemCachingDecorator
+		implements SymmetricCompetitionProblem {
+
+	public Pair<? extends InteractionResult> compete(EvolutionState state, Individual competitor1,
+			Individual competitor2) {
+		return test(state, competitor1, competitor2);
+	}
+
+}
Index: /java/ecj/cecj/problems/TestBasedProblem.java
===================================================================
--- /java/ecj/cecj/problems/TestBasedProblem.java	(revision 44)
+++ /java/ecj/cecj/problems/TestBasedProblem.java	(revision 44)
@@ -0,0 +1,17 @@
+package cecj.problems;
+
+import cecj.interaction.InteractionResult;
+import cecj.utils.Pair;
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Problem;
+
+public abstract class TestBasedProblem extends Problem implements CoevolutionaryProblem {
+
+	public abstract Pair<? extends InteractionResult> test(EvolutionState state,
+			Individual candidate, Individual test);
+
+	public boolean solves(EvolutionState state, Individual candidate, Individual test) {
+		return (test(state, candidate, test).first.getNumericValue() > 0);
+	}
+}
Index: /java/ecj/cecj/problems/TestBasedProblemCachingDecorator.java
===================================================================
--- /java/ecj/cecj/problems/TestBasedProblemCachingDecorator.java	(revision 44)
+++ /java/ecj/cecj/problems/TestBasedProblemCachingDecorator.java	(revision 44)
@@ -0,0 +1,91 @@
+package cecj.problems;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import cecj.interaction.InteractionResult;
+import cecj.utils.Pair;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+public class TestBasedProblemCachingDecorator extends TestBasedProblem {
+	public static final String P_CACHE_SIZE = "cache-size";
+	public static final String P_INNER_PROBLEM = "inner-problem";
+
+	public static final int UNBOUNDED_CACHE = Integer.MAX_VALUE;
+
+	private Map<Pair<Individual>, Pair<? extends InteractionResult>> cache;
+	private Map<Pair<Individual>, Integer> LRUtimer;
+
+	private TestBasedProblem problem;
+	private int cacheSizeLimit;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+		
+		Parameter innerProblemParam = base.push(P_INNER_PROBLEM);
+		problem = (TestBasedProblem) state.parameters
+			.getInstanceForParameter(innerProblemParam, null, TestBasedProblem.class);
+		problem.setup(state, base);
+
+		Parameter cacheSizeParam = base.push(P_CACHE_SIZE);
+		cacheSizeLimit = state.parameters.getIntWithDefault(cacheSizeParam, null, UNBOUNDED_CACHE);
+
+		cache = new HashMap<Pair<Individual>, Pair<? extends InteractionResult>>();
+		LRUtimer = new HashMap<Pair<Individual>, Integer>();
+	}
+
+	public TestBasedProblem getProblem() {
+		return problem;
+	}
+	
+	@Override
+	public Pair<? extends InteractionResult> test(EvolutionState state, Individual candidate,
+			Individual test) {
+
+		Pair<Individual> key = new Pair<Individual>(candidate, test);
+		Pair<? extends InteractionResult> result = cache.get(key);
+		if (result == null) {
+			result = problem.test(state, candidate, test);
+			cache.put(key, result);
+		}
+
+		LRUtimer.put(key, state.generation);
+		if (cache.size() > cacheSizeLimit) {
+			clearLeastRecentlyUsed();
+		}
+
+		return result;
+	}
+
+	/**
+	 * Clears least recently used pairs of individuals. Sorts the list of stored pairs of
+	 * individuals according to time of last use. Removes a half of cache storage.
+	 */
+	private void clearLeastRecentlyUsed() {
+		List<Pair<Individual>> list = new ArrayList<Pair<Individual>>(LRUtimer.keySet());
+		Collections.sort(list, new Comparator<Pair<Individual>>() {
+			public int compare(Pair<Individual> o1, Pair<Individual> o2) {
+				if (LRUtimer.get(o1) > LRUtimer.get(o2)) {
+					return -1;
+				} else if (LRUtimer.get(o1) < LRUtimer.get(o2)) {
+					return 1;
+				} else {
+					return 0;
+				}
+			}
+		});
+
+		for (int i = cacheSizeLimit / 2; i < list.size(); i++) {
+			cache.remove(list.get(i));
+			LRUtimer.remove(list.get(i));
+		}
+	}
+}
Index: /java/ecj/cecj/sampling/AllSamplingMethod.java
===================================================================
--- /java/ecj/cecj/sampling/AllSamplingMethod.java	(revision 44)
+++ /java/ecj/cecj/sampling/AllSamplingMethod.java	(revision 44)
@@ -0,0 +1,18 @@
+package cecj.sampling;
+
+import java.util.List;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+public class AllSamplingMethod extends SamplingMethod {
+
+	@Override
+	public List<Individual> sample(EvolutionState state, List<Individual> source) {
+		return source;
+	}
+
+	public void setup(EvolutionState state, Parameter base) {
+	}
+}
Index: /java/ecj/cecj/sampling/NullSamplingMethod.java
===================================================================
--- /java/ecj/cecj/sampling/NullSamplingMethod.java	(revision 44)
+++ /java/ecj/cecj/sampling/NullSamplingMethod.java	(revision 44)
@@ -0,0 +1,20 @@
+package cecj.sampling;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+public class NullSamplingMethod extends SamplingMethod {
+
+	@Override
+	public List<Individual> sample(EvolutionState state, List<Individual> source) {
+		return new ArrayList<Individual>();
+	}
+
+	public void setup(EvolutionState state, Parameter base) {
+	}
+
+}
Index: /java/ecj/cecj/sampling/RandomSamplingMethod.java
===================================================================
--- /java/ecj/cecj/sampling/RandomSamplingMethod.java	(revision 44)
+++ /java/ecj/cecj/sampling/RandomSamplingMethod.java	(revision 44)
@@ -0,0 +1,39 @@
+package cecj.sampling;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+/**
+ * A random sampling method samples randomly with repetitions given individuals collection. It can
+ * be used for so called "k-random opponents" evaluation scheme.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public class RandomSamplingMethod extends SamplingMethod {
+
+	private static final String P_SAMPLE_SIZE = "sample-size";
+
+	private int sampleSize;
+
+	public void setup(EvolutionState state, Parameter base) {
+		Parameter sampleSizeParameter = base.push(P_SAMPLE_SIZE);
+		sampleSize = state.parameters.getIntWithDefault(sampleSizeParameter, null, 1);
+	}
+
+	@Override
+	public List<Individual> sample(EvolutionState state, List<Individual> source) {
+		List<Individual> result = new ArrayList<Individual>(sampleSize);
+		if (!source.isEmpty()) {
+			for (int i = 0; i < sampleSize; i++) {
+				result.add(source.get(state.random[0].nextInt(source.size())));
+			}
+		}
+
+		return result;
+	}
+}
Index: /java/ecj/cecj/sampling/SamplingMethod.java
===================================================================
--- /java/ecj/cecj/sampling/SamplingMethod.java	(revision 44)
+++ /java/ecj/cecj/sampling/SamplingMethod.java	(revision 44)
@@ -0,0 +1,45 @@
+package cecj.sampling;
+
+import java.util.Arrays;
+import java.util.List;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Setup;
+
+/**
+ * A method of sampling a collection of individuals. Defines methods used by
+ * <code>CoevolutionaryEvaluator</code> to choose opponents for evaluating concrete individual.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public abstract class SamplingMethod implements Setup {
+
+	/**
+	 * Samples the subpopulation specified by <code>subpop</code> index and puts the results into
+	 * the <code>inds</code> array.
+	 * 
+	 * @param state
+	 *            current evolution state
+	 * @param subpop
+	 *            the index of sampled subpopulation
+	 * @param inds
+	 *            the array of sampling results
+	 */
+	public List<Individual> sample(EvolutionState state, Individual[] source) {
+		return this.sample(state, Arrays.asList(source));
+	}
+
+	/**
+	 * Samples given list of individuals and puts the results int the <code>inds</code> array.
+	 * 
+	 * @param state
+	 *            current evolution state
+	 * @param list
+	 *            the list of individuals to be sampled
+	 * @param inds
+	 *            the array of sampling results
+	 */
+	public abstract List<Individual> sample(EvolutionState state, List<Individual> source);
+}
Index: /java/ecj/cecj/statistics/AverageObjectiveFitnessChartStatistics.java
===================================================================
--- /java/ecj/cecj/statistics/AverageObjectiveFitnessChartStatistics.java	(revision 44)
+++ /java/ecj/cecj/statistics/AverageObjectiveFitnessChartStatistics.java	(revision 44)
@@ -0,0 +1,60 @@
+package cecj.statistics;
+
+import ec.EvolutionState;
+import ec.display.chart.XYSeriesChartStatistics;
+import ec.util.Parameter;
+
+public class AverageObjectiveFitnessChartStatistics extends XYSeriesChartStatistics {
+
+	private static final String P_POP = "pop";
+	private static final String P_SIZE = "subpops";
+	private static final String P_FREQUENCY = "frequency";
+	private static final String P_FITNESS_CALCULATOR = "fitness-calc";
+
+	private int numSubpopulations;
+	private int[] seriesID;
+	private int frequency;
+
+	private ObjectiveFitnessCalculator fitnessCalc;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+
+		Parameter fitnessCalcParameter = base.push(P_FITNESS_CALCULATOR);
+		fitnessCalc = (ObjectiveFitnessCalculator) state.parameters
+			.getInstanceForParameter(fitnessCalcParameter, null, ObjectiveFitnessCalculator.class);
+		fitnessCalc.setup(state, fitnessCalcParameter);
+
+		Parameter frequencyParam = base.push(P_FREQUENCY);
+		frequency = state.parameters.getIntWithDefault(frequencyParam, null, 1);
+
+		Parameter popSizeParameter = new Parameter(P_POP).push(P_SIZE);
+		numSubpopulations = state.parameters.getInt(popSizeParameter, null, 0);
+		seriesID = new int[numSubpopulations];
+		for (int i = 0; i < numSubpopulations; ++i) {
+			seriesID[i] = addSeries("SubPop " + i);
+		}
+	}
+
+	@Override
+	public void postEvaluationStatistics(EvolutionState state) {
+		super.postEvaluationStatistics(state);
+
+		if (state.generation % frequency != 0) {
+			return;
+		}
+
+		for (int subPop = 0; subPop < numSubpopulations; ++subPop) {
+			double averageFitness = 0;
+			for (int i = 0; i < state.population.subpops[subPop].individuals.length; ++i) {
+				averageFitness += fitnessCalc
+					.calculateObjectiveFitness(state,
+												state.population.subpops[subPop].individuals[i]);
+			}
+			averageFitness /= state.population.subpops[subPop].individuals.length;
+
+			addDataPoint(seriesID[subPop], state.generation, averageFitness);
+		}
+	}
+}
Index: /java/ecj/cecj/statistics/AverageObjectiveFitnessStatistics.java
===================================================================
--- /java/ecj/cecj/statistics/AverageObjectiveFitnessStatistics.java	(revision 44)
+++ /java/ecj/cecj/statistics/AverageObjectiveFitnessStatistics.java	(revision 44)
@@ -0,0 +1,137 @@
+package cecj.statistics;
+
+import java.io.File;
+import java.io.IOException;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Statistics;
+import ec.util.Output;
+import ec.util.Parameter;
+
+public class AverageObjectiveFitnessStatistics extends Statistics {
+
+	private static final String P_COUNT_LAST = "count-last";
+	private static final String P_FREQUENCY = "frequency";
+	private static final String P_FITNESS_CALCULATOR = "fitness-calc";
+	private static final String P_FITNESS_FILE = "fitness-file";
+
+	public int fitnessStatisticslog;
+
+	public AverageObjectiveFitnessStatistics() {
+		fitnessStatisticslog = 0;
+	}
+
+	private int frequency;
+	private ObjectiveFitnessCalculator fitnessCalc;
+
+	private int countLast;
+	private int lastCounter;
+	private float sumLastFitnesses;
+	private float lastFitnesses[];
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+
+		Parameter countLastParam = base.push(P_COUNT_LAST);
+		countLast = state.parameters.getIntWithDefault(countLastParam, null, -1);
+		if (countLast != -1) {
+			lastFitnesses = new float[countLast];
+			lastCounter = 0;
+			sumLastFitnesses = 0.0f;
+		}
+
+		Parameter fitnessCalcParameter = base.push(P_FITNESS_CALCULATOR);
+		fitnessCalc = (ObjectiveFitnessCalculator) state.parameters
+			.getInstanceForParameter(fitnessCalcParameter, null, ObjectiveFitnessCalculator.class);
+		fitnessCalc.setup(state, fitnessCalcParameter);
+
+		Parameter frequencyParam = base.push(P_FREQUENCY);
+		frequency = state.parameters.getIntWithDefault(frequencyParam, null, 1);
+
+		File fitnessStatisticsFile = state.parameters.getFile(base.push(P_FITNESS_FILE), null);
+		if (fitnessStatisticsFile != null) {
+			try {
+				fitnessStatisticslog = state.output.addLog(fitnessStatisticsFile, Output.V_VERBOSE,
+															false, true, false);
+			} catch (IOException i) {
+				state.output.fatal("An IOException occurred while trying to create the log "
+						+ fitnessStatisticsFile + ":\n" + i);
+			}
+		}
+	}
+
+	@Override
+	public void postEvaluationStatistics(EvolutionState state) {
+		super.postEvaluationStatistics(state);
+
+		if ((state.generation % frequency != 0) && (state.generation != state.numGenerations - 1)) {
+			return;
+		}
+
+		for (int subpop = 0; subpop < state.population.subpops.length; ++subpop) {
+			float sumFitness = 0;
+			float maxFitness = Float.NEGATIVE_INFINITY;
+			float maxSubjectiveFitness = Float.NEGATIVE_INFINITY;
+			float objectiveFitnessOfSubjectivelyBest = -1;
+
+			float[] fitnesses = new float[state.population.subpops[subpop].individuals.length];
+
+			for (int i = 0; i < state.population.subpops[subpop].individuals.length; ++i) {
+				Individual ind = state.population.subpops[subpop].individuals[i];
+				fitnesses[i] = fitnessCalc.calculateObjectiveFitness(state, ind);
+
+				sumFitness += fitnesses[i];
+				maxFitness = Math.max(maxFitness, fitnesses[i]);
+				if (ind.fitness.fitness() > maxSubjectiveFitness) {
+					maxSubjectiveFitness = ind.fitness.fitness();
+					objectiveFitnessOfSubjectivelyBest = fitnesses[i];
+				}
+			}
+
+			float sumSquareDiffs = 0;
+			float avgFitness = sumFitness / state.population.subpops[subpop].individuals.length;
+			for (int i = 0; i < state.population.subpops[subpop].individuals.length; ++i) {
+				float diff = fitnesses[i] - avgFitness;
+				sumSquareDiffs += (diff * diff);
+			}
+
+			double stdev = Math.sqrt(sumSquareDiffs
+					/ state.population.subpops[subpop].individuals.length);
+
+			if (countLast != -1) {
+				sumLastFitnesses -= lastFitnesses[lastCounter];
+				sumLastFitnesses += objectiveFitnessOfSubjectivelyBest;
+
+				lastFitnesses[lastCounter] = objectiveFitnessOfSubjectivelyBest;
+				lastCounter++;
+				lastCounter %= countLast;
+
+				float avgLastFitness = sumLastFitnesses / countLast;
+				state.output.println(state.generation + "\t" + avgFitness + "\t" + stdev + "\t"
+						+ maxFitness + "\t" + objectiveFitnessOfSubjectivelyBest + "\t"
+						+ avgLastFitness, Output.V_VERBOSE + 1, fitnessStatisticslog);
+			} else {
+				state.output.println(state.generation + "\t" + avgFitness + "\t" + stdev + "\t"
+						+ maxFitness + "\t" + objectiveFitnessOfSubjectivelyBest,
+										Output.V_VERBOSE + 1, fitnessStatisticslog);
+			}
+		}
+
+		if (state.generation == state.numGenerations - 1) {
+			saveIndividuals(state);
+		}
+	}
+
+	private void saveIndividuals(EvolutionState state) {
+		for (int subpop = 0; subpop < state.population.subpops.length; ++subpop) {
+			state.output.println("\nSubpopulation " + subpop + " individuals : ",
+									Output.V_VERBOSE + 1, fitnessStatisticslog);
+			Individual[] inds = state.population.subpops[subpop].individuals;
+			for (Individual ind : inds) {
+				ind.printIndividual(state, fitnessStatisticslog, Output.V_VERBOSE + 1);
+			}
+		}
+	}
+}
Index: /java/ecj/cecj/statistics/AverageSubjectiveFitnessChartStatistics.java
===================================================================
--- /java/ecj/cecj/statistics/AverageSubjectiveFitnessChartStatistics.java	(revision 44)
+++ /java/ecj/cecj/statistics/AverageSubjectiveFitnessChartStatistics.java	(revision 44)
@@ -0,0 +1,42 @@
+package cecj.statistics;
+
+import ec.EvolutionState;
+import ec.display.chart.XYSeriesChartStatistics;
+import ec.util.Parameter;
+
+public class AverageSubjectiveFitnessChartStatistics extends XYSeriesChartStatistics {
+
+	private static final String P_POP = "pop";
+	private static final String P_SIZE = "subpops";
+
+	private int numSubpopulations;
+	private int[] seriesID;
+
+	@Override
+	public void setup(EvolutionState state, Parameter base) {
+		super.setup(state, base);
+
+		Parameter popSizeParameter = new Parameter(P_POP).push(P_SIZE);
+		numSubpopulations = state.parameters.getInt(popSizeParameter, null, 0);
+		seriesID = new int[numSubpopulations];
+
+		for (int i = 0; i < numSubpopulations; ++i) {
+			seriesID[i] = addSeries("SubPop " + i);
+		}
+	}
+
+	@Override
+	public void postEvaluationStatistics(EvolutionState state) {
+		super.postEvaluationStatistics(state);
+
+		for (int subPop = 0; subPop < numSubpopulations; ++subPop) {
+			double averageFitness = 0;
+			for (int i = 0; i < state.population.subpops[subPop].individuals.length; ++i) {
+				averageFitness += state.population.subpops[subPop].individuals[i].fitness.fitness();
+			}
+			averageFitness /= state.population.subpops[subPop].individuals.length;
+
+			addDataPoint(seriesID[subPop], state.generation, averageFitness);
+		}
+	}
+}
Index: /java/ecj/cecj/statistics/CoevolutionaryStatistics.java
===================================================================
--- /java/ecj/cecj/statistics/CoevolutionaryStatistics.java	(revision 44)
+++ /java/ecj/cecj/statistics/CoevolutionaryStatistics.java	(revision 44)
@@ -0,0 +1,41 @@
+package cecj.statistics;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import cecj.interaction.InteractionResult;
+
+
+import ec.EvolutionState;
+import ec.simple.SimpleStatistics;
+import ec.util.Output;
+import ec.util.Parameter;
+
+public abstract class CoevolutionaryStatistics extends SimpleStatistics {
+
+	public CoevolutionaryStatistics() {
+		statisticslog = 0;
+	}
+
+	@Override
+	public void setup(final EvolutionState state, final Parameter base) {
+		super.setup(state, base);
+
+		File statisticsFile = state.parameters.getFile(base.push(P_STATISTICS_FILE), null);
+
+		if (statisticsFile != null) {
+			try {
+				statisticslog = state.output.addLog(statisticsFile, Output.V_NO_GENERAL - 1, false,
+													false, false);
+			} catch (IOException i) {
+				state.output.fatal("An IOException occurred while trying to create the log "
+						+ statisticsFile + ":\n" + i);
+			}
+		}
+	}
+
+	public abstract void printInteractionResults(EvolutionState state,
+			List<List<InteractionResult>> result, int subpop);
+
+}
Index: /java/ecj/cecj/statistics/ObjectiveFitnessCalculator.java
===================================================================
--- /java/ecj/cecj/statistics/ObjectiveFitnessCalculator.java	(revision 44)
+++ /java/ecj/cecj/statistics/ObjectiveFitnessCalculator.java	(revision 44)
@@ -0,0 +1,9 @@
+package cecj.statistics;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Setup;
+
+public interface ObjectiveFitnessCalculator extends Setup {
+	public float calculateObjectiveFitness(EvolutionState state, Individual ind);
+}
Index: /java/ecj/cecj/statistics/SimpleCoevolutionaryStatistics.java
===================================================================
--- /java/ecj/cecj/statistics/SimpleCoevolutionaryStatistics.java	(revision 44)
+++ /java/ecj/cecj/statistics/SimpleCoevolutionaryStatistics.java	(revision 44)
@@ -0,0 +1,36 @@
+package cecj.statistics;
+
+import java.util.List;
+
+import cecj.interaction.InteractionResult;
+
+import ec.EvolutionState;
+import ec.vector.DoubleVectorIndividual;
+
+public class SimpleCoevolutionaryStatistics extends CoevolutionaryStatistics {
+
+	@Override
+	public void printInteractionResults(EvolutionState state,
+			List<List<InteractionResult>> results, int subpop) {
+
+		System.out.println("Subpopulation " + subpop + " interactions result:");
+
+		for (int i = 0; i < results.size(); i++) {
+			System.out.print("Individual " + i + " : ");
+			for (int j = 0; j < results.get(i).size(); j++) {
+				System.out.print(results.get(i).get(j) + " ");
+			}
+			System.out.println(state.population.subpops[subpop].individuals[i].fitness
+				.fitnessToStringForHumans());
+		}
+
+		System.out.println("");
+	}
+
+	public void printIndividualGenome(DoubleVectorIndividual ind) {
+		for (int g = 0; g < ind.genomeLength(); g++) {
+			System.out.print((int) ind.genome[g] + " ");
+		}
+		System.out.println("");
+	}
+}
Index: /java/ecj/cecj/utils/EquivalenceComparator.java
===================================================================
--- /java/ecj/cecj/utils/EquivalenceComparator.java	(revision 44)
+++ /java/ecj/cecj/utils/EquivalenceComparator.java	(revision 44)
@@ -0,0 +1,16 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.utils;
+
+/**
+ * 
+ * @author Marcin Szubert
+ * 
+ * @param <T>
+ */
+public interface EquivalenceComparator<T> {
+	boolean equal(T o1, T o2);
+}
Index: /java/ecj/cecj/utils/Pair.java
===================================================================
--- /java/ecj/cecj/utils/Pair.java	(revision 44)
+++ /java/ecj/cecj/utils/Pair.java	(revision 44)
@@ -0,0 +1,36 @@
+/*
+  Copyright 2009 by Marcin Szubert
+  Licensed under the Academic Free License version 3.0
+ */
+
+package cecj.utils;
+
+public class Pair<T> {
+	public T first;
+	public T second;
+
+	public Pair(T first, T second) {
+		this.first = first;
+		this.second = second;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (!(obj instanceof Pair)) {
+			return false;
+		}
+
+		Pair<?> other = (Pair<?>) obj;
+		return (first.equals(other.first) && second.equals(other.second));
+	}
+
+	@Override
+	public int hashCode() {
+		return first.hashCode() + second.hashCode();
+	}
+
+	@Override
+	public String toString() {
+		return "<" + first.toString() + ", " + second.toString() + ">";
+	}
+}
Index: /java/ecj/ec/display/CommandLineConsoleWrapper.java
===================================================================
--- /java/ecj/ec/display/CommandLineConsoleWrapper.java	(revision 44)
+++ /java/ecj/ec/display/CommandLineConsoleWrapper.java	(revision 44)
@@ -0,0 +1,33 @@
+package ec.display;
+
+import java.io.File;
+
+import ec.display.Console;
+
+public class CommandLineConsoleWrapper {
+	
+	public static void main(String[] args) {
+		if (args.length > 0) {
+			String file = args[0];
+			String[] restArgs = new String[args.length - 1];
+			for (int i = 1; i < args.length; i++) {
+				restArgs[i - 1] = args[i];
+			}
+
+			Console application = new Console(restArgs);
+			application.setVisible(true);
+			openFile(application, file);
+		} else {
+			Console application = new Console(args);
+			application.setVisible(true);
+		}
+	}
+
+	private static void openFile(Console application, String file) {
+		File f = new File(file);
+		application.loadParameters(f);
+		application.playButton.setEnabled(true);
+		application.stepButton.setEnabled(true);
+		application.conPanel.enableControls();
+	}
+}
Index: /java/ecj/framsticks/FramsticksCoevolutionaryProblem.java
===================================================================
--- /java/ecj/framsticks/FramsticksCoevolutionaryProblem.java	(revision 44)
+++ /java/ecj/framsticks/FramsticksCoevolutionaryProblem.java	(revision 44)
@@ -0,0 +1,31 @@
+package framsticks;
+
+import cecj.interaction.InteractionResult;
+import cecj.problems.TestBasedProblem;
+import cecj.utils.Pair;
+import ec.EvolutionState;
+import ec.Individual;
+
+public class FramsticksCoevolutionaryProblem extends TestBasedProblem {
+
+	@Override
+	public Pair<? extends InteractionResult> test(EvolutionState state, Individual candidate,
+			Individual test) {
+
+		if (!(candidate instanceof FramsticksIndividual) || !(test instanceof FramsticksIndividual)) {
+			state.output
+					.error("The individuals for this problem should be of class FramsticksIndividual.\n");
+		}
+
+		FramsticksIndividual framstickCandidate = (FramsticksIndividual) candidate;
+		FramsticksIndividual framstickTest = (FramsticksIndividual) test;
+
+		// TODO: Prepare for multithreading
+		String fileName = "coevolutionary_evaluation_thread.gen";
+
+		FramsticksUtils utils = FramsticksUtils.getInstance(state);
+		return utils.coevolutionaryEvaluate(framstickCandidate.genotype, framstickTest.genotype,
+				fileName);
+	}
+
+}
Index: /java/ecj/framsticks/FramsticksCrossoverPipeline.java
===================================================================
--- /java/ecj/framsticks/FramsticksCrossoverPipeline.java	(revision 44)
+++ /java/ecj/framsticks/FramsticksCrossoverPipeline.java	(revision 44)
@@ -0,0 +1,69 @@
+package framsticks;
+
+import ec.BreedingPipeline;
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+public class FramsticksCrossoverPipeline extends BreedingPipeline {
+
+	public static final String P_CROSSOVER = "xover";
+	public static final int NUM_SOURCES = 2;
+
+	public boolean tossSecondParent;
+	FramsticksIndividual parents[];
+
+	public FramsticksCrossoverPipeline() {
+		parents = new FramsticksIndividual[2];
+	}
+
+	@Override
+	public int numSources() {
+		return NUM_SOURCES;
+	}
+
+	@Override
+	public int produce(int min, int max, int start, int subpopulation, Individual[] inds,
+			EvolutionState state, int thread) {
+		int n = typicalIndsProduced();
+		n = Math.max(Math.min(n, max), min);
+
+		for (int i = start; i < n + start; i++) {
+			if (sources[0] == sources[1]) {
+				sources[0].produce(2, 2, 0, subpopulation, parents, state, thread);
+				if (!(sources[0] instanceof BreedingPipeline)) {
+					parents[0] = (FramsticksIndividual) (parents[0].clone());
+					parents[1] = (FramsticksIndividual) (parents[1].clone());
+				}
+			} else {
+				sources[0].produce(1, 1, 0, subpopulation, parents, state, thread);
+				sources[1].produce(1, 1, 1, subpopulation, parents, state, thread);
+				if (!(sources[0] instanceof BreedingPipeline)) {
+					parents[0] = (FramsticksIndividual) (parents[0].clone());
+				}
+				if (!(sources[1] instanceof BreedingPipeline)) {
+					parents[1] = (FramsticksIndividual) (parents[1].clone());
+				}
+			}
+
+			parents[0].crossover(state, parents[1]);
+			parents[0].evaluated = false;
+
+			inds[i] = parents[0];
+		}
+
+		return n;
+	}
+
+	public Parameter defaultBase() {
+		return FramsticksDefaults.base().push(P_CROSSOVER);
+	}
+
+	@Override
+	public Object clone() {
+		FramsticksCrossoverPipeline clone = (FramsticksCrossoverPipeline) (super.clone());
+		clone.parents = parents.clone();
+		return clone;
+	}
+
+}
Index: /java/ecj/framsticks/FramsticksDefaults.java
===================================================================
--- /java/ecj/framsticks/FramsticksDefaults.java	(revision 44)
+++ /java/ecj/framsticks/FramsticksDefaults.java	(revision 44)
@@ -0,0 +1,13 @@
+package framsticks;
+
+import ec.DefaultsForm;
+import ec.util.Parameter;
+
+public final class FramsticksDefaults implements DefaultsForm {
+
+	public static final String P_FRAMSTICKS = "framsticks";
+	
+	public static final Parameter base() {
+		return new Parameter(P_FRAMSTICKS);
+	}
+}
Index: /java/ecj/framsticks/FramsticksEvolutionProblem.java
===================================================================
--- /java/ecj/framsticks/FramsticksEvolutionProblem.java	(revision 44)
+++ /java/ecj/framsticks/FramsticksEvolutionProblem.java	(revision 44)
@@ -0,0 +1,38 @@
+package framsticks;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Problem;
+import ec.simple.SimpleProblemForm;
+import ec.simple.SimpleFitness;
+
+public class FramsticksEvolutionProblem extends Problem implements SimpleProblemForm {
+
+	public void evaluate(EvolutionState state, Individual ind, int subpopulation, int threadnum) {
+		if (ind.evaluated) {
+			return;
+		}
+
+		if (!(ind instanceof FramsticksIndividual)) {
+			state.output.fatal("The individuals for this problem should be FramsticksIndividuals.");
+		}
+
+		FramsticksIndividual framstickIndividual = (FramsticksIndividual) ind;
+		if (!(framstickIndividual.fitness instanceof SimpleFitness)) {
+			state.output.fatal("The fitness for this problem should be SimpleFitness");
+		}
+
+		String fileName = "ind_subpop" + subpopulation + "_thread" + threadnum + ".gen";
+		FramsticksUtils utils = FramsticksUtils.getInstance(state);
+		float fitness = utils.evaluateGenotype(framstickIndividual.genotype, fileName);
+
+		((SimpleFitness) framstickIndividual.fitness).setFitness(state, fitness, false);
+		framstickIndividual.evaluated = true;
+	}
+
+	public void describe(Individual ind, EvolutionState state, int subpopulation, int threadnum,
+			int log, int verbosity) {
+		// TODO Auto-generated method stub
+		
+	}
+}
Index: /java/ecj/framsticks/FramsticksIndividual.java
===================================================================
--- /java/ecj/framsticks/FramsticksIndividual.java	(revision 44)
+++ /java/ecj/framsticks/FramsticksIndividual.java	(revision 44)
@@ -0,0 +1,73 @@
+package framsticks;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+public class FramsticksIndividual extends Individual {
+
+	public static final String P_FRAMSTICKS_INDIVIDUAL = "framssticks-ind";
+
+	public String genotype;
+
+	@Override
+	public boolean equals(Object ind) {
+		if (!this.getClass().equals(ind.getClass())) {
+			return false;
+		}
+
+		FramsticksIndividual framsticksIndividual = (FramsticksIndividual) ind;
+		return genotype.equals(framsticksIndividual.genotype);
+	}
+
+	@Override
+	public int hashCode() {
+		int hash = this.getClass().hashCode();
+		hash = (hash << 1 | hash >>> 31) ^ genotype.hashCode();
+		return hash;
+	}
+
+	public Parameter defaultBase() {
+		return FramsticksDefaults.base().push(P_FRAMSTICKS_INDIVIDUAL);
+	}
+
+	@Override
+	public void setup(final EvolutionState state, final Parameter base) {
+		super.setup(state, base);
+		genotype = FramsticksUtils.getInstance(state).getNewGenotype();
+	}
+
+	@Override
+	public Object clone() {
+		FramsticksIndividual clone = (FramsticksIndividual) (super.clone());
+		clone.genotype = genotype;
+		return clone;
+	}
+
+	public void mutate(final EvolutionState state) {
+		genotype = FramsticksUtils.getInstance(state).mutateGenotype(genotype);
+	}
+
+	public void crossover(final EvolutionState state, FramsticksIndividual other) {
+		genotype = FramsticksUtils.getInstance(state).crossoverGenotypes(genotype, other.genotype);
+	}
+
+	@Override
+	public String genotypeToStringForHumans() {
+		return genotype;
+	}
+
+	@Override
+	public void writeGenotype(EvolutionState state, DataOutput dataOutput) throws IOException {
+		dataOutput.writeUTF(genotype);
+	}
+
+	@Override
+	public void readGenotype(EvolutionState state, DataInput dataInput) throws IOException {
+		genotype = dataInput.readUTF();
+	}
+}
Index: /java/ecj/framsticks/FramsticksMutationPipeline.java
===================================================================
--- /java/ecj/framsticks/FramsticksMutationPipeline.java	(revision 44)
+++ /java/ecj/framsticks/FramsticksMutationPipeline.java	(revision 44)
@@ -0,0 +1,38 @@
+package framsticks;
+
+import ec.BreedingPipeline;
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Parameter;
+
+public class FramsticksMutationPipeline extends BreedingPipeline {
+
+	public static final String P_MUTATION = "mutate";
+	public static final int NUM_SOURCES = 1;
+
+	@Override
+	public int numSources() {
+		return NUM_SOURCES;
+	}
+
+	@Override
+	public int produce(int min, int max, int start, int subpopulation, Individual[] inds,
+			EvolutionState state, int thread) {
+		int n = sources[0].produce(min, max, start, subpopulation, inds, state, thread);
+
+		if (!(sources[0] instanceof BreedingPipeline))
+			for (int q = start; q < n + start; q++)
+				inds[q] = (Individual) (inds[q].clone());
+
+		for (int q = start; q < n + start; q++) {
+			((FramsticksIndividual) inds[q]).mutate(state);
+			((FramsticksIndividual) inds[q]).evaluated = false;
+		}
+
+		return n;
+	}
+
+	public Parameter defaultBase() {
+		return FramsticksDefaults.base().push(P_MUTATION);
+	}
+}
Index: /java/ecj/framsticks/FramsticksSpecies.java
===================================================================
--- /java/ecj/framsticks/FramsticksSpecies.java	(revision 44)
+++ /java/ecj/framsticks/FramsticksSpecies.java	(revision 44)
@@ -0,0 +1,51 @@
+package framsticks;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Species;
+import ec.util.Parameter;
+
+public class FramsticksSpecies extends Species {
+
+	public static final String P_FRAMSTICKSSPECIES = "species";
+	public final static String P_MUTATIONPROB = "mutation-prob";
+	public final static String P_CROSSOVERPROB = "crossover-prob";
+
+	public float mutationProbability;
+	public float crossoverProbability;
+
+	public Parameter defaultBase() {
+		return FramsticksDefaults.base().push(P_FRAMSTICKSSPECIES);
+	}
+
+	@Override
+	public void setup(final EvolutionState state, final Parameter base) {
+		Parameter def = defaultBase();
+
+		mutationProbability = state.parameters.getFloat(base.push(P_MUTATIONPROB), def
+				.push(P_MUTATIONPROB), 0.0, 1.0);
+		if (mutationProbability == -1.0)
+			state.output
+					.error(
+							"FramsticksSpecies must have a mutation probability between 0.0 and 1.0 inclusive",
+							base.push(P_MUTATIONPROB), def.push(P_MUTATIONPROB));
+
+		crossoverProbability = state.parameters.getFloat(base.push(P_CROSSOVERPROB), def
+				.push(P_CROSSOVERPROB), 0.0, 1.0);
+		if (crossoverProbability == -1.0)
+			state.output
+					.error(
+							"FramsticksSpecies must have a crossover probability between 0.0 and 1.0 inclusive",
+							base.push(P_CROSSOVERPROB), def.push(P_CROSSOVERPROB));
+
+		state.output.exitIfErrors();
+		super.setup(state, base);
+	}
+
+	@Override
+	public Individual newIndividual(final EvolutionState state, int thread) {
+		FramsticksIndividual newind = (FramsticksIndividual) (super.newIndividual(state, thread));
+		newind.mutate(state);
+		return newind;
+	}
+}
Index: /java/ecj/framsticks/FramsticksUtils.java
===================================================================
--- /java/ecj/framsticks/FramsticksUtils.java	(revision 44)
+++ /java/ecj/framsticks/FramsticksUtils.java	(revision 44)
@@ -0,0 +1,173 @@
+package framsticks;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.InputStreamReader;
+
+import cecj.interaction.InteractionResult;
+import cecj.interaction.RealValuedResult;
+import cecj.utils.Pair;
+
+import ec.EvolutionState;
+import ec.util.Parameter;
+
+public class FramsticksUtils {
+
+	private static final String NEW_CMD = "%s \"getsimplest 1\" -q";
+	private static final String EVAL_CMD = "%s \"ex %s\" \"eval %s %s\" -q";
+	private static final String MUTATE_CMD = "%s rnd \"mutate %s\" -q";
+	private static final String XOVER_CMD = "%s rnd \"crossover %s %s\" -q";
+
+	private static final String GENOTYPE_DESC = "org:\ngenotype:~\n%s~\n";
+	private static final String TEMPORARY_FILE_NAME = "temp.gen";
+
+	private static final String P_DIRECTORY_PATH = "directory-path";
+	private static final String P_SCRIPTS_OUTPUT = "scripts-output";
+	private static final String P_SETTINGS = "settings-file";
+	private static final String P_WORKING_DIRECTORY = "working-directory";
+	private static final String P_EXPERIMENT_DEFINITION = "expdef";
+	private static final String P_EXECUTABLE_COMMAND = "executable-cmd";
+
+	private String directoryPath;
+	private String scriptsOutputPath;
+	private String settingsFile;
+	private String workingDirectory;
+	private String experimentDefinition;
+	private String executableCommand;
+
+	private static FramsticksUtils instance;
+
+	public synchronized static FramsticksUtils getInstance(final EvolutionState state) {
+		if (instance == null) {
+			instance = new FramsticksUtils();
+			instance.setup(state);
+		}
+		return instance;
+	}
+
+	private void setup(final EvolutionState state) {
+		Parameter def = FramsticksDefaults.base();
+		directoryPath = state.parameters.getString(null, def.push(P_DIRECTORY_PATH));
+		if (directoryPath == null) {
+			state.output.fatal("No Framsticks directory specified", def.push(P_DIRECTORY_PATH));
+		}
+		scriptsOutputPath = state.parameters.getString(null, def.push(P_SCRIPTS_OUTPUT));
+		if (scriptsOutputPath == null) {
+			state.output.fatal("No scripts output file specified", def.push(P_SCRIPTS_OUTPUT));
+		}
+		settingsFile = state.parameters.getString(null, def.push(P_SETTINGS));
+		if (settingsFile == null) {
+			state.output.fatal("No settings file specified", def.push(P_SETTINGS));
+		}
+		workingDirectory = state.parameters.getString(null, def.push(P_WORKING_DIRECTORY));
+		if (workingDirectory == null) {
+			state.output.fatal("No working directory specified", def.push(P_WORKING_DIRECTORY));
+		}
+		experimentDefinition = state.parameters.getString(null, def.push(P_EXPERIMENT_DEFINITION));
+		if (experimentDefinition == null) {
+			state.output.fatal("No experiment definition specified", def
+					.push(P_EXPERIMENT_DEFINITION));
+		}
+		executableCommand = state.parameters.getString(null, def.push(P_EXECUTABLE_COMMAND));
+		if (executableCommand == null) {
+			state.output.fatal("No executable command specified", def.push(P_EXECUTABLE_COMMAND));
+		}
+	}
+
+	private String executeCommand(String command) {
+		String line;
+		String result = "";
+		try {
+			File f = new File(directoryPath);
+			Process p = Runtime.getRuntime().exec(directoryPath + command, null, f);
+			BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
+			while ((line = input.readLine()) != null) {
+				result += (line + '\n');
+			}
+			input.close();
+		} catch (Exception ex) {
+			ex.printStackTrace();
+		}
+
+		return result;
+	}
+
+	private void saveToFile(String filePath, String contents) {
+		try {
+			BufferedWriter output = new BufferedWriter(new FileWriter(filePath));
+			output.write(contents);
+			output.close();
+		} catch (Exception ex) {
+			ex.printStackTrace();
+		}
+	}
+
+	private String readFromFile(String filePath) {
+		String line;
+		String result = "";
+		try {
+			BufferedReader input = new BufferedReader(new FileReader(filePath));
+			while ((line = input.readLine()) != null) {
+				result += (line + '\n');
+			}
+			input.close();
+		} catch (Exception ex) {
+			ex.printStackTrace();
+		}
+
+		return result;
+	}
+
+	public float evaluateGenotype(String genotype, String fileName) {
+		String fileContents = String.format(GENOTYPE_DESC, genotype);
+		String filePath = workingDirectory + fileName;
+
+		saveToFile(filePath, fileContents);
+		executeCommand(String.format(EVAL_CMD, executableCommand, experimentDefinition,
+				settingsFile, filePath));
+		String evaluation = readFromFile(scriptsOutputPath);
+
+		return Float.parseFloat(evaluation.split("\t")[1]);
+	}
+
+	public Pair<? extends InteractionResult> coevolutionaryEvaluate(String candidate, String test,
+			String fileName) {
+		float candidateResult = evaluateGenotype(candidate, fileName);
+		float testResult = evaluateGenotype(test, fileName);
+
+		return new Pair<RealValuedResult>(new RealValuedResult(candidateResult),
+				new RealValuedResult(testResult));
+	}
+
+	public String mutateGenotype(String genotype) {
+		String filePath = workingDirectory + TEMPORARY_FILE_NAME;
+		saveToFile(filePath, genotype);
+		return executeCommand(String.format(MUTATE_CMD, executableCommand, filePath));
+	}
+
+	public String crossoverGenotypes(String genotype1, String genotype2) {
+		String filePath1 = workingDirectory + TEMPORARY_FILE_NAME;
+		String filePath2 = workingDirectory + "_" + TEMPORARY_FILE_NAME;
+		saveToFile(filePath1, genotype1);
+		saveToFile(filePath2, genotype2);
+		return executeCommand(String.format(XOVER_CMD, executableCommand, filePath1, filePath2));
+	}
+
+	public String getNewGenotype() {
+		return executeCommand(String.format(NEW_CMD, executableCommand));
+	}
+
+	/*
+	 * Sample usage :
+	 */
+	/*
+	 * public static void main(String[] args) { FramsticksUtils utils =
+	 * FramsticksUtils.getInstance(); System.out.println(utils.evaluateGenotype("X", "halo1.gen"));
+	 * System.out.println(utils.mutateGenotype("X"));
+	 * System.out.println(utils.crossoverGenotypes("AX", "MX"));
+	 * System.out.println(utils.getNewGenotype()); }
+	 */
+}
Index: /java/ecj/framsticks/framsticks.master.params
===================================================================
--- /java/ecj/framsticks/framsticks.master.params	(revision 44)
+++ /java/ecj/framsticks/framsticks.master.params	(revision 44)
@@ -0,0 +1,42 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = framsticks.params
+
+# When eval.masterproblem is turned on, the system assumes
+# use of the master/slave evaluator.
+eval.masterproblem = ec.eval.MasterProblem
+
+# Turning this on will provide synchronization
+# information for debugging the master/slave evaluator
+eval.masterproblem.debug-info = true
+
+# How large should each slave's job queue be?  ECJ will
+# keep slaves' TCP/IP streams filled with jobs even if the
+# slaves haven't processed them yet, which has a significant
+# effect on network performance.  Increasing this number is
+# likely to be more efficient.  Note that once a job is
+# committed to a slave, a brand new slave coming on-line cannot
+# take it -- it'll have to sit and wait, which isn't particularly
+# efficient.  At the very least, it's probably helpful to have 2
+# or 3 jobs in the queue.
+eval.masterproblem.max-jobs-per-slave = 3
+
+# How large should our job be?  If you're doing ordinary
+# non-coevolutionary evolution, you can specify how many individuals
+# should be placed into a job (maximum) and sent to the slave
+# to be evaluated at one time, using the below parameter.
+# If your individuals are small in size, this can significantly
+# improve the network bandwidth.  If the individuals are large
+# in size, it'll have no real effect.  Furthermore, if your
+# slave is running in 'evolve' mode, this parameter will determine
+# the maximum (and typical) size of the "population" the slave is
+# evolving.  This works for both steady-state and generational evolution,
+# but if you're doing coevolution, the job size is ignored -- instead
+# the job will consist of the individuals to be coevolved together.
+eval.masterproblem.job-size = 2
+
+# This defines the socket port that the master listens in
+# for incomoing Slaves to connect.
+eval.master.port = 15000
Index: /java/ecj/framsticks/framsticks.params
===================================================================
--- /java/ecj/framsticks/framsticks.params	(revision 44)
+++ /java/ecj/framsticks/framsticks.params	(revision 44)
@@ -0,0 +1,60 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+# The parameters that were laid out in Tutorial 1 (see the documentation)
+
+verbosity	= 0
+
+breedthreads	= 1
+evalthreads	= 1
+seed.0		= 4357
+
+state		= ec.simple.SimpleEvolutionState
+
+pop		= ec.Population
+init		= ec.simple.SimpleInitializer
+finish		= ec.simple.SimpleFinisher
+breed		= ec.simple.SimpleBreeder
+eval		= ec.simple.SimpleEvaluator
+stat		= ec.simple.SimpleStatistics
+exch		= ec.simple.SimpleExchanger
+
+generations		= 200
+quit-on-run-complete	= true
+checkpoint		= false
+prefix			= ec
+checkpoint-modulo	= 1
+
+stat.file		= $out.stat
+
+pop.subpops		= 1
+pop.subpop.0		= ec.Subpopulation
+
+pop.subpop.0.size 		= 20
+pop.subpop.0.duplicate-retries 	= 0
+pop.subpop.0.species 		= framsticks.FramsticksSpecies
+
+pop.subpop.0.species.fitness 	= ec.simple.SimpleFitness
+pop.subpop.0.species.ind	= framsticks.FramsticksIndividual
+
+pop.subpop.0.species.crossover-prob	= 1.0
+pop.subpop.0.species.mutation-prob	= 0.1
+
+pop.subpop.0.species.pipe			= framsticks.FramsticksMutationPipeline
+pop.subpop.0.species.pipe.source.0		= framsticks.FramsticksCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0	= ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1	= ec.select.TournamentSelection
+
+select.tournament.size		= 2
+
+eval.problem		= framsticks.FramsticksEvolutionProblem
+
+breed.elite.0 = 2
+
+framsticks.directory-path = C:/Framsticks/
+framsticks.scripts-output = C:/Framsticks/scripts_output/genosEval.txt
+framsticks.settings-file = C:/Framsticks/maze1.sim
+framsticks.working-directory = C:/Framsticks/
+framsticks.expdef = standard-eval
+framsticks.executable-cmd = frams -Q -e -s -icliutils.ini
Index: /java/ecj/framsticks/framsticks.slave.params
===================================================================
--- /java/ecj/framsticks/framsticks.slave.params	(revision 44)
+++ /java/ecj/framsticks/framsticks.slave.params	(revision 44)
@@ -0,0 +1,33 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = framsticks.master.params
+
+# We tell our slave that he's a slave.
+eval.i-am-slave = true
+
+
+# You may want to customize each slave by giving it a unique
+# name like this:
+# 
+# eval.slave-name = my-slave-name
+#
+# (do this differently for each slave:, slave-2, slave-3, etc.)
+# Otherwise, each slave will give itself an approximately unique name based
+# on the current time and the IP address of the slave.  The unique name
+# doesn't HAVE to be unique -- it's just for printing/debug purposes.
+
+
+# We want to make sure that the Slave's Statistics object does not
+# override the Master's statistics files.  The easiest way to do this
+# is to eliminate the Statistics object in the slave by setting it
+# to the (empty default) Statistics class with no children.
+
+eval.stat = ec.Statistics
+eval.stat.num-children = 0
+
+
+# The slave needs to know where the Master is.  You need to 
+# change this.
+eval.master.host = 127.0.0.1
Index: /java/ecj/games/Board.java
===================================================================
--- /java/ecj/games/Board.java	(revision 44)
+++ /java/ecj/games/Board.java	(revision 44)
@@ -0,0 +1,21 @@
+package games;
+
+public interface Board extends Cloneable {
+	public int countPieces(int i);
+
+	public int getPiece(int row, int col);
+
+	public int getPiece(int row, int col, int dir, int dist);
+
+	public void setPiece(int row, int col, int dir, int dist, int currentPlayer);
+
+	public boolean isEmpty(int row, int col);
+
+	public GameMove getShiftedMove(int row, int col, int dir, int dist);
+
+	public double evaluate(Player player);
+
+	public int getValueAt(int row, int col);
+
+	public Board clone();
+}
Index: /java/ecj/games/BoardGame.java
===================================================================
--- /java/ecj/games/BoardGame.java	(revision 44)
+++ /java/ecj/games/BoardGame.java	(revision 44)
@@ -0,0 +1,30 @@
+package games;
+
+import java.util.List;
+
+/**
+ * Interface describing game rules. Implementing class manages the game state.
+ * 
+ * @author Marcin Szubert
+ * 
+ */
+public interface BoardGame {
+
+	public boolean endOfGame();
+
+	public double evalMove(Player player, GameMove move);
+
+	public List<? extends GameMove> findMoves();
+
+	public int getCurrentPlayer();
+
+	public int getOutcome();
+
+	public void makeMove(GameMove move);
+
+	public void reset();
+
+	public void switchPlayer();
+
+	public Board getBoard();
+}
Index: /java/ecj/games/GameMove.java
===================================================================
--- /java/ecj/games/GameMove.java	(revision 44)
+++ /java/ecj/games/GameMove.java	(revision 44)
@@ -0,0 +1,7 @@
+package games;
+
+public interface GameMove {
+	public int getRow();
+
+	public int getCol();
+}
Index: /java/ecj/games/Player.java
===================================================================
--- /java/ecj/games/Player.java	(revision 44)
+++ /java/ecj/games/Player.java	(revision 44)
@@ -0,0 +1,8 @@
+package games;
+
+public interface Player {
+
+	public double getValue(int row, int col);
+
+	public void setValue(int row, int col, double value); 
+}
Index: /java/ecj/games/league/HeuristicPerformanceMeter.java
===================================================================
--- /java/ecj/games/league/HeuristicPerformanceMeter.java	(revision 44)
+++ /java/ecj/games/league/HeuristicPerformanceMeter.java	(revision 44)
@@ -0,0 +1,63 @@
+package games.league;
+
+import games.Player;
+import games.scenarios.GameScenario;
+import games.scenarios.SimpleTwoPlayersGameScenario;
+
+import java.io.InputStream;
+import java.util.Scanner;
+
+import cecj.app.othello.OthelloBoard;
+import cecj.app.othello.OthelloGame;
+import cecj.app.othello.OthelloPlayer;
+
+
+public class HeuristicPerformanceMeter {
+
+	double[] wpc = { 1.00f, -0.25f, 0.10f, 0.05f, 0.05f, 0.10f, -0.25f, 1.00f, -0.25f, -0.25f,
+			0.01f, 0.01f, 0.01f, 0.01f, -0.25f, -0.25f, 0.10f, 0.01f, 0.05f, 0.02f, 0.02f, 0.05f,
+			0.01f, 0.10f, 0.05f, 0.01f, 0.02f, 0.01f, 0.01f, 0.02f, 0.01f, 0.05f, 0.05f, 0.01f,
+			0.02f, 0.01f, 0.01f, 0.02f, 0.01f, 0.05f, 0.10f, 0.01f, 0.05f, 0.02f, 0.02f, 0.05f,
+			0.01f, 0.10f, -0.25f, -0.25f, 0.01f, 0.01f, 0.01f, 0.01f, -0.25f, -0.25f, 1.00f,
+			-0.25f, 0.10f, 0.05f, 0.05f, 0.10f, -0.25f, 1.00f };
+
+	private OthelloPlayer player;
+
+	public void readPlayer(InputStream input) {
+		Scanner s = new Scanner(input);
+		double[] playerWpc = new double[64];
+		for (int i = 0; i < 64; i++) {
+			playerWpc[i] = s.nextDouble();
+		}
+		player = new OthelloPlayer(playerWpc);
+
+		System.out.println("Player = " + player);
+	}
+
+	private void testPlayer() {
+		OthelloPlayer heuristic = new OthelloPlayer(wpc);
+		GameScenario scenario1 = new SimpleTwoPlayersGameScenario(
+			new Player[] { player, heuristic });
+		GameScenario scenario2 = new SimpleTwoPlayersGameScenario(
+			new Player[] { heuristic, player });
+		OthelloGame game = new OthelloGame(new OthelloBoard());
+
+		game.reset();
+		System.out.println("Playing as black, the result is " + scenario1.play(game));
+		System.out.println(game.getBoard());
+
+		game.reset();
+		System.out.println("Playing as white, the result is " + scenario2.play(game));
+		System.out.println(game.getBoard());
+	}
+
+	/**
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		HeuristicPerformanceMeter hpm = new HeuristicPerformanceMeter();
+		hpm.readPlayer(System.in);
+		hpm.testPlayer();
+	}
+
+}
Index: /java/ecj/games/league/League.java
===================================================================
--- /java/ecj/games/league/League.java	(revision 44)
+++ /java/ecj/games/league/League.java	(revision 44)
@@ -0,0 +1,157 @@
+package games.league;
+
+import ec.simple.SimpleFitness;
+import ec.vector.DoubleVectorIndividual;
+import games.Player;
+import games.scenarios.GameScenario;
+import games.scenarios.SimpleTwoPlayersGameScenario;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import cecj.app.othello.OthelloBoard;
+import cecj.app.othello.OthelloGame;
+import cecj.app.othello.OthelloPlayer;
+
+
+public class League {
+	
+	private List<String> names;
+	private List<List<Player>> teams;
+	
+	private int[] score;
+	private int[] wins;
+	private int[] draws;
+	private int[] losts;
+	
+	private Player bestPlayer;
+	private int bestPlayerScore;
+	private String bestPlayerTeam;
+	
+	public League() {
+		teams = new ArrayList<List<Player>>();
+		names = new ArrayList<String>();
+	}
+	
+	public void play() {
+		score = new int[teams.size()];
+		wins = new int[teams.size()];
+		draws = new int[teams.size()];
+		losts = new int[teams.size()];
+		GameScenario scenario;
+		OthelloGame game = new OthelloGame(new OthelloBoard());
+		
+		bestPlayer = null;
+		bestPlayerTeam = null;
+		bestPlayerScore = 0;
+		
+		for (int team = 0; team < teams.size(); team++) {
+			for (Player player : teams.get(team)) {
+				int playerScore = 0;
+
+				for (int opponentTeam = 0; opponentTeam < teams.size(); opponentTeam++) {
+					if (team == opponentTeam) continue;
+				
+					for (Player opponent : teams.get(opponentTeam)) {
+						scenario = new SimpleTwoPlayersGameScenario(new Player[] { player, opponent });						
+						game.reset();
+						int result = scenario.play(game);
+						score[team] += points(result);
+						playerScore += points(result);
+						if (result > 0) wins[team]++;
+						if (result == 0) draws[team]++;
+						if (result < 0) losts[team]++;
+						
+						scenario = new SimpleTwoPlayersGameScenario(new Player[] { opponent, player });
+						game.reset();
+						result = -scenario.play(game);
+						score[team] += points(result);
+						playerScore += points(result);
+						if (result > 0) wins[team]++;
+						if (result == 0) draws[team]++;
+						if (result < 0) losts[team]++;
+					}
+				}
+				
+				if (playerScore > bestPlayerScore) {
+					bestPlayerScore = playerScore;
+					bestPlayer = player;
+					bestPlayerTeam = names.get(team);
+				}
+			}
+		}
+	}
+
+	private static int points(int result) {
+		if (result > 0) {
+			return 3;
+		} else if (result == 0){
+			return 1;
+		} else {
+			return 0;
+		}
+	}
+
+	public void printTable() {
+		for (int team = 0; team < teams.size(); team++) {
+			System.out.println(names.get(team) + " : " + score[team] + "\t\t wins = " + wins[team] + " draws = " + draws[team] + " losts = " + losts[team]);
+		}
+	}
+	
+	private void addTeam(String name, String filename) {
+		DoubleVectorIndividual ind = new DoubleVectorIndividual();
+		ind.fitness = new SimpleFitness();
+		ind.genome = new double[64];
+				
+		try {
+			List<Player> team = new ArrayList<Player>();
+			LineNumberReader reader = new LineNumberReader(new FileReader(filename));
+			Integer.parseInt(reader.readLine());
+			for (int i = 0; i < 20; i++) {
+				ind.readIndividual(null, reader);
+				team.add(new OthelloPlayer(ind.genome));
+			}
+			teams.add(team);
+			names.add(name);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	private void printBestPlayer() {
+		System.out.println("\n Best player comes from team " + bestPlayerTeam + " and its score = " + bestPlayerScore);
+		
+		double[] wpc = ((OthelloPlayer)bestPlayer).getWPC();
+		for (int i = 0; i < 64; i++) {
+			if (i % 8 == 0) {
+				System.out.println(""); 
+			} else {
+				System.out.print(" "); 
+			}
+			System.out.print(Math.round(wpc[i] * 100) / 100.);
+		}
+	}
+	
+	public static void main(String[] args) {
+		League league = new League();
+		league.addTeam("CEL", "EXP_CEL_best_players");
+		league.addTeam("CEL + HoF", "EXP5v0_best_players");
+		league.addTeam("TDL", "EXP3_best_players");
+		league.addTeam("CEL + TDL", "EXP4_best_players");
+		league.addTeam("CEL + TDL + HoF", "EXP5_best_players");
+		//league.addTeam("CEL + TDL(0) + HoF", "EXP5v0_best_players");
+		//league.addTeam("CEL + TDL(1)(rand) + HoF", "EXP5v1rand_best_players");
+		//league.addTeam("CEL + TDL(2) + HoF", "EXP5v2_best_players");
+		//league.addTeam("CEL + TDL(5) + HoF", "EXP5v5_best_players");
+		//league.addTeam("CEL + TDL(10) + HoF", "EXP5v10_best_players");
+		//league.addTeam("CEL + TDL(50) + HoF", "EXP5v50_best_players");
+		
+		league.play();
+		league.printTable();
+		league.printBestPlayer();
+	}
+
+}
Index: /java/ecj/games/league/RandomPerformanceMeter.java
===================================================================
--- /java/ecj/games/league/RandomPerformanceMeter.java	(revision 44)
+++ /java/ecj/games/league/RandomPerformanceMeter.java	(revision 44)
@@ -0,0 +1,61 @@
+package games.league;
+
+import ec.util.MersenneTwisterFast;
+import games.Player;
+import games.scenarios.GameScenario;
+import games.scenarios.RandomizedTwoPlayersGameScenario;
+
+import java.io.InputStream;
+import java.util.Scanner;
+
+import cecj.app.othello.OthelloBoard;
+import cecj.app.othello.OthelloGame;
+import cecj.app.othello.OthelloPlayer;
+
+
+public class RandomPerformanceMeter {
+
+	private OthelloPlayer player;
+
+
+	public void readPlayer(InputStream input) {
+		Scanner s = new Scanner(input);
+		double[] wpc = new double[64];
+		for (int i = 0; i < 64; i++) {
+			wpc[i] = s.nextDouble();
+		}
+		player = new OthelloPlayer(wpc);	
+		
+		System.out.println("Player = " + player);
+	}
+
+
+	private int testPlayer(int repeats) {
+		MersenneTwisterFast rng = new MersenneTwisterFast(System.currentTimeMillis());
+		
+		GameScenario scenario1 = new RandomizedTwoPlayersGameScenario(rng, new Player[] { player, new OthelloPlayer()}, new double[] {0, 1.0});
+		GameScenario scenario2 = new RandomizedTwoPlayersGameScenario(rng, new Player[] { new OthelloPlayer(), player}, new double[] {1.0, 0});
+		OthelloGame game = new OthelloGame(new OthelloBoard());
+		
+		int sum = 0;
+		for (int i = 0; i < repeats; i++) {
+			game.reset();
+			sum += ((scenario1.play(game) > 0) ? 1 : 0);
+			game.reset();
+			sum += ((scenario2.play(game) < 0) ? 1 : 0);
+		}
+		
+		return sum;
+	}
+	
+	/**
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		RandomPerformanceMeter rpm = new RandomPerformanceMeter();
+		rpm.readPlayer(System.in);
+		System.out.println(rpm.testPlayer(500) + " games won out of 1000");
+	}
+
+	
+}
Index: /java/ecj/games/league/WPCLatexFormatter.java
===================================================================
--- /java/ecj/games/league/WPCLatexFormatter.java	(revision 44)
+++ /java/ecj/games/league/WPCLatexFormatter.java	(revision 44)
@@ -0,0 +1,20 @@
+package games.league;
+
+import java.util.Scanner;
+
+public class WPCLatexFormatter {
+
+	/**
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		Scanner s = new Scanner(System.in);
+		for (int i = 0; i < 64; i++) {
+			if ((i + 1) % 8 == 0) {
+				System.out.println(s.next() + " \\tabularnewline"); 
+			} else {
+				System.out.print(s.next() + " & ");
+			}
+		}	
+	}
+}
Index: /java/ecj/games/league/WPCSequenceVisualizer.java
===================================================================
--- /java/ecj/games/league/WPCSequenceVisualizer.java	(revision 44)
+++ /java/ecj/games/league/WPCSequenceVisualizer.java	(revision 44)
@@ -0,0 +1,86 @@
+package games.league;
+
+import java.awt.Color;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.util.Arrays;
+import java.util.Scanner;
+
+import com.lowagie.text.Document;
+import com.lowagie.text.PageSize;
+import com.lowagie.text.Paragraph;
+import com.lowagie.text.Rectangle;
+import com.lowagie.text.pdf.PdfPCell;
+import com.lowagie.text.pdf.PdfPTable;
+import com.lowagie.text.pdf.PdfWriter;
+
+public class WPCSequenceVisualizer {
+
+	public WPCSequenceVisualizer() {
+		
+	}
+	
+	private PdfPTable createTable(double[] wpc) {
+		System.err.println(Arrays.toString(wpc));
+
+		PdfPTable table = new PdfPTable(8);
+		for (int i = 0; i < 64; i++) {
+			PdfPCell cell = new PdfPCell(new Paragraph(" "));
+			cell.setBorder(Rectangle.NO_BORDER);
+			cell.setPadding(0.4f);
+			if (wpc[i] >= 0) {
+				cell.setBackgroundColor(new Color(0, Math.min(1, (float)wpc[i]), 0));					
+			} else {
+				cell.setBackgroundColor(new Color(Math.min(1, Math.abs((float)wpc[i])), 0, 0));
+			}
+			table.addCell(cell);
+		}
+		
+		return table;
+	}
+	
+	public void visualize(String fileIn, String fileOut, int limit, int frequency) {
+		Document document = new Document(PageSize.A4, 0, 0, 0, 0);
+		document.setMarginMirroring(true);
+
+		try {
+			PdfWriter.getInstance(document, new FileOutputStream(fileOut));
+			document.open();
+			
+			
+			PdfPTable table = new PdfPTable(4);
+			Scanner sc = new Scanner(new FileReader(fileIn));
+			for (int gen = 0; gen <= limit; gen++) {
+				for (int i = 0; i < 8; i++) {
+					sc.next();
+				}
+				
+				double[] wpc = new double[64];
+				for (int i = 0; i < 64; i++) {
+					wpc[i] = sc.nextDouble();
+				}
+				
+				if ((gen % frequency) == 0) {
+					PdfPCell cell = new PdfPCell(createTable(wpc));
+					cell.setBorder(Rectangle.NO_BORDER);
+					cell.setPadding(8.0f);
+					table.addCell(cell);
+				}
+			}
+			
+			table.setComplete(true);
+			table.setWidthPercentage(85);
+			document.add(table);
+			
+		} catch (Exception e) {
+			e.printStackTrace();
+		} 
+		
+		document.close();
+	}
+	
+	public static void main(String[] args) {
+		WPCSequenceVisualizer vis = new WPCSequenceVisualizer();
+		vis.visualize("out.stat", "out.pdf", 840, 30);
+	}
+}
Index: /java/ecj/games/league/WPCVisualizerPDF.java
===================================================================
--- /java/ecj/games/league/WPCVisualizerPDF.java	(revision 44)
+++ /java/ecj/games/league/WPCVisualizerPDF.java	(revision 44)
@@ -0,0 +1,50 @@
+package games.league;
+
+import java.awt.Color;
+import java.io.FileOutputStream;
+import java.util.Scanner;
+
+import com.lowagie.text.Document;
+import com.lowagie.text.PageSize;
+import com.lowagie.text.Paragraph;
+import com.lowagie.text.Rectangle;
+import com.lowagie.text.pdf.PdfPCell;
+import com.lowagie.text.pdf.PdfPTable;
+import com.lowagie.text.pdf.PdfWriter;
+
+public class WPCVisualizerPDF {
+
+	public static void main(String[] args) {
+		Document document = new Document(PageSize.A4);
+
+		try {
+			PdfWriter.getInstance(document, new FileOutputStream("WPC.pdf"));
+			document.open();
+
+			PdfPTable table = new PdfPTable(8);
+			Scanner sc = new Scanner(System.in);
+			double sum = 0;
+			for (int i = 0; i < 64; i++) {
+				float w = (float)sc.nextDouble();
+				sum += w;
+				System.out.println(w);
+				PdfPCell cell = new PdfPCell(new Paragraph(" "));
+				cell.setPadding(20.0f);
+				cell.setBorder(Rectangle.NO_BORDER);
+				if (w >= 0) {
+					cell.setBackgroundColor(new Color(0, Math.min(1, w), 0));					
+				} else {
+					cell.setBackgroundColor(new Color(Math.min(1, Math.abs(w)), 0, 0));
+				}
+
+				table.addCell(cell);
+			}
+			
+			System.err.println(sum / 64);
+			document.add(table);
+		} catch (Exception de) {
+			de.printStackTrace();
+		}
+		document.close();
+	}
+}
Index: /java/ecj/games/scenarios/GameScenario.java
===================================================================
--- /java/ecj/games/scenarios/GameScenario.java	(revision 44)
+++ /java/ecj/games/scenarios/GameScenario.java	(revision 44)
@@ -0,0 +1,7 @@
+package games.scenarios;
+
+import games.BoardGame;
+
+public interface GameScenario {
+	public int play(BoardGame game);
+}
Index: /java/ecj/games/scenarios/RandomizedTwoPlayersGameScenario.java
===================================================================
--- /java/ecj/games/scenarios/RandomizedTwoPlayersGameScenario.java	(revision 44)
+++ /java/ecj/games/scenarios/RandomizedTwoPlayersGameScenario.java	(revision 44)
@@ -0,0 +1,45 @@
+package games.scenarios;
+
+import ec.util.MersenneTwisterFast;
+import games.BoardGame;
+import games.GameMove;
+import games.Player;
+
+import java.util.List;
+
+public class RandomizedTwoPlayersGameScenario implements GameScenario {
+
+	private Player[] players;
+	private double[] prob;
+	private MersenneTwisterFast random;
+	
+	public RandomizedTwoPlayersGameScenario(MersenneTwisterFast random, Player[] players, double[] prob) {
+		this.players = players;
+		this.prob = prob;
+		this.random = random;
+	}
+	
+	public int play(BoardGame game) {
+		while (!game.endOfGame()) {
+			List<? extends GameMove> moves = game.findMoves();
+			if (!moves.isEmpty()) {
+				GameMove bestMove = null;
+				if (random.nextBoolean(prob[game.getCurrentPlayer()])) {
+					bestMove = moves.get(random.nextInt(moves.size()));
+				} else {
+					double bestEval = Double.NEGATIVE_INFINITY;
+					for (GameMove move : moves) {
+						double eval = game.evalMove(players[game.getCurrentPlayer()], move);
+						if (eval > bestEval) {
+							bestEval = eval;
+							bestMove = move;
+						}
+					}
+				}
+				game.makeMove(bestMove);
+			}
+			game.switchPlayer();
+		}
+		return game.getOutcome();
+	}
+}
Index: /java/ecj/games/scenarios/SelfPlayTDLScenario.java
===================================================================
--- /java/ecj/games/scenarios/SelfPlayTDLScenario.java	(revision 44)
+++ /java/ecj/games/scenarios/SelfPlayTDLScenario.java	(revision 44)
@@ -0,0 +1,89 @@
+package games.scenarios;
+
+import ec.util.MersenneTwisterFast;
+import games.Board;
+import games.BoardGame;
+import games.GameMove;
+import games.Player;
+
+import java.util.List;
+
+import cecj.app.othello.OthelloBoard;
+
+
+public class SelfPlayTDLScenario implements GameScenario {
+
+	private double prob;
+	private Player player;
+	private double learningRate;
+	private MersenneTwisterFast random;
+
+	public SelfPlayTDLScenario(MersenneTwisterFast random, Player player, double prob,
+			double learningRate) {
+		this.prob = prob;
+		this.player = player;
+		this.random = random;
+		this.learningRate = learningRate;
+	}
+
+	public int play(BoardGame game) {
+		while (!game.endOfGame()) {
+			List<? extends GameMove> moves = game.findMoves();
+			if (!moves.isEmpty()) {
+				GameMove bestMove = null;
+				if (random.nextBoolean(prob)) {
+					game.makeMove(moves.get(random.nextInt(moves.size())));
+				} else {
+					double bestEval = Float.NEGATIVE_INFINITY;
+					for (GameMove move : moves) {
+						double eval = game.evalMove(player, move);
+						if (eval > bestEval) {
+							bestEval = eval;
+							bestMove = move;
+						}
+					}
+
+					Board previousBoard = game.getBoard().clone();
+					game.makeMove(bestMove);
+					updateEvaluationFunction(previousBoard, game);
+				}
+			}
+			game.switchPlayer();
+		}
+
+		return game.getOutcome();
+	}
+
+	private void updateEvaluationFunction(Board previousBoard, BoardGame game) {
+		double evalBefore = tanh(previousBoard.evaluate(player));
+		double derivative = (1 - (evalBefore * evalBefore));
+		double error;
+
+		if (game.endOfGame()) {
+			int result;
+			if (game.getOutcome() > 0) {
+				result = 1;
+			} else if (game.getOutcome() < 0) {
+				result = -1;
+			} else {
+				result = 0;
+			}
+			error = result - evalBefore;
+		} else {
+			double evalAfter = tanh(game.getBoard().evaluate(player));
+			error = evalAfter - evalBefore;
+		}
+
+		double delta = learningRate * error * derivative;
+		for (int row = 1; row <= OthelloBoard.size(); row++) {
+			for (int col = 1; col <= OthelloBoard.size(); col++) {
+				double w = player.getValue(row, col);
+				player.setValue(row, col, w + (delta * previousBoard.getValueAt(row, col)));
+			}
+		}
+	}
+
+	private static double tanh(double x) {
+		return 2 / (1 + Math.exp(-2 * x)) - 1;
+	}
+}
Index: /java/ecj/games/scenarios/SimpleTwoPlayersGameScenario.java
===================================================================
--- /java/ecj/games/scenarios/SimpleTwoPlayersGameScenario.java	(revision 44)
+++ /java/ecj/games/scenarios/SimpleTwoPlayersGameScenario.java	(revision 44)
@@ -0,0 +1,36 @@
+package games.scenarios;
+
+import games.BoardGame;
+import games.GameMove;
+import games.Player;
+
+import java.util.List;
+
+public class SimpleTwoPlayersGameScenario implements GameScenario {
+
+	private Player[] players;
+
+	public SimpleTwoPlayersGameScenario(Player[] players) {
+		this.players = players;
+	}
+
+	public int play(BoardGame game) {
+		while (!game.endOfGame()) {
+			List<? extends GameMove> moves = game.findMoves();
+			if (!moves.isEmpty()) {
+				GameMove bestMove = null;
+				double bestEval = Double.NEGATIVE_INFINITY;
+				for (GameMove move : moves) {
+					double eval = game.evalMove(players[game.getCurrentPlayer()], move);
+					if (eval > bestEval) {
+						bestEval = eval;
+						bestMove = move;
+					}
+				}
+				game.makeMove(bestMove);
+			}
+			game.switchPlayer();
+		}
+		return game.getOutcome();
+	}
+}
