Class: StableMatch::Candidate

Inherits:
Object
  • Object
show all
Includes:
Util::InitializeWithDefaults
Defined in:
lib/stable_match/candidate.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Util::InitializeWithDefaults

included

Constructor Details

#initialize(target, raw_preferences, match_positions = 1) ⇒ Candidate

Returns a new instance of Candidate.



31
32
33
34
35
# File 'lib/stable_match/candidate.rb', line 31

def initialize( target , raw_preferences , match_positions = 1 )
  @target          = target
  @raw_preferences = raw_preferences
  @match_positions = match_positions
end

Instance Attribute Details

#match_positionsObject

The number of matches the candidate is able to make



12
13
14
# File 'lib/stable_match/candidate.rb', line 12

def match_positions
  @match_positions
end

#matchesObject

The matches this candidate has attained



9
10
11
# File 'lib/stable_match/candidate.rb', line 9

def matches
  @matches
end

#preference_positionObject

The tracked position for preferences that have been attempted for matches



15
16
17
# File 'lib/stable_match/candidate.rb', line 15

def preference_position
  @preference_position
end

#preferencesObject

An ordered array of candidates where, the lower the index, the higher the preference

WARNING – this may be instantiated with targets at first that get converted to Candidates



20
21
22
# File 'lib/stable_match/candidate.rb', line 20

def preferences
  @preferences
end

#proposalsObject

The array to track proposals that have already been made



23
24
25
# File 'lib/stable_match/candidate.rb', line 23

def proposals
  @proposals
end

#raw_preferencesObject

An ordered array of raw preference values



26
27
28
# File 'lib/stable_match/candidate.rb', line 26

def raw_preferences
  @raw_preferences
end

#targetObject

The object that the candidate represents



29
30
31
# File 'lib/stable_match/candidate.rb', line 29

def target
  @target
end

Instance Method Details

#better_match?(other) ⇒ Boolean

Is the passed candidate a better match than any of the current matches?

ARG: other – another Candidate instance to check against the current set

Returns:

  • (Boolean)


48
49
50
51
52
53
# File 'lib/stable_match/candidate.rb', line 48

def better_match?( other )
  return true if prefers?( other ) && free?
  preference_index = preferences.index other
  match_preference_indexes = matches.map { | match | preferences.index match }
  preference_index and match_preference_indexes.any? { |i| i > preference_index }
end

#exhausted_preferences?Boolean

Have all possible preferences been cycled through?

Returns:

  • (Boolean)


56
57
58
# File 'lib/stable_match/candidate.rb', line 56

def exhausted_preferences?
  preference_position >= preferences.size - 1
end

#free!Object

Delete the least-preferred candidate from the matches array



66
67
68
69
70
71
72
73
74
75
# File 'lib/stable_match/candidate.rb', line 66

def free!
  return false if matches.empty?
  match_preference_indexes = matches.map { | match | preferences.index match }
  max                      = match_preference_indexes.max # The index of the match with the lowest preference
  candidate_to_reject      = preferences[ max ]

  # Delete from both sides
  candidate_to_reject.matches.delete self
  self.matches.delete candidate_to_reject
end

#free?Boolean

Is there available positions for more matches based on the defined match_positions?

Returns:

  • (Boolean)


61
62
63
# File 'lib/stable_match/candidate.rb', line 61

def free?
  matches.length < match_positions
end

#full?Boolean

Are there no remaining positions available for matches?

Returns:

  • (Boolean)


78
79
80
# File 'lib/stable_match/candidate.rb', line 78

def full?
  !free?
end

#initialize_defaults!Object



37
38
39
40
41
42
43
# File 'lib/stable_match/candidate.rb', line 37

def initialize_defaults!
  @matches             ||= []
  @preference_position ||= -1
  @preferences         ||= []
  @proposals           ||= []
  @raw_preferences     ||= []
end

#inspectObject Also known as: pretty_inspect



82
83
84
85
86
87
88
89
90
91
92
# File 'lib/stable_match/candidate.rb', line 82

def inspect
  {
    'target'              => target,
    'match_positions'     => match_positions,
    'matches'             => matches.map( &:target ),
    'preference_position' => preference_position,
    'preferences'         => preferences.map( &:target ),
    'proposals'           => proposals.map( &:target ),
    'raw_preferences'     => raw_preferences
  }.to_yaml
end

#match!(other) ⇒ Object

Match with another Candidate

ARG: other – another Candidate instance to match with



101
102
103
104
105
# File 'lib/stable_match/candidate.rb', line 101

def match!( other )
  return false unless prefers?( other ) && !matched?( other )
  matches       << other
  other.matches << self
end

#matched?(other = nil) ⇒ Boolean

If no argument is passed: Do we have at least as many matches as available match_positions? If another Candidate is passed: Is that candidate included in the matches?

ARG: other [optional] – another Candidate instance

Returns:

  • (Boolean)


111
112
113
114
# File 'lib/stable_match/candidate.rb', line 111

def matched?( other = nil )
  return full? if other.nil?
  matches.include? other
end

#next_preference!Object

Increment preference_position and return the preference at that position



117
118
119
120
# File 'lib/stable_match/candidate.rb', line 117

def next_preference!
  self.preference_position += 1
  preferences.fetch preference_position
end

#prefers?(other) ⇒ Boolean

Is there a preference for the passed Candidate?

ARG: other – another Candidate instance

Returns:

  • (Boolean)


125
126
127
# File 'lib/stable_match/candidate.rb', line 125

def prefers?( other )
  preferences.include? other
end

#propose_to(other) ⇒ Object

Track that a proposal was made then ask the other Candidate to respond to a proposal

ARG: other – another Candidate instance



132
133
134
135
# File 'lib/stable_match/candidate.rb', line 132

def propose_to( other )
  proposals << other
  other.respond_to_proposal_from self
end

#propose_to_next_preferenceObject



137
138
139
# File 'lib/stable_match/candidate.rb', line 137

def propose_to_next_preference
  propose_to next_preference!
end

#respond_to_proposal_from(other) ⇒ Object

Given another candidate, respond properly based on current state

ARG: other – another Candidate instance



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/stable_match/candidate.rb', line 144

def respond_to_proposal_from( other )
  case
    # Is there a preference for the candidate?
    when !prefers?( other )
      false

    # Are there available positions for more matches?
    when free?
      match! other

    # Is the passed Candidate a better match than any other match?
    when better_match?( other )
      free!
      match! other

    else
      false
  end
end