elo2 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 249ef1b338e702a1f19cf4ee6e4472c5ca3c22d9
4
+ data.tar.gz: 121bea75bb56e1cac834ad81559ecdfa60160c9c
5
+ SHA512:
6
+ metadata.gz: 7a0c882c33002e9d5e52900587ad771934e4d8726f7e807c4ca931ee257fd889e7af23f8d8fd8f2b061d307a75134fc941c29d9ea59b4532574369c9b5ed5f9a
7
+ data.tar.gz: 929fde0b1092d16eb469067fe0dbc7ee3278199a3b1e807b88d8bb78c6c10052d57c3013d0b7963cbaf7aa698df4af01cb34c6bddfcf85cf0113b035f4d972ba
@@ -0,0 +1,27 @@
1
+ require 'elo/helper'
2
+ require 'elo/configuration'
3
+ require 'elo/game'
4
+ require 'elo/player'
5
+ require 'elo/rating'
6
+ require 'elo/version'
7
+
8
+ # See README.rdoc for general information about Elo.
9
+ module Elo
10
+
11
+ # Accessor to the configuration object, which,
12
+ # should be instantiated only once (and automatically).
13
+ def self.config
14
+ @config ||= Configuration.new
15
+ end
16
+
17
+ # Configure Elo in a block style.
18
+ # See Elo::Configuration for more details.
19
+ #
20
+ # Elo.configure do |config|
21
+ # config.attribute = :value
22
+ # end
23
+ def self.configure(&block)
24
+ yield(config)
25
+ end
26
+
27
+ end
@@ -0,0 +1,83 @@
1
+ module Elo
2
+
3
+ class Configuration
4
+
5
+ # This is the lower boundry of the rating you need to be a pro player.
6
+ # This setting is used in the FIDE k-factor rules. (default = 2400)
7
+ attr_accessor :pro_rating_boundry
8
+
9
+ # This is the lower boundry in the amount of games played to be a starting player
10
+ # This setting is used in the FIDE k-factor rules. (default = 30)
11
+ attr_accessor :starter_boundry
12
+
13
+ # The default k-factor is chosen when no k-factor rules apply.
14
+ # K-factor rules can be added by using the +k_factor+-method. (default = 15)
15
+ attr_accessor :default_k_factor
16
+
17
+ # This is the rating every player starts out with. (default = 1000)
18
+ attr_accessor :default_rating
19
+
20
+ # Use the settings that FIDE use for determening the K-factor.
21
+ # This is the case when all settings are unaltered. (default = true)
22
+ #
23
+ # In short:
24
+ #
25
+ # * K-factor is 25 when a player is a starter (less than 30 games played)
26
+ # * K-factor is 10 when a player is a pro (rating above 2400, now or in the past)
27
+ # * K-factor is 15 when a player in other cases
28
+ #
29
+ # If you want to use your own settings, either change the boundry settings,
30
+ # or set this setting to false and add you're own k-factor rules.
31
+ # K-factor rules can be added by using the +k_factor+-method.
32
+ attr_accessor :use_FIDE_settings
33
+
34
+ def initialize #:nodoc:
35
+ @pro_rating_boundry = 2400
36
+ @starter_boundry = 30
37
+ @default_rating = 1000
38
+ @default_k_factor = 15
39
+ @use_FIDE_settings = true
40
+ end
41
+
42
+ # Add a K-factor rule. The first argument is the k-factor value.
43
+ # The block should return a boolean that determines if this K-factor rule applies.
44
+ # The first rule that applies is the one determining the K-factor.
45
+ #
46
+ # The block is instance_eval'ed into the player, so you can access all it's
47
+ # properties directly. The K-factor is recalculated every time a match is played.
48
+ #
49
+ # By default, the FIDE settings are used (see: +use_FIDE_settings+). To implement
50
+ # that yourself, you could write:
51
+ #
52
+ # Elo.configure do |config|
53
+ # config.k_factor(10) { pro? or pro_rating? }
54
+ # config.k_factor(25) { starter? }
55
+ # config.default_k_factor = 15
56
+ # end
57
+ #
58
+ def k_factor(factor, &rule)
59
+ k_factors << { :factor => factor, :rule => rule }
60
+ end
61
+
62
+ def applied_k_factors #:nodoc:
63
+ apply_fide_k_factors if use_FIDE_settings
64
+ k_factors
65
+ end
66
+
67
+ private
68
+
69
+ def k_factors
70
+ @k_factors ||= []
71
+ end
72
+
73
+ def apply_fide_k_factors
74
+ unless @applied_fide_k_factors
75
+ k_factor(10) { pro? or pro_rating? }
76
+ k_factor(25) { starter? }
77
+ @applied_fide_k_factors = true
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ end
@@ -0,0 +1,102 @@
1
+ module Elo
2
+
3
+ # A Game is a collection of two Elo::Player objects
4
+ # and a result.
5
+ # Once the result is known, it propagates the new
6
+ # ratings to the players.
7
+ class Game
8
+
9
+ include Helper
10
+
11
+ # The result is the result of the match. It's a nubmer
12
+ # from 0 to 1 from the perspective of player +:one+.
13
+ attr_reader :result
14
+
15
+ # The first Elo::Player. The result is in perspecive of
16
+ # this player.
17
+ attr_reader :one
18
+
19
+ # The second Elo::Player.
20
+ attr_reader :two
21
+
22
+ # Every time a result is set, it tells the Elo::Player
23
+ # objects to update their scores.
24
+ def process_result(result)
25
+ @result = result
26
+ calculate
27
+ end
28
+ alias result= process_result
29
+
30
+ def calculate
31
+ if result
32
+ one.send(:played, self)
33
+ two.send(:played, self)
34
+ save
35
+ end
36
+ self
37
+ end
38
+
39
+ # Player +:one+ has won!
40
+ # This is a shortcut method for setting the score to 1
41
+ def win
42
+ process_result 1.0
43
+ end
44
+
45
+ # Player +:one+ has lost!
46
+ # This is a shortcut method for setting the score to 0
47
+ def lose
48
+ process_result 0.0
49
+ end
50
+
51
+ # It was a draw.
52
+ # This is a shortcut method for setting the score to 0.5
53
+ def draw
54
+ process_result 0.5
55
+ end
56
+
57
+ # You can override this method if you store each game
58
+ # in a database or something like that.
59
+ # This method will be called when a result is known.
60
+ def save
61
+ end
62
+
63
+ # Set the winner. Provide it with a Elo::Player.
64
+ def winner=(player)
65
+ process_result(player == one ? 1.0 : 0.0)
66
+ end
67
+
68
+ # Set the loser. Provide it with a Elo::Player.
69
+ def loser=(player)
70
+ process_result(player == one ? 0.0 : 1.0)
71
+ end
72
+
73
+ # Access the Elo::Rating objects for both players.
74
+ def ratings
75
+ @ratings ||= { one => rating_one, two => rating_two }
76
+ end
77
+
78
+ def inspect
79
+ "game"
80
+ end
81
+
82
+ private
83
+
84
+ # Create an Elo::Rating object for player one
85
+ def rating_one
86
+ Rating.new(:result => result,
87
+ :old_rating => one.rating,
88
+ :other_rating => two.rating,
89
+ :k_factor => one.k_factor)
90
+ end
91
+
92
+ # Create an Elo::Rating object for player two
93
+ def rating_two
94
+ Rating.new(:result => (1.0 - result),
95
+ :old_rating => two.rating,
96
+ :other_rating => one.rating,
97
+ :k_factor => two.k_factor)
98
+ end
99
+
100
+ end
101
+
102
+ end
@@ -0,0 +1,29 @@
1
+ module Elo
2
+
3
+ module Helper
4
+
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ # Every object can be initialized with a hash,
10
+ # almost, but not quite, entirely unlike ActiveRecord.
11
+ def initialize(attributes = {})
12
+ attributes.each do |key, value|
13
+ instance_variable_set("@#{key}", value)
14
+ end
15
+ self.class.all << self
16
+ end
17
+
18
+ module ClassMethods
19
+
20
+ # Provides a list of all instantiated objects of the class.
21
+ def all
22
+ @all ||= []
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,10 @@
1
+ module Elo
2
+ module Model
3
+ # Poor man's activemodel
4
+ def initialize(attributes = {})
5
+ attributes.each do |key, value|
6
+ public_send("#{key}=", value)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,114 @@
1
+ module Elo
2
+
3
+ # A player. You need at least two play a Game.
4
+ class Player
5
+
6
+ include Helper
7
+
8
+ # The rating you provided, or the default rating from configuration
9
+ def rating
10
+ @rating ||= Elo.config.default_rating
11
+ end
12
+
13
+ # The number of games played is needed for calculating the K-factor.
14
+ def games_played
15
+ @games_played ||= games.size
16
+ end
17
+
18
+ # A list of games played by the player.
19
+ def games
20
+ @games ||= []
21
+ end
22
+
23
+ # Is the player considered a pro, because his/her rating crossed
24
+ # the threshold configured? This is needed for calculating the K-factor.
25
+ def pro_rating?
26
+ rating >= Elo.config.pro_rating_boundry
27
+ end
28
+
29
+ # Is the player just starting? Provide the boundry for
30
+ # the amount of games played in the configuration.
31
+ # This is needed for calculating the K-factor.
32
+ def starter?
33
+ games_played < Elo.config.starter_boundry
34
+ end
35
+
36
+ # FIDE regulations specify that once you reach a pro status
37
+ # (see +pro_rating?+), you are considered a pro for life.
38
+ #
39
+ # You might need to specify it manually, when depending on
40
+ # external persistence of players.
41
+ #
42
+ # Elo::Player.new(:pro => true)
43
+ def pro?
44
+ !!@pro
45
+ end
46
+
47
+ # You can override this method if you store each game
48
+ # in a database or something like that.
49
+ # This method will be called when a result is known.
50
+ def save
51
+ end
52
+
53
+ # Calculates the K-factor for the player.
54
+ # Elo allows you specify custom Rules (see Elo::Configuration).
55
+ #
56
+ # You can set it manually, if you wish:
57
+ #
58
+ # Elo::Player.new(:k_factor => 10)
59
+ #
60
+ # This stops this player from using the K-factor rules.
61
+ def k_factor
62
+ return @k_factor if @k_factor
63
+ Elo.config.applied_k_factors.each do |rule|
64
+ return rule[:factor] if instance_eval(&rule[:rule])
65
+ end
66
+ Elo.config.default_k_factor
67
+ end
68
+
69
+ # Start a game with another player. At this point, no
70
+ # result is known and nothing really happens.
71
+ def versus(other_player, options = {})
72
+ Game.new(options.merge(:one => self, :two => other_player)).calculate
73
+ end
74
+
75
+ # Start a game with another player and set the score
76
+ # immediately.
77
+ def wins_from(other_player, options = {})
78
+ versus(other_player, options).win
79
+ end
80
+
81
+ # Start a game with another player and set the score
82
+ # immediately.
83
+ def plays_draw(other_player, options = {})
84
+ versus(other_player, options).draw
85
+ end
86
+
87
+ # Start a game with another player and set the score
88
+ # immediately.
89
+ def loses_from(other_player, options = {})
90
+ versus(other_player, options).lose
91
+ end
92
+
93
+ def inspect
94
+ "player"
95
+ end
96
+
97
+ private
98
+
99
+ # A Game tells the players informed to update their
100
+ # scores, after it knows the result (so it can calculate the rating).
101
+ #
102
+ # This method is private, because it is called automatically.
103
+ # Therefore it is not part of the public API of Elo.
104
+ def played(game)
105
+ @games_played = games_played + 1
106
+ games << game
107
+ @rating = game.ratings[self].new_rating
108
+ @pro = true if pro_rating?
109
+ save
110
+ end
111
+
112
+ end
113
+
114
+ end
@@ -0,0 +1,59 @@
1
+ module Elo
2
+
3
+ # This class calculates the rating between two players,
4
+ # but only from one persons perspective. You need two Rating-instances
5
+ # to calculate ratings for both players. Luckily, Elo::Game handles
6
+ # this for you automatically.
7
+ class Rating
8
+
9
+ include Helper
10
+
11
+ # The rating of the player you DON"T wish to calculate.
12
+ attr_reader :other_rating
13
+
14
+ # The rating of the player you wish to calculate.
15
+ attr_reader :old_rating
16
+
17
+ # The k-factor you wish to use for this calculation.
18
+ attr_reader :k_factor
19
+
20
+ # The new rating is... wait for it... the new rating!
21
+ def new_rating
22
+ old_rating + change.round
23
+ end
24
+
25
+ private
26
+
27
+ # The result of the match. 1 means that the player won, 0 means that the
28
+ # player lost and 0.5 means that it was a draw.
29
+ def result
30
+ raise "Invalid result: #{@result.inspect}" unless valid_result?
31
+ @result.to_f
32
+ end
33
+
34
+ # Only values between 0 and 1 are considered to be valid scores.
35
+ def valid_result?
36
+ (0..1).include? @result
37
+ end
38
+
39
+ # The expected score is the probably outcome of the match, depending
40
+ # on the difference in rating between the two players.
41
+ #
42
+ # For more information visit
43
+ # {Wikipedia}[http://en.wikipedia.org/wiki/Elo_rating_system#Mathematical_details]
44
+ def expected
45
+ 1.0 / ( 1.0 + ( 10.0 ** ((other_rating.to_f - old_rating.to_f) / 400.0) ) )
46
+ end
47
+
48
+ # The change is the points you earn or lose.
49
+ #
50
+ # For more information visit
51
+ # {Wikipedia}[http://en.wikipedia.org/wiki/Elo_rating_system#Mathematical_details]
52
+ def change
53
+ k_factor.to_f * ( result.to_f - expected )
54
+ end
55
+
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,3 @@
1
+ module Elo
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1 @@
1
+ require 'elo'
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elo2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - John Hawthorn
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ description: The Elo rating system is a method for calculating the relative skill
28
+ levels of players in two-player games such as cess and Go.
29
+ email:
30
+ - john.hawthorn@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - lib/elo.rb
36
+ - lib/elo/configuration.rb
37
+ - lib/elo/game.rb
38
+ - lib/elo/helper.rb
39
+ - lib/elo/model.rb
40
+ - lib/elo/player.rb
41
+ - lib/elo/rating.rb
42
+ - lib/elo/version.rb
43
+ - lib/elo2.rb
44
+ homepage: http://github.com/iain/elo
45
+ licenses: []
46
+ metadata: {}
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project:
63
+ rubygems_version: 2.4.5
64
+ signing_key:
65
+ specification_version: 4
66
+ summary: The Elo rating system is a method for calculating the relative skill levels
67
+ of players in two-player games such as cess and Go.
68
+ test_files: []