class Drawy::Engine

Attributes

couples[RW]
people[RW]
result[RW]

Public Class Methods

add_people(names) click to toggle source
# 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
build_list() click to toggle source

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
draw(options = {}) click to toggle source
# 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
is_couple?(x, y) click to toggle source
# 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