標籤:
我們能夠根據國際象棋的規則吃,建立移動產生器。基本邏輯是,假定一個展開己方蠕蟲的存在,這是可能沒有其他的緻密氣。這是不是對其他部分可以落子。在其他情況下。必須堅持
另一片落子,考慮到特殊情況,當自己可以提其他片,自己可以下到那裡沒有氣。和一般吃跳棋。勝,無法形成劫爭。所以走法產生器就相對非
常簡單。
對於怎樣確定己方是不是存在一氣的棋串,能夠利用上一節介紹的算氣演算法。
int CMoveGenerator::CreatePossibleMove(BYTE position[GRID_NUM][GRID_NUM], int nPly, int nSide){ m_nMoveCount = 0; BYTE antiSide = (nSide + 1) % 2; cleanGlobal(); setGo(position); //檢測己方是否有一氣的棋竄,有則輸出對應走法。 for (int i = 0; i < GRID_NUM; i++) for (int j = 0; j < GRID_NUM; j++){ if(go[i][j]==nSide&&g_gozi[i][j]==0){ str_lib(i,j,go[i][j]); if (goqi==1) { for (int k = 0; k < GRID_NUM; k++) for (int w = 0; w < GRID_NUM; w++){ if (gokong[k][w] == 1){ AddMove(k, w, nPly); } } } } } 64 //正常情況下,尋找敵方棋子周邊的空位,緊其氣 for (int i = 0; i < GRID_NUM; i++) for (int j = 0; j < GRID_NUM; j++) { if (go[i][j] == antiSide) { if (i > 0 && go[i - 1][j] == NOSTONE){ AddMove(i - 1, j, nPly); } if (i < GRID_NUM - 1 && go[i + 1][j] == NOSTONE){ AddMove(i + 1, j, nPly); } if (j>0 && go[i][j - 1] == NOSTONE){ AddMove(i, j - 1, nPly); } if (j < GRID_NUM - 1 && go[i][j + 1] == NOSTONE){ AddMove(i, j + 1, nPly); } } } return m_nMoveCount;}
可以最佳化此演算法,以後方便興許的搜尋引擎進行剪枝。
給走法設定一個分數。可以提子則此步設為30+提子數。可以打吃則為20+打吃棋子數。可以長氣,則為10+長氣的棋子數。其它臨時設計為0。可以用一個額定長度的優先隊列,保留幾個分數最佳的走法。
或是必要時進行排序。
搜尋時優先優先搜尋得分較高的走法,這樣大幅度提高搜尋演算法剪枝的效率。
這段是走法啟示的代碼
偽碼例如以下:
for(int i=0;i<Grid_Num;i++)for(int j=0;j<Grid_Num;j++){ cleanupGlobal(); if(go[i][j]==NOSTONE) { bool isVilid=false; if(i>0&&go[i-1][j]==antiSide) { go[i][j]=nSide; if(g_gozi[i-1][j]==0) { isVilid=true; str_lib(i-1,j,antiSide); switch(goqi){case 0:case 1:....} } } if(i<Grid_Num-1&&go[i+1][j]==antiSide) { go[i][j]=nSide; if(g_gozi[i-1][j]==0) { isValid=true; str_lib(i-1,j,antiSide); switch(goqi){case 0:case 1:....} } }... if(isValid) { sumScore(i,j,nSide); addMove(i,j,nSide); }44 }}std::sort();
這種演算法是採取啟發學習法,研究命名為靜態啟示。而不是曆史的啟示,曆史啟示不需要象棋知識是動態啟示,啟示舉措與國際象棋有關的知識。
人機博弈-吃跳棋遊戲(三)代移動