3
            var diceToRoll = [2,2]; 
            var diceRolled = new Array(); 


            function recurse(diceToRoll, diceRolled) {      
                roll = diceToRoll[0]                        
                diceLeftToRoll = diceToRoll;                
                diceLeftToRoll.shift();                 

                for(loop=1; loop<(roll+1); loop++) {    
                    result = diceRolled;                        
                    result.push(loop);                      

                    if(diceLeftToRoll.length == 0) {        
                        console.log(result);    
                        result.pop(); 
                    } else {
                        recurse(diceLeftToRoll, result);
                    }
                }
            }

            recurse(diceToRoll, diceRolled);    

我正在尝试编写一个递归函数来打印任意数量的骰子的可能结果。例如,dd100 ( diceToRoll = [6, 10, 10, 100])( diceToRoll = [6, 6, 6, 6, 6]) 等。在示例中,我使用了最简单的情况(或两个 2 面骰子)。

我预计结果是 [1,1]、[1,2]、[2,1]、[2,2] 但它只记录 [1,1]、[1,2]。这对于任何数量或类型的骰子都是一样的——只有最深层次的递归才能正常工作。

我想我在它的逻辑中遗漏了一些明显的东西/或者误解了 JavaScript 中的变量范围,但我真的很难理解它。

编辑1(使程序目的的解释更清楚)

该程序的目的是列出任意数量骰子上的所有可能值。所以骰子6意味着值的范围1..6。同样,一个双面骰子2, 意味着值的范围1..2。因此,对于示例 ( ) 中的两个双面骰子,diceToRoll[2,2]可能的值为 1,1 1,2 2,1 和 2,2 - 这是应该返回的值。

4

2 回答 2

1

您必须使用 . 声明“滚动”(和其他局部变量)var

        function recurse(diceToRoll, diceRolled) {      
            var roll = diceToRoll[0]                        
            var diceLeftToRoll = diceToRoll;                
            diceLeftToRoll.shift();                 

            for(var loop=1; loop<(roll+1); loop++) {    
                var result = diceRolled;                        
                result.push(loop);                      

                if(diceLeftToRoll.length == 0) {        
                    console.log(result);    
                    result.pop(); 
                } else {
                    recurse(diceLeftToRoll, result);
                }
            }
        }

没有var,“滚动”和“循环”是全局的。

我不确定“结果”的意义是什么;它只是对“diceRolled”数组的引用,所以我不确定你为什么不直接使用它。

编辑——我不确定你的代码到底想做什么,但另一个重要的问题是:

      var diceLeftToRoll = diceToRoll;
      diceLeftToRoll.shift();

当您对一个引用数组的值进行赋值时,您不会复制该数组。因此,两个变量都指向同一个数组对象,第一个元素将被删除。如果您改为使“diceLeftToRoll”成为另一个数组的副本,那么事情会有所不同:

      var diceLeftToRoll = diceToRoll.slice(1); // copy all but 1st element

然而,我认为整个事情不会奏效,因为我现在认为“结果”变量是试图做类似的事情。

再次编辑这是一个以列表形式返回结果的替代版本。除了添加到结果中的最终条目之外,这避免了制作副本。

function allRolls( dice ) {
  var list = [], rolled = [];

  function roll( dn ) {
      var dp = rolled.length;
      for (var dv = 1; dv <= dice[dn]; ++dv) {
        rolled[dp] = dv;
        if (dn < dice.length - 1)
          roll(dn + 1)
        else
          list.push(rolled.slice(0));
      }
      rolled.length = dp;
  }

  if (dice.length) roll(0);

  return list;
}

allRolls([3, 3, 3]);

该功能涉及完成所有工作的内部功能。它传递了要掷骰子的“骰子”列表中的索引;最初,这是 0。

该函数跟踪另外两个列表:累积的可能滚动,以及一个表示“滚动到目前为止”的数组,供递归内部函数使用。

在每个递归级别,函数迭代当前骰子的面(即dice[dn])。每次迭代都会将该骰子值放在“滚动”数组末尾的插槽中;每次迭代都使用相同的插槽。现在,如果循环注意到“dn”表示列表中的最后一个骰子,那么它会复制“rolled”数组并将其添加到结果列表中。如果不是,那么它会进行递归调用,将下一个骰子索引向下传递。

然后,外部函数只是检查是否有任何骰子要掷,如果有,就掷骰子。它返回累积的列表。

于 2013-05-19T13:57:29.787 回答
1

您的代码有几个问题:

  1. 使用var关键字来定义局部变量。

  2. 将数组分配给另一个变量不会复制其内容,只是引用同一个数组。Array.slice()如果要克隆阵列,请使用。

这是一个固定的功能:

var diceToRoll = [2,2],
    diceRolled = []; 

function recurse(diceToRoll, diceRolled) {      
    var roll = diceToRoll[0],
        diceLeftToRoll = diceToRoll.slice(1),
        loop,
        result;                 

    for(loop=1; loop<=roll; loop++) {    
        result = diceRolled.slice(0);                        
        result.push(loop);                      

        if(diceLeftToRoll.length === 0) {        
            console.log(result);    
            result.pop(); 
        } else {
            recurse(diceLeftToRoll, result);
        }
    }
}

recurse(diceToRoll, diceRolled);

笔记

diceToRoll = diceToRoll.slice(1)

相当于

diceToRoll = diceToRoll.slice(0);
diceToRoll.shift();

在这里摆弄:http: //jsbin.com/isebef/1/edit

于 2013-05-19T14:27:43.023 回答