📄 bluegammon.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;
import bluegammon.gui.MenuCanvas;
import bluegammon.gui.PopupCanvas;
import bluegammon.gui.StringInputHandler;
import bluegammon.gui.popup.Popup;
import bluegammon.gui.popup.PopupListener;
import bluegammon.io.BackgammonConnection;
import bluegammon.io.Handshake;
import bluegammon.io.PlayerListenerProxy;
import bluegammon.logic.BoardMediator;
import bluegammon.logic.GameRecord;
import bluegammon.logic.LocalPlayer;
import bluegammon.logic.Player;
import bluegammon.logic.RemotePlayer;
import bluegammon.logic.Rules;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
/**
* <p>
* The <code>Bluegammon</code> class represents the Bluegammon MIDlet
* game altogether. It coordinates the macro state of the application.
* </p><p>
* This class collects common functionality as starting and stopping a
* backgammon game, showing a popup, or getting string input from user. It is
* invoked statically since it mainly is a mediator.
* </p>
*
* @author Peter Andersson
*/
public class Bluegammon implements PopupListener, CommandListener
{
/** Current canvas that is displayed */
protected static PopupCanvas m_currentCanvas;
/** Current listener to popups */
protected static PopupListener m_popupListener;
/** Popup instance cache */
protected static Popup m_popupCache;
/** Text box used for collecting user string input */
protected static TextBox m_textBox;
/** Handler when user has entered string input */
protected static StringInputHandler m_inputHandler;
/** The connection used in remote games */
protected static BackgammonConnection m_remoteConnection;
/** Instance of this class, used as PopupListener or CommandListener */
protected static Bluegammon m_inst;
/** Key for device id (int)*/
public static final int DEVICE_ID = 0;
/** Key for player name (char[])*/
public static final int PLAYER_NAME = 1;
/** Key for saved game boolean flag (boolean)*/
public static final int HAS_SAVED_LOCAL_GAME = 2;
/** Key for saved game data (byte[])*/
public static final int SAVED_GAME_DATA = 3;
/** Key for preferred color (boolean)*/
public static final int BLACK_PREFERRED = 4;
/** Key for audio off (boolean)*/ // Negative flag because default boolean = false
public static final int AUDIO_OFF = 5;
/** Key for vibration off (boolean)*/
public static final int VIBRA_OFF = 6;
/** Key for preferred rules (int)*/
public static final int RULES_PREFERRED = 7;
/** Max number of opponent scores that can be persistent */
public static final int GAMERECORDS_SIZE = 16;
/** First key in gamerecords, device ids (int) */
public static final int GAMEREC_OP_ID = 8;
/** First key in gamerecords, opponent name (char[]) */
public static final int GAMEREC_OP_NAME = GAMEREC_OP_ID + GAMERECORDS_SIZE;
/** First key in gamerecords, player score (int) */
public static final int GAMEREC_MY_SCORE = GAMEREC_OP_NAME + GAMERECORDS_SIZE;
/** First key in gamerecords, opponent score (int) */
public static final int GAMEREC_OP_SCORE = GAMEREC_MY_SCORE + GAMERECORDS_SIZE;
/** First key in gamerecords, number of games against this opponent (int) */
public static final int GAMEREC_GAME_COUNT = GAMEREC_OP_SCORE + GAMERECORDS_SIZE;
/** First key in gamerecords, timestamp (long) */
public static final int GAMEREC_TIMESTAMP = GAMEREC_GAME_COUNT + GAMERECORDS_SIZE;
/** First key in gamerecords, saved game data (byte[]) */
public static final int GAMEREC_SAVED_GAME_DATA = GAMEREC_TIMESTAMP + GAMERECORDS_SIZE;
/** Nbr of keys */
protected static final int NBR_OF_KEYS = 8 + 7 * GAMERECORDS_SIZE;
/** Command used during user string input */
protected static final Command OK =
new Command(Resources.getString(Resources.TXT_C_OK), Command.OK, 1);
/** Command used during user string input */
protected static final Command CANCEL =
new Command(Resources.getString(Resources.TXT_C_CANCEL), Command.CANCEL, 1);
/** Represents a game that is only played on this device */
public static int GAME_TYPE_LOCAL = 0;
/** Represents a distributed game where this device acts server */
public static int GAME_TYPE_REMOTE_SERVER = 1;
/** Represents a distributed game where this device acts client */
public static int GAME_TYPE_REMOTE_CLIENT = 2;
/** Current game type */
protected static int m_gameType;
/**
* Sets current game type, one of <code>GAME_TYPE_LOCAL</code>,
* <code>GAME_TYPE_REMOTE_SERVER</code>, <code>GAME_TYPE_REMOTE_CLIENT</code>.
* @param gameType The current game type.
*/
protected static void setGameType(int gameType)
{
m_gameType = gameType;
}
/**
* Returns current game type, one of <code>GAME_TYPE_LOCAL</code>,
* <code>GAME_TYPE_REMOTE_SERVER</code>, <code>GAME_TYPE_REMOTE_CLIENT</code>.
* @return The current game type.
*/
public static int getGameType()
{
return m_gameType;
}
/**
* Sets the connection used in remote game. Must be set before invoking
* <code>startRemoteGame</code>
* @param conn The connection used with remote player.
*/
public synchronized static void setBackgammonConnection(BackgammonConnection conn)
{
m_remoteConnection = conn;
}
/**
* Returns true if there exists a saved phone game
*
* @return true if saved game exists, false otherwise
*/
public static boolean hasSavedLocalGame()
{
return RmsFacade.getBoolean(HAS_SAVED_LOCAL_GAME);
}
/**
* Start a new game for two players on one phone.
*/
public synchronized static void startLocalGame()
{
setGameType(GAME_TYPE_LOCAL);
Audio.stopSound(Audio.MUSIC);
Player p1 =
new LocalPlayer(1, "Whitey".toCharArray(), true, BoardMediator.getCanvas());
Player p2 =
new LocalPlayer(2, "Blackie".toCharArray(), false, BoardMediator.getCanvas());
Audio.stopSound(Audio.MUSIC);
BoardMediator.init(p1, p2, false);
setCanvas(BoardMediator.getCanvas());
}
/**
* Starts a remote game, either as server or as client. This method uses the
* connection set in method <code>setBackgammonConnection</code>. It handshakes
* with the other device and starts a new game, or resumes a game if any of the
* devices has a saved game. On conflicting preferred settings (color and rules)
* the server wins.
*
* @param server True if server, false if client.
* @param localName The name of this player.
* @see Bluegammon#setBackgammonConnection(BackgammonConnection)
*/
public static void startRemoteGame(boolean server, char[] localName)
{
DataInputStream in = m_remoteConnection.getInput();
DataOutputStream out = m_remoteConnection.getOutput();
if (in == null || out == null)
{
// Occurs when connecting to a closed connection
// i.e. the remote device pressed cancel during connecting phase
return;
}
Bluegammon.showPopup(Resources.getChars(Resources.TXT_STARTING_GAME), null, 10, 0, 0, null);
setGameType(server ? GAME_TYPE_REMOTE_SERVER : GAME_TYPE_REMOTE_CLIENT);
Handshake handshake = new Handshake();
boolean fail = false;
try
{
if (server)
{
handshake.serverHandshake(in, out, new String(localName));
}
else
{
handshake.clientHandshake(in, out, new String(localName));
}
}
catch (Throwable t)
{
fail = true;
Bluegammon.showPopup(Resources.getChars(Resources.TXT_HANDSHAKE_FAIL), Popup.ALT_OK, 0, 0, 0, null);
System.err.println("Handshake failed");
t.printStackTrace();
return;
}
if (!fail)
{
boolean resumed = handshake.getSavedGame() != null;
Player p1 =
new LocalPlayer(Device.getDeviceId(),
localName,
handshake.isWhite(),
BoardMediator.getCanvas());
PlayerListenerProxy proxy = new PlayerListenerProxy(out);
p1.addListener(proxy);
Player p2 =
new RemotePlayer(handshake.getRemoteId(),
handshake.getRemoteName(),
!handshake.isWhite(),
in);
BoardMediator.init(p1, p2, resumed);
if (resumed)
{
boolean remoteResume = handshake.isRemoteResume();
byte[] b = handshake.getSavedGame();
ByteArrayInputStream bais = new ByteArrayInputStream(b);
try
{
BoardMediator.loadGame(bais, remoteResume);
bais.close();
}
catch (IOException e)
{
e.printStackTrace();
}
b = null;
bais = null;
System.gc();
}
setCanvas(BoardMediator.getCanvas());
Audio.stopSound(Audio.MUSIC);
// Show the rules of this game if connecting as client or
// if this is a resumed game
if (!server || resumed)
{
showRules();
}
else
{
Popup p = Bluegammon.getCurrentPopup();
if (p != null) p.dispose();
}
}
getCanvas().repaint();
}
/**
* Resumes a saved game
*/
public static void resumeSavedLocalGame()
{
Player p1 = new LocalPlayer(1, "Whitey".toCharArray(), true,
BoardMediator.getCanvas());
Player p2 = new LocalPlayer(2, "Blackey".toCharArray(), false,
BoardMediator.getCanvas());
BoardMediator.init(p1, p2, true);
setGameType(GAME_TYPE_LOCAL);
byte[] b = RmsFacade.get(SAVED_GAME_DATA);
ByteArrayInputStream bais = new ByteArrayInputStream(b);
try
{
BoardMediator.loadGame(bais, false);
bais.close();
}
catch (IOException e)
{
e.printStackTrace();
}
b = null;
bais = null;
System.gc();
Audio.stopSound(Audio.MUSIC);
setCanvas(BoardMediator.getCanvas());
showRules();
}
/**
* Exits a game. If the game is not finished it is stored,
* so it can be resumed later.
*/
public synchronized static void exitGame()
{
// Local game
if (getGameType() == GAME_TYPE_LOCAL)
{
if (!BoardMediator.isGameFinished())
{
// Local game is not finished, save it
try
{
if (BoardMediator.getCurrentPlayer() != null)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BoardMediator.saveGame(baos);
baos.close();
RmsFacade.set(SAVED_GAME_DATA, baos.toByteArray());
RmsFacade.setBoolean(HAS_SAVED_LOCAL_GAME, true);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
else
{
// Local game is finished, remove any local saved game
RmsFacade.set(SAVED_GAME_DATA, null);
RmsFacade.setBoolean(HAS_SAVED_LOCAL_GAME, false);
}
}
// Remote game
else if (getGameType() == GAME_TYPE_REMOTE_CLIENT ||
getGameType() == GAME_TYPE_REMOTE_SERVER)
{
Player opponent = BoardMediator.getOpponentPlayer();
if (!BoardMediator.isGameFinished())
{
// Remote game is not finished, save it
try
{
if (BoardMediator.getCurrentPlayer() != null)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -