5

わかりました、これを考慮してください:

arrays、、、およびを含む大きな配列が-1あります。ab

-1フィールドが空であることを意味します:

var board = [
    [-1,-1, a],
    [-1,-1, b],
    [ b,-1, a]
]

今、私はこれに対して小さな配列をチェックしたいと思います:

var solutions = [
    [
        [1, 1, 1]
    ],
    [
        [1],
        [1],
        [1]
    ],
    [
        [1],
        [0,1],
        [0,0,1]
    ],
    [
        [0,0,1],
        [0,1],
        [1]
    ]
]

からの1つの既存の値がboardのパターンと一致するかどうかを確認しsolutionsます。


いずれかaのパターンに一致しますか?
いずれかbのパターンに一致しますか?


クレイジーなネストされたループを作成するよりも良い方法を誰かが見ることができますか?

var q,w,e,r,t,y;

q=w=e=r=t=y=0;

for( ; q < 3; q++ ) {
    for( ; w < 3; w++ ) {
        for( ; e < SOLUTIONS.length; e++ ) {
            .... and so on...
        }
    }
}

この例では、三目並べを使用しました。

しかし、私は何でもかまいません。

4

5 に答える 5

3

What you can do is to compile the patterns for speed. The same way as same languages allow regular expressions to be compiled for speed.

function compile(pattern) {
    var code = "matcher = function(a) { return "
    var first = null
    for (var n = 0; n < pattern.length; n++) {
        for (var m = 0; m < pattern[n].length; m++) {
            if (pattern[n][m] == 0) continue
            var nm = "["+n+"]["+m+"]"
            if (first == null) {
                code += "a" + nm + " != -1";
                first = " && a" + nm + " == "
            }
            code += first + "a" + nm
      }
    }
    code += "; }";
    eval(code);
    return matcher
}

So what is this doing?

For example

    compile([[1],[0,1],[0,0,1]]).toString()

will create the following function

    "function (a) { return a[0][0] != -1 && a[0][0] == a[0][0] && a[0][0] == a[1][1] && a[0][0] == a[2][2]; }"

So how do you use it?

To match positions on your board use it as follows

var patterns = solutions.collect(function(each) { return compile(each); })
var matches = patterns.any(function(each) { return each(board); })

 

NB, the very last snipped above assumes you're using one of the many popular higher-order programming libraries, as for example lodash, to provide collect and any functions on the array prototype, if not use plain old for loops instead.

于 2012-11-23T19:40:01.030 に答える
0

非常に興味深い質問です。+1:)これが私の見解です。

完全な解決策については、私のフィドルhttp://jsfiddle.net/BuddhiP/J9bLC/を確認してください。ここで要点を説明しようと思います。

私はこのようなボードから始めます。簡単なので、-1ではなく0を使用しました。

    var a = 'a', b = 'b';
    var board = [
       [a, 0, a],
       [b, b, b],
       [a, 0, a]
       ];

私の戦略は単純です。

  1. いずれかの行に同じプレーヤー(aまたはb)があるかどうかを確認します。同じプレーヤーがいる場合は、勝者がいます。
  2. それ以外の場合は、列のいずれかに同じプレーヤーがあるかどうかを確認します
  3. それ以外の場合は、対角線にプレーヤーがいるかどうかを確認します

これらが3つの勝利事例です。

最初に、行のセット(例:[a、0、b])を取得し、行全体に同じ値が含まれているかどうか、およびその値がゼロ(またはこの場合は-1)でないかどうかを確認できる関数を作成しました。

checkForWinner = function () {
    lines = Array.prototype.slice.call(arguments);
    // Find compact all rows to unique values.
    var x = _.map(lines, function (l) {
        return _.uniq(l);
    });
    // Find the rows where all threee fields contained the same value.
    var y = _.filter(x, function (cl) {
        return (cl.length == 1 && cl[0] !== 0);
    });
    var w = (y.length > 0) ? y[0] : null;
    return w;
};

ここでは、一意の値を続けて取得します。ゼロではない一意の値が1つだけ見つかった場合は、彼が勝者です。

行に勝者がいない場合は、列を確認します。コードを再利用するために、_。zip()メソッドを使用して列を行に変換してから、上記と同じ関数を使用して勝者がいるかどうかを確認します。

var board2 = _.zip.apply(this, board);
winner = checkForWinner.apply(this, board2);

それでも勝者が見つからない場合は、対角線を確認してください。この関数は、ボードから2つの対角線を2行として抽出し、同じcheckForWinner関数を使用して、対角線がいずれかのプレーヤーによって支配されているかどうかを確認するように作成しました。

extractDiagonals = function (b) {
    var d1 = _.map(b, function (line, index) {
        return line[index];
    });
    var d2 = _.map(b, function (line, index) {
        return line[line.length - index - 1];
    });
    return [d1, d2];
};

最後に、ここで実際にボードで勝者を確認します。

// Check rows
winner = checkForWinner.apply(this, board);
if (!winner) {
    var board2 = _.zip.apply(this, board);

    // Check columns, now in rows
    winner = checkForWinner.apply(this, board2);
    if (!winner) {
        var diags = extractDiagonals(board);
        // Check for the diagonals now in two rows.
        winner = checkForWinner.apply(this, diags);
    }
}

関数を直接呼び出す代わりにapply()メソッドを使用する理由がわからない場合は、apply()を使用すると、配列要素を引数のリストとして関数に渡すことができます。

私はそれらをテストしませんでしたが、これは4x4以上のマトリックスでも機能するはずだと思います。

ソリューションをテストする時間がほとんどなかったので、エラーが見つかった場合はお知らせください。

于 2012-11-28T10:56:29.750 に答える
0

いいえ、必要なのは3つのネストされたループだけです。1つはパターンをループし、2つは2次元のプレイフィールドをループします。

function checkPatterns(patterns, player, field) {
    pattern: for (var p=0; p<patterns.length; p++) {
        for (var i=0; i<patterns[p].length; i++)
            for (var j=0; j<patterns[p][i].length; j++)
                if (patterns[p][i][j] && player !== field[i][j])
                    continue pattern;
        // else we've matched all
        return p;
    }
    // else none was found
    return -1;
}
function getSolution(player)
    return SOLUTIONS[checkPatterns(SOLUTIONS, player, currentBOARD)] || null;
}

OK、プレーヤー用に4番目のループが必要になる場合がありますが(players.any(getSolution))、それでもクレイジーになることはなく、2人のプレーヤーのみにインライン化される場合もあります。

ただし、「パターン配列」を作成するよりも、パターン自体のアルゴリズムを構築する方が簡単な場合があります。

function hasWon(player, field) {
    vert: for (var i=0; i<field.length; i++) {
        for (var j=0; j<field[i].length; j++)
            if (field[i][j] !== player)
                continue vert;
        return "vertical";
    }
    hor: for (var j=0; j<field[0].length; j++) {
        for (var i=0; i<field.length; i++)
            if (field[i][j] !== player)
                continue hor;
        return "horizontal";
    }
    for (var i=0, l=true, r=true, l=field.length; i<l; i++) {
        l == l && field[i][i] === player;
        r == r && field[l-i-1][l-i-1] === player;
    }
    if (l || r)
        return "diagonal";
    return null;
}
于 2012-11-23T12:23:15.320 に答える
0

ボードを文字列にすることができます。

 var board = 
   "-1,-1,a,
    -1,-1,b,
     b,-1,a"

そしてあなたの解決策は文字列の配列にすることができます(ボードに似ています)

var solutions = [ 
   "1,1,1,
    0,0,0,
    0,0,0"
    ,
   "1,0,0,
    0,1,0,
    0,0,1"

]

次に、比較のために、-1とbを0に置き換え、aを1に置き換えてから、文字列を単純に比較します。

これは、別のループ内に10の異なるループを持つよりもはるかに高速です

于 2012-11-27T22:30:24.487 に答える
0

すべてを通過するには、常にループが必要です。読みやすく、柔軟性を高めることができます。以下のコードは、1を超える任意の数の行/列で機能し、2を超えるプレーヤーでも簡単に調整できます。

var board1 = [
[-1,-1, 'a'],
[-1,-1, 'b'],
['b',-1, 'a']
];
var board2 = [
['a','a', 'a'],
[-1,-1, 'b'],
['b',-1, 'a']
];
var board3 = [
[-1,'b', 'a'],
[-1,'b', 'b'],
['b','b', 'a']
];
var board4 = [
['a',-1, 'a'],
[-1,'a', 'b'],
['b',-1, 'a']
];

var solutions = [
[
    [1, 1, 1]
],
[
    [1],
    [1],
    [1]
],
[
    [1],
    [0,1],
    [0,0,1]
],
[
    [0,0,1],
    [0,1],
    [1]
]
];

function checkForWinner(playfield) {
    var sl = solutions.length; //solutions
    var bl = playfield.length; //board length
    var bw = playfield[0].length; //board width
    while(sl--) {
        //foreach solution
        var l = solutions[sl].length;

        if (l==1) {
            //horizontal
            //loop trough board length to find a match
            var tl = bl;
            while(tl--) {
                var pat = playfield[tl].join('')
                var r = checkRow(pat)
                if (r!==false)
                    return r;
            }
        } else {
            //vertical or diagonal
            var l1 = solutions[sl][0].length;
            var l2 = solutions[sl][1].length;

            if (l1==l2) {
                //vertical                  
                var tw = bw;
                while (tw--) {
                    //loop for each column  
                    var pat = "";   
                    var tl = l;
                    while(tl--) {
                        //loop for vertical
                        pat += playfield[tl][tw];
                    }

                    var r = checkRow(pat)
                    if (r!==false)
                        return r;
                }

            } else {
                //diagonal
                var pat = "";
                while(l--) {
                    //loop for vertical
                    var tw = solutions[sl][l].length;
                    while (tw--) {
                        //loop for horizontal                       
                        if (solutions[sl][l][tw]!=0)
                            pat += playfield[l][tw];
                    }
                }

                var r = checkRow(pat)
                if (r!==false)
                    return r;
            }
        }
    }
    return 'no winner';
}

function checkRow(pat) {
    if (!(pat.indexOf('a')>=0 || pat.indexOf('-1')>=0)) {
        //only b on row. player B won
        return 'B';
    }

    if (!(pat.indexOf('b')>=0 || pat.indexOf('-1')>=0)) {
        //only a on row. player A won
        return 'A';
    }

    return false;
}

console.log(checkForWinner(board1));
console.log(checkForWinner(board2));
console.log(checkForWinner(board3));
console.log(checkForWinner(board4));
于 2012-11-27T23:07:52.393 に答える