GameScreen 繼承 Canvas,使用 Image、Graphics 繪製棋盤、棋子、結果。關鍵點:
Game 類package example.tictactoe;
import java.util.Random;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
class GameScreen extends Canvas implements CommandListener {
private static final int BLACK = 0x000000, WHITE = 0x00FFFFFF, RED = 0x00FF0000, BLUE = 0x000000FF;
private static final int NO_MOVE = -1;
private final TicTacToeMIDlet midlet;
private final Game game;
private final Command exitCommand, newGameCommand;
private final Random random = new Random();
private int screenWidth, screenHeight, boardCellSize, boardSize, boardTop, boardLeft;
private boolean playerIsCircle, computerIsCircle;
private int preCursorPosition, cursorPosition, computerMove = NO_MOVE, playerMove = NO_MOVE;
private int computerGamesWonTally = 0, playerGamesWonTally = 0;
private boolean isRestart;
public GameScreen(TicTacToeMIDlet midlet, boolean playerIsCircle) {
this.midlet = midlet; this.playerIsCircle = playerIsCircle;
computerIsCircle = !playerIsCircle;
game = new Game(random);
initializeBoard();
exitCommand = new Command("Exit", Command.EXIT, 1);
newGameCommand = new Command("New", Command.SCREEN, 2);
addCommand(exitCommand); addCommand(newGameCommand); setCommandListener(this);
initialize();
}
private void initialize() {
game.initialize(); preCursorPosition = cursorPosition = 0; playerMove = NO_MOVE;
boolean computerFirst = ((random.nextInt() & 1) == 0);
computerMove = computerFirst ? game.makeComputerMove() : NO_MOVE;
isRestart = true; repaint();
}
public void paint(Graphics g) {
if (game.isGameOver()) paintGameOver(g); else paintGame(g);
}
private void paintGame(Graphics g) {
if (isRestart) { g.setColor(WHITE); g.fillRect(0,0,screenWidth,screenHeight); drawBoard(g); isRestart=false; }
drawCursor(g);
if (playerMove != NO_MOVE) drawPiece(g, playerIsCircle, playerMove);
if (computerMove != NO_MOVE) drawPiece(g, computerIsCircle, computerMove);
}
private void paintGameOver(Graphics g) {
String statusMsg, tallyMsg = "You:" + playerGamesWonTally + " Me:" + computerGamesWonTally;
if (game.isComputerWinner()) { statusMsg = "I win!"; computerGamesWonTally++; }
else if (game.isPlayerWinner()) { statusMsg = "You win"; playerGamesWonTally++; }
else statusMsg = "Stalemate";
Font font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM);
int strHeight = font.getHeight(), statusW = font.stringWidth(statusMsg), tallyW = font.stringWidth(tallyMsg);
int strWidth = Math.max(statusW, tallyW);
int x = Math.max(0, (screenWidth - strWidth) / 2);
int y = Math.max(0, (screenHeight - 2 * strHeight) / 2);
g.setColor(WHITE); g.fillRect(0,0,screenWidth,screenHeight);
g.setColor(BLACK);
g.drawString(statusMsg, x, y, Graphics.TOP | Graphics.LEFT);
g.drawString(tallyMsg, x, y + 1 + strHeight, Graphics.TOP | Graphics.LEFT);
}
public void commandAction(Command c, Displayable d) {
if (c == exitCommand) midlet.quit(); else if (c == newGameCommand) initialize();
}
private void initializeBoard() {
screenWidth = getWidth(); screenHeight = getHeight();
if (screenWidth > screenHeight) {
boardCellSize = (screenHeight - 2) / 3;
boardLeft = (screenWidth - boardCellSize * 3) / 2; boardTop = 1;
} else {
boardCellSize = (screenWidth - 2) / 3;
boardLeft = 1; boardTop = (screenHeight - boardCellSize * 3) / 2;
}
}
protected void keyPressed(int keyCode) {
if (game.isGameOver()) return;
int action = getGameAction(keyCode);
switch (action) {
case FIRE: doPlayerMove(); break;
case RIGHT: doMoveCursor(1,0); break;
case DOWN: doMoveCursor(0,1); break;
case LEFT: doMoveCursor(-1,0); break;
case UP: doMoveCursor(0,-1); break;
}
}
private void doPlayerMove() {
if (game.isFree(cursorPosition)) {
makePlayerMove(cursorPosition); playerMove = cursorPosition;
if (!game.isGameOver()) computerMove = game.makeComputerMove();
repaint();
}
}
private void doMoveCursor(int dx, int dy) {
int newPos = cursorPosition + dx + 3 * dy;
if (newPos >= 0 && newPos < 9) { preCursorPosition = cursorPosition; cursorPosition = newPos; repaint(); }
}
private void drawPiece(Graphics g, boolean isCircle, int pos) {
int x = (pos % 3) * boardCellSize + 3, y = (pos / 3) * boardCellSize + 3;
if (isCircle) drawCircle(g, x, y); else drawCross(g, x, y);
}
private void drawCircle(Graphics g, int x, int y) {
g.setColor(BLUE);
g.fillArc(x+boardLeft, y+boardTop, boardCellSize-4, boardCellSize-4, 0, 360);
g.setColor(WHITE);
g.fillArc(x+4+boardLeft, y+4+boardTop, boardCellSize-12, boardCellSize-12, 0, 360);
}
private void drawCross(Graphics g, int x, int y) {
g.setColor(RED);
for (int i=0;i<4;i++) {
g.drawLine(x+1+i+boardLeft, y+boardTop, x+boardCellSize-8+i+boardLeft, y+boardCellSize-5+boardTop);
g.drawLine(x+1+i+boardLeft, y+boardCellSize-5+boardTop, x+boardCellSize-8+i+boardLeft, y+boardTop);
}
}
private void drawCursor(Graphics g) {
g.setColor(WHITE);
g.drawRect((preCursorPosition%3)*boardCellSize+2+boardLeft, (preCursorPosition/3)*boardCellSize+2+boardTop, boardCellSize-3, boardCellSize-3);
g.setColor(BLACK);
g.drawRect((cursorPosition%3)*boardCellSize+2+boardLeft, (cursorPosition/3)*boardCellSize+2+boardTop, boardCellSize-3, boardCellSize-3);
}
private void drawBoard(Graphics g) {
g.setColor(WHITE); g.fillRect(0,0,screenWidth,screenHeight);
g.setColor(BLACK);
for (int i=0;i<4;i++) {
g.fillRect(boardLeft, boardCellSize*i+boardTop, boardCellSize*3+2, 2);
g.fillRect(boardCellSize*i+boardLeft, boardTop, 2, boardCellSize*3);
}
}
}
獨立於 UI 的邏輯類,使用位運算高效判定勝負:
package example.tictactoe;
import java.util.Random;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
class Game {
private static final int[] WINS = {
0x007, 0x038, 0x1C0, 0x124, 0x092, 0x049, 0x111, 0x054
};
private static final int DRAWN_GAME = 0x1FF;
private int playerState, computerState; private Random random;
Game(Random random) { this.random = random; initialize(); }
void initialize() { playerState = 0; computerState = 0; }
boolean isFree(int pos) { int bit = 1<>>1) % free;
for (int i=0;i<9;i++) if (isFree(i)) { if (pick==0) return i; pick--; }
return -1;
}
private static boolean isWin(int state) {
for (int w: WINS) if ((state & w) == w) return true; return false;
}
}
MIDlet-Name: TicTacToe
MIDlet-Vendor: Forum Nokia
MIDlet-Version: 1.1.1
MIDlet-Jar-Size: 11409
MIDlet-Jar-URL: TicTacToe.jar
MIDlet-1: TicTacToe, /tictactoe.png, example.tictactoe.TicTacToeMIDlet
MicroEdition-Profile: MIDP-1.0
MicroEdition-Configuration: CLDC-1.0