棋盤的表示
轉載請保留作者資訊:
作者:88250
MSN & Gmail & QQ:[email protected]
在象棋博弈程式中,首先我們要确定下棋盤-棋子的資料結構描述。
目前,主要有兩種棋盤-棋子(以下稱之為“局面”, situation)表示法,一種是“棋盤數組”,另一種是“位棋盤”。
由于位棋盤最初是國際象棋(8*8, 剛好64bits)裡引入的,而中國象棋是9*10的棋盤,不易用位棋盤表示。但是,位棋盤最大的優點就是奇高的運算效率與空間節省。是以,多數參加博弈比賽或是商業博弈軟體都是用位棋盤作為基本的資料結構的。
本文以棋盤數組表示法表示一個局面,因為這樣便于閱讀代碼的人了解。這裡,我們要做一個決定:是否使用object-oriented的開發。
使用面向對象開發,棋子可以從抽象到具體,各種搜尋算法與控制可以使用一些設計模式獲得很好的代碼可讀性與易修改性。但是,博弈程式的核心是要高效,對象技術給我們帶來的優點的代價就是性能問題(我曾經嘗試過用很面向對象的觀點寫這個程式,效率很低下)。是以,我們應該以面向過程的方式開發這個象棋程式(Java寫過程化代碼,貌似有點不倫不類- -!)。
作出決定後,棋盤可以表示如下:
chessboard = new int[][]{
{1, 0, 0, 4, 0, 0, 11, 0, 0, 8},
{2, 0, 3, 0, 0, 0, 0, 10, 0, 9},
{5, 0, 0, 4, 0, 0, 11, 0, 0, 12},
{6, 0, 0, 0, 0, 0, 0, 0, 0, 13},
{7, 0, 0, 4, 0, 0, 11, 0, 0, 14},
{6, 0, 0, 0, 0, 0, 0, 0, 0, 13},
{5, 0, 0, 4, 0, 0, 11, 0, 0, 12},
{2, 0, 3, 0, 0, 0, 0, 10, 0, 9},
{1, 0, 0, 4, 0, 0, 11, 0, 0, 8},
};
其中,0表示無子,1~14分别代表了一種棋子。
這裡,沒有使用Java的enum類型,主要是當心性能的問題(JDK1.5後的enum也很面向對象的,呵呵)。而且,以常量代替枚舉我認為并不會給了解程式帶來太大的障礙(1就是紅車)。
要移動棋子的化隻需如下操作:
final public int makeMove(int fromX, int fromY, int toX, int toY) {
int chessman = chessboard[fromX][fromY];
if (chessman == 0) {
// invalid move
return -100;
}
if (isValidMove(fromX, fromY, toX, toY)) {
// backup motion
int latestBeEaten = chessboard[toX][toY];
latestMotions.push(new LatestMotion(chessman,
fromX, fromY,
toX, toY,
latestBeEaten,
isRedGo));
// move
chessboard[fromX][fromY] = 0;
chessboard[toX][toY] = chessman;
isRedGo = !isRedGo;
return latestBeEaten;
} else {
// invalid move
return -100;
}
}這個方法裡有一個重要的方法:isValidMove,用于判斷一次移動是否合法。還有一個曆史招法記錄stack,用于unMove:
final public void unMove() {
LatestMotion latestMotion = latestMotions.pop();
// recovery move
chessboard[latestMotion.fromX][latestMotion.fromY] = latestMotion.who;
// recovery eaten
chessboard[latestMotion.toX][latestMotion.toY] = latestMotion.killed;
// recovery who's go
isRedGo = latestMotion.isRedGo;
}LatestMotion這個類是用于描述最近一次移動棋子的資訊:
package cn.edu.ynu.sei.chinesechess.infrastructure.common;
final public class LatestMotion {
public int who;
public int fromX;
public int fromY;
public int toX;
public int toY;
public int killed;
public boolean isRedGo;
public LatestMotion(int who, int fromX, int fromY, int toX, int toY, int killed,
boolean isRedGo) {
this.who = who;
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
this.killed = killed;
this.isRedGo = isRedGo;
}
}至此,我們基本已經可以使用這個棋盤進行中國象棋的博弈了 : )
(郁悶。。。。Blog的“插入代碼”功能壞了- -#)