From: Dick Davies Date: 2005-01-18T08:57:05+09:00 Subject: Re: [Solution] Animal Quiz (#15) * Ruby Quiz [0123 14:23]: Thanks, had fun with that. Sounded easy at first read but had me stumped several times last night. Got a slightly hacky version, but hopefully shortish version. Largely based on Exception abuse :) Tricky bit was figuring out the tree updating - knocking together a quick tree and getting the traversal right helped a lot there. The updating bit wrote itself after that. I'm sure there's a more rubyish way of switching the node from 'animal mode' to 'question mode', but it seems to avoid a lot of book-keeping and linked-list-esque linking and unlinking of references, so it'll do... It's fairly short so here you go: --------------------------------8<----------------------------------- #!/usr/bin/env ruby class TreeNode attr_accessor :yes, :no, :question, :animal def initialize(animal=nil) @animal = animal @question = @no = @yes = nil end def walk begin return (prompt(question) ? yes.walk : no.walk) rescue NoMethodError # yes, no or question was nil. Make a guess. if ( prompt "I think I am a #{animal}. Am I?") puts "Yay! Let's start again." else update_tree end end end def update_tree puts "OK, I give up. What am i?" new_animal = gets.chomp.intern puts "Give me a question which is true for #{new_animal} and false for #{animal}" new_question = gets.chomp # become a decision branch and connect our forks @no = TreeNode.new(animal) @yes = TreeNode.new(new_animal) @animal = nil @question = new_question puts "Duly noted. Let's try again:" end def prompt(str) # no question to ask, so punt raise NoMethodError unless str puts "#{str} ( q/Q to quit) :" response = gets exit if response =~ /q.*/i return true if response =~ /y.*/i false end end top = TreeNode.new(:elephant) loop { top.walk } --------------------------------8<----------------------------------- -- 'Good news, everyone! I've taught the toaster to feel love!' -- Prof. Farnsworth Rasputin :: Jack of All Trades - Master of Nuns