Package pdp.scrabble.ia.impl

Source Code of pdp.scrabble.ia.impl.DawgMoveGen

package pdp.scrabble.ia.impl;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import pdp.scrabble.dictionary.DAWGItf;
import pdp.scrabble.game.Bag;
import pdp.scrabble.game.Board;
import pdp.scrabble.game.GameEnvironment;
import pdp.scrabble.game.Letter;
import pdp.scrabble.game.Location;
import pdp.scrabble.game.Player;
import pdp.scrabble.game.Rack;
import pdp.scrabble.game.impl.LocationImpl;
import pdp.scrabble.ia.AIBoardModel;
import pdp.scrabble.ia.AbstractMoveGenStep;
import pdp.scrabble.ia.CrossCheckSet;
import pdp.scrabble.ia.Direction;
import pdp.scrabble.ia.MoveAccumulator;

/** Class generating moves using a DAWG (Directed Acyclic Word Graph)
* Across moves are generated first, followed by down moves.
* When encountering a Joker, it puts a lowercase in the word instead of a regular uppercase */
public class DawgMoveGen extends AbstractMoveGenStep {

    private DAWGItf dawg;
    private AIBoardModel model;
    private CrossCheckSet[] allowedLetters = new CrossCheckSet[2];

    /** main constructor
     * @param graph the DAWG reference
     * @param storage a move accumulator to store legal moves
     *  */
    public DawgMoveGen(GameEnvironment env, Player p, DAWGItf graph, MoveAccumulator storage) {
  super(env, p, storage);
  this.dawg = graph;
  storage.setTarget(this.moves);
  this.model = new AIBoardModel(env.board());
  this.allowedLetters[0] = new DawgCrossCheckSet(dawg, model);
  this.allowedLetters[1] = new DawgCrossCheckSet(dawg, model);
    }

    private Set<Character> getCharsSet(Rack letters) {
  Set<Character> set = new HashSet<Character>();
  for (Letter l : letters)
      set.add(new Character(l.getName()));
  return set;
    }

    private Set<Letter> getLettersSet(Rack letters) {
  Set<Letter> set = new CopyOnWriteArraySet<Letter>();
  for (Letter l : letters)
      set.add(l);
  return set;
    }

    @Override
    public void generate(Board board, Rack letters) {
  model.update(board);
  allowedLetters[Direction.ACROSS.ordinal()].compute(Direction.DOWN);
  allowedLetters[Direction.DOWN.ordinal()].compute(Direction.ACROSS);

  if (model.isFree(Board.HORI_DIM/2, Board.VERT_DIM/2)) { // cas du premier coup : le centre est vide et doit etre couvert par le coup
      Location start = new LocationImpl(Board.HORI_DIM/2, Board.VERT_DIM/2);
      generateForSquare(Direction.ACROSS, start, model, letters);
      generateForSquare(Direction.DOWN, start, model, letters);
  }
  else {
      generate(Direction.ACROSS,letters);
      generate(Direction.DOWN, letters);
  }
    }

    private void generate(Direction dir, Rack letters) {
  //allowedLetters[dir.ordinal()].compute(dir.equals(Direction.ACROSS) ? Direction.DOWN : Direction.ACROSS);
  for (int i=0 ; i<Board.VERT_DIM ; i++)
      generateForRow(dir, i, model, letters);
    }

    private void generateForRow(Direction dir, int row, AIBoardModel board, Rack letters) {
  Location square = (dir.equals(Direction.ACROSS) ? new LocationImpl(row, 0) : new LocationImpl(0, row));
  while (board.contains(square)) {
      if(board.isAnchorSquare(square.getV(), square.getH()))
    generateForSquare(dir, square, board, letters);
      dir.applyTo(square);
  }
    }

    private void generateForSquare(Direction dir, Location square, AIBoardModel board, Rack letters) {
  Location prev = dir.applyReverseTo(square.clone());
  if (board.contains(prev) &&
    !board.isFree(prev)) {
      // must compute prefix word and find corresponding node in dawg
      StringBuilder str = new StringBuilder();
      int node = dawg.getRoot();
      Location prefix = dir.applyReverseTo(square.clone());
      while (board.contains(prefix) && !board.isFree(prefix)) {
    str.append(board.getCharAt(prefix));
    dir.applyReverseTo(prefix);
      }
      str.reverse();
      for (int i=0 ; i<str.length() && node!=-1 ; i++)
    node = dawg.getChild(node, str.charAt(i));
      if (node!=-1)
    extendRight(dir, board, letters, square, str, node, true);
  }
  else {
      int limit = getLeftPartMaxLength(board, square.clone(), dir);
      leftPart(dir, board, letters, square, new StringBuilder(), dawg.getRoot(), limit);
  }
    }

    private void leftPart(Direction dir, AIBoardModel board, Rack letters,
      Location square, StringBuilder partialWord, int node, int limit) {
  extendRight(dir, board, letters, square, partialWord, node, true);
  if (limit > 0)
  {
      int child=0;
      for (Letter l : getLettersSet(letters)) {
    char c=l.getName();
    if (c == Bag.JOKER) {
        for (int i=0 ; i<Bag.AVAILABLE_LETTERS.length ; i++) {
      char joker = Bag.AVAILABLE_LETTERS[i];
      if ((child=dawg.getChild(node, joker))!=-1) {
          Letter tmp = removeFromRack(letters, c);
          leftPart(dir, board, letters, square,
            partialWord.append(Character.toLowerCase(joker)),
            child, limit-1);
          partialWord.deleteCharAt(partialWord.length()-1);
          letters.addLetter(tmp);
      }
        }
    }
    else if (c!=Bag.JOKER && (child=dawg.getChild(node, c)) != -1) // the letter labels an edge out of node
    {
        Letter tmp = letters.removeLetter(l);
        leftPart(dir, board, letters, square, partialWord.append(c), child, limit-1);
        partialWord.deleteCharAt(partialWord.length()-1);
        letters.addLetter(tmp);
    }
      }
  }
    }

    private Letter removeFromRack(Rack letters, char c) {
  for (int i=0 ; i<letters.getNumberOfLetters() ; i++)
      if (letters.getLetter(i).getName() == c) {
    Letter tmp = letters.getLetter(i);
    letters.removeLetter(tmp);
    return tmp;
      }
  return null;
    }

    private void extendRight(Direction dir, AIBoardModel board,
      Rack letters, Location square,
      StringBuilder partialWord, int node, boolean firstCall) {
  if (!board.contains(square)) {
      if (!firstCall && dawg.isTerminal(node)) {
    registerMove(partialWord.toString(),
      beginingOfWord(square.clone(), dir, partialWord.toString()),
      dir, letters);
      }
      return;
  }
  if (board.isFree(square.getV(), square.getH())) {
      if (!firstCall && dawg.isTerminal(node)) {
    registerMove(partialWord.toString(),
      beginingOfWord(square.clone(), dir, partialWord.toString()),
      dir, letters);
      }
      int child;

      for (Letter l : getLettersSet(letters)) {
    char c = l.getName();
    if (c == Bag.JOKER) {
        for (int i=0 ; i<Bag.AVAILABLE_LETTERS.length ; i++) {
      char joker = Bag.AVAILABLE_LETTERS[i];
      if ((child=dawg.getChild(node, joker))!=-1 &&
        allowedLetters[dir.ordinal()].get(square).isAllowed(joker)) {
          Letter tmp = removeFromRack(letters, c);
          extendRight(dir, board, letters, dir.applyTo(square),
            partialWord.append(Character.toLowerCase(joker)),
            child, false);
          dir.applyReverseTo(square);
          partialWord.deleteCharAt(partialWord.length()-1);
          letters.addLetter(tmp);
      }
        }
    }
    if (c!=Bag.JOKER
      &&((child = dawg.getChild(node, c)) != -1)
      && allowedLetters[dir.ordinal()].get(square).isAllowed(c)) {
        Letter tmp = letters.removeLetter(l);
        extendRight(dir, board, letters, dir.applyTo(square),
          partialWord.append(c), child, false);
        dir.applyReverseTo(square);
        partialWord.deleteCharAt(partialWord.length() - 1);
        letters.addLetter(tmp);
    }
      }

  }
  else {
      char c = board.getCharAt(square);
      int child = dawg.getChild(node, c);
      if (child != -1) {
    extendRight(dir, board, letters, dir.applyTo(square), partialWord.append(c), child, false);
    dir.applyReverseTo(square);
    partialWord.deleteCharAt(partialWord.length()-1);
      }
  }
    }

    private Location beginingOfWord(Location end, Direction dir, String word) {
  for (int i=0 ; i<word.length() ; i++)
      dir.applyReverseTo(end);
  return end;
    }

    private void registerMove(String word, Location first, Direction dir, Rack leave) {
  StringBuilder build = new StringBuilder();
  for (Letter l : leave)
      build.append(l.getName());
  registerMove(new ClassicMoveModel(word, first, dir, build.toString()));
    }

    private int getLeftPartMaxLength(AIBoardModel board, Location square, Direction dir) {
  Location prev = dir.applyReverseTo(square.clone());
  if (!board.contains(prev) ||
    model.isAnchorSquare(prev.getV(), prev.getH())) return 0;
  return getLeftPartMaxLength(board, prev, dir)+1;
    }

}
TOP

Related Classes of pdp.scrabble.ia.impl.DawgMoveGen

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.