Thursday, December 27, 2007

Christmas gift swap ruby program

A guy I work with named Brad has told me several stories about how he's gotten his kids (I think in particular one daughter) to geek out with him a little by sitting down and writing some code with him. Simple stuff like penny flippers, dice rollers, math homework, etc. This motivated me to sit down with my 13 year old sister and write a short little ruby script with her in order to generate the Christmas gift swap list. Our family will be able to use this next year instead of having to manually draw names out of a hat.


require 'pp'

def print_swap_list(names_hat)
#puts "The names (out of order):"
#pp names_hat

buyers = Array.new + names_hat.sort!
buyers_copy = Array.new + buyers
#puts "The names (ordered alphabetically):"
#pp buyers

#buyers.each_with_index do |buyer, number|
# puts "#{number} - #{buyer}"
#end

receivers = Array.new

while(buyers_copy.size != 0)
random_name = buyers_copy[rand(buyers_copy.size)]
if (buyers_copy[receivers.size] != random_name) then
receivers << random_name
buyers_copy.delete_if { |the_buyer_in_the_buyers_copy_list| the_buyer_in_the_buyers_copy_list == random_name }
end
end

0.upto(names_hat.size - 1) do |number|
puts "#{number + 1} - #{buyers[number]} | #{number + 1} - #{receivers[number]}"
end
end

puts "================================================="
puts "Creating the gift swap list."
puts "================================================="
# PUT THE NAMES OF THE PEOPLE THAT SHOULD GO INTO THE HAT HERE!
names_hat = %w'Name1 Name2 Name3 Name4 Name5 Name6 etc'
print_swap_list(names_hat)
puts "================================================="

5 comments:

Rod said...

def print_swap_list(names_hat)
names_random=names_hat.sort_by{rand}
names_random.each_with_index do |giver, i|
puts "#{giver} gives a gift to #{names_random[ (i+1) % names_random.size ]}"
end
end

Rod said...

it's also worth noting that your program can have a string of bad luck that causes it to run forever :)

this is actually a lot like one of the interview questions i like to ask - shuffling an array. If you do it by picking a random element and removing it, you can wind up picking poorly over and over, causing it to have to throw the result away and try again, over and over. Your runtime is O(x), where x is random.

Whenever randomizing a finite set, it's better to do a finite number of swaps so that the runtime has an upper bound.

You taught your sister how to be a bad programmer ;)

Bryan said...

Not a huge surprise. There was no one here to QA it. I did think to myself for a moment that it wasn't terribly efficient, because the 'rand' function could've picked the same thing over and over... but then I didn't care that much, since it was a Christmas swap list... and I'm pretty sure I'd gotten about all of my sister's attention as she was going to give at that point.

When my kids get old enough to understand this kind of thing, I'll make sure to show them your example instead of mine.

Bryan said...

So, I looked back at your example to make sure I understood why it was better, and I do now... but I'm going to make an excuse for why I did it the way I did.

The whole time I was working through the problem with her, I was using the analogy of drawing paper out of a hat. Keep in mind this girl had never even written hello world before this. Being super explicit about the steps being taken seemed like the right way to at least teach her rather than show her some magical 'sort_by{rand}' code that does exactly what she needs it to do. I wanted to code in the notion of putting the thing back in the hat to show her exactly how one can model computer code after something in real life.

That, and I didn't see your better solution right off either.

The other solution is that we could always prevent the program from having any chance of running forever by allowing a person to buy a gift for themselves.

Rod said...

I know, your way was better for a kid to learn programming. I was just busting your balls. ;)