The observed PIN

链接

CodeWar-The observed PIN

题目

好啦,侦探,我们的一个同事已经成功观察到我们的目标人物——强盗Robby。我们跟踪他到了一个秘密仓库,我们认为这里能找到所有他偷的东西。仓库的门用的是一个电子密码锁。不幸的是我们的间谍不确定他看到Robby输入的密码。

密码盘是下面这种布局:

┌───┬───┬───┐
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
├───┼───┼───┤
│ 7 │ 8 │ 9 │
└───┼───┼───┘
    │ 0 │
    └───┘

他记录的密码是1357,但他还说他看到的每个数字也可能是另一个相邻数字(水平或者垂直,但不是斜角)。比如说1可能是2或者45可能是246或者8

他还提到,他了解这种类型的锁。你可以输入无限次数的错误密码,它们不会把系统锁定或者发出警报。这也是我们可以尝试各种可能性的原因。

你能否帮助我们找出所有的变化?它最好是一个函数,为一个观察到的长度为1到8个数字的密码所产生的变化组成的数组。我们可以把函数命名为getPINs。但请注意所有密码都为字符串,因为密码可能由’0’开头。

思路

function getPINs(observed) {
  return combineArr(observed.split(""));
  function po(a) {
      switch(a) {
          case "1":
              return ["2", "4", '1'];
              break;
          case "2":
              return ["1", "3", "5", '2'];
              break;
          case '3':
              return ['2', '6', '3'];
              break;
          case '4':
              return ['1', '5', '7', '4'];
              break;
          case '5':
              return ['2', '4', '6', '8', '5'];
              break;
          case '6':
              return ['3', '5', '9', '6'];
              break;
          case '7':
              return ['4', '8', '7'];
              break;
          case '8':
              return ['5', '7', '9', '0', '8'];
              break;
          case '9':
              return ['6', '8', '9'];
              break;
          case '0':
              return ['8', '0'];
              break;
      }
  }
  function combineArr(arr) {
      if (arr.length == 1) {
          return po(arr[0]);
      } else if (arr.length == 2) {
          var arr1 = po(arr[0]);
          var arr2 = po(arr[1]);

          var result = [];
          for (var i=0; i<arr1.length; i++) {
              for (var j=0; j<arr2.length; j++) {
                  result.push(arr1[i] + arr2[j]);
              }
          }
          return result;
      } else if (arr.length > 2) {
          var arr3 = po(arr[0]);
          arr.shift()
          var arr4 = combineArr(arr);
          var result = [];
          for (var m=0; m<arr3.length; m++) {
              for (var n=0; n<arr4.length; n++) {
                  result.push(arr3[m] + arr4[n]);
              }
          }
          return result;
      }
  }
}

Best Practice

function getPINs(observed) {
  var adjacent = [
    /* 0 */ [0, 8],
    /* 1 */ [1, 2, 4],
    /* 2 */ [1, 2, 3, 5],
    /* 3 */ [2, 3, 6],
    /* 4 */ [1, 4, 5, 7],
    /* 5 */ [2, 4, 5, 6, 8],
    /* 6 */ [3, 5, 6, 9],
    /* 7 */ [4, 7, 8],
    /* 8 */ [5, 7, 8, 9, 0],
    /* 9 */ [6, 8, 9]
  ];

  return observed
    .split('')
    .map(function(d) { return adjacent[d|0]; })
    .reduce(function(pa, da) {
      return da.reduce(function(pv, d) {
        return pv.concat(pa.map(function(p) {
          return '' + p + d;
        }));
      }, []);
    }, ['']);
}
function getPINs(observed) {
  return observed.split('')
  .map( t => ({
    '0': [ '0', '8' ],
    '1': [ '1', '2', '4' ],
    '2': [ '1', '2', '3', '5' ],
    '3': [ '2', '3', '6' ],
    '4': [ '1', '4', '5', '7' ],
    '5': [ '2', '4', '5', '6', '8' ],
    '6': [ '3', '5', '6', '9' ],
    '7': [ '4', '7', '8' ],
    '8': [ '5', '7', '8', '9', '0' ],
    '9': [ '6', '8', '9' ]
  }[t]))
  .reduce((pre, cur)=> [].concat.apply([], pre.map(t => cur.map(g => t + g))));
}
function mixNMatch(add, addTo) {
  var out = [];
  add.forEach(function(v, i) {addTo.forEach(function(w, j) {out.push(v + w);});});
  return out;
}

function getPINs(observed) {
  var map = {1:['1','2','4'], 2:['1','2','3','5'], 3:['2','3','6'], 4:['1','4','5','7'], 5:['2','4','5','6','8'],
             6:['3','5','6','9'], 7:['4','7','8'], 8:['5','7','8','9','0'], 9:['6','8','9'], 0:['8','0']};
  return observed.length == 1 ? map[observed[0]] : mixNMatch(map[observed[0]], getPINs(observed.slice(1)));
}