打破听众的递归
我试图打破一个使这段代码递归的特殊情况。
我有一个Javafx游戏,其中有人和计算机玩家在轮到他的时候玩,并且可以有很多回合。
计算机应该自动播放并立即移动到下一个播放器并且不向UI显示任何直接指示(但是可以查看它之后做了什么)。
问题是在只有电脑玩家的情况下,我们会在当前装载电脑的时候来到这里,输入条件,因为所有玩家都是电脑,设置下一个播放器的电路板,然后无需完成通话,请拨打此电话同样的function:
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){}
而不是听众和绑定运行游戏,但必须有更好的方法来打破这种递归。
还有一种方法是在没有听众和绑定的情况下不进入递归吗?
笔记:
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 }); } });
这会将更新委托给新的Runnable
,可以在FX Application Thread上执行的计划,并立即退出处理程序。 因此,对currentBoardPane.setValue(...)
的调用稍后执行,不再递归。
事实上,如果你做了一点工作:
private final Executor aiExecutor = Executors.newSingleThreadExecutor(); // ... currentBoardPane.addListener((e) -> { if(gameManager.checkIfCurrentPlayerIsComputer()){ Task makeMoveTask = new Task () { @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发生时是不可接受的。 (如果计算移动只需要很少的时间,这仍然可以正常工作。)这假设playAutoMovesForCurrentPlayer()
不会更新UI。