堆栈溢出与Java中的递归

时间:2017-11-14 17:06:00

标签: java recursion minimax

我正在尝试编写一个永远不会在Tic Tac Toe丢失的AI,我想使用minimax算法来实现这一目标。但是,当我尝试运行程序时,出现堆栈溢出,我似乎无法找到错误。你能看看我告诉我我做错了什么吗?它在我认为的递归中并没有那么深,因为它应该只经历所有可能的游戏结果,最多可以达到8个动作(因为玩家是第一个玩,而不是AI)。可能是我做错了什么,但我找不到任何东西。

编辑:这是完整的代码,机制函数是主要部分: EDIT2:修复了构造函数

Exception in thread "main" java.lang.StackOverflowError
    at Packet.Logic$TicTacToe.mechanics(Logic.java:54)
    at Packet.Logic$TicTacToe.mechanics(Logic.java:84)
    at Packet.Logic$TicTacToe.mechanics(Logic.java:87)
    at Packet.Logic$TicTacToe.mechanics(Logic.java:84)
    at Packet.Logic$TicTacToe.mechanics(Logic.java:87)
    at Packet.Logic$TicTacToe.mechanics(Logic.java:84)
    at Packet.Logic$TicTacToe.mechanics(Logic.java:87)

此外,这是我得到的确切错误:

at Packet.Logic$TicTacToe.mechanics(Logic.java:84)
at Packet.Logic$TicTacToe.mechanics(Logic.java:87) 

在这部分之后,这些部分出现了很多次(至少50次)

if (win(newBoard,this.playerHuman)){

第54行:

scores.add(this.mechanics(possibleBoard, this.playerHuman));

第84行:

scores.add(this.mechanics(possibleBoard, this.playerAI));

第87行:

{{1}}

2 个答案:

答案 0 :(得分:0)

存在一些问题,但是您可以通过以下方式调试此问题:

在您的班级中添加int debugLen = debug.length(); debug.append("\nSetting ").append(availableSpotNumber).append(" to ").append(player); possibleBoard[availableSpotNumber] = player; try { if (player == this.playerAI) { scores.add(this.mechanics(possibleBoard, this.playerHuman)); } else { scores.add(this.mechanics(possibleBoard, this.playerAI)); } moves.add(availableSpotNumber); } catch (StackOverflowError error) { throw new StackOverflowError(debug.toString()); } debug.setLength(debugLen); possibleBoard[availableSpotNumber] = this.emptySpace; 字段,然后像这样更改主循环:

Setting 0 to 1
Setting 0 to 2
Setting 0 to 1
Setting 0 to 2
etc..

然后你会看到发生了什么,这将为你提供接下来要解决的问题的线索。例如,当前版本正在执行此操作,用于初始人工移动1:

{{1}}

但是,如果你太懒,你可以找到固定版本here

答案 1 :(得分:0)

这可能是也可能不是代码问题,因为Java不是一个功能齐全的语言,它来递归,你可能希望看到这个答案:Does Java 8 have tail call optimization?

基本上,允许无限深度递归的语言必须具有尾递归优化。使用尾调用优化,如果返回值是具有不同参数的完全相同的函数的结果,则将替换堆栈而不是添加到堆栈的新调用。

如果某种语言没有尾调用优化,那么即使递归调用具有正确的终止条件,您也会受到堆栈大小的限制,即使递归调用具有正确的终止条件(注意:我还没有对其进行分析)代码深入,所以显然在递归逻辑本身可能存在问题)。如果要调整堆栈大小,请使用-Xss Java运行时参数。通常,增加堆栈大小是一种很好的启发式方法(尽管不是一种万无一失的方法),可以检查错误是使用语言还是使用算法。