2012-04-27 17 views
5

Ok, considerare questo:Corrispondenza dell'array secondario nell'array. Schema nello schema

ho un grande array contenente arrays, -1, a e b.

Il -1 significa che il campo è vuoto:

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

Ora voglio controllare le matrici più piccole agains questo:

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

per vedere se un valore esistente da board partita il modello in solutions.


Does a partita qualsiasi modello?
b corrisponde a uno qualsiasi dei motivi?


Chi di voi vedere un modo migliore di fare un ciclo nidificato folle:

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

In questo esempio ho usato tic-tac-toe.

Ma potrei essere qualsiasi cosa.

+0

Presumo, per un tic-tac-toe, nei modelli 'solution' non si vogliono confrontare gli zeri ma le celle vuote. – akuhn

+0

potresti provare a convertire gli array a 1 livello in profondità per semplificare il confronto. Ma io non conosco alcun array più lento snippet ... :( – ajax333221

risposta

0

Domanda molto interessante. +1 :) Ecco la mia opinione su questo.

Controllare il mio violino http://jsfiddle.net/BuddhiP/J9bLC/ per la soluzione completa. Proverò a spiegare i punti principali qui.

Inizio con una scheda come questa. Ho usato 0 invece di -1 perché è più facile.

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

La mia strategia è semplice.

  1. Verificare se una delle righe ha lo stesso giocatore (aob), in tal caso abbiamo un vincitore.
  2. Else, Controllare se una delle colonne ha lo stesso giocatore
  3. Else, Controllare se diagonali ha un giocatore

Questi sono i tre casi vincenti.

Per prima cosa ho creato una funzione che può richiedere un set di righe (Es: [a, 0, b]) e controllare se l'intera riga contiene lo stesso valore e se tale valore non è zero (o -1 nel Astuccio).

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

Qui prendo valori unici di fila, e se riesco a trovare un solo valore unico che non è uguale a zero, il che è il vincitore.

Se non c'è nessun vincitore nelle righe, quindi controllo le colonne. Per riutilizzare il mio codice, utilizzo il metodo _.zip() per trasformare colonne in righe e quindi utilizzare la stessa funzione sopra per verificare se abbiamo un vincitore.

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

Se ancora non trovo un vincitore, il tempo di controllare le diagonali. Ho scritto questa funzione per estrarre due diagonali dal tabellone come due file, e utilizzare la stessa funzione checkForWinner per vedere se le diagonali sono dominate da uno qualsiasi dei giocatori.

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

Infine questo è dove ho effettivamente controllare la scheda per un vincitore:

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

Se qualcuno di voi si chiedono perché io uso applicare() il metodo invece di chiamare direttamente la funzione, la ragione è applicabile () consente di passare elementi di un array come elenco di argomenti a una funzione.

Credo che questo dovrebbe funzionare anche per le matrici 4x4 o superiori, anche se non li ho testati.

Ho avuto pochissimo tempo per testare la soluzione, quindi per favore fatemi sapere se trovate errori.

+0

Downvote per il cablaggio tic-tac-toe ma non per risolvere la domanda generale dell'OP su come abbinare qualsiasi schema contro qualsiasi scheda: – akuhn

+0

hmm .. Davvero? :) OP sembra pensare che ho risposto al suo domanda correttamente. Corrispondenza ** qualsiasi ** schema su ** qualsiasi ** board ** NON ** può essere risposto in questo forum, avresti bisogno di un libro per questo. OP desiderava un abbinamento di modelli di moda tic-tac-toe (un singolo valore in una riga/colonna/diag) su qualsiasi scheda di dimensioni che questa soluzione è pienamente in grado di gestire, e lo fa in un modo molto più semplice. – BuddhiP

0

No, avete solo bisogno di tre cicli annidati: Da uno a ciclo sui vostri modelli, e due per trasferire l'bidimensionale campo di gioco:

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, potrebbe essere necessario un quarto ciclo per i giocatori (players.any(getSolution)), ma questo non lo rende più folle e potrebbe essere anche solo per due giocatori.

Tuttavia, potrebbe essere più facile che la formulazione di "matrici" modello per la costruzione di algoritmi per i modelli stessi:

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

Che cosa si può fare è di compilare i modelli per la velocità. Allo stesso modo delle stesse lingue è possibile compilare le espressioni regolari per la velocità.

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 
} 

Quindi cosa sta facendo?

Per esempio

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

creerà la seguente funzione

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

Così come si usa?

per abbinare posizioni sul vostro bordo usano come segue

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

 

NB, l'ultimo stato tagliato sopra presuppone che si sta utilizzando uno dei tanti popolari librerie di programmazione di ordine superiore, come ad esempio lodash, per fornire le funzioni collect e any sul prototipo dell'array, se non si utilizza invece il vecchio ciclo semplice per loops.

0

si può avere il bordo per essere una stringa:

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

e le vostre soluzioni può essere un array di stringhe (simile alla scheda)

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

]

poi per il confronto, sostituire il -1 eb con lo 0 e il 1 con quindi confrontare semplicemente le stringhe

questo è molto più veloce di avere 10 loop diversi all'interno di un altro ciclo

+0

Questo è stato il mio primo pensiero, ma ciò significa che è necessario definire il modello per ogni riga. La soluzione non combacia se la riga centrale è 1,1, 1 a meno che non aggiungiate anche 0,0,0,1,1,1,0,0,0,0 alla partita, che funzionerebbe per il campo 3x, ma espandendo a 9x9 otterreste molte soluzioni. una copia del campo di gioco per ogni controllo per fare le sostituzioni e poiché javascript fa i riferimenti dell'array, è necessario clonare l'array per ogni controllo, quindi eseguire il ciclo su tutte le righe e le colonne per creare un nuovo array (o usare c = board.splice (0) per la leggibilità, non per la velocità) –

0

Avrete sempre bisogno di cicli per passare attraverso tutto. Puoi renderlo più facile da leggere e più flessibile. Il codice qui sotto funzionerà per qualsiasi numero di righe/colonne maggiore di 1 e con una semplice regolazione anche per più di 2 giocatori.

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