棋盘的表示
转载请保留作者信息:
作者:88250
Blog:http:/blog.csdn.net/DL88250
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就是红车)。
要移动棋子的化只需如下操作:
/**
* Move a chessman to destination. If the point at
* (<code>fromX</code>, <code>fromY</code>) has no any chessman, do nothing.
* There is three condition when we makeMove a chessman:
* @param fromX x coordinate of which chessman do this move
* @param fromY y coordinate of which chessman do this move
* @param toX x coordinate of which chessman's destination
* @param toY y coordinate of which chessman's destination
* @return <ul>
* <li>if the (<code>fromY</code>, <code>fromY</code>) has no chessman or
* the move is invalid, returns <code>Constants.MOVE_INVALID</code>,
* value of it equals to -100</li>
* <li>if move successfully, returns the destination ID. the ID maybe
* a chessman ID(be eaten) or 0(empty chessboard grid)</li>
* </ul>
*/
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:
/**
* Undo the latest motion.
*/
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这个类是用于描述最近一次移动棋子的信息:
/*
* @(#)LatestMotion.java
* Author: 88250 <[email protected]>, http://blog.csdn.net/DL88250
* Created on May 24, 2008, 5:03:23 PM
*
* 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 3 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package cn.edu.ynu.sei.chinesechess.infrastructure.common;
/**
* A chessman's latest motion.
* @author 88250 <[email protected]>, http://blog.csdn.net/DL88250
* @version 1.1.0.0, May 28, 2008
*/
final public class LatestMotion {
/**
* who do this motion
*/
public int who;
/**
* x coordinate of chessman' location
*/
public int fromX;
/**
* y coordinate of chessman' location
*/
public int fromY;
/**
* x coordinate of chessman's destination
*/
public int toX;
/**
* y coordinate of chessman's destination
*/
public int toY;
/**
* the chessman killed other chessman
*/
public int killed;
/**
* is red's turn?
*/
public boolean isRedGo;
/**
* Constructor with parameters.
* @param who who do the motion
* @param fromX x coordinate of chessman's location
* @param fromY y coordinate of chessman's location
* @param toX x coordinate of chessman's destination
* @param toY y coordinate of chessman's destination
* @param killed the chessman killed other chessman
* @param isRedGo is red's turn?
*/
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的“插入代码”功能坏了- -#)