Previous exists logic error 
Correct again...

=begin
My second solution.

Most solutions do a tree walk.
Kids will get boring soon,
because it always ask the questions in the same order.
No fun at all...

Here I try to do "ask question in random order".
( ==> Not good to quick find the answer. )


Random select "possible" question.
If we try to count the "weight" of the possible questions,
and select the "heaviest" one, we end up like tree walk order.
Except, if there are equal-heavy, example:
      Q1            Q2
     /  \   ==>    /  \
   Q2   Q2        Q1   Q1

Note: You could change the program to take
the average weigth question instead of 
random select.
   
Since we random ask "possible" questions,
that may help to get more information about 
existing knowledge animal, example:
     Q1    ==>      Q1
    /  \          /    \
   Q2   c        Q2     Q3
  /  \          /  \   /  \
 a    b        a    b  Q2  c
                        \    
                         d
		       
==> this may happend ask Q2 first, then Q1,
and finally distinct c,d by Q3.


A little explanation about my data structure:
* db_questions: array to store questions. (index 0 no use)
* db_animals: hash; key == animals, 
  value == array of questions, the absolute value map
  to db_questions's index; and positive for 'Yes' answer
  and negative for 'No' answer.
  
=end

require 'yaml'

ANIMALS_FILE = 'animals.yaml'
QUESTIONS_FILE = 'questions.yaml'


# reuse Jim Weirich ConsoleUi class and modified
class ConsoleUi
  def ask(prompt)
    print prompt + "\n"
    answer = gets
    answer ? answer.chomp : nil
  end

  def ask_if(prompt)
    answer = ask(prompt + "  (y or n)")
    answer =~ /^\s*[Yy]/
  end
	
  def say(*msg)
    puts msg
  end
end

def ui
  $ui ||= ConsoleUi.new
end

def get_possible_questions(animals, asked_questions)
  questions = []
  animals.each_value do |qs|
    qs.each do |q| 
    	q = q.abs;
	if !questions.include?(q) &&
	   !asked_questions.include?(q) &&
	   !asked_questions.include?(-q)
    	  questions << q 
	end
    end
  end
  questions
end

def filter_animals(animals, question)
  animals.each do |animal, questions|
    animals.delete(animal) if questions.include? question
  end
end

db_animals = File.exist?(ANIMALS_FILE) ? 
             YAML.load_file(ANIMALS_FILE) :
	     { 'an elephant' => [] }
	     
db_questions = File.exist?(QUESTIONS_FILE) ? 
               YAML.load_file(QUESTIONS_FILE) :
	       [ '' ]

loop do
  asked_questions = []
  animals = db_animals.dup
 
  ui.say "Think of an animal..."

  while animals.size > 1
    qs = get_possible_questions(animals, asked_questions)
    q = qs[rand(qs.size)]
    q = -q unless ui.ask_if db_questions[q]
    asked_questions << q
    filter_animals(animals, -q)
  end

  animal = animals.keys[0]
  if ui.ask_if "Is it #{animal}?"
    ui.say "I win!"
    # update knowledge, we may have more infomation
    # about the animal, since we random asked questions
    db_animals[animal] += asked_questions
    db_animals[animal].uniq!
  else
    ui.say "You win. Help me play better next time."
    new_animal = ui.ask "What animal were you thinking of?"
    question = ui.ask "Give me a question to distinguish " +
               "#{animal} from #{new_animal}."
    response = ui.ask_if "For #{new_animal}, " +
               "what is the answer to your question?"
    ui.say "Thanks."
    
    if db_animals.key?(new_animal)
      ui.say "Hey! You are cheating, accroding asked questions," +
             "it cannot be #{new_animal}."
      # ...
    end
    
    q = db_questions.index(question)
    if q
      if asked_questions.include?(q) || asked_questions.include?(-q)
        ui.say "Hey! That question already asked! You try to confuse me."
	# ...
      end
    else
      db_questions << question
      q = db_questions.size - 1
    end
    db_animals[animal] << (response ? -q : q)
    db_animals[animal].uniq!
    db_animals[new_animal] = asked_questions
    db_animals[new_animal] << (response ? q : -q)    
  end

  break unless ui.ask_if "Play again?"
  ui.say "\n\n"
end

open(ANIMALS_FILE, 'w') { |f| f.puts db_animals.to_yaml }
open(QUESTIONS_FILE, 'w') { |f| f.puts db_questions.to_yaml }
-- 

David Tran
http://www.doublegifts.com