上一节写到,能够走棋了,只是没有规则,随便怎么走都可以。今天,就来制定规则。
在走棋之前需要判断是否可以走。所以必须有个函数来判断是否可以走棋,这个判断函数需要的参数是走的哪颗棋子,走到哪里去,是否吃棋。
bool canMove(int moveid,int row,int col,int killid);
实现该函数。
1、如果选择的颜色和要吃的颜色是一样的,也可以形容点错了,想换个要走的棋子。
if(_s[moveid]._red == _s[killid]._red) //颜色一样
{
//换选择
_selectid=killid;
update();
return false;
}
return true;
2、实现每个不同类型棋子的规则
将问题简单化,划分几个小问题来解决。
switch (_s[moveid]._type)
{
case Stone::CHE:
return canMoveChe(moveid, killid, row, col);
case Stone::MA:
return canMoveMa(moveid, killid, row, col);
case Stone::PAO:
return canMovePao(moveid, killid, row, col);
case Stone::BING:
return canMoveBing(moveid, killid, row, col);
case Stone::JIANG:
return canMoveJiang(moveid, killid, row, col);
case Stone::SHI:
return canMoveShi(moveid, killid, row, col);
case Stone::XIANG:
return canMoveXiang(moveid, killid, row, col);
}
函数一:将
现在依次实现每个函数,函数1,是关于将的实现方法。1、首先目标位置在九宫内,2、移动的步长是一个格子。
bool Board::canMoveJiang(int moveid, int killid, int row, int col)
{
if(killid != -1 && _s[killid]._type == Stone::JIANG)
return canMoveChe(moveid, killid, row, col);
GetRowCol(row1, col1, moveid);
int r = relation(row1, col1, row, col);
if(r != 1 && r != 10) return false;
if(col < 3 || col > 5) return false;
if(isBottomSide(moveid))
{
if(row < 7) return false;
}
else
{
if(row > 2) return false;
}
return true;
}
把计算距离的公式写成了一个函数,这样不用每次都次都写一遍了。
int Board::relation(int row1, int col1, int row, int col)
{
return qAbs(row1-row)*10+qAbs(col1-col);
}
还有一个关键,就是判断方向,也就是红棋黑棋。走的坐标也是不一样的。
bool Board::isBottomSide(int id)
{
return _bSide == _s[id]._red;
}
函数二:士
士的也只是在九宫格内走动,而且只能走对角线。 代码前半部分一样,只是计算公式d时的值不一样。
bool Board::canMoveShi(int moveid, int, int row, int col)
{
GetRowCol(row1, col1, moveid);
int r = relation(row1, col1, row, col);
if(r != 11) return false;
if(col < 3 || col > 5) return false;
if(isBottomSide(moveid))
{
if(row < 7) return false;
}
else
{
if(row > 2) return false;
}
return true;
}
函数3:象
象,计算的d值是22。还要找到象眼,也就是象走的位置。象的killid用不到,就不用了,但是不要这个参数就会报错,就可以直接写上int就行,在c++中这个叫哑元。
函数GetRowCol()是将行和列取出来。
#define GetRowCol(__row, __col, __id) \
int __row = _s[__id]._row;\
int __col = _s[__id]._col
bool Board::canMoveXiang(int moveid, int, int row, int col)
{
GetRowCol(row1, col1, moveid);
int r = relation(row1, col1, row, col);
if(r != 22) return false;
int rEye = (row+row1)/2;
int cEye = (col+col1)/2;
if(getStoneId(rEye, cEye) != -1)
return false;
if(isBottomSide(moveid))
{
if(row < 4) return false;
}
else
{
if(row > 5) return false;
}
return true;
}
函数getStoneId(),是用来判断该点是否有棋子,如果没有就返回-1,如果由就返回该棋子的id。
int Board::getStoneId(int row, int col)
{
for(int i=0; i<32; ++i)
{
if(_s[i]._row == row && _s[i]._col == col && !isDead(i))
return i;
}
return -1;
}
函数四:车
车和炮都是走直线的,所以用一个函数来判断是否走的是直线。
bool Board::canMoveChe(int moveid, int, int row, int col)
{
GetRowCol(row1, col1, moveid);
int ret = getStoneCountAtLine(row1, col1, row, col);
if(ret == 0)
return true;
return false;
}
判断是否直线。返回-1不再一条直线,如果在直线上则返回这条直线有多少条棋子。
int Board::getStoneCountAtLine(int row1, int col1, int row2, int col2)
{
int ret = 0;
if(row1 != row2 && col1 != col2)
return -1;
if(row1 == row2 && col1 == col2)
return -1;
if(row1 == row2)
{
int min = col1 < col2 ? col1 : col2;
int max = col1 < col2 ? col2 : col1;
for(int col = min+1; col<max; ++col)
{
if(getStoneId(row1, col) != -1) ++ret;
}
}
else
{
int min = row1 < row2 ? row1 : row2;
int max = row1 < row2 ? row2 : row1;
for(int row = min+1; row<max; ++row)
{
if(getStoneId(row, col1) != -1) ++ret;
}
}
return ret;
}
函数五:马
bool Board::canMoveMa(int moveid, int, int row, int col)
{
GetRowCol(row1, col1, moveid);
int r = relation(row1, col1, row, col);
if(r != 12 && r != 21)
return false;
if(r == 12)
{
if(getStoneId(row1, (col+col1)/2) != -1)
return false;
}
else
{
if(getStoneId((row+row1)/2, col1) != -1)
return false;
}
return true;
}
函数六:炮
bool Board::canMovePao(int moveid, int killid, int row, int col)
{
GetRowCol(row1, col1, moveid);
int ret = getStoneCountAtLine(row, col, row1, col1);
if(killid != -1)
{
if(ret == 1) return true;
}
else
{
if(ret == 0) return true;
}
return false;
}
函数七:兵
这个比较复杂一点,要判断是否过河,过河的兵走法不一样。
bool Board::canMoveBing(int moveid, int, int row, int col)
{
GetRowCol(row1, col1, moveid);
int r = relation(row1, col1, row, col);
if(r != 1 && r != 10) return false;
if(isBottomSide(moveid))
{
if(row > row1) return false;
if(row1 >= 5 && row == row1) return false;
}
else
{
if(row < row1) return false;
if(row1 <= 4 && row == row1) return false;
}
return true;
}