我正在创建一个非常天真的人工智能(它甚至不应该被称为人工智能,因为它只是测试了很多可能性,并为他挑选了最好的一个),为我正在制作的棋盘游戏。这是为了简化手工测试的数量,我将需要做的平衡游戏。
AI是一个人玩的,做以下事情:在每回合中,AI和其中一个英雄一起,在战场上攻击最多9个怪物中的一个。他的目标是尽快完成战斗(以最少的回合)和最少数量的怪物激活。
为了达到这个目的,我已经为AI实现了一种思想超前算法,在这个算法中,他没有在当前执行最好的移动,而是根据其他英雄未来动作的可能结果选择一个移动。这是他所做的代码片段,它是用PHP编写的:
/** Perform think ahead moves
*
* @params int $thinkAheadLeft (the number of think ahead moves left)
* @params int $innerIterator (the iterator for the move)
* @params array $performedMoves (the moves performed so far)
* @param Battlefield $originalBattlefield (the previous state of the Battlefield)
*/
public function performThinkAheadMoves($thinkAheadLeft, $innerIterator, $performedMoves, $originalBattlefield, $tabs) {
if ($thinkAheadLeft == 0) return $this->quantify($originalBattlefield);
$nextThinkAhead = $thinkAheadLeft-1;
$moves = $this->getPossibleHeroMoves($innerIterator, $performedMoves);
$Hero = $this->getHero($innerIterator);
$innerIterator++;
$nextInnerIterator = $innerIterator;
foreach ($moves as $moveid => $move) {
$performedUpFar = $performedMoves;
$performedUpFar[] = $move;
$attack = $Hero->getAttack($move['attackid']);
$monsters = array();
foreach ($move['targets'] as $monsterid) $monsters[] = $originalBattlefield->getMonster($monsterid)->getName();
if (self::$debug) echo $tabs . "Testing sub move of " . $Hero->Name. ": $moveid of " . count($moves) . " (Think Ahead: $thinkAheadLeft | InnerIterator: $innerIterator)\n";
$moves[$moveid]['battlefield']['after']->performMove($move);
if (!$moves[$moveid]['battlefield']['after']->isBattleFinished()) {
if ($innerIterator == count($this->Heroes)) {
$moves[$moveid]['battlefield']['after']->performCleanup();
$nextInnerIterator = 0;
}
$moves[$moveid]['quantify'] = $moves[$moveid]['battlefield']['after']->performThinkAheadMoves($nextThinkAhead, $nextInnerIterator, $performedUpFar, $originalBattlefield, $tabs."\t", $numberOfCombinations);
} else $moves[$moveid]['quantify'] = $moves[$moveid]['battlefield']['after']->quantify($originalBattlefield);
}
usort($moves, function($a, $b) {
if ($a['quantify'] === $b['quantify']) return 0;
else return ($a['quantify'] > $b['quantify']) ? -1 : 1;
});
return $moves[0]['quantify'];
}这样做是递归地检查未来的移动,直到达到$thinkAheadleft值,或直到找到解决方案(即,所有怪物都被击败)。当到达其退出参数时,与$originalBattlefield (第一次移动之前的战场状态)相比,它计算战场状态。计算方法如下:
/** Quantify the current state of the battlefield
*
* @param Battlefield $originalBattlefield (the original battlefield)
*
* returns int (returns an integer with the battlefield quantification)
*/
public function quantify(Battlefield $originalBattlefield) {
$points = 0;
foreach ($originalBattlefield->Monsters as $originalMonsterId => $OriginalMonster) {
$CurrentMonster = $this->getMonster($originalMonsterId);
$monsterActivated = $CurrentMonster->getActivations() - $OriginalMonster->getActivations();
$points+=$monsterActivated*($this->quantifications['activations'] + $this->quantifications['activationsPenalty']);
if ($CurrentMonster->isDead()) $points+=$this->quantifications['monsterKilled']*$CurrentMonster->Priority;
else {
$enragePenalty = floor($this->quantifications['activations'] * (($CurrentMonster->Enrage['max'] - $CurrentMonster->Enrage['left'])/$CurrentMonster->Enrage['max']));
$points+=($OriginalMonster->Health['left'] - $CurrentMonster->Health['left']) * $this->quantifications['health'];
$points+=(($CurrentMonster->Enrage['max'] - $CurrentMonster->Enrage['left']))*$enragePenalty;
}
}
return $points;
}当量化一些事物时,净正点,一些净负点到状态。人工智能所做的是,他不使用在他当前移动后计算出来的点数来决定该采取哪一种移动,而是使用在思想超前部分之后计算出来的点数,并根据其他英雄的可能动作选择一个移动。
基本上,AI正在做的是说,这不是目前最好的选择,攻击怪物1,但如果其他英雄会做这个和这个行动,从长远来看,这将是最好的结果。
在选择一个移动后,AI对英雄执行一个移动,然后对下一个英雄重复这个过程,用+1移动计算。
问题:我的问题是,我假设,一个人工智能,‘思考提前’3-4移动,应该找到一个更好的解决方案,比一个人工智能,只执行最好的移动目前。但是我的测试用例显示了不同的情况,在某些情况下,一个人工智能,它没有使用思考提前选项,即目前只发挥最好的移动,击败一个正在思考的人工智能一个单一的移动。有时,只考虑提前3步的人工智能,就会击败认为提前4或5步的人工智能。为什么会发生这种情况?我的假设不正确吗?若然,为甚麽呢?我是不是用错号码来计算重量了?我对此进行了调查,并运行了一个测试,自动计算要使用的权重,测试可能的权重间隔,并尝试使用最佳结果(即产生最少的循环次数和/或最少的激活次数的结果),但我前面描述的问题仍然存在于这些权重中。
我被限制在当前版本的脚本中提前5步思考,就像任何更大的“向前思考”一样,脚本变得非常慢(如果提前5次思考,它会在大约4分钟内找到一个解决方案,但如果6次提前思考,它甚至在6小时内都找不到可能的第一步)。
如何战斗:战斗以下列方式工作:由AI控制的许多英雄(2-4),每个英雄都有许多不同的攻击(1-x),可以在战斗中使用一次或多次,正在攻击一些怪物(1-9)。根据攻击的价值,怪物失去生命,直到死亡。每次攻击后,如果被攻击的怪物没有死,他就会被激怒,而在每个英雄做了一个动作之后,所有的怪物都会被激怒。当怪物达到愤怒极限时,它们就会启动。
免责声明:我知道不是用于这种操作的语言,但是由于这只是一个内部项目,我宁愿牺牲速度,以便能够尽快用我的本地编程语言编写代码。
更新:我们目前使用的量化方法如下所示:
$Battlefield->setQuantification(array(
'health' => 16,
'monsterKilled' => 86,
'activations' => -46,
'activationsPenalty' => -10
));发布于 2019-01-13 18:51:48
如果你的游戏中有随机性,那么任何事情都可能发生。指出这一点,因为它只是不清楚从你在这里张贴的材料。
如果没有随机性,演员可以看到游戏的全部状态,那么一个更长的前瞻性绝对应该表现得更好。如果没有,则清楚地表明您的评估函数提供了不正确的状态值估计。
在查看您的代码时,您的量化值没有列出,在您的模拟中,看起来您只是让同一个玩家重复移动,而不考虑其他参与者的可能操作。您需要一步一步地运行一个完整的模拟,以便生成准确的未来状态,并且您需要查看不同状态的值估计,以确定您是否同意它们,并相应地对量化进行调整。
另一种确定价值估计问题的方法是,在0.0到1.0的范围内,以百分比的形式明确地预测你赢得这一轮的机会,然后选择给你带来最高胜算的移动。计算到目前为止所造成的伤害和被杀死的怪物数量并不能告诉你为了赢得这场比赛你还有多少事情要做。
https://stackoverflow.com/questions/54075788
复制相似问题