我已经让我的大脑因为井字游戏类型而被打破了。 问题是高水平的ai表现缓慢(即使是低水平也没那么快)。
AI使用递归方法从可用移动的数量中找到最佳移动。
以下是一些代码:
@impelementation AIClass
- (NSMutableArray *)findLegalMoves
{
// Here is code that finds available legal moves
// Loop over board array
}
- (float)scoreOpponentsTurn:(float)min max:(float)max depth:(int)depth
{
moveType t; // moveType is struct defined in .h file
// typedef struct { int x, y; } moveType
NSMutableArray *moves = [self findLegalMoves];
for ( NSValue *val in moves ) {
[val getValue:&it]
float score = [self scoreMove:it min:min max:max depth:depth];
if ( score > min ) {
min = score;
}
if ( score > max ) {
min = 1000000000;
}
}
return min;
}
- (float)scoreMove:(moveType)m min:(float)min max:(float)max depth:(int)depth
{
NSMutableArray *changes = [[NSMutableArray alloc] init];
NSMutableArray *undo = [[NSMutableArray alloc] init];
float score;
[self.board evaluateChangesOnCol:m.x Row:m.y];
if ( [self.board checkForWin:&changes undo:&undo] ) {
score = 1000000000 + [self calcH]; //calcH - evals heuristic like sum of params
} else if ( depth > 0 ) {
score = - [self scoreOpponentsTurn:-1000000000 max:-min depth:depth - 1];
} else {
score = [self calcH];
}
[self.board applyChanges:undo];
}
- (moveType)findBestMove
{
NSMutableArray *legalMoves = [self findLegalMoves];
NSMutableArray *bestMoves = [[NSMutableArray alloc] init];
int min = -1000000000;
int max = 1000000000;
moveType move;
for ( NSValue *moveIt in legalMoves ) {
[moveIt getValue:&move];
float score = [self scoreMove:move min:min max:max depth:depth];
// Here i have some conditions to decide current move is best or not
}
// and pick random move from best moves and assign it to move variable
return move;
}
@end
如果合法移动的数量如3和更多(通过递归搜索它增长)这个算法 工作很慢。
这是我的第一个客观经验。 以下是我对如何提高绩效的猜测:
抱歉我的英文。
答案 0 :(得分:3)
在一个自然适合递归的算法中丢弃递归并不是一个好主意。相反,您需要memoize递归解决方案。这种常见技巧可以加速递归解决方案,并且具有数量级的常见子问题。
考虑这两个动作序列:
x:(1,1) o:(2,1) x:(1,0) o:(2,0)
和
x:(1,0) o:(2,0) x:(1,1) o:(2,1)
序列不同,但它们达到了相同的最终状态:
| | x | o
------------
| | x | o
这是缓慢的根本原因:当你的程序第二次到达重复状态时,它会像第一次看到它一样评估位置。这是浪费的:相同的三次前瞻位置将被评估四次;如果有四次前瞻,它们将被评估八次,依此类推。这会导致慢度与2^N
成比例,其中N
是您前瞻的深度。
修复此问题需要添加查找表。鉴于游戏的状态,如果之前计算过此分数,此表将为您或对手提供分数。您的递归函数将构建一个位置键,并在分数表中尝试查找。如果答案在那里,它将立即返回。否则,您的函数将构造答案,并将其存储在位置键。下次通过不同的一系列动作发生相同的位置时,答案将被重复使用。
答案 1 :(得分:1)
您可能想尝试Alpha-beta pruning。您的游戏可能具有较高的分支因子,在这种情况下,您可能希望避免搜索不会影响结果的区域。
您还可以将搜索范围限制在一定深度。选择一个可以检索合格动作的深度,但不会花太长时间。