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
wordSet   type [] word 
   where ∧/{size it[i-1] = size it[i] for i in [1,size it)}
dictionary type [] wordSet
   where ∧/{size it[i] = 0 or size it[i][0] = i for i in [0,size it)}

partialBindings 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 partialBindings
) ⇒ (
   matchCount 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 []partialBindings := {}
   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
      workingBindings var := bindings
      loop for x in [0,size pattern)
         w const = word[x]
         p const = pattern[x]
         c const = workingBindings[p]
         while c = w or c = unknown and available[w]
         if c = unknown then
            (workingBindings[p], available[w]) := (w, false)
         end if
      present
         matches @:= {workingBindings}
      end loop
   end loop
   matchCount := size matches = 0    
   if matchCount > 1 then
      newBindings var := matches[0]
      loop for i in [1,size matches)
         loop for c in [A,Z]
            if newBindings[c] ≠ matches[i][c] then
               newBindings[c] := 0
            end if
         end loop
      end loop
      workingBindings = newBindings
   elif matchCount > 0 then
      workingBindings := matches[0]
   end if
end proc

dictionary var dictionary := {{}} @@ 40
loop
   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
   remainingClues var []word := {}
   loop for i in [0,size clues)
      outcome const = check(clues[i], dictionary, bindings)
      until outcome = 0
      if outcome > 1 then
	 remainingClues @:= {clues[i]}
      end if
   present
      clues := {}
      failed := true
   absent
      clues := newClues
      failed := false
   end
end loop
if failed then
   print "Failed", bindings
else
   print "Succeeded", bindings
end if