package de.tu_dresden.inf.ggp06_2.strategies;
import java.util.*;
import de.tu_dresden.inf.ggp06_2.resolver.Predicate;
import de.tu_dresden.inf.ggp06_2.resolver.Const;
import de.tu_dresden.inf.ggp06_2.resolver.Expression;
import de.tu_dresden.inf.ggp06_2.resolver.ExpressionList;
import de.tu_dresden.inf.ggp06_2.resolver.structures.GameNode;
import de.tu_dresden.inf.ggp06_2.resolver.structures.GameState;
import de.tu_dresden.inf.ggp06_2.simulator.Game;
import de.tu_dresden.inf.ggp06_2.simulator.flags.TimerFlag;
public class SinglePlayerSearch extends AbstractStrategy {
private Map<Expression, Long> historyHeuristic;
private int depthTreshold = 4;
private int depthIncrement = 1;
private int availableBoosts = 3;
private boolean someGoalReached;
public int iteration;
public SinglePlayerSearch(Game game, String role){
super(game, role);
historyHeuristic = new HashMap<Expression, Long>();
someGoalReached = false;
}
public SinglePlayerSearch(Game game, String role, TimerFlag flag){
this(game, role);
this.timerFlag = flag;
}
public boolean isSomeGoalReached() {
return someGoalReached;
}
@Override
public Expression pickMove(GameNode node){
return doTheSearch( node );
}
private Expression doTheSearch(GameNode node) {
Expression bestDirectMove;
try {
bestDirectMove = game.getLegalMoves(role, node.getState(), timerFlag).get(0);
} catch (InterruptedException ex) {
return new Predicate(Const.aDoes, role, Const.aNoop);
}
double nodeValue = node.getNodeValue();
for ( GameNode aNode : game.stateTree.getChildren(node) )
if ( aNode.getNodeValue() == nodeValue ) {
bestDirectMove = aNode.getMoves().get( 0 );
break;
}
int incr = 1;
nodeValue = 0.0;
try {
while ( !(nodeValue == 1.0) ) {
nodeValue = doSearchIteration( node, incr * depthIncrement );
List<GameNode> nodeList = game.stateTree.getChildren(node);
for ( GameNode aNode : nodeList )
if ( node.getNodeValue() == aNode.getNodeValue() ) {
bestDirectMove = aNode.getMoves().get( 0 );
break;
}
incr++;
}
} catch (InterruptedException ex) {
return bestDirectMove;
}
for ( GameNode aNode : game.stateTree.getChildren(node) )
if ( aNode.getNodeValue() == nodeValue ) {
bestDirectMove = aNode.getMoves().get(0);
break;
}
return bestDirectMove;
}
private double doSearchIteration( GameNode node, int depth )
throws InterruptedException {
iteration++;
if ( node.getNodeValue() == 1.0 )
return 1.0;
double value = 0.0;
if ( node.getState().isTerminal() ) {
value = heuristicValue(node);
storeNodeValue(node, depth, value);
} else if ( wasPriorVisited(node) ) {
value = priorValue(node);
} else if (0 == depth) {
value = heuristicValue(node);
storeNodeValue(node, depth, value);
} else {
Set<Expression> moves = new HashSet<Expression>();
ExpressionList legalMoves = game.getLegalMoves( role, node.getState(), timerFlag);
for (Expression exp : legalMoves)
moves.add( exp );
value = processAvailableMoves( node, depth, moves, legalMoves );
storeNodeValue(node, depth, value);
}
return value;
}
private double priorValue(GameNode node) {
List<GameNode> nodes = game.stateTree.gsHash2Nodes.get( node.getState().hashCode() );
int nodeDepth = node.getSearchDepth();
for (GameNode aNode : nodes)
if ( aNode.getSearchDepth() > nodeDepth )
return aNode.getNodeValue();
return node.getNodeValue();
}
private void storeNodeValue(GameNode node, int depth, double value) {
node.setSearchDepth( depth );
node.setNodeValue( value );
}
private boolean wasPriorVisited(GameNode node) {
List<GameNode> nodes = game.stateTree.gsHash2Nodes.get( node.getState().hashCode() );
int nodeDepth = node.getSearchDepth();
for (GameNode aNode : nodes)
if ( aNode.getSearchDepth() > nodeDepth )
return true;
return false;
}
private double processAvailableMoves( GameNode node,
int depth,
Set<Expression> moves,
ExpressionList legalMoves )
throws InterruptedException {
double tmpValue, currentBest = -1;
Expression currentBestMove = legalMoves.get(0);
int childOrder = moves.size();
while( !moves.isEmpty() ) {
Expression aMove = extractMoveAccordingToHH(moves);
GameNode nextNode = game.produceNextNode( node,
new ExpressionList(aMove),
timerFlag );
boolean boostingPerformed = false;
if ( depth == 1 &&
node.getDepth() > depthTreshold &&
availableBoosts > 0 ) {
depth = childOrder * depthIncrement;
availableBoosts--;
boostingPerformed = true;
}
tmpValue = doSearchIteration( nextNode, depth-1 );
if ( boostingPerformed )
availableBoosts++;
if ( tmpValue > currentBest ){
currentBest = tmpValue;
currentBestMove = aMove;
}
if ( 1.0 == currentBest )
break;
childOrder--;
}
updateHistoryHeuristic( currentBestMove,
node.getDepth() - game.stateTree.getRootNode().getDepth() );
return currentBest;
}
private Expression extractMoveAccordingToHH(Set<Expression> moves) {
Iterator<Expression> iter = moves.iterator();
Expression extractedMove = iter.next();
long hhValueOfExtractedMove = historyHeuristic.containsKey(extractedMove) ?
historyHeuristic.get(extractedMove) :
0;
while ( iter.hasNext() ) {
Expression iteratedMove = iter.next();
if ( historyHeuristic.containsKey(iteratedMove) ) {
long hhValueOfIteratedMove = historyHeuristic.get(iteratedMove);
if ( hhValueOfExtractedMove < hhValueOfIteratedMove ) {
extractedMove = iteratedMove;
hhValueOfExtractedMove = hhValueOfIteratedMove;
}
}
}
moves.remove(extractedMove);
return extractedMove;
}
private void updateHistoryHeuristic( Expression currentBestMove,
int importance ) {
long increment = Math.round( Math.pow( importance, 2 ) );
long i = historyHeuristic.containsKey(currentBestMove) ?
historyHeuristic.get(currentBestMove) :
0;
historyHeuristic.put(currentBestMove, i + increment);
}
/**
* This method returns a neuristic value for the game node.
* @param node
* @return Returns an int value from the interval [0.0, 1.0].
*/
private final double heuristicValue(GameNode node) {
GameState state = node.getState();
if ( !state.isRoleGoalValue(role) )
return 0.0;
someGoalReached = true;
return state.isTerminal() ? state.getRoleGoalValue(role) / 100.0 :
(state.getRoleGoalValue(role) - 1.0) / 100.0;
}
}