## Ruby *As it stands, this is not a valid answer, as it accesses the word list. I'm currently working on a version that doesn't do so, but it might take a while.* A joint submission from user [PragTob](http://codegolf.stackexchange.com/users/20217/pragtob) and myself. <!-- language: lang-rb --> MAX_TURNS = 6 words_by_length = File.read('wordlist.txt').split.group_by &:length while !(input=gets.chomp)['END'] current_turns = MAX_TURNS won = false fitting_words = words_by_length[input.length] characters_used = '_' while (current_turns > 0) && !won pattern_regex = Regexp.new(input.gsub('_', "[^#{characters_used}]")) fitting_words = fitting_words.select do |word| pattern_regex.match word end char_count = Hash.new 0 fitting_words.each do |word| word.chars.uniq.each {|c| char_count[c] += 1 } end chars = char_count.keys.reject {|c| /[#{characters_used}]/.match c }.sort_by {|c|-char_count[c]} characters_used << chars[0] puts chars[0] $stdout.flush old_input = input input = gets.chomp current_turns -= 1 if input == old_input won = !input[?_] end if won words_by_length[input.length].delete input end end Currently this takes about 13 seconds on my machine, but there is certainly room for some speed optimisation. It averages a score of about 3940 and total error of 6050. I say "averages", because the algorithm depends on the order of the words used. This is roughly how it works: - for each guess, we figure out all possible words from the given list, count in how many of them each character occurs and guess the most common one - here is how we determine "all possible words": - we start with all words on word list - every time we guess a word correctly, we delete it - at each turn we also remove all words that do not fit the input pattern - finally we remove all words where "blanks" in the input pattern correspond to characters we already guessed It's getting late over here and that's currently the best method we can think of. We might be able to make minor improvements by including logic to throw out missed words as well (say we missed three words that all read `_o_` at the end, and there are three words like this left in our list, we could throw those out as well). But it seems that this might take at least as much code as we already have, and the improvements may or may not be negligible.