On Friday 14 January 2005 09:23 am, Ruby Quiz wrote:
> Here's a program I've had a lot of fun with and might make a good Ruby
> Quiz entry.  The program is a animal quiz program.
>
> It works like this.  The program starts by telling the user to think
> of an animal.  It then begins asking a series of yes/no questions
> about that animal: does it swim, does it have hair, etc.  ...

Here's my solution ...

#-- animals.rb ----------------------------------------------
#!/usr/bin/env ruby

require 'yaml'
require 'ui'

def ui
  $ui ||= ConsoleUi.new
end

class Question
  def initialize(question, yes, no)
    @question = question
    @yes = yes
    @no = no
    @question << "?" unless @question =~ /\?$/
    @question.sub!(/^([a-z])/) { $1.upcase }
  end

  def walk
    if ui.ask_if @question
      @yes = @yes.walk
    else
      @no = @no.walk
    end
    self
  end
end

class Animal
  attr_reader :name
  def initialize(name)
    @name = name
  end

  def walk
    if ui.ask_if "Is it #{an name}?"
      ui.say "Yea!  I win!\n\n"
      self
    else
      ui.say "Rats, I lose"
      ui.say "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 a #{an name} from #{an new_animal}."
      response = ui.ask_if "For #{an new_animal}, the answer to your question 
would be?"
      ui.say "Thank you\n\n"
      if response
	Question.new(question, Animal.new(new_animal), self)
      else
	Question.new(question, self, Animal.new(new_animal))
      end
    end
  end

  def an(animal)
    ((animal =~ /^[aeiouy]/) ? "an " : "a ") + animal
  end
end

if File.exist? "animals.yaml"
  current = open("animals.yaml") { |f| YAML.load(f.read) }
else
  current = Animal.new("mouse")
end

loop do
  current = current.walk
  break unless  ui.ask_if "Play again?"
  ui.say "\n\n"
end

open("animals.yaml", "w") do |f| f.puts current.to_yaml end
# END --------------------------------------------------------

The above code depends upon a very simple UI module:

#-- ui.rb ---------------------------------------------------------
#!/usr/bin/env ruby

class ConsoleUi
  def ask(prompt)
    print prompt + " "
    answer = gets
    answer ? answer.chomp : nil
  end

  def ask_if(prompt)
    answer = ask(prompt)
    answer =~ /^\s*[Yy]/
  end

  def say(*msg)
    puts msg
  end
end
# END -----------------------------------------------------------

-- 
-- Jim Weirich    jim / weirichhouse.org     http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct, 
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)