通过时间限制逃离递归

时间:2013-09-15 12:14:32

标签: java recursion

我正在编写一个程序来玩跳棋,每次移动都是定时的。我正在使用alpha-beta修剪找到最佳动作。我只能在决策树中走得那么深,因为:

  1. 决策树对于跳棋来说是巨大的
  2. 我必须决定移动时间限制
  3. 当我的时间用完时,即使堆栈上有很多帧,有没有办法立即从调用堆栈中逃脱?我想过抛出异常,但这似乎是一个糟糕的决定。

    这就是我现在正在做的事情,但它还不够快

    public Board play(Board board) {
        ArrayList<Board> actions = board.findPossibleMoves();
    
        if (actions.size() == 0) {
            return new Board();
        } 
    
        int depth = 3;
        // Each move has 1 second (1000ms)
        TimeLimit tl = new TimeLimit(1000);
        double alpha = Double.NEGATIVE_INFINITY;
        double beta = Double.POSITIVE_INFINITY;
    
        Board bestSoFar = actions.get(0);
    
        double v = Double.NEGATIVE_INFINITY;
        for (Board b : actions) {
            if (tl.isTimeUp())
              return bestSoFar;
    
            double result = minValue(b, depth, alpha, beta, tl);
            if (result >= v) {
                bestSoFar = b;
                v = result;
            }
            if (v >= beta) return b;
            alpha = Math.max(alpha, v);
        }
        return bestSoFar;
    }
    
    private double maxValue(Board board, int depth, double alpha, double beta, TimeLimit tl) {
        if (tl.isTimeUp())
            return score(board);
        ...
    }
    
    private double minValue(Board board, int depth, double alpha, double beta, TimeLimit tl) {
        if (tl.isTimeUp())
            return score(board);
        ...
    }
    

1 个答案:

答案 0 :(得分:2)

鉴于递归将在严格定时的环境中使用,可以考虑几个选项。这些列在下面:

选项1:

在整个方法体中添加更多if语句,特别是在可以阻止的代码段之前,以确保代码执行在时间到期后立即停止。必须实现特定的缓冲间隔,以便为返回语句提供时间向上传播回堆栈。

<强>优点:

  • 易于实施。
  • 相对简单有效。

<强>缺点:

  • 降低了代码的可读性。
  • 不保证执行将在指定时间内完成。


选项2:

将执行代码移植到辅助线程,该辅助线程在执行时逐步写入对象。然后主线程可以在触发此线程时启动计时器。当计时器到期时,主线程只需要检索此对象并通知工作线程死亡。

<强>优点:

  • 极其准确(由于同步导致延迟几乎在点上检索到结果)
  • 不需要缓冲间隔 - 递归函数可以根据需要尽可能深入,而不是通过尝试使返回传播适合计时器而被束缚。
  • 允许正常关闭执行代码,因为它不再受时间限制(取得结果并允许线程以自己的速度死亡)。

<强>缺点:

  • 多线程 - 由于此解决方案是多线程的,因此可能不适用于所有方案。
  • 需要大量额外代码,并可能需要对现有代码进行更改才能实现。