acts_as_elo 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -29,6 +29,6 @@ bob.elo_rank # => 1200
29
29
  jack.elo_rank # => 1200
30
30
 
31
31
  bob.elo_win!(jack)
32
- bob.elo_rank # => 1205
33
- jack.elo_rank # => 1995
32
+ bob.elo_rank # => 1215
33
+ jack.elo_rank # => 1985
34
34
  ```
@@ -2,7 +2,7 @@
2
2
  $:.push File.expand_path('../lib', __FILE__)
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'acts_as_elo'
5
- s.version = '0.2.0'
5
+ s.version = '1.0.0'
6
6
  s.platform = Gem::Platform::RUBY
7
7
  s.authors = ['tjbladez']
8
8
  s.email = ['nick@tjbladez.net']
@@ -10,8 +10,16 @@ module Acts
10
10
  # Available options are:
11
11
  # * default_rank - change the starting rank
12
12
  # * one_way - limits update of the rank to only self
13
+ # * proficiency_map - hash that has two keys
14
+ # * rank_limits - array of two elements, ranks that limit categories of
15
+ # player proficiency. Between novice and intermediate; intermediate and pro.
16
+ # Defaults: 1299, 2399
17
+ # * coefficients - proficiency coefficient for each category.
18
+ # Defaults: 30 for novice, 15 for intermediate, 10 for a pro
13
19
  def acts_as_elo(opts = {})
14
- default_rank = opts[:default_rank] || 1200
20
+ default_rank = opts[:default_rank] || 1200
21
+ proficiency_map = opts[:proficiency_map] || {:coefficients => [30, 15, 10],
22
+ :rank_limits => [1299, 2399] }
15
23
 
16
24
  unless opts.empty?
17
25
  class << self
@@ -33,7 +41,10 @@ module Acts
33
41
  define_method(:elo_rank) do
34
42
  @elo_rank ||= default_rank
35
43
  end
44
+ end
36
45
 
46
+ define_method(:elo_proficiency_map) do
47
+ proficiency_map
37
48
  end
38
49
  end
39
50
 
@@ -63,8 +74,17 @@ module Acts
63
74
  send_opts = {one_way: true}
64
75
 
65
76
  # Formula from: http://en.wikipedia.org/wiki/Elo_rating_system
66
- diff = (opponent.elo_rank.to_f - elo_rank.to_f).abs
67
- expected = 1 / (1 + 10 ** (diff / 400))
77
+ diff = opponent.elo_rank.to_f - elo_rank.to_f
78
+ expected = 1 / (1 + 10 ** (diff / 400))
79
+ coefficient = elo_proficiency_map[:coefficients][1]
80
+
81
+ if elo_rank < elo_proficiency_map[:rank_limits].first
82
+ coefficient = elo_proficiency_map[:coefficients].first
83
+ end
84
+
85
+ if elo_rank > elo_proficiency_map[:rank_limits].last
86
+ coefficient = elo_proficiency_map[:coefficients].last
87
+ end
68
88
 
69
89
  if opts[:result] == :win
70
90
  points = 1
@@ -79,7 +99,7 @@ module Acts
79
99
 
80
100
  opponent.elo_update(self, send_opts) unless one_way
81
101
 
82
- self.elo_rank = (elo_rank + 10*(points-expected)).round
102
+ self.elo_rank = (elo_rank + coefficient*(points-expected)).round
83
103
  rescue Exception => e
84
104
  puts "Exception: #{e.message}"
85
105
  end
@@ -31,15 +31,55 @@ context "User with many questions" do
31
31
  hookup { topic.questions.each {|q| q.elo_rank = 1200 }}
32
32
  hookup { topic.questions.first.elo_lose!(topic)}
33
33
 
34
- asserts(:elo_rank).equals(1205)
35
- asserts("questions have their ranks updated"){ topic.questions.map(&:elo_rank)}.equals([1195, 1200])
34
+ asserts(:elo_rank).equals(1215)
35
+ asserts("questions have their ranks updated"){ topic.questions.map(&:elo_rank)}.equals([1185, 1200])
36
36
  end
37
37
 
38
38
  context "when question is answered incorrectly" do
39
39
  hookup { topic.questions.each {|q| q.elo_rank = 1200 }}
40
40
  hookup { topic.questions.first.elo_win!(topic) }
41
41
 
42
- asserts(:elo_rank).equals(1195)
43
- asserts("questions have their ranks updated"){ topic.questions.map(&:elo_rank)}.equals([1205, 1200])
42
+ asserts(:elo_rank).equals(1185)
43
+ asserts("questions have their ranks updated"){ topic.questions.map(&:elo_rank)}.equals([1215, 1200])
44
44
  end
45
- end
45
+ end
46
+
47
+ class ProfessionalPlayer
48
+ include Acts::Elo
49
+ acts_as_elo :default_rank => 2400
50
+ end
51
+
52
+ class IntermediatePlayer
53
+ include Acts::Elo
54
+ acts_as_elo :default_rank => 2000
55
+ end
56
+
57
+ context "Professional playing against the intermediate player" do
58
+ setup { [ProfessionalPlayer.new, IntermediatePlayer.new] }
59
+
60
+ asserts("default ranks are 2500 and 1200") {
61
+ topic.map(&:elo_rank)
62
+ }.equals([2400, 2000])
63
+
64
+ context "when professional wins" do
65
+ hookup {topic.first.elo_rank = 2400}
66
+ hookup {topic.last.elo_rank = 2000}
67
+
68
+ hookup {topic.first.elo_win!(topic.last)}
69
+
70
+ asserts("professional is barely rewarded") {topic.first.elo_rank}.equals(2401)
71
+ asserts("intermediate barely loses rank") {topic.last.elo_rank}.equals(1999)
72
+ end
73
+ context "when intermediate player wins" do
74
+ hookup {topic.first.elo_rank = 2400}
75
+ hookup {topic.last.elo_rank = 2000}
76
+
77
+ hookup {topic.last.elo_win!(topic.first)}
78
+
79
+ asserts("professional loses some rank") {topic.first.elo_rank}.equals(2391)
80
+ asserts("intermediate rewarded greatly") {topic.last.elo_rank}.equals(2014)
81
+ end
82
+ end
83
+
84
+
85
+
@@ -3,14 +3,14 @@ require Pathname.new('.') + 'helper'
3
3
 
4
4
  class Player
5
5
  include Acts::Elo
6
-
6
+
7
7
  acts_as_elo
8
8
  end
9
9
 
10
10
 
11
11
  context "Two players are opponents of each other" do
12
12
  setup { [Player.new, Player.new] }
13
-
13
+
14
14
  asserts("default ranks are 1200") {
15
15
  topic.map(&:elo_rank)
16
16
  }.equals([1200, 1200])
@@ -18,21 +18,21 @@ context "Two players are opponents of each other" do
18
18
  context "when first one wins" do
19
19
  hookup {topic.each {|pl| pl.elo_rank = 1200 }}
20
20
  hookup {topic.first.elo_win!(topic.last)}
21
-
22
- asserts("ranks are updated") {topic.map(&:elo_rank)}.equals([1205, 1195])
21
+
22
+ asserts("ranks are updated") {topic.map(&:elo_rank)}.equals([1215, 1185])
23
23
  end
24
24
 
25
25
  context "when first one loses" do
26
- hookup {topic.each {|pl| pl.elo_rank = 1200 }}
26
+ hookup {topic.each {|pl| pl.elo_rank = 1200 }}
27
27
  hookup {topic.first.elo_lose!(topic.last)}
28
-
29
- asserts("ranks are updated") {topic.map(&:elo_rank)}.equals([1195, 1205])
28
+
29
+ asserts("ranks are updated") {topic.map(&:elo_rank)}.equals([1185, 1215])
30
30
  end
31
31
 
32
32
  context "when they draw" do
33
- hookup {topic.each {|pl| pl.elo_rank = 1200 }}
33
+ hookup {topic.each {|pl| pl.elo_rank = 1200 }}
34
34
  hookup {topic.first.elo_draw!(topic.last)}
35
-
35
+
36
36
  asserts("ranks are updated") {topic.map(&:elo_rank)}.equals([1200, 1200])
37
37
  end
38
38
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_elo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-09 00:00:00.000000000Z
12
+ date: 2012-03-12 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
- requirement: &70327763632440 !ruby/object:Gem::Requirement
16
+ requirement: &70227977617200 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.0.0
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70327763632440
24
+ version_requirements: *70227977617200
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: riot
27
- requirement: &70327763631380 !ruby/object:Gem::Requirement
27
+ requirement: &70227977616580 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70327763631380
35
+ version_requirements: *70227977616580
36
36
  description: Provides sophisticated yet easy to understand ranking system with minimum
37
37
  changes to the system
38
38
  email: