acts_as_elo 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: