【问题标题】:How to check in 2d array if four elements in row and column are the same?如果行和列中的四个元素相同,如何检查二维数组?
【发布时间】:2017-10-29 00:32:07
【问题描述】:

我试图获得一个嵌套的 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'。

有人有什么建议吗?

【问题讨论】:

  • 显示想要的结果
  • 如果二维数组中有一对四,它应该只返回一个布尔值。
  • @Moritz 你对成对是什么意思? [[1,2,2,1][1,1,1,1]] ?
  • 哦,抱歉,我的意思是四个相同的条目,例如 [1, 1, 1, 1], [2, 2, 2, 2]。

标签: javascript arrays algorithm multidimensional-array foreach


【解决方案1】:

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

【讨论】:

  • 谢谢,您的建议更容易理解。现在可以了!
【解决方案2】:
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。

【讨论】:

  • 感谢您的建议,很遗憾,我不太了解这种方法。
  • 你能做一个运行代码sn-p吗?因为当我试图理解你的代码时,我得到了错误。
【解决方案3】:

这是我的尝试,只使用基本的 for 循环和迭代。我敢肯定这不像@Redu 的例子那么有效。

每种类型的集合都是一个单独的函数。输出采用坐标的形式,显示集合在矩阵中的位置、开始位置和结束位置。显然,输出可以是布尔值或您想要的任何其他值。我刚刚以这种方式格式化输出以证明它有效。

我将过滤部分留给了用户,在这种情况下,我特别允许使用 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; }

【讨论】:

    【解决方案4】:

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

    我的解决方案将返回n 连续项目的坐标和值,这些项目可以在m*m 2D 板上水平、垂直或对角地存在。在这个 2D 板上,0 代表空白空间,而 @987654324 @ 和 2 代表相反的值。

    基本思想是将m*m 板子分段为n*n 重叠(通过1 个项目偏移)板段(块)。

    一旦我们有了n*n 子板,我们将获得用于水平的可用行多尺寸n 数组,用于垂直的可用列多尺寸n 数组和2 个n 尺寸数组,用于每个对角线。

    在我们的示例中,我们有一个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]];
    

    在这个棋盘上,左上角是 (0,0),右下角是 (4,4)。因此,如果我们的 n 值为 4,您会很快注意到我们应该期待三个类似的命中

    1. 从 (2, 0) 到 (2, 3) 命中 2s
    2. 从 (0, 4) 到 (3, 4) 命中 1s
    3. 从 (1, 1) 到 (4, 4) 命中 2s

    结果在一个对象中返回如下;

    { '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 ] }
    

    其中sxsy 表示属性中的开始(x,y) 坐标,exey 表示结束(x,y) 坐标。该值是供您使用所有必需信息进一步处理的。

    这里是代码;

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

    【讨论】:

      猜你喜欢
      • 2020-01-22
      • 2020-06-14
      • 1970-01-01
      • 2021-09-05
      • 2012-07-04
      • 2022-11-30
      • 1970-01-01
      • 1970-01-01
      • 2020-09-15
      相关资源
      最近更新 更多