Task[edit]
Solve the "Impossible Puzzle":


X and Y are two different whole numbers greater than 1. Their sum is no greater than 100, and Y is greater than X. S and P are two mathematicians (and consequently perfect logicians); S knows the sum X+Y and P knows the product X*Y. Both S and P know all the information in this paragraph.
The following conversation occurs:

 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?


Guidance
It can be hard to wrap one's head around what the three lines of dialog between S (the "sum guy") and P (the "product guy") convey about the values of X and Y.

So for your convenience, here's a break-down:





 Quote

 Implied fact


 1)

 S says "P does not know X and Y."

 For every possible sum decomposition of the number X+Y, the product has in turn more than one product decomposition.


 2)

 P says "Now I know X and Y."

 The number X*Y has only one product decomposition for which fact 1 is true.


 3)

 S says "Now I also know X and Y."

 The number X+Y has only one sum decomposition for which fact 2 is true.

Terminology:

 "sum decomposition" of a number = Any pair of positive integers (A, B) so that A+B equals the number. Here, with the additional constraint 2 ≤ A < B.
 "product decomposition" of a number = Any pair of positive integers (A, B) so that A*B equals the number. Here, with the additional constraint 2 ≤ A < B.


Your program can solve the puzzle by considering all possible pairs (X, Y) in the range 2 ≤ X < Y ≤ 98, and then successively eliminating candidates based on the three facts. It turns out only one solution remains!

See the Python example for an implementation that uses this approach with a few optimizations.

See also
   Wikipedia:   Sum and Product Puzzle

 
# For readability:
def collect(c): map(select(c));
 
# stream-oriented checks:
def hasMoreThanOne(s): [limit(2;s)] | length > 1;
 
def hasOne(s): [limit(2;s)] | length == 1;
 
def prod: .[0] * .[1];
 
## A stream of admissible [x,y] values
def xy:
  [range(2;50) as $x  # 1 < X < Y < 100
   | range($x+1; 101-$x) as $y
   | [$x, $y] ] ;
 
# The stream of [x,y] pairs matching "S knows the sum is $sum"
def sumEq($sum): select( $sum == add );
 
# The stream of [x,y] pairs matching "P knows the product is $prod"
def prodEq($p): select( $p == prod );
 
## The solver:
def solve:
  xy as $s0
 
# S says P does not know:
  | $s0
  | collect(add as $sum
      | all( $s0[]|sumEq($sum);
             prod as $p
             | hasMoreThanOne($s0[] | prodEq($p)))) as $s1
 
# P says: Now I know:
  | $s1
  | collect(prod as $prod | hasOne( $s1[]|prodEq($prod)) ) as $s2
 
# S says: Now I also know
  | $s2[]
  | select(add as $sum | hasOne( $s2[] | sumEq($sum)) ) ;
 
solve
 