我正在尝试为 9Men的Morris游戏实施游戏AI 。
到目前为止,我的主板代表如下:
public class board
{
public node []gNode = null;
... // so the table has 24 nodes, for 9 men morris game:
gNode = new node[24];
...
int evaluateBoard(); // evaluates the current board (tokens)
}
好的,现在每个节点都表示如下:
public class node
{
node() // constructor
{ ... }
// setting current node's neighbours (maximum 4 neighbours)
void setNeighbours(int left, int right, int top, int bottom)
{ ... }
short gOccupiedByTeam = renderer.TEAM_NOTEAM; // info if this node is occupied by a token (and a wich team this token belongs to)
short []gNeighbourId = null; // info about this node neighbours (can be max. 4 in a 9Men's morris game)
short gInternalID = -1; // board's IDs (from 0..23)
short gTokenID = -1; // this node can be occupied by a token. (from 0 .. 8) -see below the token class.
short gNodeScore = -1; // a dummy node score.
vector3 gLocation = null; // 3d coordinates for this node.
}
并且令牌如下所示:
public class token
{
token(vector3 startpos, short nodeId) // Constructor.
{ ... }
public physx gPhysX = null; // 3d coordinates , velocity , accel. for this Token.
public boolean bIsAlive = false; // is this token alive ? (or eliminated?)
public boolean bFormsMill = false; // does it form a Mill?
public short gNodeID = -1; // "link" this token with a gNodeID (when placing a token on current board). See above the node class. This represents a link ID to that node.
public short gTokenMill1 = -1; // used when this token forms a mill (with gTokenMill1 token!)
public short gTokenMill2 = -1; // same.
}
这是我的Alpha-Beta修剪算法实现,其中我被卡住了:
public int getBestMove(board board, int depth, int alpha, int beta, boolean bIsPlayer)
{
// if depth reached, return current's board's Evaluation (a score).
if (depth == 0) return board.evaluateBoard(bIsPlayer);
// is it Player's turn ? (max?)
if (bIsPlayer)
{
// QUESTIONS:
// retrevie all possible "boards" below ! (all new possible token moves)
// 1. here i should generate a new board with 1st possible move (for player token1) ?? ... then a second new board with 2nd possible move still for token1 ? .. and so on until no possible moves for token1?
// (remembering that a token can move in 4 available spots - wich are a neighbour?)
//
// 2. the problem is that if i generate 4 new boards as per token 1 above let's say, then it will "eat" lot of memory for all 18 tokens and a function recursion depth of 5 for example, right ?
// 3. how do i fix point 2?
ArrayList<board> possible_boards = board.getAllPossibleBoards();
// 4. ok, some possible boards were generated, loop thru them starting with the first one and calling recursively this function, is it right ?
for(board iterator: possible_boards)
{
alpha = Math.max(alpha, getBestMove(iterator, depth - 1, alpha, beta, !bIsPlayer));
if (beta < alpha)
{
break;
}
}
// 5. how do i return best move to main calling function ? (wich token is it best move from all of these board's moves ?
return alpha;
}
else
{
ArrayList<board> possible_boards = board.getAllPossibleBoards();
for(board iterator: possible_boards)
{
beta = Math.min(beta, getBestMove(iterator, depth - 1, alpha, beta, !bIsPlayer));
if (beta < alpha)
{
break;
}
}
return beta;
}
}
好的,到目前为止这是我的功能。 我不知道即使我在正确的轨道上 ??!
我的功能有什么问题?
请回答我的上述问题(getBestMove()函数中的1到5)。
提前谢谢你,请原谅我的语言错误(我的英语不太好)
非常感谢你 saeedn 的回复!!
我以为没有人会回答我:)。我真的帮助我了解我的想法。
所以, CheckWinner( bool )将检查当前玩家是否具有非常好的优势(例如获胜或非常好到目前为止,在此深度中移动就像阻止对手一样,如果是这样,那么为当前玩家返回 BIG 分数。所有这一切都是因为玩家或对手都不会试图在每个回合中赢(一个大分数),对吗?
否则,如果 depth = 0,则返回当前所选Board( int evaluateBoard())的评估(得分),好的。
在此之后,我必须生成一个单板(带有一个令牌可移动):
while( board.generateNextPossibleBoard(nextBoard) ) // board generated and stored in "nextBoard". Also check if it is a valid board or no more boards to generate further.
好的,现在有一个新生成的电路板,递归,如果找到更好的电路板(具有更好 SCORE 的电路板),则将当前电路板保存到selectedBoard。如果没有那么切断并返回(不要再检查树下)。
再次感谢saeedn !!!
答案 0 :(得分:2)
一般来说,你的代码还可以,但是你应该记住一些要点。
首先,你应该检查节点(这里是一块板)是否是最终的(有人赢了比赛),然后检查深度是否等于零。如果有人在该状态下获胜,你可能想要返回一个大值(赢得最大玩家)和一个小值(赢得最小玩家),分别为MAXINT和MININT。
为避免高内存消耗,请勿生成所有可能的电路板。生成一个电路板并对其进行递归调用,然后生成另一个电路板并搜索该电路板,依此类推。这样,您只需将内存用于每个堆栈帧中的一个状态。这对于具有高分支因子的搜索至关重要!
最后你应该记录最大玩家的棋盘更新分数(你更新alpha的地方)。
请参阅我的伪代码以获得更多说明:
if ( board.checkWinner(bIsPlayer) ) return board.evaluateBoard(bIsPlayer);
// if depth reached, return current's board's Evaluation (a score).
if (depth == 0) return board.evaluateBoard(bIsPlayer);
board chosenBoard;
if (bIsPlayer)
{
// You should implement this method, or write your board generation code here
// returns false if no more boards could be generated
board nextBoard;
while( board.generateNextPossibleBoard(nextBoard) )
{
int v = getBestMove(iterator, depth - 1, alpha, beta, !bIsPlayer));
if ( v > alpha )
{
alpha = v;
chosenBoard = nextBoard; // return this chosenBoard by reference ;)
}
if (beta < alpha)
{
break;
}
}
return alpha;
}
else
{
// The same for beta except you don't need to update chosenBoard :)
}