package pdp.scrabble.ia.impl;
import java.util.ArrayList;
import java.util.Arrays;
import com.sun.tools.javac.util.List;
import pdp.scrabble.game.BoardCase;
import pdp.scrabble.game.GameEnvironment;
import pdp.scrabble.game.Letter;
import pdp.scrabble.game.Location;
import pdp.scrabble.ia.AbstractAlgoStep;
import pdp.scrabble.ia.AbstractEvalStep;
import pdp.scrabble.ia.Direction;
import pdp.scrabble.ia.MoveModel;
public class EvaluatorImpl extends AbstractEvalStep
{
private static final char VOWELS[] = {'a', 'e', 'i', 'o', 'u', 'y'};
private static final Character hard[] = {'h', 'k', 'q', 'w', 'x', 'y', 'z'};
private static final java.util.List<Character> HARD_LETTERS = Arrays.asList(hard);
private static final double MAX_ALLOWED_PROBABILITY = 0.08;
private static final int MAX_ALLOWED_DUPLICATE = 1;
private static final int BEST_VOWEL_AMOUNT = 3;
private static final int MIN_PENALITY = 2;
private static final int MAX_PENALITY = 5;
private GameEnvironment gameEnv = null;
public EvaluatorImpl(GameEnvironment gameEnv, AbstractAlgoStep previous)
{
super(gameEnv, null, previous);
this.gameEnv = gameEnv;
}
//Returns whether the letter is a vowel or not.
private boolean isVowel(char c)
{
for (int i = 0; i < VOWELS.length; i++)
if (c == VOWELS[i]) return true;
return false;
}
//Points the word would give if the move was played.
private int computeTheoricalWordPoints(Direction direction, Location loc, String word)
{
boolean isVer = direction == Direction.DOWN;
int wordPoints = 0;
int wordMult = 1;
int letterPoints = 0;
int letterMult = 1;
char c = '0';
for (int i = 0; i < word.length(); i++)
{
//Get next board case depending on the direction.
BoardCase nextBoardCase = this.gameEnv.board().getCase(
(isVer) ? loc.getV() + i : loc.getV(),
(isVer) ? loc.getH() : loc.getH() + i);
wordMult *= Math.max(nextBoardCase.getWordMult(), 1);
c = word.charAt(i);
letterPoints = (c == Bag.JOKER)? 0 : this.gameEnv.bag().getLetterValue(c+"");
if (!nextBoardCase.getMultUsed()) letterMult = Math.max(nextBoardCase.getLetterMult(), 1);
wordPoints += letterPoints * letterMult;
letterMult = 1;
}
return wordMult * wordPoints;
}
//Points regarding the weighting of the remaining letters on the rack.
private int computeRackLeaveValue(MoveModel move)
{
String rackLeave = move.getRackLeave();
String word = move.getWord();
int rackPoints = 5 * word.length();
char c = '0';
float probability = 0;
//Rack relative value.
int rackLetters[] = new int[26];
int vowelAmount = 0;
for (int i = 0; i < rackLeave.length(); i++)
{
c = Character.toLowerCase(rackLeave.charAt(i));
if (c == Bag.JOKER)
continue;
if (++rackLetters[c - 'a'] > MAX_ALLOWED_DUPLICATE)
rackPoints -= MIN_PENALITY;
if (isVowel(c))
if (++vowelAmount > BEST_VOWEL_AMOUNT)
rackPoints -= MIN_PENALITY;
if (c == 'q')
if (move.getWord().contains('u'+""))
if (!rackLeave.contains('u'+"") && !rackLeave.contains(Bag.JOKER + ""))
rackPoints -= MAX_PENALITY;
probability = (gameEnv.bag().getRemainingLettersNumber() == 0) ? 0 :
(gameEnv.bag().getOriginalNumberOf(c) - gameEnv.board().countLetter(c)
- rackLetters[c - 'a']) / (gameEnv.bag().getRemainingLettersNumber());
if (probability > MAX_ALLOWED_PROBABILITY)
rackPoints -= MIN_PENALITY;
}
//Played word relative value.
for (int i = 0; i < word.length(); i++)
{
c = Character.toLowerCase(word.charAt(i));
if (c == Bag.JOKER)
continue;
if (HARD_LETTERS.contains(c))
rackPoints += MAX_PENALITY;
probability = (gameEnv.bag().getRemainingLettersNumber() == 0) ? 0 :
(gameEnv.bag().getOriginalNumberOf(c) - gameEnv.board().countLetter(c)
- rackLetters[c - 'a']) / (gameEnv.bag().getRemainingLettersNumber());
if (probability > MAX_ALLOWED_PROBABILITY)
rackPoints += MIN_PENALITY;
}
return rackPoints;
}
public int evaluate(MoveModel move)
{
return this.computeTheoricalWordPoints(move.getDirection(), move.getLocation(), move.getWord())
+ this.computeRackLeaveValue(move);
}
}