採用 MVC 架構,核心類別職責分工:
| 類別 | 職責 |
|---|---|
| ChineseChess | 主視窗、選單管理、模式切換(對戰/製作/演示) |
| ChessBoard | 棋盤繪製、棋子佈局、滑鼠事件處理、走法驗證委派 |
| ChessPiece | 棋子視覺呈現(名稱、顏色、圖片繪製) |
| ChessPoint | 棋盤座標點封裝(位置、是否有子、棋子引用) |
| Rule | 各棋子走法規則封裝(車、馬、象/相、士/仕、帥/將、炮、兵/卒) |
| MakeChessManual | 棋譜記錄、顯示、悔棋功能 |
| Demon | 棋譜演示控制(單步、自動播放、速度控制、重播) |
| MoveStep | 單步移動資料封裝(可序列化) |
// ChessBoard 建構子片段
public ChessBoard(int w, int h, int r, int c) {
// 初始化 9x10 棋盤座標點
point = new ChessPoint[r + 1][c + 1];
for (int i = 1; i <= r; i++) {
for (int j = 1; j <= c; j++) {
point[i][j] = new ChessPoint(i * w, j * h, false);
}
}
// 建立 32 個棋子實例並放置初始位置
// 紅方:車馬相仕帥仕相馬車、炮、兵...
// 黑方:車馬象士將士象馬車、炮、卒...
point[1][10].setPiece(紅車1, this);
point[2][10].setPiece(紅馬1, this);
// ... 其餘初始化
}
// ChessBoard.mouseDragged
public void mouseDragged(MouseEvent e) {
ChessPiece piece = (ChessPiece) e.getSource();
e = SwingUtilities.convertMouseEvent(piece, e, this); // 轉換座標系
if (move && piece != null) {
x = e.getX(); y = e.getY();
// 僅允許當前回合方移動自已棋子
if (紅方走棋 && piece.棋子種類().equals(紅方顏色)) {
piece.setLocation(x - w/2, y - h/2);
}
}
}
// ChessBoard.mouseReleased 核心邏輯
boolean ok = rule.movePieceRule(piece, startI, startJ, m, n);
if (ok) {
// 處理吃子、更新棋盤狀態、記錄棋譜、切換回合
record.記錄棋譜(piece, startI, startJ, m, n);
rule.isWin(pieceRemoved); // 判斷勝負
}
// Rule.movePieceRule 片段
else if (piece.getName().equals("馬")) {
int xAxle = Math.abs(startI - endI);
int yAxle = Math.abs(startJ - endJ);
if (xAxle == 2 && yAxle == 1) { // 豎向走二橫向走一
if (endI > startI) { // 向下
能否走棋 = !point[startI + 1][startJ].isPiece(); // 檢查蹩馬腿
} else { // 向上
能否走棋 = !point[startI - 1][startJ].isPiece();
}
} else if (xAxle == 1 && yAxle == 2) { // 橫向走二豎向走一
if (endJ > startJ) { // 向右
能否走棋 = !point[startI][startJ + 1].isPiece();
} else { // 向左
能否走棋 = !point[startI][startJ - 1].isPiece();
}
}
}
// ChineseChess.actionPerformed 存檔片段
if (e.getSource() == 保存棋譜) {
int state = fileChooser.showSaveDialog(null);
if (state == JFileChooser.APPROVE_OPTION) {
File saveFile = fileChooser.getSelectedFile();
try (ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream(saveFile))) {
out.writeObject(record.獲得棋譜()); // LinkedList
}
}
}
// Demon.run 自動播放執行緒
public synchronized void run() {
for (index = 0; index < 棋譜.size(); index++) {
try { Thread.sleep(time); } catch (InterruptedException e) {}
while (演示狀態.equals("暫停演示")) { wait(); }
演示一步(index);
}
演示停止("棋譜演示結束");
}
MouseListener 處理點擊/釋放,MouseMotionListener 處理拖拽/移動預覽SwingUtilities.convertMouseEvent 解決棋子元件座標與棋盤座標系不一致問題Rule 類封裝所有走法邏輯,棋盤僅委派驗證,符合單一職責LinkedList 記錄每步起訖座標,配合被吃棋子資訊支援悔棋/演示MoveStep 實作 Serializable,利用 Java 原生序列化實現棋譜檔案 IO