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。したがって、例 ( ) の 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 です。

この関数は、他の 2 つのリストを追跡します。蓄積された可能なロールと、再帰的な内部関数で使用するための「これまでのロール」を表す配列です。

各再帰レベルで、関数は現在のサイコロの面 (つまりdice[dn]) を反復処理します。各反復は、そのサイコロの値を「ロールされた」配列の最後にあるスロットに配置します。各反復で同じスロットが使用されます。ここで、ループが「dn」がリストの最後のサイコロを表していることに気付いた場合、「転がされた」配列のコピーを作成し、それを結果リストに追加します。そうでない場合は、再帰呼び出しを行い、次のサイコロのインデックスを渡します。

外側の関数は、ロールするサイコロがあるかどうかを確認し、ある場合はそれらをロールします。蓄積されたリストを返します。

于 2013-05-19T13:57:29.787 に答える