2012-04-27 17 views
5

Ok, considere esto:Subarreglo coincidente en el conjunto. Esquema en el esquema

que tienen una gran matriz que contiene arrays, -1, a y b.

El -1 significa que el campo está vacío:

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

Ahora quiero comprobar las matrices más pequeñas agains esto:

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

para ver si uno valor existente de board coinciden con el patrón en solutions.


¿a corresponde con el patrón?
¿Coincide b con alguno de los patrones?


Puede alguno de ustedes ver una mejor manera de hacer un bucle anidado loco:

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

En este ejemplo he utilizado tic-tac-dedo del pie.

Pero podría ser cualquier cosa.

+0

que suponer, por un tic-tac-dedo del pie, en los 'patrones disoluciones para que no desea para que coincida con ceros, pero las celdas vacías. – akuhn

+0

puede tratar de convertir las matrices a 1 nivel de profundidad para facilitar la comparación. Pero no sé fragmento de cualquier matriz superficial ... :( – ajax333221

Respuesta

0

Pregunta muy interesante. +1 :) Aquí está mi opinión sobre esto.

Compruebe mi violín http://jsfiddle.net/BuddhiP/J9bLC/ para la solución completa. Trataré de explicar los puntos principales aquí.

Empiezo con una placa como esta. He usado 0 en lugar de -1 porque es más fácil.

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

Mi estrategia es simple.

  1. Comprueba si alguna de las filas tiene el mismo jugador (aob), de ser así tenemos un ganador.
  2. Else, Compruebe si alguna de las columnas tiene el mismo jugador
  3. Else, Compruebe si diagonales tiene un jugador

Esos son los tres casos ganadores.

Primero creé una función que puede tomar un conjunto de filas (Ej: [a, 0, b]), y verifico si toda la fila contiene el mismo valor, y si ese valor no es cero (o -1 en su caso).

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

Aquí toman valores únicos en una fila, y si puedo encontrar un solo valor único que no es cero, el que es el ganador.

Si no hay ningún ganador en las filas, entonces verifico si hay columnas. Para reutilizar mi código, uso el método _.zip() para transformar columnas en filas y luego uso la misma función anterior para verificar si tenemos un ganador.

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

Si todavía no encuentro un ganador, es hora de consultar las diagonales. He escrito esta función para extraer dos diagonales del tablero como dos filas, y uso la misma función checkForWinner para ver si las diagonales están dominadas por cualquiera de los jugadores.

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

Por último, este es el que realmente comprobar la junta para un ganador:

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

Si alguno de ustedes se preguntan por qué uso apply() método en lugar de llamar directamente a la función, la razón es aplicar () le permite pasar elementos de una matriz como una lista de argumentos a una función.

Creo que esto debería funcionar para 4x4 o superior MATRICS también, aunque no he probado ellos.

tenía muy poco tiempo para probar la solución, así que por favor, hágamelo saber si usted encuentra algún error.

+0

Downvote para cablear tic-tac-dedo del pie, pero no abordar pregunta general de OP de cómo hacer coincidir cualquier patrón contra la junta. – akuhn

+0

hmm .. de verdad? :) OP parece pensar que respondió a su pregunta correctamente Coincidencia ** cualquier ** patrón en ** cualquier ** placa ** ** no sería responsable en este foro, preferiría un libro para eso. OP quería una coincidencia de patrones de moda de tres en raya (un solo valor en una fila/columna/diag) en cualquier tablón de tamaño que esta solución sea totalmente capaz de manejar, y lo hace de una manera mucho más simple. – BuddhiP

0

No, sólo necesita tres bucles anidados: Uno de bucle sobre sus patrones, y dos al bucle de su campo de juego en dos dimensiones:

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

bien, es posible que necesite un cuarto bucle para los jugadores (players.any(getSolution)), pero eso no lo hace más loco y podría estar incluido solo para dos jugadores.

Sin embargo, podría ser más fácil que la formulación de "conjuntos de patrones" para construir algoritmos para los patrones de sí mismos:

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

Lo que puede hacer es compilar los patrones para la velocidad. De la misma manera que los mismos idiomas, se pueden compilar expresiones regulares para la velocidad.

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 
} 

¿Qué es esto?

Por ejemplo

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

creará la siguiente función

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

Entonces, ¿cómo se usa?

para que coincida con las posiciones en su tablero lo utilizan de la siguiente manera

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

 

NB, el último cortó anterior se supone que está utilizando una de las muchas bibliotecas populares de programación de orden superior, como por ejemplo lodash, para proporcionar las funciones collect y any en el prototipo de la matriz, si no es así, utilice los bucles normales antiguos.

0

Usted puede tener su tablero a ser una cadena:

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

y sus soluciones puede ser una matriz de cadenas (similar a la junta)

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

]

entonces para comparar, reemplace el -1 yb con 0s y a con 1s y luego simplemente compare las cadenas

esto es mucho más rápido que tener 10 bucles diferentes dentro de otro bucle

+0

Esa fue mi primera aswell thougt, pero eso significa que es necesario para definir el patrón para cada fila. Coincide con su solución de costumbre, si la fila del medio es 1,1, 1 a menos que también añada 0,0,0,1,1,1,0,0,0 a la coincidencia. Esto funcionaría para 3x campos, pero ampliar a 9x9 daría muchas soluciones. También debe hacer una copia del campo de juego para cada comprobación para hacer los reemplazos y dado que javascript hace referencias de matriz, necesita clonar la matriz para cada comprobación, haciendo un bucle a través de todas las filas y cols para crear una nueva matriz (o use c = board.splice (0) para facilitar la lectura, no la velocidad). –

0

Siempre necesitará bucles para atravesarlo todo. Puede hacer que sea más fácil de leer y más flexible. El siguiente código funcionará para cualquier cantidad de filas/columnas mayores que 1 y con un ajuste simple también para más de 2 jugadores.

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