我正在尝试打破使该代码递归的特殊情况。
我有一个 Javafx 游戏,其中有人类和计算机玩家,轮到他的时候玩,并且可以有很多轮。
计算机应该自动播放并立即移动到下一个播放器,并且不会向用户界面显示直接指示(但可以在之后查看它做了什么)。
问题是在只有电脑玩家的情况下,我们会在加载currentBoardPane
的时候来到这里,输入条件,因为所有玩家都是电脑,设置下一个玩家的棋盘,然后在没有完成调用的情况下再次调用相同的函数:
currentBoardPane.addListener((e) -> {
if(gameManager.checkIfCurrentPlayerIsComputer()){
gameManager.playAutoMovesForCurrentPlayer();
gameManager.setNextPlayer(); // it does current player property = next player
//update board on scene
currentBoardPaneIndex = ((currentBoardPaneIndex + 1) % gameManager.getPlayers().size());
currentBoardPane.setValue(boardPanes.get((currentBoardPaneIndex))); //this is a recursive call
}
});
相反,如果我在 GameManager
中订阅 currentPlayer
属性的监听器,那么我仍然需要从中调用 setNextPlayer()
再次递归的监听器。
如果所有玩家都是计算机,我可以做一个特例,然后从 while(true){}
运行游戏,而不是监听器和绑定(bind),但必须有更好的方法来打破这个递归。
有没有办法在仍然有监听器和绑定(bind)的情况下不进入递归?
注释:
currentBoardPane
表示屏幕上当前的游戏板,它是一个 ObjectProperty
。
最佳答案
对您的代码做出以下假设:
- 所有内容当前都在 FX 应用程序线程上运行
currentBoardPane.setValue(...)
导致 UI 更新(因此每次移动都会更新 UI)
那么“快速而肮脏”的方法是:
currentBoardPane.addListener((e) -> {
if(gameManager.checkIfCurrentPlayerIsComputer()){
gameManager.playAutoMovesForCurrentPlayer();
//update board on scene
Platform.runLater(() -> {
gameManager.setNextPlayer(); // it does current player property = next player
currentBoardPaneIndex = ((currentBoardPaneIndex + 1) % gameManager.getPlayers().size());
currentBoardPane.setValue(boardPanes.get((currentBoardPaneIndex))); //this is a recursive call
});
}
});
这会将更新委托(delegate)给新的Runnable
,安排该runnable在FX应用程序线程上执行,并立即退出处理程序。因此,对 currentBoardPane.setValue(...)
的调用稍后执行,并且不再递归。
事实上,如果您多做一点工作:
private final Executor aiExecutor = Executors.newSingleThreadExecutor();
// ...
currentBoardPane.addListener((e) -> {
if(gameManager.checkIfCurrentPlayerIsComputer()){
Task<Void> makeMoveTask = new Task<Void>() {
@Override
protected Void call() {
gameManager.playAutoMovesForCurrentPlayer();
return null ;
}
};
makeMoveTask.setOnSucceeded(e -> {
//update board on scene
gameManager.setNextPlayer(); // it does current player property = next player
currentBoardPaneIndex = ((currentBoardPaneIndex + 1) % gameManager.getPlayers().size());
currentBoardPane.setValue(boardPanes.get((currentBoardPaneIndex))); //this is a recursive call
});
aiExecutor.execute(makeMoveTask);
}
});
如果计算移动花费了足够的时间,以至于在移动发生时阻止 UI 是 Not Acceptable ,那么这正是您将使用的代码。 (如果计算移动需要很少的时间,这仍然可以正常工作。)这假设 playAutoMovesForCurrentPlayer()
不更新 UI。
关于java - 打破听众的递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39395942/