letter           = placeholders 1 to 26 and also letters A to Z
  word             = non-empty sequence of letters
  word_set         = collection of words all the same length
  dictionary       = collection of words partitioned by length
  partial_bindings = placeholder -> A..Z or still unknown(0)

unknown const =  0
A       const =  1   first letter
Z       const = 26   last letter

letter     type int
   where it in [A,Z]
word       type [] letter
   where size it > 0
word_set   type [] word 
   where ∧/{size it[i-1] = size it[i] for i in [1,size it)}
dictionary type [] word_set
   where ∧/{size it[i] = 0 or size it[i][0] = i for i in [0,size it)}

partial_bindings type []int
   where size it = Z+1 and ∧/{it[i] in [unknown,Z] for i in [1,size it)}
unknown const = 0

check proc (
   pattern     in word,
   dictionary  in dictionary,
   bindings    in out partial_bindings
) ⇒ (
   match_count out int
       0 => failed
       1 => this word is solved, don't try it again
      >1 => we may have learned something but not everything
   matches var []partial_bindings := {}
   available var := {false} @@ (Z+1)
   loop for c in [A,Z]
      available[c] := bindings[c] = unknown
   end loop
   i const = size pattern
   loop for j in [0,size dictionary[i])
      word const = dictionary[i][j]
      assert size word = size pattern
      working_bindings var := bindings
      loop for x in [0,size pattern)
         w const = word[x]
         p const = pattern[x]
         c const = working_bindings[p]
         while c = w or c = unknown and available[w]
         if c = unknown then
            (working_bindings[p], available[w]) := (w, false)
         end if
         matches @:= {working_bindings}
      end loop
   end loop
   match_count := size matches = 0    
   if match_count > 1 then
      new_bindings var := matches[0]
      loop for i in [1,size matches)
         loop for c in [A,Z]
            if new_bindings[c] ≠ matches[i][c] then
               new_bindings[c] := 0
            end if
         end loop
      end loop
      working_bindings = new_bindings
   elif match_count > 0 then
      working_bindings := matches[0]
   end if
end proc

dictionary var dictionary := {{}} @@ 40
   n var int
   while get (n)
   word var word := {0} @@ n
   loop for i in [0,n)
      get word[i]
      assert word[i] in [A,Z]
   end loop
   dictionary[n] @:= {word}
end loop

bindings var := {0}@@(Z+1)
loop  read the partial solution
   for code in [A,Z]
   get bindings[code]
end loop

clues var []word
loop  read the clues
   n var int
   while get(n)
   clue var word := {0} @@ n
   loop for i in [0,n)
      get clue[i]
      assert clue[i] in [A,Z]
   end loop
   clues @:= {clue}
end loop
failed var := false
loop while size clues > 0 and not failed
   remaining_clues var []word := {}
   loop for i in [0,size clues)
      outcome const = check(clues[i], dictionary, bindings)
      until outcome = 0
      if outcome > 1 then
	 remaining_clues @:= {clues[i]}
      end if
      clues := {}
      failed := true
      clues := new_clues
      failed := false
end loop
if failed then
   print "Failed", bindings
   print "Succeeded", bindings
end if