⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chesscanvas.java

📁 J2ME编写的完整国际象棋程序
💻 JAVA
字号:
/*
ChessCanvas.java - Source Code for Mobile Chess, Part IV

Mobile Chess - a Chess Program for Java ME
Designed by Morning Yellow, Version: 1.06, Last Modified: May 2008
Copyright (C) 2004-2008 www.elephantbase.net

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package chess;

import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

class ChessCanvas extends Canvas {
	private static final int PHASE_LOADING = 0;
	private static final int PHASE_WAITING = 1;
	private static final int PHASE_THINKING = 2;
	private static final int PHASE_EXITTING = 3;

	private static final int RESP_CLICK = 0;
	private static final int RESP_ILLEGAL = 1;
	private static final int RESP_MOVE = 2;
	private static final int RESP_MOVE2 = 3;
	private static final int RESP_CAPTURE = 4;
	private static final int RESP_CAPTURE2 = 5;
	private static final int RESP_SPECIAL = 6;
	private static final int RESP_SPECIAL2 = 7;
	private static final int RESP_CHECK = 8;
	private static final int RESP_CHECK2 = 9;
	private static final int RESP_WIN = 10;
	private static final int RESP_DRAW = 11;
	private static final int RESP_LOSS = 12;

	private static Image imgBackground, imgChess, imgThinking;
	private static final String[] IMAGE_NAME = {
		null, null, null, null, null, null, null, null,
		"wk", "wq", "wr", "wb", "wn", "wp", null, null,
		"bk", "bq", "br", "bb", "bn", "bp", null, null,
	};
	private static int widthBackground, heightBackground;
	private static Font fontLarge = Font.getFont(Font.FACE_SYSTEM,
			Font.STYLE_BOLD + Font.STYLE_ITALIC, Font.SIZE_LARGE);
	private static Font fontSmall = Font.getFont(Font.FACE_SYSTEM,
			Font.STYLE_BOLD, Font.SIZE_SMALL);

	static {
		try {
			imgBackground = Image.createImage("/images/background.png");
			imgChess = Image.createImage("/images/chess.png");
			imgThinking = Image.createImage("/images/thinking.png");
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
		widthBackground = imgBackground.getWidth();
		heightBackground = imgBackground.getHeight();
	}

	ChessMIDlet midlet;
	byte[] retractData = new byte[ChessMIDlet.RS_DATA_LEN];

	private Position pos = new Position();
	private Search search = new Search(pos, 12);
	private String message;
	private int cursorX, cursorY;
	private int sqSelected, mvLast;
	// Assume FullScreenMode = false
	private int normalWidth = getWidth();
	private int normalHeight = getHeight();

	Alert altAbout = new Alert("About \"Mobile Chess\"", null, imgChess, AlertType.INFO);
	Command cmdBack = new Command("Back", Command.ITEM, 1);
	Command cmdRetract = new Command("Retract", Command.ITEM, 1);
	Command cmdAbout = new Command("About", Command.ITEM, 1);
	volatile int phase = PHASE_LOADING;

	private boolean init = false;
	private Image imgBoard, imgSelected, imgCursor;
	private Image[] imgPieces = new Image[24];
	private int squareSize, width, height;
	private int left, right, top, bottom;

	private boolean bCompatible = false;

	ChessCanvas(ChessMIDlet midlet_) {
		this.midlet = midlet_;
		setFullScreenMode(true);
		altAbout.setTimeout(Alert.FOREVER);
		altAbout.setString(midlet.getAppProperty("MIDlet-Description") + "\n\r\f" +
				"www.elephantbase.net Honor Products\n\r\f\n\r\f" +
				"(C) 2004-2008 www.elephantbase.net\n\r\f" + 
				"This product accords with the GNU General Public License");
		addCommand(cmdBack);
		addCommand(cmdRetract);
		addCommand(cmdAbout);

		if (midlet.getAppProperty("MobileChess-Compatible").toLowerCase().equals("true")) {
			bCompatible = true;
		}

		setCommandListener(new CommandListener() {
			public void commandAction(Command c, Displayable d) {
				if (phase == PHASE_WAITING || phase == PHASE_EXITTING) {
					if (false) {
						// Code Style
					} else if (c == cmdBack) {
						back();
					} else if (c == cmdRetract) {
						retract();
					} else if (c == cmdAbout) {
						about();
					}
				}
			}
		});
	}

	void load() {
		setFullScreenMode(true);
		cursorX = 4;
		cursorY = 6;
		sqSelected = mvLast = 0;
		if (midlet.rsData[0] == 0) {
			// pos.fromFen(Position.STARTUP_FEN[midlet.handicap]);
			pos.fromFen(midlet.txtFen.getString());
		} else {
			// Restore Record-Score Data
			pos.clearBoard();
			for (int sq = 0; sq < 128; sq ++) {
				int pc = midlet.rsData[sq + 256];
				if (pc > 0) {
					pos.addPiece(sq, pc);
				}
			}
			if (midlet.flipped) {
				pos.changeSide();
			}
			pos.setIrrev(midlet.rsData[384], midlet.rsData[385] & 255);
		}
		// Backup Retract Status
		System.arraycopy(midlet.rsData, 0, retractData, 0, ChessMIDlet.RS_DATA_LEN);
		// Call "responseMove()" if Computer Moves First
		phase = PHASE_LOADING;
		if ((pos.sdPlayer == 0 ? midlet.flipped : !midlet.flipped) && !pos.isMate()) {
			new Thread() {
				public void run() {
					while (phase == PHASE_LOADING) {
						try {
							sleep(100);
						} catch (Exception e) {
							// Ignored
						}
					}
					responseMove();
				}
			}.start();
		}
	}

	protected void paint(Graphics g) {
		if (phase == PHASE_LOADING) {
			// Wait 1 second for resizing
			width = getWidth();
			height = getHeight();
			for (int i = 0; i < 10; i ++) {
				if (width != normalWidth || height != normalHeight) {
					break;
				}
				try {
					Thread.sleep(100);
				} catch (Exception e) {
					// Ignored
				}
				width = getWidth();
				height = getHeight();
			}
			if (!init) {
				init = true;
				// "width" and "height" are Full-Screen values
				String imagePath = "/images/";
				squareSize = Math.min(width / 8, height / 8);
				if (false) {
					// Code Style
				} else if (squareSize >= 41) {
					squareSize = 41;
					imagePath += "large/";
				} else if (squareSize >= 29) {
					squareSize = 29;
					imagePath += "medium/";
				} else if (squareSize >= 21) {
					squareSize = 21;
					imagePath += "small/";
				} else {
					squareSize = 16;
					imagePath += "tiny/";
				}
				int boardSize = squareSize * 8;
				try {
					imgBoard = Image.createImage(imagePath + "board.png");
					imgSelected = Image.createImage(imagePath + "selected.png");
					imgCursor = Image.createImage(imagePath + "cursor.png");
					for (int pc = 0; pc < 24; pc ++) {
						if (IMAGE_NAME[pc] == null) {
							imgPieces[pc] = null;
						} else {
							imgPieces[pc] = Image.createImage(imagePath + IMAGE_NAME[pc] + ".png");
						}
					}
				} catch (Exception e) {
					throw new RuntimeException(e.getMessage());
				}
				left = (width - boardSize) / 2;
				top = (height - boardSize) / 2;
				right = left + boardSize - 32;
				bottom = top + boardSize - 32;
			}
			phase = PHASE_WAITING;
		}
		for (int x = 0; x < width; x += widthBackground) {
			for (int y = 0; y < height; y += heightBackground) {
				g.drawImage(imgBackground, x, y, Graphics.LEFT + Graphics.TOP);
			}
		}
		g.drawImage(imgBoard, width / 2, height / 2, Graphics.HCENTER + Graphics.VCENTER);
		for (int sq = 0; sq < 128; sq ++) {
			if (Position.IN_BOARD(sq)) {
				int pc = pos.squares[sq];
				if (pc > 0) {
					drawSquare(g, imgPieces[pc], sq);
				}
			}
		}
		int sqSrc = 0;
		int sqDst = 0;
		if (mvLast > 0) {
			sqSrc = Position.SRC(mvLast);
			sqDst = Position.DST(mvLast);
			drawSquare(g, imgSelected, sqSrc);
			drawSquare(g, imgSelected, sqDst);
		} else if (sqSelected > 0) {
			drawSquare(g, imgSelected, sqSelected);
		}
		int sq = Position.COORD_XY(cursorX + Position.FILE_LEFT, cursorY + Position.RANK_TOP);
		if (midlet.flipped) {
			sq = Position.SQUARE_FLIP(sq);
		}
		drawSquare(g, imgCursor, sq);
		if (phase == PHASE_THINKING) {
			int x, y;
			if (midlet.flipped) {
				x = (Position.FILE_X(sqDst) < 8 ? left : right);
				y = (Position.RANK_Y(sqDst) < 4 ? top : bottom);
			} else {
				x = (Position.FILE_X(sqDst) < 8 ? right: left);
				y = (Position.RANK_Y(sqDst) < 4 ? bottom: top);
			}
			g.drawImage(imgThinking, x, y, Graphics.LEFT + Graphics.TOP);
		} else if (phase == PHASE_EXITTING) {
			g.setFont(fontLarge);
			g.setColor(0xff0000);
			g.drawString(message, width / 2, height / 2, Graphics.HCENTER + Graphics.BASELINE);
		}

		if (bCompatible) {
			g.setFont(fontSmall);
			g.setColor(0x0000ff);
			g.drawString("* - Back", 0, height, Graphics.LEFT + Graphics.BASELINE);
			g.drawString("0 - Retract", width / 2, height, Graphics.HCENTER + Graphics.BASELINE);
			g.drawString("# - About", width, height, Graphics.RIGHT + Graphics.BASELINE);
		}
	}

	protected void keyPressed(int code) {
		if (phase == PHASE_EXITTING) {
			midlet.startMusic("form");
			Display.getDisplay(midlet).setCurrent(midlet.form);
			return;
		}
		if (phase == PHASE_THINKING) {
			return;
		}

		if (bCompatible) {
			switch (code) {
			case KEY_STAR:
				back();
				return;
			case KEY_NUM0:
				retract();
				return;
			case KEY_POUND:
				about();
				return;
			}
		}

		int deltaX = 0, deltaY = 0;
		int action = getGameAction(code);
		if (action == FIRE || code == KEY_NUM5) {
			clickSquare();
		} else {
			switch (action) {
			case UP:
				deltaY = -1;
				break;
			case LEFT:
				deltaX = -1;
				break;
			case RIGHT:
				deltaX = 1;
				break;
			case DOWN:
				deltaY = 1;
				break;
			default:
				switch (code) {
				case KEY_NUM1:
					deltaX = -1;
					deltaY = -1;
					break;
				case KEY_NUM2:
					deltaY = -1;
					break;
				case KEY_NUM3:
					deltaX = 1;
					deltaY = -1;
					break;
				case KEY_NUM4:
					deltaX = -1;
					break;
				case KEY_NUM6:
					deltaX = 1;
					break;
				case KEY_NUM7:
					deltaX = -1;
					deltaY = 1;
					break;
				case KEY_NUM8:
					deltaY = 1;
					break;
				case KEY_NUM9:
					deltaX = 1;
					deltaY = 1;
					break;
				}
			}
			cursorX = (cursorX + deltaX + 8) % 8;
			cursorY = (cursorY + deltaY + 8) % 8;
		}
		repaint();
		serviceRepaints();
	}

	protected void pointerPressed(int x, int y) {
		if (phase == PHASE_EXITTING) {
			midlet.startMusic("form");
			Display.getDisplay(midlet).setCurrent(midlet.form);
			return;
		}
		if (phase == PHASE_THINKING) {
			return;
		}
		if (bCompatible && height - y < fontSmall.getHeight()) {
			switch (x * 3 / width) {
			case 0:
				back();
				return;
			case 1:
				retract();
				return;
			case 2:
				about();
				return;
			}
		}
		cursorX = Util.MIN_MAX(0, (x - left) / squareSize, 7);
		cursorY = Util.MIN_MAX(0, (y - top) / squareSize, 7);
		clickSquare();
		repaint();
		serviceRepaints();
	}

	private void clickSquare() {
		int sq = Position.COORD_XY(cursorX + Position.FILE_LEFT, cursorY + Position.RANK_TOP);
		if (midlet.flipped) {
			sq = Position.SQUARE_FLIP(sq);
		}
		int pc = pos.squares[sq];
		if ((pc & Position.SIDE_TAG(pos.sdPlayer)) != 0) {
			midlet.playSound(RESP_CLICK);
			mvLast = 0;
			sqSelected = sq;
		} else {
			if (sqSelected > 0 && addMove(Position.MOVE(sqSelected, sq)) && !responseMove()) {
				midlet.rsData[0] = 0;
				phase = PHASE_EXITTING;
			}
		}
	}

	private void drawSquare(Graphics g, Image image, int sq) {
		int sqFlipped = (midlet.flipped ? Position.SQUARE_FLIP(sq) : sq);
		int sqX = left + (Position.FILE_X(sqFlipped) - Position.FILE_LEFT) * squareSize;
		int sqY = top + (Position.RANK_Y(sqFlipped) - Position.RANK_TOP) * squareSize;
		g.drawImage(image, sqX, sqY, Graphics.LEFT + Graphics.TOP);
	}

	/** Player Move Result */
	private boolean getResult() {
		return getResult(-1);
	}

	/** Computer Move Result */
	private boolean getResult(int response) {
		if (pos.isMate()) {
			if (pos.inCheck()) {
				midlet.playSound(response < 0 ? RESP_WIN : RESP_LOSS);
				message = (response < 0 ? "You Win!" : "You Lose!");
			} else {
				midlet.playSound(RESP_DRAW);
				message = "Draw by Stalemate!";
			}
			return true;
		}
		if (pos.isRep(2)) {
			midlet.playSound(RESP_DRAW);
			message = "Draw by Repetition!";
			return true;
		}
		if (pos.moveNum > 100) {
			midlet.playSound(RESP_DRAW);
			message = "Draw by 50-Move Rule!";
			return true;
		}
		if (response >= 0) {
			midlet.playSound(response);
			// Backup Retract Status
			System.arraycopy(midlet.rsData, 0, retractData, 0, ChessMIDlet.RS_DATA_LEN);
			// Backup Record-Score Data
			midlet.rsData[0] = 1;
			System.arraycopy(pos.squares, 0, midlet.rsData, 256, 128);
			midlet.rsData[384] = (byte) pos.castlingBits();
			midlet.rsData[385] = (byte) pos.enPassantSquare();
		}
		return false;
	}

	private boolean addMove(int mv) {
		if (pos.legalMove(mv)) {
			int pcSrc = pos.squares[Position.SRC(mv)];
			if (pos.makeMove(mv)) {
				midlet.playSound(pos.inCheck() ? RESP_CHECK : pos.specialMove() ?
						RESP_SPECIAL : pos.captured() ? RESP_CAPTURE : RESP_MOVE);
				if (pos.captured() || Position.PIECE_TYPE(pcSrc) == Position.PIECE_PAWN) {
					pos.setIrrev();
				}
				sqSelected = 0;
				mvLast = mv;
				return true;
			}
			midlet.playSound(RESP_ILLEGAL);
		}
		return false;
	}

	boolean responseMove() {
		if (getResult()) {
			return false;
		}
		phase = PHASE_THINKING;
		repaint();
		serviceRepaints();
		mvLast = search.searchMain(1000 << (midlet.level << 1));
		int pc = pos.squares[Position.SRC(mvLast)];
		pos.makeMove(mvLast);
		int response = pos.inCheck() ? RESP_CHECK2 : pos.specialMove() ?
				RESP_SPECIAL2 : pos.captured() ? RESP_CAPTURE2 : RESP_MOVE2;
		if (pos.captured() || Position.PIECE_TYPE(pc) == Position.PIECE_PAWN) {
			pos.setIrrev();
		}
		phase = PHASE_WAITING;
		repaint();
		serviceRepaints();
		return !getResult(response);
	}

	void back() {
		midlet.rsData[0] = 0;
		midlet.startMusic("form");
		Display.getDisplay(midlet).setCurrent(midlet.form);
	}

	void retract() {
		// Restore Retract Status
		System.arraycopy(retractData, 0, midlet.rsData, 0, ChessMIDlet.RS_DATA_LEN);
		load();
		repaint();
		serviceRepaints();
	}

	void about() {
		Display.getDisplay(midlet).setCurrent(altAbout);
		phase = PHASE_LOADING;
		setFullScreenMode(true);
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -