Class: ICU::RatedTournament

Inherits:
Object
  • Object
show all
Defined in:
lib/icu_ratings/tournament.rb

Overview

Creating Tournaments

ICU::RatedTournament objects are created directly.

t = ICU::RatedTournament.new

They have some optional parameters which can be set via the constructor or by calling the same-named setter methods. One is called desc (short for description) the value of which can be any object but will, if utilized, typically be the name of the tournament as a string.

t = ICU::RatedTournament.new(:desc => "Irish Championships 2010")
puts t.desc                         # "Irish Championships 2010"

Another optional parameter is start for the start date. A Date object or a string that can be parsed as a string can be used to set it. The European convention is preferred for dates like “03/06/2013” (3rd of June, not 6th of March). Attempting to set an invalid date will raise an exception.

t = ICU::RatedTournament.new(:start => "01/07/2010")
puts t.start.class                  # Date
puts t.start.to_s                   # "2010-07-01"

Also, there is the option no_bonuses. Bonuses are a feature of the ICU rating system. If you are rating a non-ICU tournament (such as a FIDE tournament) where bonues are not awarded use this option.

t = ICU::RatedTournament.new(:desc => 'Linares', :start => "07/02/2009", :no_bonuses => true)

Note, however, that the ICU system also has its own unique way of treating provisional, unrated and foreign players, so the only FIDE tournaments that can be rated using this software are those that consist solely of rated players.

Rating Tournaments

To rate a tournament, first add the players (see ICU::RatedPlayer for details):

t.add_player(1, :rating => 2534, :kfactor => 16)
# ...

Then add the results (see ICU::RatedResult for details):

t.add_result(1, 1, 2, 'W')
# ...

Then rate the tournament by calling the rate! method:

t.rate!

Now the results of the rating calculations can be retrieved from the players in the tournement or their results. For example, player 1’s new rating would be:

t.player(1).new_rating

See ICU::RatedPlayer and ICU::RatedResult for more details.

The rate! method takes some optional arguments to control the algoritm, for example:

t.rate!(max_iterations2: 30)

The complete set of current options is:

  • max_iterations1: the maximum number of re-estimation iterations before the bonus calculation (default 30)

  • max_iterations2: the maximum number of re-estimation iterations after the bonus calculation (default 1)

  • threshold: the maximum difference allowed between re-estimated ratings in a stabe solution (default 0.5)

Error Handling

Some of the above methods have the potential to raise RuntimeError exceptions. In the case of add_player and add_result, the use of invalid arguments would cause such an error. Theoretically, the rate! method could also throw an exception if the iterative algorithm it uses to estimate performance ratings of unrated players failed to converge. However an instance of non-convergence has yet to be observed in practice.

Since exception throwing is how errors are signalled, you should arrange for them to be caught and handled in some suitable place in your code.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#descObject

Returns the value of attribute desc.



83
84
85
# File 'lib/icu_ratings/tournament.rb', line 83

def desc
  @desc
end

#iterations1Object (readonly)

Returns the value of attribute iterations1.



84
85
86
# File 'lib/icu_ratings/tournament.rb', line 84

def iterations1
  @iterations1
end

#iterations2Object (readonly)

Returns the value of attribute iterations2.



84
85
86
# File 'lib/icu_ratings/tournament.rb', line 84

def iterations2
  @iterations2
end

#no_bonusesObject

Returns the value of attribute no_bonuses.



84
85
86
# File 'lib/icu_ratings/tournament.rb', line 84

def no_bonuses
  @no_bonuses
end

#startObject

Returns the value of attribute start.



84
85
86
# File 'lib/icu_ratings/tournament.rb', line 84

def start
  @start
end

Instance Method Details

#add_player(num, args = {}) ⇒ Object

Add a new player to the tournament. Returns the instance of ICU::RatedPlayer created. See ICU::RatedPlayer for details.



88
89
90
91
92
# File 'lib/icu_ratings/tournament.rb', line 88

def add_player(num, args={})
  raise "player with number #{num} already exists" if @player[num]
  args[:kfactor] = ICU::RatedPlayer.kfactor(args[:kfactor].merge({ :start => start, :rating => args[:rating] })) if args[:kfactor].is_a?(Hash)
  @player[num] = ICU::RatedPlayer.new(num, args)
end

#add_result(round, player, opponent, score) ⇒ Object

Add a new result to the tournament. Two instances of ICU::RatedResult are created. One is added to the first player and the other to the second player. The method returns nil. See ICU::RatedResult for details.



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/icu_ratings/tournament.rb', line 97

def add_result(round, player, opponent, score)
  n1 = player.is_a?(ICU::RatedPlayer) ? player.num : player.to_i
  n2 = opponent.is_a?(ICU::RatedPlayer) ? opponent.num : opponent.to_i
  p1 = @player[n1] || raise("no such player number (#{n1})")
  p2 = @player[n2] || raise("no such player number (#{n2})")
  r1 = ICU::RatedResult.new(round, p2, score)
  r2 = ICU::RatedResult.new(round, p1, r1.opponents_score)
  p1.add_result(r1)
  p2.add_result(r2)
  nil
end

#player(num) ⇒ Object

Return a player (ICU::RatedPlayer) given a player number (returns nil if the number is invalid).



132
133
134
# File 'lib/icu_ratings/tournament.rb', line 132

def player(num)
  @player[num]
end

#playersObject

Return an array of all players, in order of player number.



127
128
129
# File 'lib/icu_ratings/tournament.rb', line 127

def players
  @player.keys.sort.map{ |num| @player[num] }
end

#rate!(opt = {}) ⇒ Object

Rate the tournament. Called after all players and results have been added.



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/icu_ratings/tournament.rb', line 110

def rate!(opt={})
  max_iterations1 = opt[:max_iterations1] || 30
  max_iterations2 = opt[:max_iterations2] || 1
  threshold = opt[:threshold] || 0.5
  players.each { |p| p.init }
  @iterations1 = performance_ratings(max_iterations1, threshold)
  players.each { |p| p.rate! }
  if !no_bonuses && calculate_bonuses > 0
    players.each { |p| p.rate! }
    @iterations2 = performance_ratings(max_iterations2, threshold)
    calculate_bonuses
  else
    @iterations2 = 0
  end
end