博弈树搜索技术简介:
博弈树的搜索算法,负值极大搜索,alpha-beta搜索,渴望搜索,PVS极窄窗口搜索等。通常来说,搜索算法常常和以下技术联合在一起。
如下:
1.置换表,记录已经搜索过的棋局,避免再次搜索。
2.吃子启发,优先试下能够吃对方棋子的走法。
3.杀手启发,历史启发简化版。
4.历史启发,优先试下历史统计数据得出的比较好的走法。
5.静止期搜索,继续对某些叶子结点搜索,避免水平线效应。
6.迭代加深搜索,根据搜索时间,状态。决定是否继续搜索。
有兴趣的朋友可以深入研究一下上述技术和算法。
吃子棋搜索算法:
我的程序最初的实现使用的负值极大搜索算法,之后改用alpha-beta搜索算法,后来又使用PVS极窄窗口搜索算法。
在我自己的实现里没有使用置换表,历史启发等技术。是因为吃子棋每层的走法数相对较少,所以并没有使用。
但我们知道,这些技术可以很大的提高搜索效率。
吃子棋搜索算法源码:
接下来,看看吃子棋搜索算法的源代码:
负值极大算法
- int CNegaMaxEngine::negaMax(int depth)
- {
- int currentMaxScore = -20000;
- int score;
- int nextMoveCount;
- int overNum = IsGameOver(CurPosition, depth);
- if (overNum != 0)return overNum;
- if (depth <= 0)
- return m_pEval->Eveluate(CurPosition, (m_nMaxDepth - depth ) % 2 );
- nextMoveCount = m_pMG->CreatePossibleMove(CurPosition, depth, (m_nMaxDepth - depth) % 2);
- for (int i = 0; i < nextMoveCount; i++)
- {
- MakeMove(&m_pMG->m_MoveList[depth][i], (m_nMaxDepth - depth) % 2);
- score = -negaMax(depth-1);
- UnMakeMove(&m_pMG->m_MoveList[depth][i]);
- if (score>currentMaxScore)
- {
- currentMaxScore = score;
- if (depth == m_nMaxDepth){
-
- m_cmBestMove = m_pMG->m_MoveList[depth][i];
- }
- }
- }
- return currentMaxScore;
- }
alpha-beta算法
- int CAlphtBetaEngine::alphabeta(int depth,int alpha ,int beta)
- {
-
- int score;
- int nextMoveCount;
- int overNum = IsGameOver(CurPosition, depth);
-
- if (overNum != 0)return overNum;
-
- int whoTurn = (m_nMaxDepth - depth) % 2;
- if (depth <= 0)
- return m_pEval->Eveluate(CurPosition, whoTurn);
- nextMoveCount = m_pMG->CreatePossibleMove(CurPosition, depth, whoTurn);
- for (int i = 0; i < nextMoveCount; i++)
- {
- MakeMove(&m_pMG->m_MoveList[depth][i], whoTurn);
- score = -alphabeta(depth - 1, -beta, -alpha);
- UnMakeMove(&m_pMG->m_MoveList[depth][i]);
- if (score>alpha)
- {
- alpha = score;
- if (depth == m_nMaxDepth){
-
- m_cmBestMove = m_pMG->m_MoveList[depth][i];
- }
- }
- if (alpha >= beta)break;
- }
- return alpha;
- }
PVS算法:
- int CPVS_Engine::PrincipalVariation(int depth, int alpha, int beta)
- {
- int score;
- int Count, i;
- BYTE type;
- int best;
-
- i = IsGameOver(CurPosition, depth);
- if (i != 0)
- return i;
-
- if (depth <= 0)
- return m_pEval->Eveluate(CurPosition, false);
-
- Count = m_pMG->CreatePossibleMove(CurPosition, depth, (m_nMaxDepth - depth ) % 2);
-
-
- MakeMove(&m_pMG->m_MoveList[depth][0], (m_nMaxDepth - depth ) % 2);
- best = -PrincipalVariation(depth - 1, -beta, -alpha);
- UnMakeMove(&m_pMG->m_MoveList[depth][0]);
- if (depth == m_nMaxDepth)
- m_cmBestMove = m_pMG->m_MoveList[depth][0];
-
- for (i = 1; i<Count; i++)
- {
-
- if (best < beta)
- {
- if (best > alpha)
- alpha = best;
- MakeMove(&m_pMG->m_MoveList[depth][i], (m_nMaxDepth - depth ) % 2);
- score = -PrincipalVariation(depth - 1, -alpha - 1, -alpha);
- if (score > alpha && score < beta)
- {
- best = -PrincipalVariation(depth - 1, -beta, -score);
- if (depth == m_nMaxDepth)
- m_cmBestMove = m_pMG->m_MoveList[depth][i];
- }
- else if (score > best)
- {
- best = score;
- if (depth == m_nMaxDepth)
- m_cmBestMove = m_pMG->m_MoveList[depth][i];
- }
- UnMakeMove(&m_pMG->m_MoveList[depth][i]);
- }
- }
-
- return best;
- }