package de.tu_dresden.inf.ggp06_2.strategies;
import java.util.Map;
import org.apache.log4j.Logger;
import de.tu_dresden.inf.ggp06_2.resolver.Atom;
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.Predicate;
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;
/**
* The Novelty class - inherits AbstractStrategy and implements
* pickMove() method by selecting the move which leads to a game
* state that differs the most form the current game state. The
* difference is computed by the countTheChangedFluents() method
* as the total number of fluents that are true in one state but
* not in the other.
* In the case of multiple moves with the same novelty ratio,
* pickMove() chooses the first move.
* The move is not considered if it leads to a game state that
* has been encountered before.
*
* TODO: Reconsider if all fluents should be counted as equal,
* perhaps some weights on fluents might be introduced...
*
* Reconsider if the repeated game states should be
* considered. If not, uncomment the line 69.
*
* Should pickMove() return multiple moves in the case of the
* same novelty ratio?
*
* @author Novak Novakovic
*
*/
public class Novelty extends AbstractStrategy {
private static final Logger logger = Logger.getLogger(Novelty.class);
public Novelty(Game game, String role){
super(game,role);
}
@Override
public Expression pickMove(GameNode node) {
ExpressionList legalMoves;
try {
legalMoves = game.getLegalMoves(
this.role, node.getState(), timerFlag);
}
catch ( InterruptedException e1 ) {
return new Predicate(Const.aDoes, role, Const.aNoop);
}
Expression pickedMove = null;
if (!legalMoves.isEmpty()){
if (logger.isTraceEnabled()){
logger.trace( "available moves: "+legalMoves );
}
Expression bestMove = legalMoves.get( 0 );
int noveltyRate = -1;
for (Expression aMove: legalMoves){
if (logger.isTraceEnabled()){
logger.trace( "processing move: "+aMove );
}
ExpressionList movesList = new ExpressionList(aMove);
GameNode nextNode = null;
try {
nextNode = game.produceNextNode( node, movesList, this.timerFlag );
}
catch ( InterruptedException e ) {
return bestMove;
}
if (logger.isTraceEnabled()){
logger.trace( "nextState: "+ nextNode.getState() );
}
/*if (this.stateTree.wasPlayed(nextState.hashCode())){
noveltyRate = 0;
continue;
} */
int tmp = countTheChangedFluents(node.getState(), nextNode.getState());
if (-1 == noveltyRate ||
tmp > noveltyRate) {
bestMove = aMove;
noveltyRate = tmp;
}
}
if (logger.isTraceEnabled()){
logger.trace( " dicided for: "+bestMove );
}
pickedMove = bestMove;
}
if (null == pickedMove){
return new Predicate(Const.aDoes, role, Const.aNoop);
}
return pickedMove;
}
private int countTheChangedFluents(GameState oldState, GameState newState){
int counter = 0;
Map<Atom, ExpressionList> oldFluents = oldState;
Map<Atom, ExpressionList> newFluents = newState;
for (Atom oldAtom : oldFluents.keySet()){
for (ExpressionList oldExpressionList : oldFluents.values())
for (Expression oldExpression : oldExpressionList)
if (!newFluents.get( oldAtom ).contains( oldExpression ))
counter++;
}
for (ExpressionList newAtom : newFluents.values()){
for (ExpressionList newExpressionList : newFluents.values())
for (Expression newExpression : newExpressionList)
if (!newAtom.contains( newExpression ))
counter++;
}
return counter;
}
}