【问题标题】:Check if my matrix is a magic square javascript检查我的矩阵是否是魔方 javascript
【发布时间】:2019-11-24 02:27:05
【问题描述】:

我们被分配使用输入框创建一个 3x3 矩阵并编写代码来检查给定的数字加起来是否正确,以生成一个幻方。没有提示框,我们可以使用数组来完成任务。在使用“document.myform....value”方法之前,我已经使用输入框来获取值,但我不知道如何使用数组来实现它。

这是我目前所拥有的:

function myArray() {
  var matrix = new Array[];
  for (var i = 0; i < 3; i++) {
    matrix[i] = new Array(3)
  }
  enterValues();
}

function enterNum() {
  for (var row = 0; row < 3; row++) {
    for (var col = 0; col < 3; col++)
      matrix[row][col].innerHTML;
  }
}

function magicSquare() {
  var magSqu = false;
  var sum = 0;
  for (var col = 0; col < 3; col++) {
    sum = sum + matrix[0][col];
  }
  var rowSum = 0;
  for (var i = 1; i < 3; i++) {
    for (var j = 0; j < 3; j++) {
      rowSum = rowSum + matrix[i][j];
      if (rowSum != sum) {
        magSqu = false;
        break;
      }
    }
  }
  var sum_diagonal = 0;
  if (magSqu) {
    for (var i = 0; i < 3; i++)
      for (var j = 0; j < 3; j++)
        if (i == j)
          sum_diagonal += matrix[i][j];
    if (sum_diagonal != sum) {
      magSqu = false;
    }
  }
  if (magSqu) {
    sum_diagonal = 0;
    for (var i = 0; i < 3; i++)
      for (var j = 0; j < 3; j++)
        if ((i + j) == 2)
          sum_diagonal += matrix[i][j];
    if (sum_diagonal != sum) {
      magSqu = false;
    }
  }
  if (magSqu == true) {
    document.getElementById("result").innerHTML = "This is a magic square.";
  } else {
    document.getElementById("result").innerHTML = "This is not a magic square.";
  }
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Magic Square</title>
  <link rel="stylesheet" type="text/css" href="style.css" />

</head>

<body>
  <table border='1'>
    <tbody>
      <tr>
        <td id="r1c1"><input type="text" name="inp11"></td>
        <td id="r1c2"><input type="text" name="inp12"></td>
        <td id="r1c3"><input type="text" name="inp13"></td>
      </tr>
      <tr>
        <td id="r2c1"><input type="text" name="inp21"></td>
        <td id="r2c2"><input type="text" name="inp22"></td>
        <td id="r2c3"><input type="text" name="inp23"></td>
      </tr>
      <tr>
        <td id="r3c1"><input type="text" name="inp31"></td>
        <td id="r3c2"><input type="text" name="inp32"></td>
        <td id="r3c3"><input type="text" name="inp33"></td>
      </tr>
    </tbody>
  </table>
  <input type="submit" id="magicButton" value="Compute Score" onclick="magicSquare();">
  <div id="result"> </div>
</body>

</html>

我哪里错了?

【问题讨论】:

  • 您可能需要更正一个错字:new Array[]。应该是[]Array()

标签: javascript arrays matrix magic-square


【解决方案1】:

你错过的大部分事情是

  1. 将数组定义为 [] 或 new Array(),这是 @ggorlen 所说的
  2. 我没有使用名称,而是将其更改为 id,以便我们可以获取该特定元素的值。
  3. 使用输入标签时,使用value 属性而不是innerHTML 获取内部值
  4. 我们需要在初始加载时调用函数myArray()
  5. 将矩阵变量移到顶层,因为它被所有函数共同使用。
  6. 删除了提交类型的输入按钮,这是可选的,因为它有助于保留用于演示目的的输入。

希望这能解决您的问题!

var matrix = [];
myArray();
function myArray() {
  for (var i = 0; i < 3; i++) {
    matrix[i] = new Array(3).fill(1)
  }
  enterValues();
}

function enterValues() {
  for (var row = 0; row < 3; row++) {
    for (var col = 0; col < 3; col++) {
      document.getElementById(`inp` + (row+ 1) + (col+ 1)).value = matrix[row][col];
    }
  }
}

function enterNum() {
  for (var row = 0; row < 3; row++) {
    for (var col = 0; col < 3; col++)
      matrix[row][col] = document.getElementById(`inp` + (row+ 1) + (col+ 1)).value;
  }
}

function magicSquare() {
  enterNum();
  var magSqu = false;
  var sum = 0;
  for (var col = 0; col < 3; col++) {
    sum = sum + matrix[0][col];
  }
  var rowSum = 0;
  for (var i = 1; i < 3; i++) {
    for (var j = 0; j < 3; j++) {
      rowSum = rowSum + matrix[i][j];
      if (rowSum != sum) {
        magSqu = false;
        break;
      }
    }
  }
  var sum_diagonal = 0;
  if (magSqu) {
    for (var i = 0; i < 3; i++)
      for (var j = 0; j < 3; j++)
        if (i == j)
          sum_diagonal += matrix[i][j];
    if (sum_diagonal != sum) {
      magSqu = false;
    }
  }
  if (magSqu) {
    sum_diagonal = 0;
    for (var i = 0; i < 3; i++)
      for (var j = 0; j < 3; j++)
        if ((i + j) == 2)
          sum_diagonal += matrix[i][j];
    if (sum_diagonal != sum) {
      magSqu = false;
    }
  }
  if (magSqu == true) {
    document.getElementById("result").innerHTML = "This is a magic square.";
  } else {
    document.getElementById("result").innerHTML = "This is not a magic square.";
  }
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Magic Square</title>
  <link rel="stylesheet" type="text/css" href="style.css" />

</head>

<body>
  <table border='1'>
    <tbody>
      <tr>
        <td id="r1c1"><input type="text" id="inp11"></td>
        <td id="r1c2"><input type="text" id="inp12"></td>
        <td id="r1c3"><input type="text" id="inp13"></td>
      </tr>
      <tr>
        <td id="r2c1"><input type="text" id="inp21"></td>
        <td id="r2c2"><input type="text" id="inp22"></td>
        <td id="r2c3"><input type="text" id="inp23"></td>
      </tr>
      <tr>
        <td id="r3c1"><input type="text" id="inp31"></td>
        <td id="r3c2"><input type="text" id="inp32"></td>
        <td id="r3c3"><input type="text" id="inp33"></td>
      </tr>
    </tbody>
  </table>
  <input type="button" id="magicButton" value="Compute Score" onclick="magicSquare();">
  <div id="result"> </div>
</body>

</html>

【讨论】:

  • 虽然,我玩过它,不管我在里面放什么数字,总是等于“不是正方形”——即使我知道的数列等于 15。跨度>
  • @EllisJordan 我解释了我的答案中的所有错误。 if (rowSum != sum) 在您的循环中为时过早,并且每次都失败。没有检查所有数字都是唯一的。这个答案没有解决这些问题,似乎只是试图让你回到正轨,修复你的语法错误并将你连接到 DOM,这是一个很好的步骤。
  • 是的,事后我看到了。对不起!谢谢!
【解决方案2】:

代码中有很多问题。我的一般建议是分小块工作,一次解决一个问题。代码看起来好像是一举编写的,没有定期进行测试以确保其正常工作。当您开始运行它时,问题的数量已经累积到难以调试的程度。

其中一些问题包括:

  • 缺乏与 DOM 的交互。使用innerHTML 设置结果是一个好的开始,但是没有逻辑可以从用户那里获取数据。使用表单、事件侦听器或查询选择器从文档中提取数据。在进入幻数逻辑(或硬编码数据并在进入 UI 之前找出幻数逻辑)之前,确保此方法有效。 UI 和幻数逻辑应该完全相互分离。
  • 作用域:myArray() 是您设置的用于存储矩阵的函数(将代码分解为函数是正确的想法!),但它从未被调用,也不会为其他函数返回矩阵采用。尽管您在将代码分解为函数方面做得很好,但请务必使用参数和返回值,并进一步将行/列/对角线检查分解为它们自己的函数。为函数和变量提供描述性名称(尽管myArray,您通常做得很好)。
  • matrix[row][col].innerHTML; 不执行任何操作(使用 = 符号分配给 innerHTML 或在表达式中使用属性),也未调用 enterValues()。这似乎是一项正在进行的工作,但这可能是一个很好的功能,可以隔离并开始从 DOM 中提取数据。
  • 在所有块上使用大括号:

    for (var i = 0; i < 3; i++)
      for (var j = 0; j < 3; j++)
        if (i == j)
          sum_diagonal += matrix[i][j];
    if (sum_diagonal != sum) {
      magSqu = false;
    }
    

    是一场等待发生的灾难,尽管它在这里看起来确实是正确的。 sum_diagonal 应该是 sumDiagonal(或 diagonalSum)——JS 对所有变量使用驼峰式(PascalCase 用于类)。内循环不是必需的。重写可能是:

    for (let i = 0; i < 3; i++) {
      sumDiagonal += matrix[i][i];
    }
    
    if (sumDiagonal !== sum) {
      magSqu = false;
    }
    
  • 硬编码 3 在这里有效,但我会尝试概括逻辑以适用于任何 n

  • 使用=== 进行所有比较。这样可以避免由于意外类型强制导致的严重错误。
  • 您的幻方检验无法解释数字不明显的情况。这会错误地将全零的 3x3 矩阵视为幻方。我建议展平列表并使用Set 来检查每个元素是否都是唯一的。
  • 另一个错误是以下代码:

    var rowSum = 0;
    for (var i = 1; i < 3; i++) {
      for (var j = 0; j < 3; j++) {
        rowSum = rowSum + matrix[i][j];
        if (rowSum != sum) { // <-- this is premature!
          magSqu = false;
          break;
        }
      }
    }
    

    在上面的sn-p中,行求和应该只在行求和完成后进行测试,而不是求和过程中。它会错误地报告错误。试试:

    let rowSum = 0;
    
    for (let i = 1; i < 3; i++) {
      for (let j = 0; j < 3; j++) {
        rowSum += matrix[i][j];            
      }
    
      if (rowSum !== sum) {
        magSqu = false;
        break;
      }
    }
    

考虑到这一点,我更喜欢将任务分解为使用数组内置函数执行迭代而不是显式循环的小函数的解决方案:

const sum = a => a.reduce((a, e) => a + e);
const diag = m => m.map((row, i) => row[i]);
const rotate = m => 
  m.map((_, i) => m.map((_, j) => m[j][i]).reverse())
;
const isMagic = square => {
  const targetSum = square.length && sum(square[0]);
  const valid = a => sum(a) === targetSum;
  const rotated = rotate(square);  
  const flat = square.flat();
  return new Set(flat).size === flat.length &&
    square.every(valid) &&
    rotated.every(valid) &&
    valid(diag(square)) &&
    valid(diag(rotated))
};

[
  [
    [2,7,6],
    [9,5,1],
    [4,3,8]
  ],
  [
    [8,1,6],
    [3,5,7],
    [4,9,2]
  ],
].forEach(e => console.log(isMagic(e)));

这满足了幻方的所有要求:所有数字都应该是唯一的,并且每一行、每一列和对角线的总和必须是相同的数字。

使用置换函数,我可以对其进行测试,以确保它找到给定大小的所有预期正方形。注意:这是一个繁重的计算,可能会使浏览器挂起片刻。

const sum = a => a.reduce((a, e) => a + e);
const diag = m => m.map((row, i) => row[i]);
const rotate = m => 
  m.map((e, i) => e.map((_, j) => m[j][i]).reverse())
;
const isMagic = square => {
  const targetSum = square.length && sum(square[0]);
  const valid = a => sum(a) === targetSum;
  const rotated = rotate(square);  
  const flat = square.flat();
  return new Set(flat).size === flat.length &&
    square.every(valid) &&
    rotated.every(valid) &&
    valid(diag(square)) &&
    valid(diag(rotated))
};

function *permute(a, i=0) {
  if (i >= a.length) {
    yield a.slice();
  }

  for (let j = i; j < a.length; j++) {
    [a[i], a[j]] = [a[j], a[i]];
    yield *permute(a, i + 1);
    [a[i], a[j]] = [a[j], a[i]];
  }
};

const unflatten = a => a.reduce((acc, e, i) => {
  if (i % Math.sqrt(a.length) === 0) {
    acc.push([]);
  }
  
  acc[acc.length-1].push(e);
  return acc;
}, []);

const squares = [...permute(
    Array(9).fill().map((_, i) => i + 1)
  )].reduce((a, e) => {
    const candidate = unflatten(e);

    if (isMagic(candidate)) {
      a.push(candidate);
    }

    return a;
  }, [])
;

console.log(squares.length, "magic squares of size 3:");

for (const square of squares) {
  console.log(square.map(e => e.join(" ")).join("\n"));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-17
    • 1970-01-01
    • 2017-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    • 2015-09-19
    相关资源
    最近更新 更多