SOURCE

console 命令行工具 X clear

                    
>
console
//参数行列数量
var rows = 2;
var cols = 3;

function testData() {
  //测试数据
  rows = 4;
  cols = 4;
  rebuildInputParams();
  
  document.getElementById('rows').value = rows;
  document.getElementById('cols').value = cols;
  
  document.getElementById('11').value = 2;
  document.getElementById('12').value = 3;
  document.getElementById('13').value = 4;
  document.getElementById('14').value = 5;

  document.getElementById('21').value = 3;
  document.getElementById('22').value = "";
  document.getElementById('23').value = 5;
  document.getElementById('24').value = 6;

  document.getElementById('31').value = 4;
  document.getElementById('32').value = 5;
  document.getElementById('33').value = 6;
  document.getElementById('34').value = 7;
  
  document.getElementById('41').value = 5;
  document.getElementById('42').value = 6;
  document.getElementById('43').value = 7;
  document.getElementById('44').value = 8;
}

//初始化参数行列数以及重新布局输入框
function init() {
  document.getElementById('rows').value = rows;
  document.getElementById('cols').value = cols;
  rebuildInputParams();
  
  testData();
}

//参数行列数量调整
function dimChange() {
  rows = document.getElementById('rows').value;
  cols = document.getElementById('cols').value;
  rebuildInputParams();
  
}

//按照分组参数重设参数输入框
function rebuildInputParams() {
  var paramsDiv = document.getElementById('params');
  paramsDiv.innerHTML = "";
  for (var r = 0; r < rows; r++) {
    for (var c = 0; c < cols; c++) {
      var input = document.createElement('input');
      input.id = (r + 1) * 10 + c + 1;
      input.type = "Number";
      paramsDiv.appendChild(input);
    }
    paramsDiv.innerHTML += '<br><br>';
  }
  document.getElementById('msg').style.visibility = "hidden";
}

//开始
init();

function run() {
  //testData();
  
  //获取参数,params 二维数据,target[行,列,解]
  getParamsData();
  if (rows < 4 && cols < 4) {
    //数据太少,请脑算找规律
    return null;
  }
  //分析数据生成行列计算规则,生成 patterns 列表,包括行规则和列规则
  analyse();
  //逐个未知数套用行列规则
  solve();
}

//用户输入的参数
var params = [];
//要求解的参数位置
var target = []; //row, column, solved
function getParamsData() {
  params = [];
  for (var r = 0; r < rows; r++) {
    row = [];
    for (var c = 0; c < cols; c++) {
      var input = document.getElementById((r + 1) * 10 + c + 1);
      if (input.value.trim() === "") {
        row.push(null);
        target.push([r, c, false]);
      } else {
        row.push(Number(input.value.trim()));
      }
    }
    params.push(row);
  }
}

//运算符,支持一元一次系数运算
function add(a, b) {
  if (Array.isArray(a)) {
    return [a[0] + b, a[1]];
  }
  if (Array.isArray(b)) {
    return [a + b[0], b[1]];
  }
  return a + b;
}

function minus(a, b) {
  if (Array.isArray(a)) {
    return [a[0] - b, a[1]];
  }
  if (Array.isArray(b)) {
    return [a - b[0], b[1]];
  }
  return a - b;
}

function multiply(a, b) {
  if (Array.isArray(a)) {
    return [a[0] * b, a[1] * b];
  }
  if (Array.isArray(b)) {
    return [a * b[0], a * b[1]];
  }
  return a * b;
}

function divide(a, b) {
  if (Array.isArray(a)) {
    if (b !== 0) {
      return [a[0] / b, a[1] / b];
    } else {
      return null;
    }
  }
  if (Array.isArray(b)) {
    if (b[0] !== 0 && b[1] !== 0) {
      return [a / b[0], a / b[1]];
    } else {
      return null;
    }
  }

  if (b !== 0) {
    return a / b;
  } else {
    return null;
  }
}
//**************************************
//运算符数组,以及对应的显示符号和优先级
var operations = [{
  func: add,
  symbo: '+',
  priority: 1
},
{
  func: minus,
  symbo: '-',
  priority: 1
},
{
  func: multiply,
  symbo: '×',
  priority: 2
},
{
  func: divide,
  symbo: '÷',
  priority: 2
}];

//分析数据生成模式
var patterns;
function analyse() {
  patterns = [];
  //生成数据排列模式和运算排列模式
  var colParamsIndex = permutation(cols);
  var rowParamsIndex = permutation(rows);
  //n 个数据之间只能有 n - 1 个运算符
  var colOperationsIndex = permutation(operations.length, cols - 1)
  var rowOperationsIndex = permutation(operations.length, rows - 1);
  
  //行模式推算
  for (var cp = 0; cp < colParamsIndex.length; cp++) {
    if (isArrayRepeat(colParamsIndex[cp])) {
      continue; //数据不能重复排列,运算符可以
    } else {
      for (var co = 0; co < colOperationsIndex.length; co++) {
        var row = [];
        var result = [];
        for (var i = 0; i < rows; i++) {
					var ans = evaluate("row", i, colParamsIndex[cp], colOperationsIndex[co], null);
          if (ans === null) {
            row.push(null);
          } else {
            row.push(ans.answer);
          }
          result.push(ans);
        }
        var ap = isAP(row);
				if (ap !== null) {
          patterns.push({
            type: "row",
            paramsIndex: colParamsIndex[cp],
            operationIndex: colOperationsIndex[co],
            result: result,
            ap: ap
          })
        }
      }
    }
  }
  //列模式推算
  for (var rp = 0; rp < rowParamsIndex.length; rp++) {
    if (isArrayRepeat(rowParamsIndex[rp])) {
      continue;
    } else {
      for (var ro = 0; ro < rowOperationsIndex.length; ro++) {
        var col = [];
        var result = [];
        for (var j = 0; j < cols; j++) {
          var ans = evaluate("col", j, rowParamsIndex[rp], rowOperationsIndex[ro], null);
          if (ans === null) {
            col.push(null);
          } else {
            col.push(ans.answer);
          }
          result.push(ans);
        }
        var ap = isAP(col);
        if (ap !== null) {
          patterns.push({
            type: "col",
            paramsIndex: rowParamsIndex[rp],
            operationIndex: rowOperationsIndex[ro],
            result: result,
            ap: ap
          })
        }
      }
    }
  }
}

//生成系数全排列,有重复。
function permutation(indexLength, selected) {
  selected = selected || indexLength;
  var permutations = [];
  var p = [];
  for (var i = 0; i < Math.pow(indexLength, selected); i++) {
    p = convertBase(i, indexLength);
    while (p.length < selected) {
      p.push(0);
    }
    permutations.push(p);
  }
  return permutations;
}

//将任意数字转换为以 base 底的数字数组
function convertBase(num, base) {
  var ct = [];
  var quotient, remainder;
  while (true) {
    quotient = parseInt(num / base);
    remainder = num % base;
    ct.push(remainder);
    if (quotient > 0) {
      num = quotient;
    } else {
      break;
    }
  }
  return ct;
}

//检查数组是否有重复的元素,运算符可以全排列,参数数据只能全组合
function isArrayRepeat(array) {
  var arr = array;
  for (var i = 0; i < arr.length - 1; i++) {
    for (var j = i + 1; j < arr.length; j++) {
      if (arr[i] === arr[j]) {
        return true;
      }
    }
  }
  return false;
}




function solve() {
  
}


function evaluate(type, index, paramsIndex, operationsIndex, answer) {
  //默认不解未知数
  var i, j;
  if (type === "row") {
    i = index;
    //检查是否有空值
    for (var j = 0; j < cols; j++) {
      if (params[i][j] === null) {
        return null;
      }
    }
    var r = params[i][paramsIndex[0]];
    var s = r.toString();
    for (var j = 0; j < operationsIndex.length; j++) {
      r = operations[operationsIndex[j]].func(r, params[i][paramsIndex[j + 1]]);
      if (j > 0 && operations[operationsIndex[j - 1]].priority < operations[operationsIndex[j]].priority) {
        s = '(' + s + ')';//优先级较低的运算在前,要加括号
      }
      s += operations[operationsIndex[j]].symbo + params[i][paramsIndex[j + 1]].toString();
    }
  } else if (type === "col") {
    j = index;
    for (var i = 0; i < rows; i++) {
      if (params[i][j] === null) {
        return null;
      }
    }
    var r = params[paramsIndex[0]][j];
    var s = r.toString();
    for (var i = 0; i < operationsIndex.length; i++) {
      r = operations[operationsIndex[i]].func(r, params[paramsIndex[i + 1]][j]);
      if (i > 0 && operations[operationsIndex[i - 1]].priority < operations[operationsIndex[i]].priority) {
        s = '(' + s + ')';
      }
      s += operations[operationsIndex[i]].symbo + params[paramsIndex[i + 1]][j];
    }
  }

  //求解模式
  if (answer) {
    return {
      equation: s,
      answer: answer,
      x: (answer - r[0]) / r[1]
    };
  } else { //计算模式
    return {
      equation: s,
      answer: r,
      x: null
    };
  }
}

//给定数组是否等差,返回公差 or null
function isAP(data) {
  var notnull = 0;
  var a = null;
  var b = null;
  for (var i = 0; i < data.length; i++) {
    if (data[i] !== null) {
      notnull += 1;
      if (a === null) {
        a = [data[i], i];
      } else if (b === null) {
        b = [data[i], i];
      }
    }
  }
  //不足3个数据不能判断
  if (notnull < 3) {
    return null;
  }

  var d = (a[0] - b[0]) / (a[1] - b[1]);
  for (var i = 0; i < data.length; i++) {
  	if (data[i] !== null && (data[i] - a[0]) !== (i - a[1]) * d) {
      return null;
    }
  }
  
  for (var i = 0; i < data.length; i++) {
    if (data[i] === null) {
      data[i] = (i - a[1]) * d + a[0];
    }
  }
  
  return [d, data];
}





<h1>
  小学生数字找规律
</h1>
<p><input id=rows type=number onchange=dimChange()>
  组,每组
  <input id=cols type=number onchange=dimChange()>
  个数字。
</p>
<div>
  ---------------------------------------------
  <p>
    已知数字,请按顺序填写。要求解的位置请留白。
  </p>
  <div id=params>
  </div>
  ---------------------------------------------
  <br>
  <button onclick=run()>
    开始计算
  </button>
  <p id=msg hidden>
    根据已知数据,共计算出
    <span id=patternCount></span>
    条规则
  </p>
  <div id=solve></div>
</div>
input {
  width: 50px;
  height: 1.5rem;
  font-size: 1rem;
  font-weight: bold;
  text-align: center;
  margin: 0 10px;
}

input.error {
  background-color: lightpink;
  color: darkred;
}

span#patternCount {
  color: darkred;
  font-weight: bold;
  font-size: 1.2rem;
}

p.solution {
  font-weight: bold;
  color: red;
}