Class: ICU::Player

Inherits:
Object
  • Object
show all
Extended by:
Accessor
Defined in:
lib/icu_tournament/player.rb,
lib/icu_tournament/tournament_sp.rb,
lib/icu_tournament/tournament_krause.rb

Overview

Player

A player in a tournament must have a first name, a last name and a number which is unique in the tournament but otherwise arbitary.

bobby = ICU::Player.new('robert j', 'fischer', 17)

Names are automatically cannonicalised (tidied up).

bobby.first_name                 # => 'Robert J.'
bobby.last_name                  # => 'Fischer'

In addition, players have a number of optional attributes which can be specified via setters or in constructor hash options: id (either FIDE or national), fed (federation), title, rating, rank and dob (date of birth).

peter = ICU::Player.new('Peter', 'Svidler', 21, :fed => 'rus', :title => 'g', :rating = 2700)
peter.dob = '17th June, 1976'
peter.rank = 1

Some of these values will also be canonicalised to some extent. For example, the date of birth conforms to a yyyy-mm-dd format, the chess title will be two to three capital letters always ending in M and the federation, if it’s three letters long, will be upper-cased.

peter.dob                        # => 1976-07-17
peter.title                      # => 'GM'
peter.fed                        # => 'RUS'

It is preferable to add results (ICU::Result) to a player via the tournament (ICU::Tournament) object’s add_result method rather than the method of the same name belonging to player instances. Doing so allows mirrored results to be added to both players with one method call (e.g. one player won, the other lost). A player’s results can later be retieved via the results accessor.

Total scores is available via the points method.

peter.points                     # => 5.5

A player’s id is their ID number in some external database (typically either ICU or FIDE).

peter.id = 16790                 # ICU, or
peter.id = 4102142               # FIDE

Players can be compared to see if they’re roughly or exactly the same, which may be useful in detecting duplicates. If the names match and the federations don’t disagree then two players are equal according to the _==_ operator. The player number is irrelevant.

john1 = ICU::Player.new('John', 'Smith', 12)
john2 = ICU::Player.new('John', 'Smith', 22, :fed = 'IRL')
john2 = ICU::Player.new('John', 'Smith', 32, :fed = 'ENG')

john1 == john2                   # => true (federations don't disagree because one is unset)
john2 == john3                   # => false (federations disagree)

If, in addition, rating, dob, gender and id do not disagree then two players are equal according to the stricter criteria of eql?.

mark1 = ICU::Player.new('Mark', 'Orr', 31, :fed = 'IRL', :rating => 2100)
mark2 = ICU::Player.new('Mark', 'Orr', 33, :fed = 'IRL', :rating => 2100, :title => 'IM')
mark3 = ICU::Player.new('Mark', 'Orr', 37, :fed = 'IRL', :rating => 2200, :title => 'IM')

mark1.eql?(mark2)                # => true (ratings agree and titles don't disagree)
mark2.eql?(mark3)                # => false (the ratings are not the same)

The presence of two players in the same tournament that are equal according to _==_ but unequal according to _eql?__ is likely to indicate a data entry error.

If two instances represent the same player and are equal according to _==_ then the id, rating, title and fed attributes of the two can be merged. For example:

fox1 = ICU::Player.new('Tony', 'Fox', 12, :id => 456)
fox2 = ICU::Player.new('Tony', 'Fox', 21, :rating => 2100, :fed => 'IRL', :gender => 'M')
fox1.merge(fox2)

Any attributes present in the second player but not in the first are copied to the first. All other attributes are unaffected.

fox1.rating                      # => 2100
fox1.fed                         # => 'IRL'
fox1.gender                      # => 'M'

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Accessor

attr_accessor, attr_date, attr_date_or_nil, attr_integer, attr_integer_or_nil, attr_positive, attr_positive_or_nil, attr_string, attr_string_or_nil

Constructor Details

#initialize(first_name, last_name, num, opt = {}) ⇒ Player

Constructor. Must supply both names and a unique number for the tournament.



98
99
100
101
102
103
104
105
106
# File 'lib/icu_tournament/player.rb', line 98

def initialize(first_name, last_name, num, opt={})
  self.first_name = first_name
  self.last_name  = last_name
  self.num        = num
  [:id, :fed, :title, :rating, :rank, :dob, :gender].each do |atr|
    self.send("#{atr}=", opt[atr]) unless opt[atr].nil?
  end
  @results = []
end

Instance Attribute Details

#fedObject

Returns the value of attribute fed.



95
96
97
# File 'lib/icu_tournament/player.rb', line 95

def fed
  @fed
end

#first_nameObject

Returns the value of attribute first_name.



95
96
97
# File 'lib/icu_tournament/player.rb', line 95

def first_name
  @first_name
end

#genderObject

Returns the value of attribute gender.



95
96
97
# File 'lib/icu_tournament/player.rb', line 95

def gender
  @gender
end

#last_nameObject

Returns the value of attribute last_name.



95
96
97
# File 'lib/icu_tournament/player.rb', line 95

def last_name
  @last_name
end

#resultsObject (readonly)

Returns the value of attribute results.



95
96
97
# File 'lib/icu_tournament/player.rb', line 95

def results
  @results
end

#titleObject

Returns the value of attribute title.



95
96
97
# File 'lib/icu_tournament/player.rb', line 95

def title
  @title
end

Instance Method Details

#==(other) ⇒ Object

Loose equality test. Passes if the names match and the federations are not different.



187
188
189
190
191
192
193
194
# File 'lib/icu_tournament/player.rb', line 187

def ==(other)
  return true if equal?(other)
  return false unless other.is_a? Player
  return false unless @first_name == other.first_name
  return false unless @last_name  == other.last_name
  return false if @fed && other.fed && @fed != other.fed
  true
end

#add_result(result) ⇒ Object

Add a result. Don’t use this method directly - use ICU::Tournament#add_result instead.



154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/icu_tournament/player.rb', line 154

def add_result(result)
  raise "invalid result" unless result.class == ICU::Result
  raise "player number (#{@num}) is not matched to result player number (#{result.player})" unless @num == result.player
  already = @results.find_all { |r| r.round == result.round }
  return if already.size == 1 && already[0].eql?(result)
  raise "round number (#{result.round}) of new result is not unique and new result is not the same as existing one" unless already.size == 0
  if @results.size == 0 || @results.last.round <= result.round
    @results << result
  else
    i = (0..@results.size-1).find { |n| @results[n].round > result.round }
    @results.insert(i, result)
  end
end

#eql?(other) ⇒ Boolean

Strict equality test. Passes if the playes are loosly equal and also if their ID, rating, gender and title are not different.

Returns:

  • (Boolean)


197
198
199
200
201
202
203
204
# File 'lib/icu_tournament/player.rb', line 197

def eql?(other)
  return true if equal?(other)
  return false unless self == other
  [:id, :rating, :title, :gender].each do |m|
    return false if self.send(m) && other.send(m) && self.send(m) != other.send(m)
  end
  true
end

#find_result(round) ⇒ Object

Lookup a result by round number.



169
170
171
# File 'lib/icu_tournament/player.rb', line 169

def find_result(round)
  @results.find { |r| r.round == round }
end

#merge(other) ⇒ Object

Merge in some of the details of another player.



207
208
209
210
211
212
# File 'lib/icu_tournament/player.rb', line 207

def merge(other)
  raise "cannot merge two players that are not equal" unless self == other
  [:id, :rating, :title, :fed, :gender].each do |m|
    self.send("#{m}=", other.send(m)) unless self.send(m)
  end
end

#nameObject

Return the full name, last name first.



123
124
125
# File 'lib/icu_tournament/player.rb', line 123

def name
  "#{last_name}, #{first_name}"
end

#pointsObject

Return the player’s total points.



174
175
176
# File 'lib/icu_tournament/player.rb', line 174

def points
  @results.inject(0.0) { |t, r| t += r.points }
end

#renumber(map) ⇒ Object

Renumber the player according to the supplied hash. Return self.



179
180
181
182
183
184
# File 'lib/icu_tournament/player.rb', line 179

def renumber(map)
  raise "player number #{@num} not found in renumbering hash" unless map[@num]
  self.num = map[@num]
  @results.each{ |r| r.renumber(map) }
  self
end

#to_krause(rounds) ⇒ Object

Format a player’s 001 record as it would appear in a Krause formatted file (including the final newline).



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/icu_tournament/tournament_krause.rb', line 318

def to_krause(rounds)
  krause = '001'
  krause << sprintf(' %4d', @num)
  krause << sprintf(' %1s', case @gender; when 'M' then 'm'; when 'F' then 'w'; else ''; end)
  krause << sprintf(' %2s', case @title; when nil then ''; when 'IM' then 'm'; when 'WIM' then 'wm'; else @title[0, @title.length-1].downcase; end)
  krause << sprintf(' %-33s', "#{@last_name},#{@first_name}")
  krause << sprintf(' %4s', @rating)
  krause << sprintf(' %3s', @fed)
  krause << sprintf(' %11s', @id)
  krause << sprintf(' %10s', @dob)
  krause << sprintf(' %4.1f', points)
  krause << sprintf(' %4s', @rank)
  (1..rounds).each do |r|
    result = find_result(r)
    krause << sprintf('  %8s', result ? result.to_krause : '')
  end
  krause << "\n"
end

#to_sp_text(rounds, format) ⇒ Object

Format a player’s record as it would appear in an SP text export file.



362
363
364
365
366
367
368
369
# File 'lib/icu_tournament/tournament_sp.rb', line 362

def to_sp_text(rounds, format)
  attrs = [num.to_s, name, id.to_s, ('%.1f' % points).sub(/\.0/, '')]
  (1..rounds).each do |r|
    result = find_result(r)
    attrs << (result ? result.to_sp_text : " : ")
  end
  format % attrs
end