在数组中匹配子数组。计划方案

时间:2012-04-27 10:19:59

标签: javascript arrays sub-array

好的,请考虑一下:

我有一个包含arrays-1ab的大数组。

-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]
    ]
]

查看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...
        }
    }
}

在这个例子中,我使用了tic-tac-toe。

但我可以做任何事。

5 个答案:

答案 0 :(得分:3)

您可以做的是编译模式以提高速度。与相同语言相同的方式允许编译正则表达式以提高速度。

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
}

那是做什么的?

例如

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

将创建以下功能

    "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]; }"

那么你如何使用它?

要匹配电路板上的位置,请按以下步骤使用

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

注意,上面最后一个剪辑假设您正在使用许多流行的高阶编程库之一,例如lodash,以提供collect和{{1}函数在数组原型上,如果不是使用普通的旧for循环。

答案 1 :(得分:0)

不,你只需要三个嵌套循环:一个循环你的模式,两个循环你的二维游戏领域:

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;
}

好的,你可能需要玩家的第四个循环(players.any(getSolution)),但这并不会让它变得更加疯狂,也可能只为两个玩家内联。

然而,它可能比制定“模式数组”更容易为模式本身构建算法:

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;
}

答案 2 :(得分: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个不同的循环要快得多

答案 3 :(得分: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));

答案 4 :(得分:0)

非常有趣的问题。 +1 :)这是我对此的看法。

检查我的小提琴http://jsfiddle.net/BuddhiP/J9bLC/以获得完整的解决方案。我将尝试解释这里的要点。

我从这样的董事会开始。我用了0而不是-1因为它更容易。

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

我的策略很简单。

  1. 检查是否有任何行具有相同的播放器(a或b),如果有,我们就有赢家。
  2. 否则,检查是否有任何列具有相同的播放器
  3. 否则,检查对角线是否有玩家
  4. 这是三个获胜案例。

    首先我创建了一个可以占用行集的函数(例如:[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;
    };
    

    在这里,我连续获取唯一值,如果我只能找到一个不是零的唯一值,那么他就是胜利者。

    如果行中没有获胜者,我会检查列。为了重用我的代码,我使用_.zip()方法将列转换为行,然后使用上面相同的函数来检查我们是否有赢家。

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

    如果我仍然没有找到胜利者,请及时检查对角线。我已经编写了这个函数来从板上提取两个对角线作为两行,并使用相同的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()方法而不是直接调用该函数,则reason is()允许您将数组元素作为参数列表传递给函数。

    我相信这应该适用于4x4或更高版本的matrics,虽然我没有测试它们。

    我没有多少时间来测试解决方案,所以如果您发现任何错误,请告诉我。