java - 打破听众的递归

标签 java recursion javafx java-8 javafx-8

我正在尝试打破使该代码递归的特殊情况。

我有一个 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

最佳答案

对您的代码做出以下假设:

  1. 所有内容当前都在 FX 应用程序线程上运行
  2. 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/

相关文章:

java - 我可以从递归返回到 main 而不展开堆栈吗?

java - 如何在 JavaFX 中制作 TimeSpinner?

java - 如何在 TimerTask 执行时暂停主线程?

javascript - 递归遍历目录时等待所有 promise 都已解决

java - 如何将以对象为键的 map 列表转换为 map ?

Java:给定数组、整数和数组长度,递归搜索数组中的整数

java - IntelliJ IDEA - 错误 : JavaFX runtime components are missing,,需要运行此应用程序

java - 清除其他类的文本字段

java - 为什么数组使用扫描仪在 java 中显示两个索引

java - 如何判断 IF 中是否单击了按钮?