📄 boardstate.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;
/**
* <p>
* Singleton class holding game logic and state of a game. There can
* only be one state per device, thus the singleton pattern.</p><p>
* Extends the <code>Board</code> class with player-, turn-, dice- and rule-logic.
* The <code>BoardState</code> is detached from gui. State reports when
* pieces are moved etc can be retreived by implementing the
* <code>BoardStateListener</code> interface and registering this instance
* in the <code>BoardState</code>.
* </p>
*
* @see bluegammon.logic.BoardMediator
* @author Peter Andersson
*/
public class BoardState extends Board
{
// Interaction game states
/** Flag indicating if turns should be chosen */
protected boolean m_chooseTurns = true;
/** Flag indicating if dice is thrown */
protected boolean m_diceThrown = false;
// Player and turn state
/** Player one */
protected static Player m_player1;
/** Player two */
protected static Player m_player2;
/** Current player */
protected static Player m_currentPlayer;
// Rule game states
/** Flag indicating if game is finished */
protected boolean m_gameFinished = true;
/** Integer array of the dice values */
protected int[] m_dice = new int[4];
/** Number of dice values (2 for different dice values, 4 for double throw) */
protected int m_diceVals = 2;
/** Flag indicating if possible moves for current player has been calculated */
protected boolean m_possibleMovesCalculated = false;
/** Integer array of possible moves */
protected int[][] m_possibleMoves = new int[256][3];
/** Possible move board source index */
public static final int PM_SOUR = 0;
/** Possible move board destination index */
public static final int PM_DEST = 1;
/** Possible move dice value index */
public static final int PM_DICE = 2;
/** Number of possible moves for current player */
protected int m_possibleMoveCount = 0;
/** Integer array of undoable moves */
protected int[][] m_undoableMoves = new int[5][4];
/** Undoable move board source index */
protected static final int UNDO_SOURCE = 0;
/** Undoable move board destination index */
protected static final int UNDO_DEST = 1;
/** Undoable move on guard flag (if >=0, guard will be moved to this pos ) */
protected static final int UNDO_GUARD = 2;
/** The dicevalue that should be put back to dicevalues */
protected static final int UNDO_DICEVALUE = 3;
/** Number of undoable moves */
protected int m_undoableMoveCount = 0;
/** Listener of this state. For compact framework, only allow one listener. */
protected BoardStateListener m_listener;
/** BoardState instance */
protected static BoardState m_instance;
/**
* Registers a boardstate-listener that will receive
* events upon state changes.
*
* @param listener The listener.
*/
public void setGameListener(BoardStateListener listener)
{
m_listener = listener;
}
// Player stats
/**
* Defines the two backgammon players.
* @param player1 Player one.
* @param player2 Player two.
*/
public void setPlayers(Player player1, Player player2)
{
m_player1 = player1;
m_player2 = player2;
}
/**
* Returns whether the game is finished or not
* @return true if finished, false otherwise
*/
public boolean isGameFinished()
{
return m_gameFinished;
}
/**
* Marks this game as finished
* @param b true for finished, false otherwise
*/
public void setGameFinished(boolean b)
{
m_gameFinished = b;
m_possibleMovesCalculated = false;
}
/**
* Returns the color of current player.
* @return true for white player, false for black player
*/
public boolean isCurrentPlayerWhite()
{
return m_currentPlayer.isWhite();
}
/**
* Returns current player.
* @return current player.
*/
public Player getCurrentPlayer()
{
return m_currentPlayer;
}
/**
* Returns waiting player.
* @return noncurrent player.
*/
public Player getWaitingPlayer()
{
if (m_player1 == m_currentPlayer)
{
return m_player2;
}
else
{
return m_player1;
}
}
/**
* Sets the turn to the player having specified color
* without notifying listener about the change.
* @param white True for white player, false for black player
*/
public void setCurrentPlayer(boolean white)
{
Player p = m_player1;
if (white && !m_player1.isWhite() ||
!white && m_player1.isWhite())
{
p = m_player2;
}
m_currentPlayer = p;
}
/**
* Sets the turn to the player having specified color
* and notifies listener about the change.
* @param whiteTurn True for white player, false for black player
*/
public void setTurn(boolean whiteTurn)
{
setCurrentPlayer(whiteTurn);
if (m_listener != null) m_listener.turnChange(whiteTurn);
}
// Movement
/**
* Moves a piece of specified color, from specified index
* to specified destination on board. Handles specific backgammon rules, i.e.
* if white moves to an index where one black piece resides, whereas the black
* piece is put under guard. Step (1) of performing a move.
* @param index The source index to move from
* @param dest The destination index to move to
* @param white The color of the piece to move
*/
public synchronized void makeMove(int index, int dest, boolean white)
{
int[] player = WHITE, opponent = BLACK;
if (!white)
{
player = BLACK;
opponent = WHITE;
}
player[index] -= 1;
player[dest] += 1;
m_undoableMoves[m_undoableMoveCount][UNDO_SOURCE] = dest;
m_undoableMoves[m_undoableMoveCount][UNDO_DEST] = index;
m_undoableMoves[m_undoableMoveCount][UNDO_GUARD] = -1;
if (m_listener != null) m_listener.pieceMoved(white, index, dest);
if (dest != POS_OUT && opponent[dest] == 1)
{
m_undoableMoves[m_undoableMoveCount][UNDO_GUARD] = dest;
opponent[dest] = 0;
opponent[POS_GUARD]++;
if (m_listener != null) m_listener.pieceMoved(!white, dest, POS_GUARD);
}
if (player[POS_OUT] == 15)
{
setGameFinished(true);
if (m_listener != null)
m_listener.gameFinished(
white,
calculatePiecesLeft(!white),
calculatePoints(!white));
}
}
/**
* Consumes a dice value, called when a player moves a piece.
* Populates undoable moves vector and consumes the dice value
* used for move.
* Step (2) of performing a move.
* @param diceIndex The diceindex that was used for the move.
*/
public synchronized void consumeDice(int diceIndex)
{
m_undoableMoves[m_undoableMoveCount][UNDO_DICEVALUE] = m_dice[diceIndex];
for (int d = diceIndex; d < m_dice.length-1; d++)
{
m_dice[d] = m_dice[d+1];
}
m_diceVals--;
m_possibleMovesCalculated = false;
}
/**
* Commits a move, step (3) of performing a move. Updates
* undoable move count and checks if game is ended because of this
* move.
* @param white The color of the pieces whose moves are to be commited.
* @param diceValue The dicevalue that was used for the move.
*/
public synchronized void commitMove(boolean white, int diceValue)
{
int[] player = WHITE, opponent = BLACK;
if (!white)
{
player = BLACK;
opponent = WHITE;
}
m_undoableMoveCount++;
if (m_listener != null) m_listener.undoAdded(m_undoableMoveCount, diceValue);
}
/**
* Undoes the last move. Does nothing if there are no moves to undo.
* @param white The color of the player that undoes
* @return the source index of the undoed move.
*/
public synchronized int undoLastMove(boolean white)
{
int oldSource = -1;
if (m_undoableMoveCount > 0)
{
int[] player = WHITE, opponent = BLACK;
if (!white)
{
player = BLACK;
opponent = WHITE;
}
m_undoableMoveCount--;
int source = m_undoableMoves[m_undoableMoveCount][UNDO_SOURCE];
int dest = m_undoableMoves[m_undoableMoveCount][UNDO_DEST];
int guard = m_undoableMoves[m_undoableMoveCount][UNDO_GUARD];
int diceVal = m_undoableMoves[m_undoableMoveCount][UNDO_DICEVALUE];
oldSource = dest;
player[source]--;
player[dest]++;
if (m_listener != null) m_listener.pieceMoved(white, source, dest);
if (guard >= 0)
{
opponent[POS_GUARD]--;
opponent[guard]++;
if (m_listener != null) m_listener.pieceMoved(!white, POS_GUARD, guard);
}
m_dice[m_diceVals++] = diceVal;
m_possibleMovesCalculated = false;
if (m_listener != null) m_listener.undoPerformed(m_undoableMoveCount, diceVal);
}
return oldSource;
}
// Game intelligence
/**
* Calculates possible moves and returns array, composed as
* int[possibleMoveIndex][PM_SOUR | PM_DEST | PM_DICE] where PM_SOUR
* denotes the source index, PM_DEST denotes the destination index, and
* PM_DICE denotes the dice value index that is used for the move.<br><br>
* The array is sorted depending on player color, allowing consistent
* movement of source and destination cursors by simply increasing or
* decreasing the move index. <br><br>
* To get number of possible moves, i.e. the length of the array, see
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -