如果行和列中的四个元素相同,如何检入二维数组?

时间:2017-05-28 17:10:50

标签: javascript arrays algorithm multidimensional-array foreach

我正在尝试获得一个嵌套的forEach循环,它在二维数组中找到一对四。

这是我的数组的示例:

[0, 0, 0, 0, 0],
[0, 2, 0, 0, 0],
[0, 1, 2, 0, 0],
[0, 1, 2, 2, 0],
[1, 2, 1, 1, 2],

它应该忽略0并且只能找到四个带有'1'或'2'的条目的水平,垂直和对角线对。

有人有任何建议吗?

4 个答案:

答案 0 :(得分:1)

我认为这是一个基本问题,它是许多棋盘游戏算法的核心,因此值得一般解决方案。

我的解决方案将返回nm*m连续项目的坐标和值,这些项目可以在0 2D板上水平,垂直或对角存在。在这个2D板上,1代表2m*m表示相反值的空格。

基本思路是将n*n板重新分段为n*n重叠(按1项偏移)板块(块)。

我们拥有n子板后,我们将获得可用行的多个n数组用于水平,可用列的多个n数组用于垂直和2 5*5每个对角线的大小数组一个。

在我们的示例中,我们有一个var board = [[0, 0, 2, 0, 0], [0, 2, 2, 0, 0], [0, 1, 2, 0, 0], [0, 1, 2, 2, 0], [1, 1, 1, 1, 2]]; 板,如下所示;

n

在这个板上左上角是(0,0),右下角是(4,4)。因此,如果我们的{ 'sx: 2, sy: 0, ex: 2, ey: 3': [ [ 2, 0 ], [ 2, 3 ], 2 ], 'sx: 0, sy: 4, ex: 3, ey: 4': [ [ 0, 4 ], [ 3, 4 ], 1 ], 'sx: 1, sy: 1, ex: 4, ey: 4': [ [ 1, 1 ], [ 4, 4 ], 2 ] } 值为4,您很快就会注意到我们应该期待三次点击,例如

  1. 从(2,0)到(2,3)命中2s
  2. 从(0,4)到(3,4)命中1s
  3. 从(1,1)到(4,4)命中2s
  4. 结果在对象中返回如下;

    sx

    其中syex表示起始(x,y)坐标,eyfunction checkBoard(b,n){ function chunk2D(b,n){ var chunks = [], chunk; if (!n || b.length < n || b[0].length < n ) return "no way..!"; for (var i = 0; i <= b.length - n; i++){ for (var j = 0; j <= b[0].length - n; j++){ chunk = {x:j, y:i, c:[]}; for (var k = 0; k < n; k++){ chunk.c.push(b[i+k].slice(j,j+n)); } chunks.push(chunk); chunk = []; } } return chunks; } function getDiagonals(a){ var len = a.length, result = [[],[]]; for (var i = 0; i < len; i++){ result[0].push(a[i][i]); result[1].push(a[i][len-1-i]); } return result; } function getColumns(a){ return a.map((r,i) => r.map((_,j) => a[j][i])); } var chunks = chunk2D(b,n), diags, columns, found; return chunks.reduce(function(r,c,i){ diags = getDiagonals(c.c); found = diags[0].reduce((p,d) => p !== 0 && d !== 0 && p == d ? d : 0); found && (r["sx: " + c.x + ", sy: " + c.y + ", ex: " + (c.x+n-1) + ", ey: " + (c.y+n-1)] = [[c.x,c.y],[c.x+n-1,c.y+n-1],found]); found = diags[1].reduce((p,d) => p !== 0 && d !== 0 && p == d ? d : 0); found && (r["sx: " + c.x + ", sy: " + (c.y+n-1) + ", ex: " + (c.x+n-1) + ", ey: " + c.y] = [[c.x,c.y+n-1],[c.x+n-1,c.y],found]); columns = getColumns(c.c); columns.forEach(function(col,j){ // colums check found = col.reduce((p,d) => p !== 0 && d !== 0 && p == d ? d : 0); found && (r["sx: " + (c.x+j) + ", sy: " + c.y + ", ex: " + (c.x+j) + ", ey: " + (c.y+n-1)] = [[c.x+j,c.y],[c.x+j,c.y+n-1],found]); }); c.c.forEach(function(row,j){ // rows check found = row.reduce((p,d) => p !== 0 && d !== 0 && p == d ? d : 0); found && (r["sx: " + c.x + ", sy: " + (c.y+j) + ", ex: " + (c.x+n-1) + ", ey: " + (c.y+j)] = [[c.x,c.y+j],[c.x+n-1,c.y+j],found]); }); return r; }, {}); } var board = [[0, 0, 2, 0, 0], [0, 2, 2, 0, 0], [0, 1, 2, 0, 0], [0, 1, 2, 2, 0], [1, 1, 1, 1, 2]]; console.log(checkBoard(board,4));表示属性中的结束(x,y)坐标。该值可供您进一步处理所有必需信息。

    这是代码;

    &#13;
    &#13;
    \s
    &#13;
    &#13;
    &#13;

答案 1 :(得分:0)

var horizontal=[[0, 0, 0, 0, 0],[0, 2, 0, 0, 0],[0, 1, 2, 0, 0],[0, 1, 2, 2, 0],[1, 2, 1, 1, 2]];

var vertical=horizontal.reduce(function(arr,row)=>(row.forEach((el,i)=>arr[i].push(el)),arr),[]);

var result=[1,2].some(e=>horizontal.some(row=>row.filter(el=>el===e).length>=4))||vertical.some(row=>row.filter(el=>el===e).length>=4)));

只需计算每个方向每行中的一个和两个,如果有一些超过四个,则返回true。

答案 2 :(得分:0)

Jonas的回答比这个好得多,但如果你不理解他的语法,这里有一个简化的,更详细的版本:

var field = [
  [0, 0, 0, 0, 0],
  [0, 2, 0, 0, 0],
  [0, 1, 2, 0, 0],
  [0, 1, 2, 2, 0],
  [1, 2, 1, 1, 2]
];

function checkVertical(field, player){
  for(i = 0; i < 5; ++i){
    if (field[0][i] === player 
        && field[1][i] === player
        && field[2][i] === player
        && field[3][i] === player
    ) return true;
    
    if (field[1][i] === player 
        && field[2][i] === player
        && field[3][i] === player
        && field[4][i] === player
    ) return true;
  }
  return false;
}

function checkHorizontal(field, player){
  for(i = 0; i < 5; ++i){
    if (field[i][0] === player 
        && field[i][1] === player
        && field[i][2] === player
        && field[i][3] === player
    ) return true;
    
    if (field[i][1] === player 
        && field[i][2] === player
        && field[i][3] === player
        && field[i][4] === player
    ) return true;
  }
  return false;
}

function checkDiagonal1(field, player){
  // exercise for the reader
  return false;
}

function checkDiagonal2(field, player){
  // exercise for the reader
  return false;
}

function isWin(field, player){
  return checkVertical(field, player) 
    || checkHorizontal(field, player)
    || checkDiagonal1(field, player)
    || checkDiagonal2(field, player);
 
}

console.log(isWin(field, 1));

答案 3 :(得分:0)

这是我使用基本的for循环和迭代来刺激它。我确信这不如@Red的例子那么有效。

每种类型的集都是一个单独的功能。输出采用坐标的形式,显示集合所在矩阵的位置,开始位置以及结束位置。显然,输出可以是布尔值或其他任何你想要的输出。我只是通过这种方式格式化输出以证明它有效。

我已经将过滤部分留给了用户,在这种情况下,我特意允许0(你的规范要求忽略它们),因为你的示例输入数据将永远不会返回水平或对角线调用的集合。下面的示例会筛选出包含少于4个元素的任何集合。

此示例假定行的长度都相同。如果行的长度不同,则需要更多逻辑。

const Matrix = function(matrix) { this.matrix = matrix; }

Matrix.prototype.getHorizontalSequences = function() {
  const matrix = this.matrix, sets = [];

  for(let i = 0; i < matrix.length; ++i) {
    const row = matrix[i];

    for(let j = 0; j < row.length; ++j) {
      const start = j;
      let k = j + 1;

      for(; k < row.length; ++k) {
        if(row[j] !== row[k]) break;
      }

      sets.push({ row: i, val: row[j], start: start, end: k - 1 });
      j = k - 1;
    }
  }
  
  return sets;
};

Matrix.prototype.getVerticalSequences = function() {
  const matrix = this.matrix, sets = [];

  for(let i = 0; i < matrix[0].length; ++i) {
    for(let j = 0; j < matrix.length; ++j) {
      const start = j;
      let k = j + 1;

      for(; k < matrix.length; ++k) {
        if(matrix[j][i] !== matrix[k][i]) break;
      }

      sets.push({ col: i, val: matrix[j][i], start: start, end: k - 1 });
      j = k - 1;
    }
  }
  
  return sets;
};

Matrix.prototype.getDiagonalSequences = function() {
  const matrix = this.matrix, sets = [];

  for(let i = 0; i < matrix[0].length; ++i) {
    for(let j = i; j < matrix.length; ++j) {
      const start = j;
      let k = j + 1;

      for(; k < matrix.length; ++k) {
        if(matrix[j][i] !== (matrix[j + k] || [])[i + k]) break;
      }

      sets.push({ col: i, val: matrix[j][i], start: start, end: k });
      j = k - 1;
    }
  }
  
  return sets;
};

let matrix = new Matrix([
  [0, 0, 0, 0, 0],
  [0, 2, 0, 0, 0],
  [0, 1, 2, 0, 0],
  [0, 1, 2, 2, 0],
  [1, 2, 1, 1, 2]
])

console.log(matrix.getHorizontalSequences().filter(e => (e.end + 1) - e.start >= 4));
console.log(matrix.getVerticalSequences().filter(e => (e.end + 1) - e.start >= 4));
console.log(matrix.getDiagonalSequences().filter(e => (e.end + 1) - e.start >= 4));
.as-console-wrapper { max-height: 100% !important; }