acts_as_elo 0.1.0 → 0.2.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 +6 -7
- data/acts_as_elo.gemspec +2 -2
- data/lib/acts_as_elo/acts/elo.rb +34 -18
- data/test/advance_test.rb +10 -11
- metadata +7 -7
data/README.md
CHANGED
@@ -2,17 +2,18 @@
|
|
2
2
|
|
3
3
|
### What is it?
|
4
4
|
|
5
|
-
Provides sophisticated yet easy to understand ranking system with minimum changes to the system.
|
6
|
-
Elo ranking system is heavily used in tournaments, player rankings in chess, sports, leader boards, multiplayer games, ranking of test questions, tasks etc.
|
5
|
+
Provides sophisticated yet easy to understand ranking system with minimum changes to the system.
|
6
|
+
Elo ranking system is heavily used in tournaments, player rankings in chess, sports, leader boards, multiplayer games, ranking of test questions, tasks etc.
|
7
7
|
|
8
8
|
Read more about it on [wiki](http://en.wikipedia.org/wiki/Elo_rating_system)
|
9
9
|
|
10
10
|
### Usage
|
11
|
-
|
11
|
+
|
12
12
|
`acts_as_elo` is very easy to use
|
13
13
|
|
14
14
|
1. Install: `gem install acts_as_elo`
|
15
|
-
2. Add `include Acts::Elo` and `acts_as_elo`
|
15
|
+
2. Add `include Acts::Elo` and `acts_as_elo`
|
16
|
+
3. Call any of the 3 methods: `elo_win!`, `elo_lose!` and `elo_draw!`
|
16
17
|
|
17
18
|
### Example
|
18
19
|
|
@@ -30,6 +31,4 @@ jack.elo_rank # => 1200
|
|
30
31
|
bob.elo_win!(jack)
|
31
32
|
bob.elo_rank # => 1205
|
32
33
|
jack.elo_rank # => 1995
|
33
|
-
```
|
34
|
-
|
35
|
-
That's it. No additional classes are involved.
|
34
|
+
```
|
data/acts_as_elo.gemspec
CHANGED
@@ -2,12 +2,12 @@
|
|
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.
|
5
|
+
s.version = '0.2.0'
|
6
6
|
s.platform = Gem::Platform::RUBY
|
7
7
|
s.authors = ['tjbladez']
|
8
8
|
s.email = ['nick@tjbladez.net']
|
9
9
|
s.homepage = 'http://github.com/tjbladez/acts_as_elo'
|
10
|
-
s.summary = %q{
|
10
|
+
s.summary = %q{Sophisticated ranking made easy}
|
11
11
|
s.description = %q{Provides sophisticated yet easy to understand ranking system with minimum changes to the system}
|
12
12
|
|
13
13
|
# Load Paths...
|
data/lib/acts_as_elo/acts/elo.rb
CHANGED
@@ -3,10 +3,15 @@ module Acts
|
|
3
3
|
def self.included(base)
|
4
4
|
base.extend(ClassMethods)
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
7
|
module ClassMethods
|
8
|
+
# `acts_as_elo` hooks into your object to provide you with the ability to
|
9
|
+
# set and get `elo_rank` attribute
|
10
|
+
# Available options are:
|
11
|
+
# * default_rank - change the starting rank
|
12
|
+
# * one_way - limits update of the rank to only self
|
8
13
|
def acts_as_elo(opts = {})
|
9
|
-
default_rank = opts[:default_rank] || 1200
|
14
|
+
default_rank = opts[:default_rank] || 1200
|
10
15
|
|
11
16
|
unless opts.empty?
|
12
17
|
class << self
|
@@ -15,42 +20,53 @@ module Acts
|
|
15
20
|
@acts_as_elo_options = opts
|
16
21
|
end
|
17
22
|
|
18
|
-
class_eval do
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
+
class_eval do
|
24
|
+
if Object::const_defined?("ActiveRecord") && self.ancestors.include?(ActiveRecord::Base)
|
25
|
+
|
26
|
+
define_method(:elo_rank) do
|
27
|
+
self[:elo_rank] ||= default_rank
|
28
|
+
end
|
29
|
+
|
30
|
+
else
|
31
|
+
|
32
|
+
attr_writer :elo_rank
|
33
|
+
define_method(:elo_rank) do
|
34
|
+
@elo_rank ||= default_rank
|
35
|
+
end
|
36
|
+
|
23
37
|
end
|
24
38
|
end
|
25
39
|
|
26
|
-
include Acts::Elo::InstanceMethods unless self.included_modules.include?(Acts::Elo::InstanceMethods)
|
40
|
+
include Acts::Elo::InstanceMethods unless self.included_modules.include?(Acts::Elo::InstanceMethods)
|
27
41
|
end
|
28
|
-
end
|
29
|
-
|
42
|
+
end
|
43
|
+
|
30
44
|
module InstanceMethods
|
31
45
|
def elo_win!(opponent, opts={})
|
32
46
|
elo_update(opponent, opts.merge!(:result => :win))
|
33
47
|
end
|
34
|
-
|
48
|
+
|
35
49
|
def elo_lose!(opponent, opts={})
|
36
50
|
elo_update(opponent, opts.merge!(:result => :lose))
|
37
51
|
end
|
38
|
-
|
52
|
+
|
39
53
|
def elo_draw!(opponent, opts={})
|
40
54
|
elo_update(opponent, opts.merge!(:result => :draw))
|
41
55
|
end
|
42
|
-
|
56
|
+
|
43
57
|
def elo_update(opponent, opts={})
|
44
58
|
begin
|
45
59
|
if self.class.respond_to?(:acts_as_elo_options) && self.class.acts_as_elo_options[:one_way]
|
46
60
|
one_way = true
|
47
61
|
end
|
48
62
|
one_way ||= opts[:one_way]
|
63
|
+
send_opts = {one_way: true}
|
64
|
+
|
65
|
+
# Formula from: http://en.wikipedia.org/wiki/Elo_rating_system
|
49
66
|
diff = (opponent.elo_rank.to_f - elo_rank.to_f).abs
|
50
67
|
expected = 1 / (1 + 10 ** (diff / 400))
|
51
|
-
send_opts = {one_way: true}
|
52
68
|
|
53
|
-
if opts[:result] == :win
|
69
|
+
if opts[:result] == :win
|
54
70
|
points = 1
|
55
71
|
send_opts.merge!(result: :lose)
|
56
72
|
elsif opts[:result] == :lose
|
@@ -60,14 +76,14 @@ module Acts
|
|
60
76
|
points = 0.5
|
61
77
|
send_opts.merge!(result: :draw)
|
62
78
|
end
|
63
|
-
|
79
|
+
|
64
80
|
opponent.elo_update(self, send_opts) unless one_way
|
65
81
|
|
66
|
-
|
82
|
+
self.elo_rank = (elo_rank + 10*(points-expected)).round
|
67
83
|
rescue Exception => e
|
68
84
|
puts "Exception: #{e.message}"
|
69
85
|
end
|
70
86
|
end
|
71
|
-
end
|
87
|
+
end
|
72
88
|
end
|
73
89
|
end
|
data/test/advance_test.rb
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
require 'pathname'
|
2
2
|
require Pathname.new('.') + 'helper'
|
3
3
|
|
4
|
-
# When user answers the question based on the on current rank of the user
|
4
|
+
# When user answers the question based on the on current rank of the user
|
5
5
|
# and current rank of the question both user and question ranks will be updated
|
6
6
|
class User
|
7
7
|
include Acts::Elo
|
8
|
-
|
8
|
+
|
9
9
|
attr_accessor :questions
|
10
|
-
|
11
|
-
acts_as_elo :one_way => true
|
10
|
+
acts_as_elo
|
12
11
|
end
|
13
12
|
|
14
13
|
class Question
|
15
14
|
include Acts::Elo
|
16
|
-
|
15
|
+
|
17
16
|
attr_accessor :user
|
18
17
|
acts_as_elo
|
19
18
|
end
|
@@ -21,25 +20,25 @@ end
|
|
21
20
|
|
22
21
|
context "User with many questions" do
|
23
22
|
helper(:question) { |user| Question.new.tap {|q| q.user = user} }
|
24
|
-
|
23
|
+
|
25
24
|
setup { User.new }
|
26
25
|
hookup { topic.questions = [question(topic), question(topic)] }
|
27
|
-
|
26
|
+
|
28
27
|
asserts(:elo_rank).equals(1200)
|
29
28
|
asserts("questions have default ranks"){ topic.questions.map(&:elo_rank)}.equals([1200, 1200])
|
30
|
-
|
29
|
+
|
31
30
|
context "when question is answered correctly" do
|
32
31
|
hookup { topic.questions.each {|q| q.elo_rank = 1200 }}
|
33
32
|
hookup { topic.questions.first.elo_lose!(topic)}
|
34
|
-
|
33
|
+
|
35
34
|
asserts(:elo_rank).equals(1205)
|
36
35
|
asserts("questions have their ranks updated"){ topic.questions.map(&:elo_rank)}.equals([1195, 1200])
|
37
36
|
end
|
38
|
-
|
37
|
+
|
39
38
|
context "when question is answered incorrectly" do
|
40
39
|
hookup { topic.questions.each {|q| q.elo_rank = 1200 }}
|
41
40
|
hookup { topic.questions.first.elo_win!(topic) }
|
42
|
-
|
41
|
+
|
43
42
|
asserts(:elo_rank).equals(1195)
|
44
43
|
asserts("questions have their ranks updated"){ topic.questions.map(&:elo_rank)}.equals([1205, 1200])
|
45
44
|
end
|
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: 0.2.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-
|
12
|
+
date: 2012-03-09 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
16
|
-
requirement: &
|
16
|
+
requirement: &70327763632440 !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: *70327763632440
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: riot
|
27
|
-
requirement: &
|
27
|
+
requirement: &70327763631380 !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: *70327763631380
|
36
36
|
description: Provides sophisticated yet easy to understand ranking system with minimum
|
37
37
|
changes to the system
|
38
38
|
email:
|
@@ -75,7 +75,7 @@ rubyforge_project:
|
|
75
75
|
rubygems_version: 1.8.10
|
76
76
|
signing_key:
|
77
77
|
specification_version: 3
|
78
|
-
summary:
|
78
|
+
summary: Sophisticated ranking made easy
|
79
79
|
test_files:
|
80
80
|
- test/advance_test.rb
|
81
81
|
- test/basic_test.rb
|