简体   繁体   中英

How to find a consecutive sequence of symbols in a squared matrix

I need help finding the right algorithm. I have a 2d array, for example:

var arr = [
[""," "," "," ",""],
[""," "," "," ",""],
[""," "," ","X",""],
["","X","X","X",""],
[""," "," ","X",""]];

And I want to verify if this array has three next symbols that match each other in any direction (horizontal or vertical, or cross), then display this symbols.

I'm doing it like this:

Run through array:

for(var i = 0; i < arr.length; i+=1){
   for(var j = 0; j < arr.length; j+=1){

Then verify if match:

if(arr[i][j] == "X" && arr[i+1][j] == "X" && arr[i+2][j] == "X"){

       console.log(arr[i][j]);

But it will give an error, because i+1 and i+2 are behind the array.

I've tried to make verification if:

  if(arr[i][j+1] < arr.length)

But it doesn't count the last rows.

How can I do it?

i < arr.length-2 ,循环应该停止,因为您要确保i+2在范围之内。

Three consecutive X symbols are uniquely defined by their center and the direction (horizontal, vertical or one of two diagonals). I'd do it like this (thanks @DarthJS):

for (var i = 0; i < arr.length; i+=1) {
    for (var j = 0; j < arr.length; j+=1) {
        // Horizontal
        if (i > 0 && i < arr.length - 1 &&
            arr[i-1][j] == "X" && arr[i][j] == "X" && arr[i+1][j] == "X") {
            console.log(arr[i][j]);
        }
        // Vertical
        if (j > 0 && j < arr.length - 1 &&
            arr[i][j-1] == "X" && arr[i][j] == "X" && arr[i][j+1] == "X") {
            console.log(arr[i][j]);
        }
        // Diagonal
        if (i > 0 && i < arr.length - 1 &&
            j > 0 && j < arr.length - 1) {
            if (arr[i-1][j-1] == "X" && arr[i][j] == "X" && arr[i+1][j+1] == "X") {
                console.log(arr[i][j]);
            }
            if (arr[i-1][j+1] == "X" && arr[i][j] == "X" && arr[i+1][j-1] == "X") {
                console.log(arr[i][j]);
            }
        }
    }
}

you can try to count successive for each row, column or diagonal.

Given a step function that count successive "X"

data = {
    succX = 0
};

function step (data, arr, i, j) {
    data.succX = arr[i][j] === "X" ? data.succX + 1 : 0;
    return data.succX >= 3;;
}

Then, you can iterate and look for step result. If step return true , we might store the corresponding sequence and stop searching.

Iterate over each row

for (var i = 0, nbRow = arr.length; i < nbRow; i++) {
    for (var j = 0, nbCol = arr[i].length; j < nbCol; j++) {
        data.winSeq = data.winSeq || step(data, arr, i, j) && [[i, j-2], [i, j-1], [i, j]];
    }
}

data.succX = 0;

Iterate over each column

for (var j = 0, nbCol = arr[0].length; j < nbCol; j++) {
    for (var i = 0, nbRow = arr.length; i < nbRow; i++) {
        data.winSeq = data.winSeq || step(data, arr, i, j) && [[i-2, j], [i-1, j], [i, j]];
    }
}

Iterate over each diagonal

for (var d = 0, dim = arr.length, nbDiag = dim * 2 - 1; d < nbDiag; d++) {
    var maxE = d >= dim ? nbDiag - d - 1 : d;
    for (var e = 0; e <= maxE; e++) {
        var i = Math.min(d, dim -1) - e,
            j = Math.max(0, d - dim + 1) + e;
        data.winSeq = data.winSeq || step(data, arr, i, j) && [[i, j-2], [i+1, j-1], [i+2, j]];
    }
    data.succX = 0;
}

for (var d = 0, dim = arr.length, nbDiag = dim * 2 - 1; d < nbDiag; d++) {
    var maxE = d >= dim ? nbDiag - d - 1 : d;
    for (var e = 0; e <= maxE; e++) {
        var i = dim - 1 -Math.min(d, dim -1) + e,
            j = Math.max(0, d - dim + 1) + e;
        data.winSeq = data.winSeq || step(data, arr, i, j) && [[i-2, j-2], [i-1, j-1], [i, j]];
    }
    data.succX = 0;
}

At the end, data.winSeq contains either undefined or a valid sequence.

You can see the whole process illustrated in the snippet right below.

 var delay = 0; function findWinSeq(arr, seqLength) { var data = { succX: 0 }; // Iteration step function step (data, arr, i, j) { if (arr[i][j] === "X") { data.succX++; colorize(i, j, "validCell", delay); } else { data.succX = 0; colorize(i, j, "selectCell", delay); } var hasWon = data.succX >= seqLength; delay += hasWon ? 2000 : 120; return hasWon; } // Count for each row for (var i = 0, nbRow = arr.length; i < nbRow; i++) { for (var j = 0, nbCol = arr[i].length; j < nbCol; j++) { data.winSeq = data.winSeq || step(data, arr, i, j) && [[i, j-2], [i, j-1], [i, j]]; } } data.succX = 0; // Count for each column for (var j = 0, nbCol = arr[0].length; j < nbCol; j++) { for (var i = 0, nbRow = arr.length; i < nbRow; i++) { data.winSeq = data.winSeq || step(data, arr, i, j) && [[i-2, j], [i-1, j], [i, j]]; } } // Count for each diagonal for (var d = 0, dim = arr.length, nbDiag = dim * 2 - 1; d < nbDiag; d++) { var maxE = d >= dim ? nbDiag - d - 1 : d; for (var e = 0; e <= maxE; e++) { var i = Math.min(d, dim -1) - e, j = Math.max(0, d - dim + 1) + e; data.winSeq = data.winSeq || step(data, arr, i, j) && [[i, j-2], [i+1, j-1], [i+2, j]]; } data.succX = 0; } for (var d = 0, dim = arr.length, nbDiag = dim * 2 - 1; d < nbDiag; d++) { var maxE = d >= dim ? nbDiag - d - 1 : d; for (var e = 0; e <= maxE; e++) { var i = dim - 1 -Math.min(d, dim -1) + e, j = Math.max(0, d - dim + 1) + e; data.winSeq = data.winSeq || step(data, arr, i, j) && [[i-2, j-2], [i-1, j-1], [i, j]]; } data.succX = 0; } return data.winSeq || null; } var tests = [ [ [" "," "," "," "," "], [" ","X"," ","X"," "], [" "," ","X"," "," "], [" "," "," ","X"," "], [" ","X"," "," "," "] ], [ [" "," "," "," "," "], [" ","X"," ","X"," "], [" "," "," "," "," "], [" "," "," ","X"," "], [" ","X"," "," "," "] ], [ [" "," "," "," "," "], [" ","X"," ","X"," "], [" "," "," "," ","X"], [" "," "," ","X"," "], [" ","X","X"," "," "] ], [ [" "," "," "," "," "], [" "," "," ","X"," "], [" "," ","X","X"," "], [" "," "," ","X"," "], [" ","X"," "," "," "] ], [ [" "," "," "," "," "], ["X","X","X","X"," "], [" "," ","X"," "," "], [" "," "," ","X"," "], [" ","X"," "," "," "] ], ]; // Just some fancy stuffs function colorize(i, j, color, delay) { function _colorize(i, j, color) { // Reset first valid cell if needed if (color === "selectCell") { var cells = document.getElementsByClassName("validCell"); for(var k = 0, cell; cell = cells[k]; k++) { cell.className = "cell"; } } // Apply color to the next cell var previous = document.getElementsByClassName("selectCell")[0]; if (previous !== undefined) { previous.className = "cell"; } document.getElementById([i,j].join("")).className = color; } setTimeout(_colorize, delay, i, j, color); } function buildBoard (test) { var board = document.getElementById("board"); board.style.width = test.length * 40 + "px"; board.innerHTML = ""; for (var i = 0, marker, cell, dim = test.length; i < dim; i++) { for (var j = 0; j < dim; j++) { cell = document.createElement('div'); cell.className = "cell"; cell.id = [i,j].join(""); if (test[i][j] === "X") { marker = document.createElement('div'); marker.className = "marker"; cell.appendChild(marker); } board.appendChild(cell); } } } for (var i = 0, test; test = tests[i]; i++) { setTimeout(function (test) { setTimeout(function (test) { buildBoard(test); }, delay, test); findWinSeq(test, 3); }, 750 * i, test); } 
 #board { padding: 0; margin: 0; font-size: 0; } .cell, .validCell, .selectCell { display: inline-block; box-sizing: border-box; border: 1px solid #888; width: 40px; height: 40px; } .validCell { background: #CDEB8B; } .selectCell { background: #DDD; } .marker { background: #888; width: 16px; height: 16px; margin: 12px 0 0 12px; } 
 <div id="board"></div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM