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));
		}
	}

}
