package net.woodyfolsom.msproj.policy;

import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;

public abstract class MonteCarlo implements Policy {
	protected Policy movePolicy;
	protected long searchTimeLimit;
	
	public MonteCarlo(Policy movePolicy, long searchTimeLimit) {
		this.movePolicy = movePolicy;
		this.searchTimeLimit = searchTimeLimit;
	}
	
	public abstract MonteCarloTreeNode descend(MonteCarloTreeNode node);
	
	@Override
	public String getAction(GameConfig gameConfig, GameState gameState,
			String initialColor) {
		long initialTime = System.currentTimeMillis();
		
		//If for some reason no moves are evaluated within the time limit, pass.
		//Note that this may lose the game by forfeit even when picking any random move could
		//result in a win.
		
		String bestMove = Policy.PASS;
		
		MonteCarloTreeNode rootNode = new MonteCarloTreeNode(gameConfig, gameState, initialColor);
		MonteCarloTreeNode selectedNode;
		while (System.currentTimeMillis() - initialTime < searchTimeLimit) {
			//TODO these return types may need to be lists for some MC methods
			selectedNode = descend(rootNode);	
			selectedNode = grow(selectedNode);
			int reward = rollout(selectedNode);
			update(selectedNode, reward);
		}
		
		return bestMove;
	}
	
	public abstract MonteCarloTreeNode grow(MonteCarloTreeNode node);
	
	public abstract int rollout(MonteCarloTreeNode node);
	
	public abstract void update(MonteCarloTreeNode node, int reward);
	
	static String getColorToPlay(String color, boolean playAsOpponent) {
		if (playAsOpponent) {
			if ("w".equals(color)) {
				return "b";
			} else if ("b".equals(color)) {
				return "w";
			} else {
				return "?"; // invalid color will cause randomMoveGenerator to
							// PASS
			}
		} else {
			return color;
		}
	}
}