package pdp.scrabble.ia.impl;
import pdp.scrabble.dictionary.DAWGItf;
import pdp.scrabble.game.Bag;
import pdp.scrabble.game.Board;
import pdp.scrabble.game.Location;
import pdp.scrabble.game.impl.LocationImpl;
import pdp.scrabble.ia.AIBoardModel;
import pdp.scrabble.ia.CrossCheckSet;
import pdp.scrabble.ia.Direction;
import pdp.scrabble.utility.CrossCheck;
/** CrossCheckSet based on a DAWG dictionary.
* It allows to make algorithms faster
* @author alexandre
*
*/
public class DawgCrossCheckSet implements CrossCheckSet {
private DAWGItf dawg;
private AIBoardModel model;
private CrossCheck[][] crossChecks = new CrossCheck[Board.HORI_DIM][Board.VERT_DIM];
public DawgCrossCheckSet(DAWGItf graph, AIBoardModel model) {
this.dawg = graph;
this.model = model;
for (int i=0 ; i<Board.VERT_DIM ; i++)
for (int j=0 ; j<Board.HORI_DIM ; j++)
crossChecks[i][j] = new CrossCheck();
}
private Location beginingOfWord(Location square, Direction dir) {
Location prev = dir.applyReverseTo(square.clone());
if (!model.contains(prev) || model.isFree(prev))
return square;
else
return beginingOfWord(prev, dir);
}
private void computeSquareForLetter(Location currentSquare, Direction dir, int currentNode, char letter) {
int firstX=currentSquare.getV(), firstY=currentSquare.getH(); // save first square coords
int child = dawg.getChild(currentNode, letter);
if (child == -1) {
crossChecks[firstX][firstY].set(letter, false);
return;
}
else {
dir.applyTo(currentSquare);
while (model.contains(currentSquare)
&& !model.isFree(currentSquare)) {
child = dawg.getChild(child, model.getCharAt(currentSquare));
if (child == -1) {
crossChecks[firstX][firstY].set(letter, false);
return;
}
else {
dir.applyTo(currentSquare);
}
} // here, we are at end of word
crossChecks[firstX][firstY].set(letter, dawg.isTerminal(child));
}
}
private void computeCrossCheckForSquare(Location square, Direction dir) {
int i = square.getV();
int j = square.getH();
if(!model.isFree(square)) {
crossChecks[i][j].clear();
crossChecks[i][j].set(model.getCharAt(square), true);
return;
}
//non-anchor squares have no adjacency, thus complete crossChecks
if (!model.hasNeighbours(square.clone(), dir)) {
crossChecks[i][j].fill();
return;
}
// to compute for anchor square, we need to get back to the beggining of the word
// and check for each letter if it forms a valid word
else {
Location currentSquare = beginingOfWord(square, dir);
int currentNode = dawg.getRoot();
while (!model.isFree(currentSquare)) {
currentNode = dawg.getChild(currentNode, model.getCharAt(currentSquare));
dir.applyTo(currentSquare);
}
for (Character c : Bag.AVAILABLE_LETTERS) {
computeSquareForLetter(currentSquare.clone(), dir, currentNode, c);
}
}
}
// TODO complete ths function to compute only new squares
// public void update(AIBoardModel newModel) {
// List
// for (int i=0 ; i<Board.HORI_DIM ; i++)
// for (int j=0 ; j<Board.VERT_DIM ; j++) {
// if (!this.model.isAnchorSquare(i, j) && newModel.isAnchorSquare(i, j)) {
//
// }
// }
// }
public void compute(Direction dir) {
for (int i=0 ; i<Board.VERT_DIM ; i++)
for (int j=0 ; j<Board.HORI_DIM ; j++) {
computeCrossCheckForSquare(new LocationImpl(i, j), dir);
}
}
@Override
public CrossCheck get(int x, int y) {
return crossChecks[x][y];
}
@Override
public CrossCheck get(Location loc) {
return get(loc.getV(), loc.getH());
}
}