![]() |
[QUIZ] Secret Santas (#2)
The three rules of Ruby Quiz:
1. Please do not post any solutions or spoiler discussion for this quiz until 48 hours have passed from the time on this message. 2. Support Ruby Quiz by submitting ideas as often as you can: http://www.grayproductions.net/ruby_quiz/ 3. Enjoy! -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Honoring a long standing tradition started by my wife's dad, my friends all play a Secret Santa game around Christmas time. We draw names and spend a week sneaking that person gifts and clues to our identity. On the last night of the game, we get together, have dinner, share stories, and, most importantly, try to guess who our Secret Santa was. It's a crazily fun way to enjoy each other's company during the holidays. To choose Santas, we use to draw names out of a hat. This system was tedious, prone to many "Wait, I got myself..." problems. This year, we made a change to the rules that further complicated picking and we knew the hat draw would not stand up to the challenge. Naturally, to solve this problem, I scripted the process. Since that turned out to be more interesting than I had expected, I decided to share. This weeks Ruby Quiz is to implement a Secret Santa selection script. Your script will be fed a list of names on STDIN. An example might be: Luke Skywalker <luke@theforce.net> Leia Skywalker <leia@therebellion.org> Toula Portokalos <toula@manhunter.org> Gus Portokalos <gus@weareallfruit.net> Bruce Wayne <bruce@imbatman.com> Virgil Brigman <virgil@rigworkersunion.org> Lindsey Brigman <lindsey@iseealiens.net> Note: If you cannot tell, I made those addresses up and you'll need to replace them with something meaningful. Please don't pester those people, should they happen to be real. The format for these names is: FIRST_NAME space FAMILY_NAME space <EMAIL_ADDRESS> newline We'll keep things simple and say that people only have two names, so you don't have to worry about tricky names like Gray II. Your script should then choose a Secret Santa for every name in the list. Obviously, a person cannot be their own Secret Santa. In addition, my friends no longer allow people in the same family to be Santas for each other and your script should take this into account. Output is obvious. E-mail the Santa and tell them who their person is. The extra credit for this quiz is to convince all your friends how much fun this can really be, so you can put your script to good use. Go forth spreading holiday cheer into the world! |
Re: [QUIZ] Secret Santas (#2)
Hi James,
What should the script do if there is no solution for the input set, e.g. the set is two people in the same family? Moses |
Re: [QUIZ] Secret Santas (#2)
On Oct 1, 2004, at 4:37 PM, Moses Hohman wrote:
> Hi James, > > What should the script do if there is no solution for the input set, > e.g. the set is two people in the same family? Egad, knew I forgot to mention something! My bad, sorry. Told ya'll I still need some breaking in at quiz writing. <laughs> I will only feed your script valid combinations, so if you don't want to worry about it, don't. If you do want to build in a sanity check, a simple error message should be fine. Handle it however you are comfortable. James Edward Gray II |
Re: [QUIZ] Secret Santas (#2)
No worries, I probably should have figured that out for myself anyway,
but I felt like asking. On Oct 1, 2004, at 4:53 PM, James Edward Gray II wrote: > On Oct 1, 2004, at 4:37 PM, Moses Hohman wrote: > >> Hi James, >> >> What should the script do if there is no solution for the input set, >> e.g. the set is two people in the same family? > > Egad, knew I forgot to mention something! My bad, sorry. Told ya'll > I still need some breaking in at quiz writing. <laughs> > > I will only feed your script valid combinations, so if you don't want > to worry about it, don't. If you do want to build in a sanity check, > a simple error message should be fine. Handle it however you are > comfortable. > > James Edward Gray II > > |
Re: [QUIZ] Secret Santas (#2)
On Oct 1, 2004, at 6:50 AM, Ruby Quiz wrote:
> Your script will be fed a list of names on STDIN. I've never worked with STDIN before; does this mean a single call to #gets will return a newline-delimited list of names, or I should loop calls to #gets until it returns nil? -- (-, /\ \/ / /\/ |
Re: [QUIZ] Secret Santas (#2)
Gavin Kistner wrote:
>> Your script will be fed a list of names on STDIN. > I've never worked with STDIN before; does this mean a single call to > #gets will return a newline-delimited list of names, or I should loop > calls to #gets until it returns nil? STDIN and ARGF are both IOs. STDIN reads from the standard input. ARGF reads from the standard input and file names that are in ARGV. IO#gets returns one line with a \n at the end or nil when there are no more lines available. There's also IO#read which returns the whole file as a String and IO#readlines which returns the whole file as an Array of lines. (Each with a \n at the end.) Regards, Florian Gross |
Re: [QUIZ] Secret Santas (#2)
> Output is obvious. E-mail the Santa and tell them who their person is.
Will you accept solutions that just print out the e-mails instead of sending them? :) |
Re: [QUIZ] Secret Santas (#2)
On Oct 2, 2004, at 5:09 PM, Joe Cheng wrote:
>> Output is obvious. E-mail the Santa and tell them who their person >> is. > > Will you accept solutions that just print out the e-mails instead of > sending them? :) Why? Are you not yet familiar with "net/smtp"? It's a standard lib, so this is a good excuse to learn it and it's surprisingly simple... :D There's no right and wrong answers to a Ruby Quiz. The goal is to think, learn and have a little fun. Submit whatever does that for you. James Edward Gray II |
[SOLUTION] Secret Santas (#2)
I'm still new to Ruby, but giving this a crack anyway.
I could have made more classes to model the problem better, but didn't bother. Everything's done by a Hat with higher intelligence than regular hats (that doesn't deserve a capital H). To run, type "ruby santa.rb", then enter each person's name and email in the format specified. When you're done the script tells you the result of the selection. The email part is a bit rogue, but that's just a matter of creating a more comprehensive email message. It's disabled by default, just uncomment the lines in Hat#notify. It doesn't take into account of creating loops smaller than total number of people. i.e. If there're 4 people, 3 of them maybe Secret Santas of each other, leaving one stranded. Robo require 'net/smtp' #a very smart Hat that even knows how to email class Hat #represents a member of the Christmas gathering Member = Struct.new(:firstName, :lastName, :email, :minion) def initialize @members = [] @pool = [] end #put a new member into the hat def put(firstName, lastName, email) member = Member.new(firstName, lastName, email) @members << member @pool << member end #match each Secret Santa to a person def match @members.each do |santa| santa.minion = draw(santa) notify(santa) end end #draw a person out of the hat for a Secret Santa def draw(santa) validPool = filter(santa) person = validPool.at(rand(validPool.size)) @pool.delete(person) end #filter out people who're in the same family as Secret Santa def filter(santa) @pool.select do |member| member.lastName != santa.lastName end end #notify each Secret Santa who they'll be watching over def notify(santa) if santa.minion != nil msg = "#{santa.firstName} #{santa.lastName} is watching over " + "#{santa.minion.firstName} #{santa.minion.lastName}" else msg = "#{santa.firstName} #{santa.lastName} is watching over nobody" end puts msg #Net::SMTP.start('smtp.example.com', 25) do |smtp| # smtp.send_message(msg, 'hat@magic.com', santa.email) #end end end def main h = Hat.new while (s = gets()) != nil s.scan(/^(.*?) (.*?) <(.*?)>$/) do |firstName, lastName, email| h.put(firstName, lastName, email) end end h.match end if __FILE__ == $0 main end |
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('<no valid santa found>', '', '') 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 |
| All times are GMT. The time now is 09:11 PM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.