我们能够依据吃子棋的规则。创建走法生成器,基本的逻辑是,假设己方存在一气的棋串,则能够无需紧对方的气,也就是能够不用贴着对方的棋子落子。
其它情况下,必须贴
着对方的棋子落子。考虑到某些特殊情况,当己方能提对方棋子时,己方就能够下到没有气的地方,而且一般的吃子棋,先提子者胜。无法形成劫争。所以走法生成器就相对非
常简单。
对于怎样确定己方是不是存在一气的棋串,能够利用上一节介绍的算气算法。
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();
这个算法是走法启示。学名为静态启示,而不是历史启示,历史启示并不须要棋类的知识属于动态启示。而走法启示则与棋类知识相关联。