class Drawy::Engine
Attributes
Public Class Methods
# File lib/drawy/engine.rb, line 6 def add_people(names) self.people ||= [] self.couples ||= {} names.delete_if(&:empty?) names.map!(&:downcase) couples[names.first] = names.last if names.size == 2 self.people += names end
This probably deserves a bit of insight on what’s going on Basically we just build a list from people names keeping the order (note that people array has been shuffled) If we encounter a person following its partner we just take the next person first and add the partner after
Example: We have %w(john anna dan camille henrik) in names and we have { ‘john’ => ‘anna’ } in couples Step 1: remove john and put him in the list => list = %w(john) Step 2: remove anna, she’s in couple with john so remove dan and put him in the list => list = %w(john dan) Step 3: now anna is not in couple with dan so add her to the list => list = %w(john dan anna) Step 4: remove camille and put her in the list => list = %w(john dan anna camille) Step 5: remove henrik and put him in the list => list = %w(john dan anna camille henrik) An extra step is sometimes needed if the last person is in couple with the previous one because there’s nobody left to add in between the two so we just arbitrarily put him at position 1
The complexity is O(n), n representing the number of people
# File lib/drawy/engine.rb, line 45 def build_list list = [] names = people.dup while names.any? if is_couple?(list[-1], names[0]) aside = names.shift break if names.empty? list << names.shift list << aside aside = nil else list << names.shift end end list.insert(1, aside) if aside list end
# File lib/drawy/engine.rb, line 17 def draw(options = {}) # shuffle: false option is used for testing purposes people.shuffle! unless options[:shuffle] == false list = build_list # Here build_list returns a list like so: %w(john dan anna camille) # Now we want to have direct access to a person's associated person so that # looking up the result for "john" returns "dan" without having to go through the array for every requested name # Therefore we need result to be { 'john' => 'dan', 'dan' => 'anna', 'anna' => 'camille', 'camille' => 'john' } self.result = Hash[list.zip(list.rotate)] end
# File lib/drawy/engine.rb, line 66 def is_couple?(x, y) return false if [x, y].include?(nil) couples[x] == y || couples[y] == x end