/**
* Title: Pancet<p>
*
* Description: The move library for Pancet, a game applet. This
* stores tried moves in the form of a move tree. It's responsible
* for the storage, history, and access to moves. It also creates
* new moves when faced with new situations.<p>
*
* Copyright: Copyright (c) 2005<p>
*
* @author Mark Bondurant
* @version 3.0
*/
import java.util.HashMap;
import java.util.Random;
class MoveLib implements GameConstants {
private Hashtable lib = new Hashtable();
private Random ran = new Random();
/**
* Parent is our linkage back to the previous move. The
* value of the last move made will be added to the next
* in order to chain them together. This is used later
* when we have to purge branches of the tree that have
* proven themselves to be unuseful.
*/
private int parent[] = {0, 0, 0, 0};
/**
* To ease some of the painful process of learning, we load
* the library with some of the more obvious moves.
*/
MoveLib() {
// add some basic smarts
lib.put(Move.key(new int[] {7, 1, 0, 0}), new Move(MOVE_ROOT, BOWL_B, true));
lib.put(Move.key(new int[] {6, 1, 0, 0}), new Move(MOVE_ROOT, BOWL_B, true));
lib.put(Move.key(new int[] {5, 1, 0, 0}), new Move(MOVE_ROOT, BOWL_B, true));
lib.put(Move.key(new int[] {4, 1, 0, 0}), new Move(MOVE_ROOT, BOWL_B, true));
lib.put(Move.key(new int[] {3, 1, 0, 0}), new Move(MOVE_ROOT, BOWL_B, true));
lib.put(Move.key(new int[] {2, 1, 0, 0}), new Move(MOVE_ROOT, BOWL_B, true));
lib.put(Move.key(new int[] {1, 1, 0, 0}), new Move(MOVE_ROOT, BOWL_B, true));
lib.put(Move.key(new int[] {2, 7, 0, 0}), new Move(MOVE_ROOT, BOWL_A, true));
lib.put(Move.key(new int[] {2, 6, 0, 0}), new Move(MOVE_ROOT, BOWL_A, true));
lib.put(Move.key(new int[] {2, 5, 0, 0}), new Move(MOVE_ROOT, BOWL_A, true));
lib.put(Move.key(new int[] {2, 4, 0, 0}), new Move(MOVE_ROOT, BOWL_A, true));
lib.put(Move.key(new int[] {2, 3, 0, 0}), new Move(MOVE_ROOT, BOWL_A, true));
lib.put(Move.key(new int[] {2, 2, 0, 0}), new Move(MOVE_ROOT, BOWL_A, true));
lib.put(Move.key(new int[] {1, 2, 0, 0}), new Move(MOVE_ROOT, BOWL_A, true));
lib.put(Move.key(new int[] {1, 3, 0, 0}), new Move(MOVE_ROOT, BOWL_A, true));
lib.put(Move.key(new int[] {1, 4, 0, 0}), new Move(MOVE_ROOT, BOWL_A, true));
lib.put(Move.key(new int[] {1, 5, 0, 0}), new Move(MOVE_ROOT, BOWL_A, true));
lib.put(Move.key(new int[] {1, 6, 0, 0}), new Move(MOVE_ROOT, BOWL_A, true));
lib.put(Move.key(new int[] {1, 7, 0, 0}), new Move(MOVE_ROOT, BOWL_A, true));
}
/**
* This returns the stored move count, which is displayed on
* the game board. In this way the user can see the move tree
* grow as moves are made, and shrink when the tree is pruned
* back.
*/
int storedMoves() {
return lib.size();
}
/**
* This has proven useful in debugging and thus, has been left in.
*/
public String toString() {
return "MoveLib has " + this.storedMoves() + " moves stored";
}
void resetParent() {
for (int i=0; i<4; i++) parent[i] = 0;
}
/**
* getMove attempts to look up a move in the library, based on the
* current state of the board. If none is found, a new random move is
* created, added to the library, and returned as if a move was found.
*/
int getMove(int[] board) {
String key = Move.key(board); // create a key for lookup
Move m = (Move) lib.get(key); // attempt to lookup move
// if there is no move in library, create one
if (m == null) {
if (board[BOWL_A] == 0) // the cases where we only
m = new Move(parent, BOWL_B, true); // have one choice
else {
if (board[BOWL_B] == 0)
m = new Move(parent, BOWL_A, true);
else
// create a random move
m = new Move(parent, BOWL_A + (int) (ran.nextFloat() * 2));
}
// save the move
lib.put(Move.key(board), m);
}
// store this board so it can be linked to the next
for(int i=0; i<4; i++) parent[i] = board[i];
return m.move();
}
/**
* lostGame trims back the move tree to the last guess made. We flip it
* to force exploration of the untried branch.
*/
void lostGame() {
String parentKey;
String key = Move.key(parent);
// purge tried losing moves
Move m = (Move) lib.get(key);
while (m.flipped() && m.parent_key() != "0000") {
parentKey = m.parent_key();
lib.remove(key);
key = parentKey;
m = (Move) lib.get(key);
}
// store flipped move
lib.remove(key);
m.flip();
lib.put(key, m);
// reset parent for the next game
resetParent();
}
}