--/fjOwTFLoeqy+p+1VGt
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

Late response, with a question about the solvabilty of these
kind of problems in general.

I used a similar approach and get similar answers to Glenns, only 
much slower (although mine finishes in finite time :)  When running
Glens program, I get many partial solutions in < 1 Sec (including most
that my program finds) - then his progam consumes 99% of my CPU
time indefinately. On my PC, mine runs in ~10 S for crypto1
(partial answer)  ~16 S for crypto2, full correct answer,
and  ~80 S for crypto3, producing garbage. (can I buy a
vowel? :)

Actually I added the ablity to provide a partial map
to help prime the solver - still cant make sense of crypto3.

The main question I have is how does one handle non-dictionary
words that match a dictionary word signature - and then force
other wrong choices.  The specific case is "alva" which can
map to "aqua". Once I have "aqua" as plain text, it prevents
the solver from using the letter 'u' in genius - making that
word match denims.

In fact I can envsion quotes with non-dictionary words that
could map, wrongly, to a set of all dictionary words - i.e.
the solution with 1 or more "unsolved" words would be more
correct than the solution with no unsolved words...

There's also the situation of "bent, cent, vent, went" - where
the choice of any of them doesn't affect any other words in the
cypher text - providing no help selecting between them.

In both these cases, I don't think backtracking can help - other
than to provide a number of possible solutions that a person
could read and pick from?

Addionally, while I agree that brute force w/26! possible maps
is impractial, after a certain point, would it make sense to
use the brute force approach for the "remaining" letters - 
somwhere in the 8-10 letters remaining?

Thanks to all involved in providing this - been reading for a
while, but this is my first try at solving one ... took *way*
more time than I intended, but was lots of fun.  Looking forward
to more in the future.

Vance

--/fjOwTFLoeqy+p+1VGt
Content-Disposition: attachment; filename=rq13
Content-Type: application/x-ruby; name=rq13
Content-Transfer-Encoding: 7bit

#! /bin/env ruby

def sig(w)
#  rtn  ' 
  rtn   
  ltrs  .split(//)
  ndx   
  while l  trs.shift 
    if fnd  trs.index(l)
#      rtn + dx.to_s + ',' +  (fnd+ndx+1).to_s + ' ' 
      rtn  tn*100 + ndx*10 + fnd
    end
    ndx + 
  end
  return rtn
end

def get_words (fname, ary )
  file  ile.open(fname)
  while word  ile.gets
    ary.push(word.chomp) 
  end
  file.close
end

def choices (dict, word, dpairs, pairs, re  il)
  re  .'* word.length unless re
  c  val("dict.grep(\/^#{re}\$\/)")
  c  .delete_if{ |w| dpairs[w] ! airs[word] }
  return c
end

def decode (cyphertext, cypher, plain)
  code  }
  ('a'..'z').each { |l| code[l]  .'}
  kl  ypher.split(//)
  wl  lain.split(//)
  kl.each_index { |i|
    code[kl[i]]  l[i] if code[kl[i]] '.'
  }
  clear  ]
  cyphertext.each {|w|
     next unless w
     word  "
     w.each_byte { |c|
       word << code[c.chr] if c
     }
     clear <<  word
  }
  return clear 
end 

def count_options (puzzle, dictionary, pairs, dpairs, sizes, clear)
min_choices  0000
savi  1
savl  1
savt  ]
puzzle.each_index { |i|

  t  hoices(dictionary, puzzle[i], dpairs, pairs, clear[i])

  sizes[i]  .length
  next if (clear[i] && clear[i] !~ /\./)
  if sizes[i] > 0 && sizes[i] < min_choices
    min_choices  izes[i]
    savt   
    savi  
  end
}
if savi -1
  return nil, nil
else
  return puzzle[savi], savt
end
end

### MAIN 

dictionary  ]
puzzle  ]
to_try  } 

get_words(ARGV[0], dictionary)
#dictionary.push('a')
#dictionary.push('i')

get_words(ARGV[1], puzzle)

#puzzle.each {|a| a.uniq! if a }

# find words w/dup letters
pairs  }
puzzle.each {|w| pairs[w]  ig(w) }

dpairs  }
dictionary.each {|w| dpairs[w]  ig(w) }

sizes  ]
clear  ]

eword  ]
tries  []
newtries  []

etxt  "
ctxt  "
trial  "
c2p  }
cta  ]

# first time
if ARGV[3]
  etxt ۲ݮ  ctxt ۳ݮ  clear  ecode(puzzle, etxt, ctxt)
end
  
eword[0], tries  ount_options(puzzle, dictionary, pairs, dpairs, sizes, clear)
puts "#{puzzle.join(' ')}\n" 
puts "#{sizes.join(' ')}"


begin
  tries_s  ]
  trial_s  ]
  clear_s  ]
  sizes_s  ]
  zeros  ]
  num_opts  ]

  etxt + word[0]
  eword_s  word[0]

  i  
  tries.each{ |trial| 

    next if ( sig(etxt) ! ig(ctxt+trial))   # incompatible signatures

    clear  ecode(puzzle, etxt, ctxt+trial)
    eword[i], tries_s[i]  ount_options(puzzle, dictionary, pairs, dpairs, sizes, clear)

    puts "#{clear.join(' ')}"
#    puts "#{sizes.join(' ')}"

    clear_s[i]  lear
    sizes_s[i]  izes
    trial_s[i]  rial
    zeros[i]  izes.grep(0).length
    i + 
  }


  break unless i > 0

  # find best "trial" 
  best  1
  num_choices  0000
  sizes_s.each_index { |i|
    sizes_s[i].each_index { |j|
      if (sizes_s[i][j] > 0 &&
         sizes_s[i][j] < um_choices &&
         clear_s[i][j] /\./) 
        best   
        num_choices  izes_s[i][j]
      end
    } 
  }

  if best -1   # no unresolved options w/1 choice ...
    best  eros.rindex(zeros.min) || -1
  end

  if best  ! 1
    ctxt + rial_s[best]
    tries  ries_s[best]
    clear  lear_s[best]
    eword[0]  word[best] 
    puts "DBG - selected #{eword_s} -> #{trial_s[best]}" 
  end

end while eword[0]


exit

--/fjOwTFLoeqy+p+1VGt--