# 着法合法性判断

MSN & Gmail & QQDL88250@gmail.com

/**
* This method be used to determine the specified move is valid or not.
* Firstly, let's glance at the <em>Chinese chess move rules</em>:
* <p>
* <h2>Jiang</h2>
* <ol>
* <li>
* it can only move straight, the distance of one
* motion must equals to 1
* </li>
* <li>
* it can only move within the "Base".
* </li>
* <li>
* it can eat opponent's Jiang while nothing between them,
* and the "eatways" must be a line.
* </li>
* </ol>
* </p>
* <p>
* <h2>Shi</h2>
* <ol>
* <li>
* it can only move to catercorner point of a square,
* that square's width equals to 1
* </li>
* <li>
* it can only move within the "Base". Refers to
* </li>
* </ol>
* </p>
* <p>
* <h2>Xiang</h2>
* <ol>
* <li>
* it can only move to catercorner point of a rectangle,
* that square's width equals to 2
* </li>
* <li>
* the aspect of this motion must has no chessman on the center of
* the square, no matter ours nor opponent's。The following example
* is invalid:<br>
* #---------<br>
* |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br>
* ----<b>&nbsp;&nbsp;X&nbsp;----</b><br>
* |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br>
* ---------Xiang
* </li>
* <li>
* a xiang can't move beyond our "He Jie"
* </li>
* </ol>
* </p>
* <p>
* <h2>Ma</h2>
* <ol>
* <li>
* it can only move to catercorner point of a rectangle,
* that rectangle's width equals to 1, and height equals to
* 2
* </li>
* <li>
* the aspect(the longger distance direction) of this motion
* must has no chessman , no matter ours nor opponent's。The
* following example is invalid:<br>
* #----<br>
* |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br>
* -----<b>X</b><br>
* |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br>
* -----Ma
* </li>
* </ol>
* </p>
* <p>
* <h2>Che</h2>
* <ol>
* <li>it can only move straight</li>
* </ol>
* </p>
* <p>
* <h2>Pao</h2>
* <ol>
* <li>
* it can only move straight
* </li>
* <li>
* it can eat opponent chessman between a chessman along a line,
* like this:<br>
* Pao----#------OpponentChessMan<br>
* <b>NOTE:</b> the motion only occur when eating
* </li>
* </ol>
* </p>
* <p>
* <h2>Bing</h2>
* <ol>
* <li>it can move forward, no backward</li>
* <li>only when it passed the "Chu He Hang Jie",
* it can turn left/right forward</li>
* <li>motion distance equals 1</li>
* </ol>
* </p>
* @param fromX x coordinate of a motion's start
* @param fromY y coordinate of a motion's start
* @param toX x coordinate of a motion's destination
* @param toY y coordinate of a motion's destination
* @return if is valid, returns <code>true</code>, otherwise,
* returns <code>false</code>
*/
final public boolean isValidMove(int fromX, int fromY, int toX, int toY) {
if (basicMoveIsValid(fromX, fromY, toX, toY)) {
int moveId = chessboard[fromX][fromY];
int targetId = chessboard[toX][toY];

switch (moveId) {
case 7:
//<editor-fold defaultstate="collapsed" desc="Hong Jiang">
if (toX < 3 || toX > 5) {
// violate the first rule
return false;
}

if (targetId == 14) {
int pivotCount = calcChessmanCountAlongLine(fromX, fromY,
toX, toY);
if (pivotCount == 0) {
// the thrid rule
return true;
}
}

if (toY > 2) {
// violate the first rule
return false;
}

if (distanceSq(fromX, fromY, toX, toY) != 1) {
// violate the first rule
return false;
}
//</editor-fold>
break;
case 14:
//<editor-fold defaultstate="collapsed" desc="Hei Jiang">
if (toX < 3 || toX > 5) {
// violate the first rule
return false;
}

if (targetId == 7) {
int pivotCount = calcChessmanCountAlongLine(fromX, fromY,
toX, toY);
if (pivotCount == 0) {
// the thrid rule
return true;
}
}

if (toY < 7) {
// violate the first rule
return false;
}

if (distanceSq(fromX, fromY, toX, toY) != 1) {
// violate the first rule
return false;
}
//</editor-fold>
break;
case 6:
//<editor-fold defaultstate="collapsed" desc="Hong Shi">
if (toX < 3 || toX > 5 || toY > 3) {
// violate the first rule
return false;
}

if (distanceSq(fromX, fromY, toX, toY) != 2) {
// violate the first rule
return false;
}
//</editor-fold>
break;
case 13:
//<editor-fold defaultstate="collapsed" desc="Hei Shi">
if (toX < 3 || toX > 5 || toY < 8) {
// violate the first rule
return false;
}

if (distanceSq(fromX, fromY, toX, toY) != 2) {
// violate the first rule
return false;
}

//</editor-fold>
break;
case 5:
//<editor-fold defaultstate="collapsed" desc="Hong Xiang">
if (toY > 4) {
return false;
}

if (distanceSq(fromX, fromY, toX, toY) != 8) {
// violate the first rule
return false;
}

if (chessboard[(fromX + toX) / 2][(fromY + toY) / 2] != 0) {
// can't move widthways, violates the second rule
return false;
}
//</editor-fold>
break;
case 12:
//<editor-fold defaultstate="collapsed" desc=" Hei Xiang">
if (toY < 6) {
return false;
}

if (distanceSq(fromX, fromY, toX, toY) != 8) {
// violate the first rule
return false;
}

if (chessboard[(fromX + toX) / 2][(fromY + toY) / 2] != 0) {
// can't move widthways, violates the second rule
return false;
}
//</editor-fold>
break;
case 2:
case 9:
//<editor-fold defaultstate="collapsed" desc="Ma">
if (distanceSq(fromX, fromY, toX, toY) != 5) {
// violate the first rule
return false;
}

if (chessboard[(fromX + toX) / 2][fromY] != 0 &&
abs(fromY - toY) == 1) {
// can't move widthways, violates the second rule
return false;
}

if (chessboard[fromX][(fromY + toY) / 2] != 0 &&
abs(fromX - toX) == 1) {
// can't move lengthways violates the second rule
return false;
}
//</editor-fold>
break;
case 1:
case 8:
//<editor-fold defaultstate="collapsed" desc="Che">
if (fromX != toX && fromY != toY) {
// must move straight
return false;
}

int pivotCount = calcChessmanCountAlongLine(fromX, fromY,
toX, toY);
// move eat motion!
if (pivotCount != 0) {
return false;
}
//</editor-fold>
break;
case 3:
case 10:
//<editor-fold defaultstate="collapsed" desc="Pao">
if (fromX != toX && fromY != toY) {
// must move straight, violates the first rule
return false;
}

pivotCount = calcChessmanCountAlongLine(fromX, fromY,
toX, toY);

if (targetId != 0) {
// move eat motion!
if (pivotCount != 1) {
return false;
}
} else {
if (pivotCount != 0) {
return false;
}
}
//</editor-fold>
break;
case 4:
case 11:
//<editor-fold defaultstate="collapsed" desc="Bing">
if (fromX != toX && fromY != toY) {
// must move straight
return false;
}

if (distanceSq(fromX, fromY, toX, toY) != 1) {
// move forware ONLY ONE step
return false;
}

if (isBlack(moveId)) {
if (fromY > 4 && fromX != toX) {
// has nor yet passed the "He Jie"
// cannot turn left/right
return false;
}
if (fromY < toY) {
// "Bing" cannot backward!
return false;
}
} else {
if (fromY < 5 && fromX != toX) {
// has nor yet passed the "He Jie"
// cannot turn left/right
return false;
}
if (fromY > toY && fromX == toX) {
// "Bing" cannot backward!
return false;
}
}
//</editor-fold>
break;
}
} else {
return false;
}

return true;
}