Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Ruby (http://www.velocityreviews.com/forums/f66-ruby.html)
-   -   [QUIZ] Secret Santas (#2) (http://www.velocityreviews.com/forums/t817025-quiz-secret-santas-2-a.html)

Ruby Quiz 10-01-2004 12:50 PM

[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!



Moses Hohman 10-01-2004 09:37 PM

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




James Edward Gray II 10-01-2004 09:53 PM

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




Moses Hohman 10-02-2004 03:59 AM

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
>
>





Gavin Kistner 10-02-2004 04:26 AM

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?
--
(-, /\ \/ / /\/




Florian Gross 10-02-2004 09:09 AM

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

Joe Cheng 10-02-2004 10:09 PM

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? :)

James Edward Gray II 10-02-2004 10:22 PM

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




Robo 10-03-2004 12:20 PM

[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



Thomas Leitner 10-03-2004 01:01 PM

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 08:54 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.