www.pudn.com > Bluegammon蓝牙的应用编程.rar > BoardMediator.java
// Copyright (c) 2005 Sony Ericsson Mobile Communications AB // // This software is provided "AS IS," without a warranty of any kind. // ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, // INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. // // THIS SOFTWARE IS COMPLEMENTARY OF JAYWAY AB (www.jayway.se) package bluegammon.logic; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import bluegammon.Audio; import bluegammon.Device; import bluegammon.Bluegammon; import bluegammon.Resources; import bluegammon.RmsFacade; import bluegammon.gui.BoardCanvas; import bluegammon.gui.popup.Popup; /** ** The
BoardMediatorclass is active during a backgammon game. It takes care * of coordination betweenBoardStateandBoardCanvasi.e. * between the gui and the logic.BoardCanvasis detached from any * backgammon-logic - this connection is made by this class by implementing *BoardStateListenerto receive events upon board state changes. The *BoardMediatorthen calls theBoardCanvasto update the gui * when state changes. ** In order to save the game at any time, but still have animations, the *
BoardStatediffers from theBoardCanvas: when the state * is changed (e.g. a move is made), theBoardStateis updated * directly. TheBoardCanvashas intermittent states; e.g. during an animation * of a piece movement, one piece is "missing" fromBoardCanvasboard until * the piece is put down. ** This class is a simple coordinater, thus it does not have any state. The *
BoardMediatoris accessed statically. ** * @see bluegammon.gui.BoardCanvas * @see bluegammon.logic.BoardState * @author Peter Andersson */ public class BoardMediator implements BoardStateListener { /** * Starts the BoardMediator. */ public static void startup() { BoardState.getInstance().setGameListener(new BoardMediator()); } /** * Initiates a new or resumed game with specified players. * @param p1 Player 1. * @param p2 Player 2. * @param resumed True if resumed, false if new game. */ public static void init(Player p1, Player p2, boolean resumed) { BoardState state = BoardState.getInstance(); BoardCanvas canvas = BoardCanvas.getInstance(); state.setPlayers(p1,p2); state.setGameFinished(false); if (!resumed) { int whiteDice = newDiceValue(); int blackDice = newDiceValue(); if (whiteDice == blackDice) { if (whiteDice > 3) { whiteDice--; } else { whiteDice++; } } boolean whiteTurn = whiteDice > blackDice; state.setStartPositions(); canvas.setStartPositions(); canvas.invalidate(); canvas.selectTurns(whiteDice, blackDice); } } /** * Shuts the BoardMediator down. */ public static void shutdown() { BoardCanvas.getInstance().shutdown(); } // Actions /** * Called from interaction, moves a player piece. * @param possibleMoveIndex How to move according to current BoardState */ public static void makePlayerMove(int possibleMoveIndex) { BoardState state = BoardState.getInstance(); int[][] moves = getPossibleMoves(); state.makeMove( moves[possibleMoveIndex][BoardState.PM_SOUR], moves[possibleMoveIndex][BoardState.PM_DEST], isCurrentPlayerWhite()); int diceValIndex = moves[possibleMoveIndex][BoardState.PM_DICE]; int diceValue = state.getDiceValue(diceValIndex); BoardCanvas.getInstance().consumeDiceValue(diceValue); state.consumeDice(diceValIndex); state.commitMove(isCurrentPlayerWhite(), diceValue); } /** * Called from interaction, undoes the last move. * Does nothing if there are no moves to undo. */ public static void undoLastMove() { BoardCanvas canvas = BoardCanvas.getInstance(); int oldSourceIdx = BoardState.getInstance().undoLastMove(isCurrentPlayerWhite()); canvas.setQueryCommit(false); canvas.cursorNearestIndex(oldSourceIdx, 0); canvas.updateUndoCommand(); canvas.updateCursor(); } /** * Called from interaction, commits players' moves. */ public static void commitTurn() { newTurn(!BoardMediator.isCurrentPlayerWhite()); BoardCanvas.getInstance().setQueryCommit(false); } /** * Called from interaction and logic, changes turn. * * @param whiteTurn true if turn changes to white player, false otherwise. */ public static void newTurn(boolean whiteTurn) { if (!BoardState.getInstance().isGameFinished()) { BoardState.getInstance().setTurn(whiteTurn); Player p = BoardState.getInstance().getCurrentPlayer(); if (p instanceof LocalPlayer) { BoardCanvas.getInstance().setCurrentLocalPlayer((LocalPlayer)p); } else { BoardCanvas.getInstance().setCurrentLocalPlayer(null); } BoardState.getInstance().newDiceValues( newDiceValue(), newDiceValue()); BoardCanvas.getInstance().throwDices(whiteTurn); if (Bluegammon.getGameType() != Bluegammon.GAME_TYPE_LOCAL && !isRemoteTurn()) { Device.vibrate(100,0,1); } } } /** * Called from interaction, exits current game. * * @param reason An integer denoting the reason for quitting, * one of
PlayerListener.LOCAL_QUIT, *PlayerListener.REMOTE_QUIT,*PlayerListener.LOCAL_GIVE_UP,*PlayerListener.REMOTE_GIVE_UP*/ public synchronized static void exitGame(int reason) { if (reason == PlayerListener.LOCAL_GIVE_UP || reason == PlayerListener.REMOTE_GIVE_UP) { boolean localLoser = reason == PlayerListener.LOCAL_GIVE_UP; boolean whiteWinner = !BoardMediator.getLocalPlayer().isWhite(); if (reason == PlayerListener.REMOTE_GIVE_UP) { whiteWinner = !whiteWinner; Bluegammon.showPopup(Resources.getChars(Resources.TXT_REMOTE_GAVE_UP), Popup.ALT_OK, 10, 0, 0, null); } int piecesLeft = BoardState.getInstance().calculatePiecesLeft(!whiteWinner); int points = BoardState.getInstance().calculatePoints(!whiteWinner); // Only show animation to the winning player, the player who gives up // probably just want to quit BoardMediator.finishGame(whiteWinner, piecesLeft, points, !localLoser); if (localLoser) { Bluegammon.exitGame(); } } else if (reason == PlayerListener.REMOTE_QUIT) { if (!isGameFinished()) { Bluegammon.showPopup(Resources.getChars(Resources.TXT_BT_REMOTE_QUIT), Popup.ALT_OK, 0, 0, 0, null); Bluegammon.exitGame(); } } else { if (Bluegammon.isShowingPopup()) { Bluegammon.getCurrentPopup().dispose(); } Bluegammon.exitGame(); } } /** * Called from IO framework remote connection is lost in a * remote game. * @param e The exception that was * the reason of losing connection. */ public synchronized static void lostRemoteConnection(IOException e) { if (!isGameFinished()) { System.err.println("Lost remote connection!"); e.printStackTrace(); Audio.playSound(Audio.CONN_FAIL); Bluegammon.showPopup(Resources.getChars(Resources.TXT_BT_CONN_LOST), Popup.ALT_OK, 0, 0, 0, null); Bluegammon.exitGame(); } } /** * Called when remote player sent a message * @param mess the message. */ public static void showMessage(char[] mess) { Device.vibrate(100,50,3); Audio.playSound(Audio.MESSAGE); mess = (new String(getOpponentPlayer().getName()) + ":\n\n" + new String(mess)).toCharArray(); Bluegammon.showPopup(mess, null, 60, 0, 0, null); } /** * Returns the player whos holding the turn, i.e. can make moves. * This method returns null if current player has not yet been chosen, * meaning that the first dice roll is still ongoing. * @return The current player or null. */ public static Player getCurrentPlayer() { return BoardState.getInstance().getCurrentPlayer(); } /** * Returns opponent player. In case of local game, this method returns * the player currently waiting for his or her turn. In a remote game, * it returns the remote player. * * @return The opponent. */ public static Player getOpponentPlayer() { Player p1 = BoardState.getInstance().getCurrentPlayer(); Player p2 = BoardState.getInstance().getWaitingPlayer(); if (Bluegammon.getGameType() == Bluegammon.GAME_TYPE_LOCAL) { return p2; } else { return (p1 instanceof LocalPlayer) ? p2 : p1; } } /** * Returns the oneLocalPlayer. If the game is local, * arbitraryLocalPlayeris returned. This method only makes * sense in remote games. * @return TheLocalPlayerin the game. */ public static LocalPlayer getLocalPlayer() { Player p1 = BoardState.getInstance().getCurrentPlayer(); Player p2 = BoardState.getInstance().getWaitingPlayer(); if (p1 instanceof LocalPlayer) { return (LocalPlayer)p1; } else if (p2 instanceof LocalPlayer) { return (LocalPlayer)p2; } else { return null; } } /** * Returns whether the current turn belongs to a remote player or not. * @return true if current turn is a remote player, false otherwise. */ public static boolean isRemoteTurn() { return BoardState.getInstance().getCurrentPlayer() instanceof RemotePlayer; } /** * Returns possible moves based on current board state. * @see bluegammon.logic.BoardState#getPossibleMoves(boolean) * @return Array with possible moves. */ public static int[][] getPossibleMoves() { return BoardState.getInstance().getPossibleMoves(isCurrentPlayerWhite()); } /** * Returns number of possible moves based on current board state * for player with current turn. If current turn is not yet resolved, * zero is returned. * @return number of possible moves. */ public static int countPossibleMoves() { if (BoardState.getInstance().getCurrentPlayer() == null) { return 0; } else { return BoardState.getInstance().countPossibleMoves(isCurrentPlayerWhite()); } } /** * Returns whether the game is finished or not * @return true if finished, false otherwise */ public static boolean isGameFinished() { return BoardState.getInstance().isGameFinished(); } /** * Forces the game state to be finished. */ public static void forceGameFinished() { BoardState.getInstance().setGameFinished(true); } /** * Returns number of possible undoable moves * @return number of possible undoable moves */ public static int countUndoableMoves() { return BoardState.getInstance().countUndoableMoves(); } /** * Returns a new dice value, a random integer between 1 and 6. * @return A new dice value between 1 and 6. */ public static int newDiceValue() { return Math.abs(Rand.random() % 6) + 1; } /** * Returns value of specified dice * @param index the dice, 0 or 1 * @return a value between 1 and 6 */ public static int getDiceValue(int index) { return BoardState.getInstance().getDiceValue(index); } /** * Returns number of pieces on specified index in current state. * If there are white pieces, * number of white pieces are returned. If there are black pieces, number of * black pieces are returned. Otherwise zero is returned. * * @param index The board index * @return Number of pieces on index. */ public static int countStatePieces(int index) { return BoardState.getInstance().countPieces(index); } /** * Returns the boardcanvas singleton instance. * @return The boardcanvas singleton instance. */ public static BoardCanvas getCanvas() { return BoardCanvas.getInstance(); } /** * Finishes a game of backgammon. Saves the score to persistence. * @param whiteWinner Color of winner, true for white, false for black. * @param loserPiecesLeft Number of pieces left for loser. * @param points Number of points per piece. * @param fireAnimation Show winning animation */ protected static void finishGame(boolean whiteWinner, int loserPiecesLeft, int points, boolean fireAnimation) { commitTurn(); if (Bluegammon.getGameType() == Bluegammon.GAME_TYPE_LOCAL) { // Wipe out the local saved game since we're finished RmsFacade.setBoolean(Bluegammon.HAS_SAVED_LOCAL_GAME, false); RmsFacade.set(Bluegammon.SAVED_GAME_DATA, null); Audio.playSound(Audio.WINNER); } else { // Save the stats if this remote game boolean localWinner = getLocalPlayer().isWhite() && whiteWinner || !getLocalPlayer().isWhite() && !whiteWinner; GameRecord.updateGameResult(getOpponentPlayer(), localWinner, points * loserPiecesLeft); // Wipe out remote saved game since we're finished GameRecord.saveGame(getOpponentPlayer(), null); Audio.playSound(localWinner ? Audio.WINNER : Audio.LOSER); } BoardState.getInstance().setGameFinished(true); if (fireAnimation) { BoardCanvas.getInstance().finishGame(whiteWinner, loserPiecesLeft, points); } } // Loading and saving /** * Loads a saved game from specified input stream. If the game * is a remote game, the colors of the players are set as specified * in the data stream. If the data is loaded from a remote device * (i.e. the opponent), the player colors need to be flipped according * to what is specified in saved data. * * @param is The input stream to load saved game data from. * @param flipColors Flag indicating if the colors of the players * should be flipped according to what is specified * in the saved game data. * @throws IOException If error occurs when loading data. */ public static void loadGame(InputStream is, boolean flipColors) throws IOException { DataInputStream dis = null; BoardState state = BoardState.getInstance(); BoardCanvas canvas = BoardCanvas.getInstance(); try { canvas.invalidate(); dis = new DataInputStream(is); state.loadState(dis); canvas.loadCanvas(dis); Rules.loadRules(dis); Rand.loadSeed(dis); boolean localWhite = dis.readBoolean(); if (Bluegammon.getGameType() != Bluegammon.GAME_TYPE_LOCAL) { // Set colors localWhite ^= flipColors; boolean currentTurnWhite = state.getCurrentPlayer().isWhite(); getLocalPlayer().setWhite(localWhite); getOpponentPlayer().setWhite(!localWhite); // Current player is set in state.loadState, // but since colors might have changed we // need to set it again state.setCurrentPlayer(currentTurnWhite); } for (int i = 0; i < Board.MAX_POS; i++) { canvas.setPieces(true, i, state.countPieces(true, i)); canvas.setPieces(false, i, state.countPieces(false, i)); } } finally { if (dis != null) { dis.close(); } } Player currentPlayer = state.getCurrentPlayer(); canvas.setCurrentLocalPlayer( (currentPlayer instanceof LocalPlayer ? (LocalPlayer)currentPlayer : null)); canvas.repaint(); } /** * Saves current game to specified output stream. * @param os The output stream to write saved game data to. * @return Number of bytes written to output stream. * @throws IOException If error occurs when writing saved game data. */ public static int saveGame(OutputStream os) throws IOException { DataOutputStream dos = null; int len = 0; try { dos = new DataOutputStream(os); len += BoardState.getInstance().saveState(dos); len += BoardCanvas.getInstance().saveCanvas(dos); len += Rules.saveRules(dos); len += Rand.saveSeed(dos); dos.writeBoolean(getLocalPlayer().isWhite()); len++; } finally { if (dos != null) dos.close(); } return len; } // Player stats /** * Returns the color of current player. * @return true for white player, false for black player */ public static boolean isCurrentPlayerWhite() { return BoardState.getInstance().isCurrentPlayerWhite(); } // BoardStateListener implementation // see interface javadoc public void turnChange(boolean whiteTurn) { } // see interface javadoc public void pieceMoved(boolean white, int from, int to) { BoardCanvas.getInstance().movePiece(white, from, to, BoardState.getInstance().countPieces(from), BoardState.getInstance().countPieces(to)-1); } // see interface javadoc public void undoAdded(int undos, int diceValue) { } // see interface javadoc public void undoPerformed(int undos, int diceValue) { BoardCanvas.getInstance().undoConsumedDiceValue(diceValue); } // see interface javadoc public void gameFinished(boolean whiteWinner, int loserPiecesLeft, int points) { finishGame(whiteWinner, loserPiecesLeft, points, true); } /** Prevent construction */ private BoardMediator() {} }