// Game of Fanorona // David Eppstein, UC Irvine, 11 Jun 1997 // // Maintain structure of a single game // // Search options etc should eventually be stored here as well; // currently a game is just represented by its current position // (which also includes back pointers into the game history). // // Various methods are synchronized because this class is where // the search thread communicates with the rest of the applet. import java.util.*; class AttemptToSetNullBoard extends RuntimeException { } class NoPreviousPosition extends AttemptToSetNullBoard { } // Since notifying all observers might take a while, we do it in a separate thread. class GameUpdateThread extends Thread { Game game; Object object; public GameUpdateThread(Game g, Object o) { game = g; object = o; } public void run() { setPriority(MIN_PRIORITY); game.gameUpdate(object); } } class Game extends Observable { // Bitwise parameters. We don't care what they are, we just store them. // See Options.java for a list of the parameter values BitSet parameters = null; public BitSet getParameters() { return parameters; } public boolean getParameter(int i) { if (parameters == null) return false; else return parameters.get(i); } public void updateParameters() { new GameUpdateThread(this,parameters).start(); } public void setParameters(BitSet p) { parameters = p; updateParameters(); } // callback for GameUpdateThread // since for some reason setChanged() isn't public public void gameUpdate(Object object) { setChanged(); notifyObservers(object); } // Board representing the current position in the game private Board board; public Game() { board = new Board(); } public void updateBoard(Board b) { new GameUpdateThread(this,board).start(); } synchronized public Board getBoard() { return board; } synchronized public void setBoard(Board b) { if (b == null) throw new AttemptToSetNullBoard(); board = b; updateBoard(b); } public void resetBoard() { setBoard(new Board(getParameter(Options.BLACK_AT_TOP), getParameter(Options.WHITE_GOES_FIRST))); } synchronized public void move(Board from, Board to) { if (board == from) setBoard(to); } // Whose turn is it? public boolean humanToMove(Board b) { if (b.whiteToMove()) return getParameter(Options.HUMAN_PLAYS_WHITE); else return getParameter(Options.HUMAN_PLAYS_BLACK); } synchronized public boolean humanToMove() { return humanToMove(board); } // is anything other than a pass available? // here rather than in MoveGenerator because it depends on options public final boolean mustPass(Board b) { if (!b.midCapture()) return false; // near start of game, rules may require pass if (getParameter(Options.NO_MULTIPLE_CAPTURES)) { Board bb = b.previousPosition.previousPosition; if (bb == null) return true; bb = bb.previousPosition; if (bb != null && bb.previousPosition == null) return true; } // run move generator and test whether non-pass move exists MoveGenerator mg = new MoveGenerator(b); return (mg.nextElement() == 0); } }