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 +2 -2
- data/acts_as_elo.gemspec +1 -1
- data/lib/acts_as_elo/acts/elo.rb +24 -4
- data/test/advance_test.rb +45 -5
- data/test/basic_test.rb +9 -9
- metadata +6 -6
data/README.md
CHANGED
data/acts_as_elo.gemspec
CHANGED
data/lib/acts_as_elo/acts/elo.rb
CHANGED
@@ -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
|
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
|
67
|
-
expected
|
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 +
|
102
|
+
self.elo_rank = (elo_rank + coefficient*(points-expected)).round
|
83
103
|
rescue Exception => e
|
84
104
|
puts "Exception: #{e.message}"
|
85
105
|
end
|
data/test/advance_test.rb
CHANGED
@@ -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(
|
35
|
-
asserts("questions have their ranks updated"){ topic.questions.map(&:elo_rank)}.equals([
|
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(
|
43
|
-
asserts("questions have their ranks updated"){ topic.questions.map(&:elo_rank)}.equals([
|
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
|
+
|
data/test/basic_test.rb
CHANGED
@@ -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([
|
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([
|
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.
|
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-
|
12
|
+
date: 2012-03-12 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
16
|
-
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: *
|
24
|
+
version_requirements: *70227977617200
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: riot
|
27
|
-
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: *
|
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:
|