打破听众的递归 [英] Breaking recursion from listeners

查看:123
本文介绍了打破听众的递归的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正试图打破一个使这段代码递归的特殊情况。

I'm trying to break a special case that makes this code recursive.

我有一个Javafx游戏,其中有人和计算机玩家在轮到他们时可以玩很多轮。

I have a Javafx game where there are human and computer players each play when it's his turn and there can be many rounds.

计算机应该自动播放并立即移动到下一个播放器并且不向UI显示任何直接指示(但是可以查看它之后的操作)。

A computer is supposed to play automatically and move to the next player immediately and show no direct indication to the UI (but it's possible to review what it did afterwards).

问题出现在只有电脑播放器的情况下,我们会在 currentBoardPane 加载的时候来到这里,输入条件,因为所有播放器都是电脑,设置下一个玩家的棋盘,然后在不完成通话的情况下,再次调用相同的功能:

The problem is in the case where there are only computer players, we will come here the moment the currentBoardPane was loaded, enter the condition since all players are computers, set the board of the next player, and then without finishing the call, call this same function again:

    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
        }
    });

如果我订阅了 currentPlayer 属性在 GameManager 然后我仍然需要从该侦听器调用 setNextPlayer(),这又是递归的。

Instead of this, if I subscribe a listener to the currentPlayer property in GameManager then I still need to call setNextPlayer() from that listener which is again recursive.

如果所有玩家都是电脑,我可以制作一个特例,然后从运行游戏,同时(true){} 而不是听众和绑定但是必须有更好的方法来打破这种递归。

I can make a special case if all players are a computer, then run the game from a while(true){} instead of listeners and binds but there has to be a better way to break this recursion.

有没有办法在没有听众的情况下进入递归绑定?

Is there a way to not get into recursion while still having listeners and binds?

注意:

currentBoardPane 表示屏幕上的当前游戏板,它是 ObjectProperty

currentBoardPane signifies the current game board on the screen and it's an ObjectProperty.

推荐答案

制作以下关于您的代码的假设:

Making the following assumptions about your code:


  1. FX应用程序主题当前正在运行

  2. currentBoardPane.setValue(...)导致UI更新ate(所以你每次移动都要更新UI)

  1. Everything is currently running on the FX Application Thread
  2. The currentBoardPane.setValue(...) causes the UI to update (so you update the UI each move)

然后一个快速而肮脏的方法是:

then a "quick and dirty" way to do this is:

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应用程序线程上执行的计划,并立即退出处理程序。因此,对 currentBoardPane.setValue(...)的调用稍后执行,不再递归。

This delegates the updates to a new Runnable, schedules that runnable to execute on the FX Application Thread, and exits the handler immediately. Thus the call to currentBoardPane.setValue(...) is executed later and is no longer recursive.

In事实上,如果你做到这一点更多的工作:

In fact, if you do just a little more work:

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是可以接受的。 (如果计算移动只需要很少的时间,这仍然可以正常工作。)这假设 playAutoMovesForCurrentPlayer()不会更新UI。

then this is exactly the code you would use if computing the move took enough time that it would not be acceptable to block the UI while it was happening. (And if computing the move takes very little time, this will still work just fine.) This assumes that playAutoMovesForCurrentPlayer() doesn't update the UI.

这篇关于打破听众的递归的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆