Created
October 4, 2016 02:42
-
-
Save anonymous/b4e66ee9a02255660dbbb399ef88ed03 to your computer and use it in GitHub Desktop.
Thrown-together solver for a geocaching puzzle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var magic = ["equals(caret(175.4, 203.9), caret(gt(37.8, 16.3), 19.5))", | |
"equals(equals(caret(gt(88.7, 66.4), 101.5), caret(72.3, 39.5)), 37.8)", | |
"equals(equals(equals(caret(22009.9, 10101.8), 7228.7), 368.7), gt(4138488.0, 4020319.0))", | |
"equals(caret(2066.8, 668.8), caret(12.9, gt(122.1, 8.4)))", | |
"equals(equals(caret(9999.9, 10375.2), caret(777.7, 37.9)), gt(96.8, 33.0))", | |
"equals(equals(equals(caret(98765.7, 3777.5), 667.7), 268.3), caret(586728.2, 412841.8))"]; | |
// unambiguous "caret(22009.9, 10101.8) = 7228.7 = 368.7 = gt(4138488.0, 4020319.0)", ? | |
// "(98765.7 ^ 3777.5) = 667.7 = 268.3 = (586728.2 ^ 412841.8)" ? | |
function patch(arr, e) { | |
if (!Array.isArray(arr)) { | |
throw new Error("1st argument must be array"); | |
} | |
for (i=0; i<arr.length; i++) | |
{ | |
if (arr[i] === undefined) { | |
break; | |
} | |
} | |
arr[i] = e; | |
} | |
// function binaryDigit(num, digit) { | |
// return +((num >>> 0).toString(2)[digit]); | |
// } | |
function compoundFactory(seed, dump) { | |
var opSeedLimit = 6*5*4; // 6_choose_3 | |
if (seed < 0 || seed >= (2*opSeedLimit*(2*2*2*2))) { | |
throw new Error("Seed outside of range"); | |
} | |
var balanced = (seed % 2 === 1); | |
seed = Math.floor(seed / 2); | |
var opSeed = seed % opSeedLimit; | |
var ops; | |
if (dump) { | |
ops = chooseFromSet(STR_OPS_SYM, 3, opSeed); | |
} else { | |
ops = chooseFromSet(OPS_SYM, 3, opSeed); | |
} | |
seed = Math.floor(seed / opSeedLimit); | |
// build a selector function | |
var selections = seed.toString(2).split('').map(x => +x); | |
var v = (a,b,n) => selections[n]===1 ? a : b; | |
// left branching | |
if (!balanced) return (x, y) => ops[0]( ops[1]( ops[2](v(x,y,0), v(x,y,1)), v(x,y,2)), v(x,y,3)); | |
// balanced | |
return (x,y) => ops[0](ops[1](v(x,y,0), v(x,y,1)), ops[2](v(x,y,2), v(x,y,3))); | |
} | |
var add = (a,b) => a+b; | |
var subtract = (a,b) => a-b; | |
var multiply = (a,b) => a*b; | |
var divide = (a,b) => a/b; | |
var backwards = (fn) => ((a,b) => fn(b,a)); | |
var sadd = (a,b) => "("+a+"+"+b+")"; | |
var ssubtract = (a,b) => "("+a+"-"+b+")"; | |
var smultiply = (a,b) => "("+a+"*"+b+")"; | |
var sdivide = (a,b) => "("+a+"/"+b+")"; | |
var OPS = [add, subtract, multiply, divide]; | |
var OPS_SYM = [add, subtract, multiply, divide, backwards(subtract), backwards(divide)]; | |
// string forms for reading | |
var STR_OPS = [sadd, ssubtract, smultiply, sdivide]; | |
var STR_OPS_SYM = [sadd, ssubtract, smultiply, sdivide, backwards(ssubtract), backwards(sdivide)]; | |
function chooseFromSet(set, count, seed) { | |
var limit = 1; | |
for (i=0; i<count; i++) { | |
limit *= (set.length - i); | |
} | |
set = Array.from(set); | |
if (seed < 0 || seed >= limit) | |
{ | |
throw new Error("Operation seed out of range"); | |
} | |
var ops = []; | |
for (count; count > 0; count--) { | |
ops.push(set.splice(seed % set.length, 1)[0]); | |
seed = Math.floor(seed/set.length); | |
} | |
return ops; | |
} | |
var valueExp = function (seed, s, dump) { | |
var compoundSeedLimit = (2*(6*5*4)*(2*2*2*2)); | |
var localChooseSeed = 3*4*3; // 3 * 4_choose_2 | |
if (seed < 0 || seed > (compoundSeedLimit * localChooseSeed)) | |
{ | |
throw new Error("Trial seed out of range"); | |
} | |
var compound = compoundFactory(seed % compoundSeedLimit, dump); | |
if (dump) { | |
console.info("compound function is ", compound("a", "b")); | |
} | |
seed = Math.floor(seed / compoundSeedLimit); | |
var ops=Array(3); | |
var compoundPos = seed % 3; | |
ops[compoundPos] = compound; | |
seed = Math.floor(seed / 3); | |
var normalOps; | |
if (dump) { | |
normalOps = chooseFromSet(STR_OPS, 2, seed); | |
} else { | |
normalOps = chooseFromSet(OPS, 2, seed); | |
} | |
patch(ops, normalOps[0]); | |
patch(ops, normalOps[1]); | |
if(dump) { | |
console.info("^ is ", ops[0]("a","b")); | |
console.info("= is ", ops[1]("a","b")); | |
console.info("> is ", ops[2]("a","b")); | |
} | |
var caret = ops[0]; | |
var equals = ops[1]; | |
var gt = ops[2]; | |
return eval(s); | |
} | |
function search () { | |
for (z=0; z<(2*(6*5*4)*(2*2*2*2))*3*4*3; z++) { | |
var r1 = valueExp(z, magic[0]); | |
if (r1 > 36.9 && r1 < 37.1) | |
{ | |
var r2 = valueExp(z, magic[3]); | |
if (r2 > 120.9 && r2 < 121.1) { | |
console.log("Found likely candidate at seed "+z+":"); | |
valueExp(z, null, true); | |
break; | |
} | |
} | |
} | |
var out = magic.map((s) => valueExp(z, s)); | |
console.log("Seed "+z+" produces values:", out); | |
var norm = out.map((x) => Math.round(x)).join(" "); | |
console.log("...normalized to "+norm); | |
} | |
search(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment