[转载] 中国象棋软件-引擎实现(三)着法生成
我們的程序需要讓電腦能夠在輪到它走子的時候執行一個它認為對它最有利的著法,那前提就是它要有諸多(也可能是唯一)可供選擇的著法,提供所有可選著法的“清單”就是我們的著法生成器所要完成的。之后用搜索函數來搜索“清單”,并用局面評估函數來逐一打分,最后就可以選擇“最佳”著法并實施了。
在著法生成器中,我采用的基本思想就是遍歷整個棋盤(一個接一個地看棋盤上的每個位置點),當發現有當前下棋方的棋子時就根據它是何種棋子而相應地找出其所有合法著法,然后存入著法隊列。
這里談到的“合法著法”包括以下幾點:
1、各棋子按其行子規則行子。諸如馬跳“日”字、象走“田”字、士在九宮內斜行等等(這里需要特別注意的是卒的行子規則隨其所在位置不同而會發生變化——過河后可以左右平移)。
2、行子不能越出棋盤界限。當然所有子都不能走到棋盤的外面,同時某些特定的子還有自己的行棋界限,如將、士不能出九宮,象不能過河。
3、行子的半路上不能有子阻攔(除了炮隔子打子之外)以及行子的目的點不能有本方棋子(當然不能自己吃自己了)。
4、將帥不能碰面(本程序中只認為將帥碰面是非法的,而其它“送死”的著法并不非法,只是產生敗局罷了)
產生了著法后要將其存入著法隊列以供搜索之用,由于搜索會搜索多層(即考慮雙方你來我往好幾步,這樣才有利于對局面進行評估而盡可能避免“目光短淺”
),所以在存著法隊列的時候還要同時存儲該著法所屬的搜索層數。因此我將著法隊列定義為二維數組MoveList[12][80],第一個下標為層數,第二個下標為每一層的全部著法數。
關于搜索層數,考慮到當前大多數機器的配置以及層數對電腦水平的影響我給數組下標設定為12,實際使用的是1到11(搜索層數的增加會顯著提高電腦的下棋水平。但有關實驗數據表明,當搜索層數大于8、9之后電腦下棋水平將主要依賴于局面評估部分。我的迅馳1.5,736M內存的筆記本只能搜索5層,再多將導致搜索時間達到無法容忍的地步,而我們指導老師的雙CPU的機器搜索到11層也很輕松)。
而對每一層的著法數,也就是當前下棋方針對某一局面的所有合法著法,在象棋實戰中一般最多也就五六十種。定義第二個數組下標為80,基本上可以保證安全。
下面是CChessMove.h的代碼。其中CCHESSMOVE類型和POINT類型分別是在前面一篇CChessDef.h中定義的走法的結構體以及棋盤上的點的結構體。
在GenerateMove函數中存在著較大范圍的代碼冗余,像
//==========生成紅車的著法 case RED_J: …… break; //==========生成黑車的著法 case BLACK_J: …… break;
之類的代碼段完全可以并到一起寫成
//==========生成車的著法 case RED_J: // fall through case BLACK_J: …… break;
的形式,之所以分開寫是由我最初的設計思想導致的(我原本計劃不遍歷棋盤而是遍歷所有棋子,后來發現這樣做得不償失所以又中途改成遍歷棋盤了)。而當最初的方案被否決并修改后,我覺得既然已經分開寫了,這樣也不會影響最后程序的執行效率,結合注釋分開寫反而讀起來更加清楚,所以也就沒改。由此導致的代碼冗余,如果哪位朋友看了覺得不爽,還望海涵 : )
// CChessMove.h
#include "CChessDef.h"
/////////////////// Data Define ///////////////////////////////////////////////
CCHESSMOVE MoveList[12][80] ; // 存儲產生的著法隊列
int nMoveCount ; // 存儲當前搜索深度已產生的著法數
/////////////////// Function Prototype ////////////////////////////////////////
// 判斷ptPosition處是否有同一方的子,若有返回true,否則返回false
inline bool HaveFriend( POINT ptPosition, int fSide );
// 判斷 x, y 處是否有同一方的子,若有返回true,否則返回false
inline bool HaveFriend( BYTE x, BYTE y, int fSide );
// 判斷ptPosition處是否有子,若有返回true,否則返回false
inline bool HaveMan( POINT ptPosition );
// 判斷 x, y 處是否有子,若有返回true,否則返回false
inline bool HaveMan( BYTE x, BYTE y );
// 檢查將帥是否碰面,若碰面返回對方王的 y 值坐標,不碰面則返回-1。
// 其中x, y分別為當前走棋方的王所在位置坐標,fSide為當前走棋方
int IsKingFaceToFace( int x, int y, int fSide );
// 產生fSide方所有著法,返回產生的著法總數。nDepth為當前搜索深度,
//用于傳給AddMoveToQueue函數
int GenerateMove( int fSide, int nDepth );
// 將產生的著法加入著法隊列。nDepth為當前搜索深度
inline void AddMoveToQueue( POINT ptFrom, POINT ptTo, int nDepth );
// 將產生的著法加入著法隊列。nDepth為當前搜索深度
inline void AddMoveToQueue( POINT ptFrom, BYTE x, BYTE y, int nDepth );
////////////////// Programmer-Defined Function ////////////////////////////////
inline bool HaveFriend( POINT ptPosition, int fSide )
{
if( CChessBoard[ptPosition.x][ptPosition.y] == 0 )
return false;
else if( SideOfMan[ CChessBoard[ptPosition.x][ptPosition.y] ] == fSide )
return true;
else
return false;
}
inline bool HaveFriend( BYTE x, BYTE y, int fSide )
{
if( CChessBoard[x][y] == 0 )
return false;
else if( SideOfMan[ CChessBoard[x][y] ] == fSide )
return true;
else
return false;
}
inline bool HaveMan( POINT ptPosition )
{
if( CChessBoard[ptPosition.x][ptPosition.y] == 0 )
return false;
else
return true;
}
inline bool HaveMan( BYTE x, BYTE y )
{
if( CChessBoard[x][y] == 0 )
return false;
else
return true;
}
int IsKingFaceToFace( int x, int y, int fSide )
{
bool bMayKingFaceToFace = false;
int i, j ;
if( fSide == RED )
{
for( i = 9; i >= 7; i -- ) // 檢查黑將是否在同列
{
if( CChessBoard[x][i] == BLACK_K )
{
bMayKingFaceToFace = true;
break;
}
}
if( bMayKingFaceToFace == false )
return -1;
for( j = y + 1; j <= i - 1 ; j ++ ) // 黑將在同列,檢查中間是否有隔擋
{
if( CChessBoard[x][j] != 0 ) // 有其他子
return -1;
}
return i; // 將帥碰面,返回黑將的 y 值坐標
}
else // fSide == BLACK
{
for( i = 0; i <= 2; i ++ ) // 檢查紅帥是否在同列
{
if( CChessBoard[x][i] == RED_K )
{
bMayKingFaceToFace = true;
break;
}
}
if( bMayKingFaceToFace == false )
return -1;
for( j = y - 1; j >= i + 1 ; j -- ) // 紅帥在同列,檢查中間是否有隔擋
{
if( CChessBoard[x][j] != 0 ) // 有其他子
return -1;
}
return i; // 將帥碰面,返回紅帥的 y 值坐標
}
}
int GenerateMove( int fSide, int nDepth )
{
BYTE nCChessID ;
POINT ptFrom , ptTo , ptHalf ;
int i;
nMoveCount = 0;
int x, y;
for( x = 0; x <= 8; x ++ )
for( y = 0; y <= 9; y ++ )
{
if( CChessBoard[x][y] != 0 )
{
nCChessID = CChessBoard[x][y];
if( SideOfMan[ nCChessID ] != fSide )//該子顏色與所要生成著法的顏色不同
continue;
ptFrom.x = x ;
ptFrom.y = y ;
switch( nCChessID )
{
//==========生成紅帥的著法
case RED_K:
// 將帥碰面
i = IsKingFaceToFace( ptFrom.x, ptFrom.y, fSide );
if( i != -1 )
AddMoveToQueue( ptFrom, ptFrom.x, i, nDepth );
//縱向
ptTo.x = ptFrom.x ;
//向前
ptTo.y = ptFrom.y + 1 ;
if(( ptTo.y <= 2 ) && ( ! HaveFriend( ptTo, fSide ) ))
AddMoveToQueue( ptFrom, ptTo, nDepth );
//向后
ptTo.y = ptFrom.y - 1 ;
if(( ptTo.y >= 0 ) && ( ! HaveFriend( ptTo, fSide ) ))
AddMoveToQueue( ptFrom, ptTo, nDepth );
//橫向
ptTo.y = ptFrom.y ;
//向左
ptTo.x = ptFrom.x - 1 ;
if(( ptTo.x >= 3 ) && ( ! HaveFriend( ptTo, fSide ) )
&& ( IsKingFaceToFace( ptTo.x, ptTo.y, fSide ) == -1 ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
//向右
ptTo.x = ptFrom.x + 1 ;
if(( ptTo.x <= 5 ) && ( ! HaveFriend( ptTo, fSide ) )
&& ( IsKingFaceToFace( ptTo.x, ptTo.y, fSide ) == -1 ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
//==========生成黑將的著法
case BLACK_K:
// 將帥碰面
i = IsKingFaceToFace( ptFrom.x, ptFrom.y, fSide );
if( i != -1 )
AddMoveToQueue( ptFrom, ptFrom.x, i, nDepth );
//縱向
ptTo.x = ptFrom.x ;
//向前
ptTo.y = ptFrom.y - 1 ;
if(( ptTo.y >= 7 ) && ( ! HaveFriend( ptTo, fSide ) ))
AddMoveToQueue( ptFrom, ptTo, nDepth );
//向后
ptTo.y = ptFrom.y + 1 ;
if(( ptTo.y <= 9 ) && ( ! HaveFriend( ptTo, fSide ) ))
AddMoveToQueue( ptFrom, ptTo, nDepth );
//橫向
ptTo.y = ptFrom.y ;
//向左
ptTo.x = ptFrom.x + 1 ;
if(( ptTo.x <= 5 ) && ( ! HaveFriend( ptTo, fSide ) )
&& ( IsKingFaceToFace( ptTo.x, ptTo.y, fSide ) == -1 ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
//向右
ptTo.x = ptFrom.x - 1 ;
if(( ptTo.x >= 3 ) && ( ! HaveFriend( ptTo, fSide ) )
&& ( IsKingFaceToFace( ptTo.x, ptTo.y, fSide ) == -1 ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
//==========生成紅車的著法
case RED_J:
//縱向
ptTo.x = ptFrom.x ;
//向前
for( ptTo.y = ptFrom.y + 1; ptTo.y <= 9; ptTo.y ++ )
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
//向后
for( ptTo.y = ptFrom.y - 1; ptTo.y >= 0; ptTo.y -- )
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
//橫向
ptTo.y = ptFrom.y ;
//向左
for( ptTo.x = ptFrom.x - 1; ptTo.x >= 0; ptTo.x -- )
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
//向右
for( ptTo.x = ptFrom.x + 1; ptTo.x <= 8; ptTo.x ++ )
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
break;
//==========生成黑車的著法
case BLACK_J:
//縱向
ptTo.x = ptFrom.x ;
//向前
for( ptTo.y = ptFrom.y - 1; ptTo.y >= 0; ptTo.y -- )
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
//向后
for( ptTo.y = ptFrom.y + 1; ptTo.y <= 9; ptTo.y ++ )
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
//橫向
ptTo.y = ptFrom.y ;
//向左
for( ptTo.x = ptFrom.x + 1; ptTo.x <= 8; ptTo.x ++ )
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
//向右
for( ptTo.x = ptFrom.x - 1; ptTo.x >= 0; ptTo.x -- )
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
break;
//==========生成紅馬的著法
case RED_M:
//ptHalf用來存儲馬腿的位置,以判斷該位置是否有子憋馬腿
ptHalf.x = ptFrom.x ;
ptHalf.y = ptFrom.y + 1 ;
if( ptHalf.y <= 8 && ! HaveMan( ptHalf ) )
{
//11點方向
ptTo.x = ptFrom.x - 1 ;
ptTo.y = ptFrom.y + 2 ;
if( ptTo.x >= 0 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
//1點方向
ptTo.x = ptFrom.x + 1 ;
ptTo.y = ptFrom.y + 2 ;
if( ptTo.x <= 8 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
ptHalf.x = ptFrom.x + 1 ;
ptHalf.y = ptFrom.y ;
if( ptHalf.x <= 7 && ! HaveMan( ptHalf ) )
{
//2點方向
ptTo.x = ptFrom.x + 2 ;
ptTo.y = ptFrom.y + 1 ;
if( ptTo.y <= 9 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
//4點方向
ptTo.x = ptFrom.x + 2 ;
ptTo.y = ptFrom.y - 1 ;
if( ptTo.y >= 0 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
ptHalf.x = ptFrom.x ;
ptHalf.y = ptFrom.y - 1 ;
if( ptHalf.y >= 1 && ! HaveMan( ptHalf ) )
{
//5點方向
ptTo.x = ptFrom.x + 1 ;
ptTo.y = ptFrom.y - 2 ;
if( ptTo.x <= 8 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
//7點方向
ptTo.x = ptFrom.x - 1 ;
ptTo.y = ptFrom.y - 2 ;
if( ptTo.x >= 0 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
ptHalf.x = ptFrom.x - 1 ;
ptHalf.y = ptFrom.y ;
if( ptHalf.x >= 1 && ! HaveMan( ptHalf ) )
{
//8點方向
ptTo.x = ptFrom.x - 2 ;
ptTo.y = ptFrom.y - 1 ;
if( ptTo.y >= 0 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
//10點方向
ptTo.x = ptFrom.x - 2 ;
ptTo.y = ptFrom.y + 1 ;
if( ptTo.y <= 9 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
break;
//==========生成黑馬的著法
case BLACK_M:
//ptHalf用來存儲馬腿的位置,以判斷該位置是否有子憋馬腿
ptHalf.x = ptFrom.x ;
ptHalf.y = ptFrom.y + 1 ;
if( ptHalf.y <= 8 && ! HaveMan( ptHalf ) )
{
//5點方向
ptTo.x = ptFrom.x - 1 ;
ptTo.y = ptFrom.y + 2 ;
if( ptTo.x >= 0 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
//7點方向
ptTo.x = ptFrom.x + 1 ;
ptTo.y = ptFrom.y + 2 ;
if( ptTo.x <= 8 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
ptHalf.x = ptFrom.x + 1 ;
ptHalf.y = ptFrom.y ;
if( ptHalf.x <= 7 && ! HaveMan( ptHalf ) )
{
//8點方向
ptTo.x = ptFrom.x + 2 ;
ptTo.y = ptFrom.y + 1 ;
if( ptTo.y <= 9 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
//10點方向
ptTo.x = ptFrom.x + 2 ;
ptTo.y = ptFrom.y - 1 ;
if( ptTo.y >= 0 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
ptHalf.x = ptFrom.x ;
ptHalf.y = ptFrom.y - 1 ;
if( ptHalf.y >= 1 && ! HaveMan( ptHalf ) )
{
//11點方向
ptTo.x = ptFrom.x + 1 ;
ptTo.y = ptFrom.y - 2 ;
if( ptTo.x <= 8 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
//1點方向
ptTo.x = ptFrom.x - 1 ;
ptTo.y = ptFrom.y - 2 ;
if( ptTo.x >= 0 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
ptHalf.x = ptFrom.x - 1 ;
ptHalf.y = ptFrom.y ;
if( ptHalf.x >= 1 && ! HaveMan( ptHalf ) )
{
//2點方向
ptTo.x = ptFrom.x - 2 ;
ptTo.y = ptFrom.y - 1 ;
if( ptTo.y >= 0 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
//4點方向
ptTo.x = ptFrom.x - 2 ;
ptTo.y = ptFrom.y + 1 ;
if( ptTo.y <= 9 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
break;
//==========生成紅炮的著法
case RED_P:
//ptHalf用來存儲炮是否有隔子打子的中間子
//縱向
ptTo.x = ptFrom.x ;
//向前
ptHalf.x = -1; //標志尚未發現中間子
for( ptTo.y = ptFrom.y + 1; ptTo.y <= 9; ptTo.y ++ )
{
if( ptHalf.x == -1 ) // 無中間子
{
if( ! HaveMan( ptTo ) )
{
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
else // if( HaveMan( ptTo ) )
{
ptHalf.x = ptTo.x ;
ptHalf.y = ptTo.y ;
}
}
else // 已有中間子
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
}
}
//向后
ptHalf.x = -1; //標志尚未發現中間子
for( ptTo.y = ptFrom.y - 1; ptTo.y >= 0; ptTo.y -- )
{
if( ptHalf.x == -1 ) // 無中間子
{
if( ! HaveMan( ptTo ) )
{
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
else // if( HaveMan( ptTo ) )
{
ptHalf.x = ptTo.x ;
ptHalf.y = ptTo.y ;
}
}
else // 已有中間子
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
}
}
//橫向
ptTo.y = ptFrom.y ;
//向左
ptHalf.x = -1; //標志尚未發現中間子
for( ptTo.x = ptFrom.x - 1; ptTo.x >= 0; ptTo.x -- )
{
if( ptHalf.x == -1 ) // 無中間子
{
if( ! HaveMan( ptTo ) )
{
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
else // if( HaveMan( ptTo ) )
{
ptHalf.x = ptTo.x ;
ptHalf.y = ptTo.y ;
}
}
else // 已有中間子
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
}
}
//向右
ptHalf.x = -1; //標志尚未發現中間子
for( ptTo.x = ptFrom.x + 1; ptTo.x <= 8; ptTo.x ++ )
{
if( ptHalf.x == -1 ) // 無中間子
{
if( ! HaveMan( ptTo ) )
{
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
else // if( HaveMan( ptTo ) )
{
ptHalf.x = ptTo.x ;
ptHalf.y = ptTo.y ;
}
}
else // 已有中間子
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
}
}
break;
//==========生成黑炮的著法
case BLACK_P:
//ptHalf用來存儲炮是否有隔子打子的中間子
//縱向
ptTo.x = ptFrom.x ;
//向后
ptHalf.x = -1; //標志尚未發現中間子
for( ptTo.y = ptFrom.y + 1; ptTo.y <= 9; ptTo.y ++ )
{
if( ptHalf.x == -1 ) // 無中間子
{
if( ! HaveMan( ptTo ) )
{
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
else // if( HaveMan( ptTo ) )
{
ptHalf.x = ptTo.x ;
ptHalf.y = ptTo.y ;
}
}
else // 已有中間子
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
}
}
//向前
ptHalf.x = -1; //標志尚未發現中間子
for( ptTo.y = ptFrom.y - 1; ptTo.y >= 0; ptTo.y -- )
{
if( ptHalf.x == -1 ) // 無中間子
{
if( ! HaveMan( ptTo ) )
{
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
else // if( HaveMan( ptTo ) )
{
ptHalf.x = ptTo.x ;
ptHalf.y = ptTo.y ;
}
}
else // 已有中間子
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
}
}
//橫向
ptTo.y = ptFrom.y ;
//向右
ptHalf.x = -1; //標志尚未發現中間子
for( ptTo.x = ptFrom.x - 1; ptTo.x >= 0; ptTo.x -- )
{
if( ptHalf.x == -1 ) // 無中間子
{
if( ! HaveMan( ptTo ) )
{
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
else // if( HaveMan( ptTo ) )
{
ptHalf.x = ptTo.x ;
ptHalf.y = ptTo.y ;
}
}
else // 已有中間子
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
}
}
//向左
ptHalf.x = -1; //標志尚未發現中間子
for( ptTo.x = ptFrom.x + 1; ptTo.x <= 8; ptTo.x ++ )
{
if( ptHalf.x == -1 ) // 無中間子
{
if( ! HaveMan( ptTo ) )
{
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
else // if( HaveMan( ptTo ) )
{
ptHalf.x = ptTo.x ;
ptHalf.y = ptTo.y ;
}
}
else // 已有中間子
{
if( HaveMan( ptTo ) )
{
if( ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
break;
}
}
}
break;
//==========生成紅相的著法
case RED_X:
if( ptFrom.x == 0 )
{
if( ! HaveFriend(2, 4, fSide) && ! HaveMan(1, 3) )
AddMoveToQueue( ptFrom, 2, 4, nDepth );
if( ! HaveFriend(2, 0, fSide) && ! HaveMan(1, 1) )
AddMoveToQueue( ptFrom, 2, 0, nDepth );
}
else if( ptFrom.x == 2 )
{
if( ptFrom.y == 4 )
{
if( ! HaveFriend(0, 2, fSide) && ! HaveMan(1, 3) )
AddMoveToQueue( ptFrom, 0, 2, nDepth );
if( ! HaveFriend(4, 2, fSide) && ! HaveMan(3, 3) )
AddMoveToQueue( ptFrom, 4, 2, nDepth );
}
else // ptFrom.y == 0
{
if( ! HaveFriend(0, 2, fSide) && ! HaveMan(1, 1) )
AddMoveToQueue( ptFrom, 0, 2, nDepth );
if( ! HaveFriend(4, 2, fSide) && ! HaveMan(3, 1) )
AddMoveToQueue( ptFrom, 4, 2, nDepth );
}
}
else if( ptFrom.x == 4 )
{
if( ! HaveFriend(2, 4, fSide) && ! HaveMan(3, 3) )
AddMoveToQueue( ptFrom, 2, 4, nDepth );
if( ! HaveFriend(2, 0, fSide) && ! HaveMan(3, 1) )
AddMoveToQueue( ptFrom, 2, 0, nDepth );
if( ! HaveFriend(6, 4, fSide) && ! HaveMan(5, 3) )
AddMoveToQueue( ptFrom, 6, 4, nDepth );
if( ! HaveFriend(6, 0, fSide) && ! HaveMan(5, 1) )
AddMoveToQueue( ptFrom, 6, 0, nDepth );
}
else if( ptFrom.x == 6 )
{
if( ptFrom.y == 4 )
{
if( ! HaveFriend(4, 2, fSide) && ! HaveMan(5, 3) )
AddMoveToQueue( ptFrom, 4, 2, nDepth );
if( ! HaveFriend(8, 2, fSide) && ! HaveMan(7, 3) )
AddMoveToQueue( ptFrom, 8, 2, nDepth );
}
else // ptFrom.y == 0
{
if( ! HaveFriend(4, 2, fSide) && ! HaveMan(5, 1) )
AddMoveToQueue( ptFrom, 4, 2, nDepth );
if( ! HaveFriend(8, 2, fSide) && ! HaveMan(7, 1) )
AddMoveToQueue( ptFrom, 8, 2, nDepth );
}
}
else // x == 8
{
if( ! HaveFriend(6, 4, fSide) && ! HaveMan(7, 3) )
AddMoveToQueue( ptFrom, 6, 4, nDepth );
if( ! HaveFriend(6, 0, fSide) && ! HaveMan(7, 1) )
AddMoveToQueue( ptFrom, 6, 0, nDepth );
}
break;
//==========生成黑象的著法
case BLACK_X:
if( ptFrom.x == 0 )
{
if( ! HaveFriend(2, 5, fSide) && ! HaveMan(1, 6 ) )
AddMoveToQueue( ptFrom, 2, 5, nDepth );
if( ! HaveFriend(2, 9, fSide) && ! HaveMan(1, 8 ) )
AddMoveToQueue( ptFrom, 2, 9, nDepth );
}
else if( ptFrom.x == 2 )
{
if( ptFrom.y == 5 )
{
if( ! HaveFriend(0, 7, fSide) && ! HaveMan(1, 6 ) )
AddMoveToQueue( ptFrom, 0, 7, nDepth );
if( ! HaveFriend(4, 7, fSide) && ! HaveMan(3, 6 ) )
AddMoveToQueue( ptFrom, 4, 7, nDepth );
}
else // ptFrom.y == 9
{
if( ! HaveFriend(0, 7, fSide) && ! HaveMan(1, 8 ) )
AddMoveToQueue( ptFrom, 0, 7, nDepth );
if( ! HaveFriend(4, 7, fSide) && ! HaveMan(3, 8 ) )
AddMoveToQueue( ptFrom, 4, 7, nDepth );
}
}
else if( ptFrom.x == 4 )
{
if( ! HaveFriend(2, 5, fSide) && ! HaveMan(3, 6 ) )
AddMoveToQueue( ptFrom, 2, 5, nDepth );
if( ! HaveFriend(2, 9, fSide) && ! HaveMan(3, 8 ) )
AddMoveToQueue( ptFrom, 2, 9, nDepth );
if( ! HaveFriend(6, 5, fSide) && ! HaveMan(5, 6 ) )
AddMoveToQueue( ptFrom, 6, 5, nDepth );
if( ! HaveFriend(6, 9, fSide) && ! HaveMan(5, 8 ) )
AddMoveToQueue( ptFrom, 6, 9, nDepth );
}
else if( ptFrom.x == 6 )
{
if( ptFrom.y == 5 )
{
if( ! HaveFriend(4, 7, fSide) && ! HaveMan(5, 6 ) )
AddMoveToQueue( ptFrom, 4, 7, nDepth );
if( ! HaveFriend(8, 7, fSide) && ! HaveMan(7, 6 ) )
AddMoveToQueue( ptFrom, 8, 7, nDepth );
}
else // ptFrom.y == 9
{
if( ! HaveFriend(4, 7, fSide) && ! HaveMan(5, 8 ) )
AddMoveToQueue( ptFrom, 4, 7, nDepth );
if( ! HaveFriend(8, 7, fSide) && ! HaveMan(7, 8 ) )
AddMoveToQueue( ptFrom, 8, 7, nDepth );
}
}
else // x == 8
{
if( ! HaveFriend(6, 5, fSide) && ! HaveMan(7, 6 ) )
AddMoveToQueue( ptFrom, 6, 5, nDepth );
if( ! HaveFriend(6, 9, fSide) && ! HaveMan(7, 8 ) )
AddMoveToQueue( ptFrom, 6, 9, nDepth );
}
break;
//==========生成紅仕的著法
case RED_S:
if( ptFrom.x == 3 )
{
if( ! HaveFriend( 4, 1, fSide ) )
AddMoveToQueue( ptFrom, 4, 1, nDepth );
}
else if( ptFrom.x == 4 )
{
if( ! HaveFriend( 3, 2, fSide ) )
AddMoveToQueue( ptFrom, 3, 2, nDepth );
if( ! HaveFriend( 3, 0, fSide ) )
AddMoveToQueue( ptFrom, 3, 0, nDepth );
if( ! HaveFriend( 5, 2, fSide ) )
AddMoveToQueue( ptFrom, 5, 2, nDepth );
if( ! HaveFriend( 5, 0, fSide ) )
AddMoveToQueue( ptFrom, 5, 0, nDepth );
}
else // ptFrom.x == 5
{
if( ! HaveFriend( 4, 1, fSide ) )
AddMoveToQueue( ptFrom, 4, 1, nDepth );
}
break;
//==========生成黑士的著法
case BLACK_S:
if( ptFrom.x == 3 )
{
if( ! HaveFriend( 4, 8, fSide ) )
AddMoveToQueue( ptFrom, 4, 8, nDepth );
}
else if( ptFrom.x == 4 )
{
if( ! HaveFriend( 3, 7, fSide ) )
AddMoveToQueue( ptFrom, 3, 7, nDepth );
if( ! HaveFriend( 3, 9, fSide ) )
AddMoveToQueue( ptFrom, 3, 9, nDepth );
if( ! HaveFriend( 5, 7, fSide ) )
AddMoveToQueue( ptFrom, 5, 7, nDepth );
if( ! HaveFriend( 5, 9, fSide ) )
AddMoveToQueue( ptFrom, 5, 9, nDepth );
}
else // ptFrom.x == 5
{
if( ! HaveFriend( 4, 8, fSide ) )
AddMoveToQueue( ptFrom, 4, 8, nDepth );
}
break;
//==========生成紅兵的著法
case RED_B:
//向前
ptTo.x = ptFrom.x ;
ptTo.y = ptFrom.y + 1 ;
if( ptTo.y <=9 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
if( ptFrom.y >= 5 ) //兵已過河
{
ptTo.y = ptFrom.y ;
//向左
ptTo.x = ptFrom.x - 1 ;
if( ptTo.x >=0 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
//向右
ptTo.x = ptFrom.x + 1 ;
if( ptTo.x <=8 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
break;
//==========生成黑卒的著法
case BLACK_B:
//向前
ptTo.x = ptFrom.x ;
ptTo.y = ptFrom.y - 1 ;
if( ptTo.y >=0 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
if( ptFrom.y <= 4 ) //兵已過河
{
ptTo.y = ptFrom.y ;
//向右
ptTo.x = ptFrom.x - 1 ;
if( ptTo.x >=0 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
//向左
ptTo.x = ptFrom.x + 1 ;
if( ptTo.x <=8 && ! HaveFriend( ptTo, fSide ) )
AddMoveToQueue( ptFrom, ptTo, nDepth );
}
break;
} // end switch
} // end if( CChessBoard[x][y] != 0 )
} // end for x 0 to 8, y 0 to 9
return nMoveCount; // 返回當前深度的走法總數
}
inline void AddMoveToQueue( POINT ptFrom, POINT ptTo, int nDepth )
{
MoveList[nDepth][nMoveCount].ptFrom.x = ptFrom.x ;
MoveList[nDepth][nMoveCount].ptFrom.y = ptFrom.y ;
MoveList[nDepth][nMoveCount].ptTo.x = ptTo.x ;
MoveList[nDepth][nMoveCount].ptTo.y = ptTo.y ;
nMoveCount ++;
}
inline void AddMoveToQueue( POINT ptFrom, BYTE x, BYTE y, int nDepth )
{
MoveList[nDepth][nMoveCount].ptFrom.x = ptFrom.x ;
MoveList[nDepth][nMoveCount].ptFrom.y = ptFrom.y ;
MoveList[nDepth][nMoveCount].ptTo.x = x ;
MoveList[nDepth][nMoveCount].ptTo.y = y ;
nMoveCount ++;
}
// end of CChessMove.h
總結
以上是生活随笔為你收集整理的[转载] 中国象棋软件-引擎实现(三)着法生成的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring+mybatis实现读写分离
- 下一篇: SAP freelancer夫妻并不难!