为每个步骤应用按钮,或延迟javascript递归

时间:2018-11-27 18:39:52

标签: javascript loops recursion delay towers-of-hanoi

我使用javascript编写了一个小程序来解决河内塔问题。我用了3座DIV塔,给第一座塔加了黑色,其余的我加了白色。当我希望程序交换2个元素时,它基本上会交换适当DIV的属性。该代码可以正常工作,但是我希望每个步骤都可见,并且在当前状态下,从头到尾只是一闪而过。我已经尝试过为每个步骤使用一个按钮,但是它没有起作用,所以setTimeout()了。 (对不起,我的英格兰不好:c)

var from = 1;
var to = 2;
var help = 3;

function swap(from, to){
    while (...){
        if (...){
            while(...){
                if (...){
                    //swaps the properties of the divs
                }
            }
        }
    }
}


function hanoi(n, from, to, help){
    if (n == 1){
        swap(from, to);
    }
    else{
        hanoi(n-1, from, help, to);
        swap(from, to);
        hanoi(n-1, help, to, from);
    }
}

我已经尝试过了,但这只是将闪光灯延迟了2秒:

function hanoi(n, from, to, help){
    if (n == 1){
        setTimeout(function(){swap(from, to);}, 2000);
    }
    else{
        hanoi(n-1, from, help, to);
        setTimeout(function(){swap(from, to);}, 2000);
        hanoi(n-1, help, to, from);
    }
}

2 个答案:

答案 0 :(得分:1)

我强烈建议您检查setTimeout如何与JavaScript事件堆栈一起使用。 Here's an awesome video

这是您的过程。

  1. 您调用hanoi,如果它通过if检查,则会自动再次调用自身。
  2. 由于setTimeout将代码的执行发送到webapis以便稍后执行,因此它将自动触发该块中的第二个hanoi
  3. 这将继续运行并触发更多hanoi并创建更多setTimeouts来将swap的执行发送到webapi。
  4. 由于所有setTimeouts均在“同一时间”触发,因此它们会同时解决2秒的等待时间。

Jonas Wilms's answer说明了解决方法。

答案 1 :(得分:0)

在您的最后一个代码块中,递归函数以递归方式执行,创建所有超时,并且在2秒后所有超时都在不久之后再次回调,这就是为什么它闪烁(in depth explanation)。相反,您还想延迟递归调用:

 function hanoi(n, from, to, help){
   if (n == 1){
    setTimeout(function(){swap(from, to);}, 2000);
   } else{
    setTimeout(function() {
       hanoi(n-1, from, help, to);
       swap(from, to);
       hanoi(n-1, help, to, from);
    }, 2000);
  }
}

尽管可行,但是这段代码并不是很漂亮。可视化和延迟循环并不是河内方法的工作。取而代之的是,我会以一种可以中断的方法来编写Hanoi逻辑,然后可以通过重新渲染和延迟的处理函数来调用它。对于发电机来说,这是一个完美的用例:

 function* hanoi(n, from, to, help){
    if (n == 1){
     swap(from, to);
    } else{
       yield* hanoi(n-1, from, help, to);
       swap(from, to);
       yield* hanoi(n-1, help, to, from);
   }
   yield; // Pass execution back to the "runStepByStep" loop, rerendering & delaying happens here
}

处理程序是:

 const timer = ms => new Promise(resolve => setTimeout(resolve, ms));

 async function runStepByStep(iterator) {
   let done = false;
  do {
    ({ done } = iterator.next());
    rerender(); // TODO: Implement this
    await timer(2000);
  } while(!done);
}

 runStepByStep( hanoi(10, 0, 2, 1) );