From: Thomas Leitner Date: 2004-10-03T22:04:56+09:00 Subject: Re: [SOLUTION] Secret Santas (#2) And here is my version of the second quiz. It does not use 'net/smtp' but shows the chosen santas on the console. Thomas ----------------------------------------------- #!/usr/bin/env ruby Person = Struct.new( :first, :last, :email ) # Parses one line and extract the data items def parse_name( name ) person = Person.new( *name.split[0..2] ) if person.first.nil? || person.last.nil? || person.email.nil? puts "Invalid input: #{name.inspect}" exit end return person end # Reads lines from the given IO object and returns a Hash with all persons as keys def parse_names( io ) list = {} list[parse_name( STDIN.readline )] = nil until io.eof return list end # Associates each person with a list of possibile Santas def build_santa_lists( list ) list.each_key do |person| possible_santas = list.keys possible_santas.reject! { |other_person| other_person.last == person.last } list[person] = possible_santas end end # A Santa is correct if there is no other person for whom only the selected Santa is left def verify_santa( list, person, santa ) list.each do |key, value| return false if key != person && value == [santa] end return true end # Choose a Santa for each person def choose_santas( list ) list.each do |person, possible_santas| begin santa = possible_santas[rand( possible_santas.length )] end until verify_santa( list, person, santa ) list.each_value { |value| value.delete( santa ) if Array === value } list[person] = santa end end # Mail the Santas which person they have got def mail_santas( list ) list.each do |person, santa| santa = Person.new('', '', '') if santa.nil? puts "Santa #{santa.first} #{santa.last} #{santa.email} for #{person.first} #{person.last} #{person.email}" end end list = parse_names( STDIN ) build_santa_lists list choose_santas list mail_santas list