//GameMaster.java /** * * @author Sean Bridges * @version 1.0.1 * * The game master controls the state of the game, and is responsible for * making the players move in sequence. * * If a subclass overrides start, restart or stop, it should call super.start, * restart or stop respectively. * * Whenever start or restart are called a new thread is created which * asks the players for their moves in sequence. * If there was an old thread, the old thread will be interrupted, and discarded. */ import java.util.*; public class GameMaster { //-------------------------------------------------------- //instance variables private Vector listeners = new Vector(); //listeners to the state, //use a vector for jdk1.0 compatability private Player[] players; //the players of the game private Board board; private int currentPlayerIndex = 0; private GameThread gameThread; //-------------------------------------------------------- //constructor /** * Creates new GameMaster. * The PlayerArray should have at least 1 player in it. * The order the players occur in the array is the order in which the * players will move. * If the array is empty, an ArrayOutOfBoundsException will be thrown. */ public GameMaster(Board board, Player[] players ) { if(players.length == 0) { System.err.println("Error, player array is empty, GameMaster() "); throw new ArrayIndexOutOfBoundsException("Game Master created with empty array"); } this.board = board; this.players = players; } //-------------------------------------------------------- //instance methods //------------------------------------------------------ //listeners /** * Add a game event listener. */ public synchronized void addListener(GameEventListener l) { listeners.addElement(l); } public synchronized void removeListener(GameEventListener l) { listeners.removeElement(l); } /** * Clone the listener vector in case the list of listeners * is modified while informing the listeners. * This means the enumeration enumerates a copy of the list, * and additions can be made to the list while informing listeners. */ private synchronized Enumeration enumerateListeners() { return ((Vector) listeners.clone() ).elements(); } private void notifyListenersMoveMade(Move aMove) { Enumeration e = enumerateListeners(); while(e.hasMoreElements()) { ((GameEventListener) e.nextElement()).moveMade(aMove); } } private void notifyListenersGameReStarted() { Enumeration e = enumerateListeners(); while(e.hasMoreElements()) { ((GameEventListener) e.nextElement()).gameRestarted(); } } private void notifyListenersGameStarted() { Enumeration e = enumerateListeners(); while(e.hasMoreElements()) { ((GameEventListener) e.nextElement()).gameStarted(); } } private void notifyListenersGameStoped() { Enumeration e = enumerateListeners(); while(e.hasMoreElements()) { ((GameEventListener) e.nextElement()).gameStoped(); } } //-------------------------------------------------------- //player management /** * The players whose move it currently is. */ private synchronized Player getCurrentPlayer() { return players[currentPlayerIndex]; } /** * Advance the player */ private synchronized void advancePlayer() { currentPlayerIndex ++; if(currentPlayerIndex >= players.length) { currentPlayerIndex = 0; } } //------------------------------------------------------ //state /** * Start the game. * Tells the board to start, starts the game loop thread, * then notifies listeners. */ public synchronized void startGame() { if(gameThread != null) { gameThread.stopThread(); gameThread = null; } board.gameStarted(); currentPlayerIndex = 0; gameThread = new GameThread(); gameThread.start(); notifyListenersGameStarted(); } /** * Stop the game. * Stops the game thread, tells the board the game is stopped, and * then notifies listeners. */ public synchronized void stopGame() { if(gameThread != null) { gameThread.stopThread(); gameThread = null; } board.gameStoped(); notifyListenersGameStoped(); } /** * Restart the game. * Stops the current game loop, tells the board to restart, * starts a new game loop, and then notifies listeneres. */ public synchronized void restartGame() { if(gameThread != null) { gameThread.stopThread(); gameThread = null; } board.gameRestarted(); currentPlayerIndex = 0; gameThread = new GameThread(); gameThread.start(); notifyListenersGameReStarted(); } //-------------------------------------------------------- //inner classes /** * The game thread class does the work of * making the players move. * Exits after stop is called. */ class GameThread extends Thread { public boolean active = true; public void stopThread() { if(active) { active = false; this.interrupt(); } } public void run() { while( active && ! board.isGameOver() ) { //get the players move. Player player = getCurrentPlayer(); Move move = player.getMove((Board) board.clone()); if(move == null) { //ignore null moves continue; } //if we are still active, make the move boolean moveMade = false; if(active) { moveMade = board.move(move); } //if we are still active, and the move was made, notify listeners if(active && moveMade) { advancePlayer(); notifyListenersMoveMade(move); } }//end while if(active && board.isGameOver()) { notifyListenersGameStoped(); } active = false; }//end run }//end class GameThread }//end class GameMaster