Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Dutch mathematician Hans Freudenthal proposed this puzzle in 1969 — at first it appears impossible because so little information is given.
- X and Y are two different whole numbers greater than 1. Y is greater than X, and their sum is no greater than 100. S and P are two logicians; S knows the sum X + Y, and P knows the product X × Y. S and P both reason perfectly, and both know everything I’ve just told you.
- S says, “P does not know X and Y.”
- P says, “Now I know X and Y.”
- S says, “Now I also know X and Y.”
- What are X and Y?
- */
- const objMap = (obj, fn) => (
- Object.entries(obj).map(([key, val]) => [key, fn(val, key)]).reduce((o, r) => (o[r[0]] = r[1], o), {})
- );
- const objFilter = (obj, fn) => (
- Object.entries(obj).filter(([key, val]) => fn(val, key)).reduce((o, r) => (o[r[0]] = r[1], o), {})
- );
- const keyedBy = (list, key) => (
- list.reduce((r, o) => (r[key(o)] = r[key(o)] || [], r[key(o)].push(o), r), {})
- );
- const numbers = [...Array(99).entries()].map(x => x[0]+2);
- const possible = Array.prototype.concat.apply([], numbers.map(x => numbers.map(y => ({x, y, p:x*y, s:x+y})))).filter(({x, y, p, s}) => (x<y && s<101));
- // const keyedBySum = possible.reduce((r, {a, b, p, s}) => (r[s] = r[s] || [], r[s].push({a, b, p, s}), r), {})
- const keyedBySum = keyedBy(possible, ({s}) => s);
- // const keyedByProduct = possible.reduce((r, {a, b, p, s}) => (r[p] = r[p] || [], r[p].push({a, b, p, s}), r), {})
- const keyedByProduct = keyedBy(possible, ({p}) => p);
- // Track S's possible knowledge for statement 1: [S says, “P does not know X and Y.”]
- // Initialise to all possibilities, keyed by sum.
- const sKnowledge0 = keyedBySum;
- // Map each possibility to a list of other possibilities with the same product.
- // (
- // So possible sum 11 has [[2,9], [3,8], [4,7], [5,6]] which gets mapped to
- // products: [[18], [24], [28], [30]] which gets mapped to
- // possibilities: [[2:9, 3:6], [2:12, 3:8, 4:6], [2:14, 4:7], [2:15, 3:10, 5:6]]
- // So all of these products have multiple possible x, y so if S sees 11 he can say P doesn't know.
- // )
- const sKnowledge1 = objMap(keyedBySum, (list) => list.map(({p}) => keyedByProduct[p]));
- // Filter out sums that contain potential x,y pairs that would be identifiable by P
- const sKnowledge2 = objFilter(sKnowledge1, (l) => l.every((l2) => l2.length > 1));
- // -- sKnowledge2 is the possible sums that S could see for statement 1 to be true. --
- // Track P's possible knowledge for statement 2: [P says, “Now I know X and Y.”]
- // Initialise to all possibilities keyed by product.
- const pKnowledge0 = keyedByProduct;
- // We know from statement 1 that P doesn't know X and Y, so filter out products that only have one factorisation
- const pKnowledge1 = objFilter(keyedByProduct, (list) => list.length > 1);
- // Now apply statement 2. P gains sKnowledge2's list of possible sums.
- // Knowing that the sum is in sKnowledge2 means that P now knows X, Y.
- // Filter out possibilities that don't have a sum in sKnowledge2
- const pKnowledge2 = objMap(pKnowledge1, (list) => list.filter(({s}) => sKnowledge2[s]));
- // Now filter out products that don't have exactly 1 set of possibilities left
- const pKnowledge3 = objFilter(pKnowledge2, (list) => list.length ===1);
- // -- pKnowledge3 now contains the possible products that satisfy statement 2 --
- // Track S's possible knowledge for statement 3: [S says, “Now I also know X and Y.”]
- // S's knowledge from before says that the possible sums are in sKnowledge2.
- // Now that S gains the knowledge of pKnowledge3, S knows the possible products
- // that P could have seen. This gives S knowledge of x,y.
- // That means that whatever sum S saw must have only one potential product in pKnowledge3.
- // sKnowledge2 is currently keyed by sum, giving an array of products. each product gives possibilities.
- // Lets clean up to get the second level keyed by product.
- // First explode children
- const sKnowledge3 = objMap(sKnowledge2, (list) => Array.prototype.concat.apply([], list));
- // Strip out possibilities that don't have the matching sum
- const sKnowledge4 = objMap(sKnowledge3, (list, sum) => list.filter(({s}) => s == sum));
- // Now we are ready to filter out products that aren't in pKnowledge3
- const sKnowledge5 = objMap(sKnowledge4, (list) => list.filter(({p}) => pKnowledge3[p]));
- // And finally, we filter out sums that now have only a single possiblity in order to make
- // statement 3 true.
- const sKnowledge6 = objFilter(sKnowledge5, (list) => list.length === 1);
- // Which leaves us with "{"17":[{"a":4,"b":13,"p":52,"s":17}]}"
- // X is 4, Y is 13. P saw 52, S saw 17.
- console.log(Object.values(sKnowledge6)[0][0]);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement