r/dailyprogrammer - 2018-01-08

https://www.reddit.com/r/dailyprogrammer/comments/7p5p2o/20180108_challenge_346_easy_cryptarithmetic_solver/

HTML

Warning: you may get unresponsive script warning

CSS

pre {
  background-color: #DDD;
  padding: 0.5em 1em;
}

Babel + JSX

console.clear();
function log(msg, ...rest){
	const pre = document.createElement('pre');
  document.body.appendChild(pre);
  pre.innerText = JSON.stringify(msg, null, 2);
  if (rest.length) log(...rest);
}
function newArray(n){
	return (new Array(n)).fill().map((_,i) => i);
}
function factorial(n){
	return newArray(n).map(i => i+1).reduce((prod, mul) => prod * mul, 1);
}
function permutations(n,r){
  return factorial(n) / factorial(n - r);
};

function substitute(letters, map){
	return letters
  	.map(letter => map[letter])
    .reverse()
		.reduce(
    	(sum, num, index) => sum + num * Math.pow(10, index),
    	0
    );
}

function solve(equation){
  const [ left, right ] = equation.split(/==?/);
  const add = left.split('+').map(a => a.trim().split(''));
  const sum = right.trim().split('');
  
  const letters = [...add,sum].reduce((acc, a) => acc.concat(a), [])
  	.filter((letter, index, letters) => letters.indexOf(letter) === index);
    
  return newArray(permutations(10, letters.length))
  	.map(variant => {
      const numberPool = newArray(10);
      return letters.reduce((acc, letter, index) => {
        return {
          ...acc,
          [letter]: numberPool.splice(
            Math.floor(variant / permutations(10,index)) % numberPool.length,
            1)[0]
        };
      }, {});
    })
    .filter(letterCombination => {
    	return [ ...add.map(a => a[0]), sum[0] ]
      	.every(l => letterCombination[l] !== 0);
    })
    .filter((letterCombination, index) => {
    	const total = add
      	.map(left => substitute(left, letterCombination))
        .reduce((sum, addr) => sum + addr, 0);
      const right = substitute(sum, letterCombination);
      return total === right;
    });
}

function run(equation){
  log(equation)
  const start = performance.now();
  const substitutions = solve(equation);
  const end = performance.now();
  substitutions.map(sub => {
  	log(equation.split('').map(l => sub.hasOwnProperty(l) ? sub[l] : l).join(''));
   ...