seed_list 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 Agora Games
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # SeedList
2
+ *Seed management for tournament brackets*
3
+
4
+ ## Overview
5
+
6
+ SeedList is designed for Rails-powered tournament engines that need to persist
7
+ a 1-indexed ordered list of players (ranked low-to-high by skill or past performance)
8
+ and then match them up appropriately in the first round of a bracket.
9
+
10
+ Players are then matched up according to a strategy specified on a per-instance basis.
11
+
12
+ See also: https://github.com/agoragames/bracket_tree
13
+
14
+ ## Example
15
+
16
+ ```ruby
17
+
18
+ class Tournament < ActiveRecord::Base
19
+ has_many :players
20
+ seed :players
21
+ end
22
+
23
+ class Player < ActiveRecord::Base
24
+ belongs_to :tournament
25
+ end
26
+ ```
27
+
28
+ ```ruby
29
+
30
+ add_column :tournaments, :players_seed_list, :text
31
+
32
+ ```
33
+
34
+
35
+ ```ruby
36
+
37
+ t = Tournament.create
38
+ => #<Tournament id: 2, players_seed_list: #<SeedList::List:0x00000002aeff68 @list=[]>>
39
+
40
+ p = t.players.create
41
+ => #<Player id: 16, tournament_id: 2>
42
+
43
+ t.reload
44
+ => #<Tournament id: 2, players_seed_list: #<SeedList::List:0x00000002d342d8 @list=[16]>>
45
+
46
+ # Seed numbers start at 1
47
+ p.seed
48
+ => 1
49
+
50
+ ```
51
+
52
+ When a player is created, the `id` is pushed to the list in the highest (worst-place) seed
53
+ position. You can then move the seed to another position in the list.
54
+
55
+ ```ruby
56
+
57
+ 3.times { t.players.create }
58
+
59
+ p.seed = 4
60
+
61
+ t.reload
62
+ => #<Tournament id: 2, players_seed_list: #<SeedList::List:0x00000002d342d8 @list=[17, 18, 19, 16]>>
63
+
64
+ ```
65
+
66
+ ## Strategies
67
+
68
+ Once your players have been created and moved to the appropriate seed positions, you can use
69
+ the included seeding strategies to match them up appropriately in the first round of the bracket.
70
+
71
+ You can easily implement your own strategies as well. The initializer must accept an array
72
+ of objects that respond to #seed with an integer, and the #seed method must return an array
73
+ of those objects sorted appropriately as pairs.
74
+
75
+ ```ruby
76
+
77
+ t.players.map { |p| p.seed }
78
+ => [1, 2, 3 , 4]
79
+
80
+ # A Knockout tournament matches players at random. The seed position is irrelevant.
81
+ SeedList::Strategy::Knockout.new(t.players).seed.map { |p| p.seed }
82
+ => [2, 3, 4, 1]
83
+
84
+ # A Playoff tournament matches the best players against the worst.
85
+ SeedList::Strategy::Playoff.new(t.players).seed.map { |p| p.seed }
86
+ => [1, 4, 2, 3]
87
+
88
+ # An Amateur tournament matches by skill similarity straight down
89
+ SeedList::Strategy::Playoff.new(t.players).seed.map { |p| p.seed }
90
+ => [1, 2, 3, 4]
91
+
92
+ ```
93
+ ## License
94
+
95
+ See the [MIT-LICENSE](https://github.com/agoragames/seed_list/blob/master/MIT-LICENSE) file.
96
+
97
+ ## Contributions
98
+
99
+ Contributions are awesome. Feature branch pull requests are the preferred method.
100
+
101
+ ## Author
102
+
103
+ Written by [Logan Koester](https://github.com/logankoester)
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'SeedList'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
@@ -0,0 +1,36 @@
1
+ module SeedList
2
+ class List
3
+ def initialize(*seeds)
4
+ @list = Array.new(seeds)
5
+ end
6
+
7
+ def move(s, i)
8
+ i -= 1
9
+ index = @list.index s
10
+ @list.delete_at index if index < i
11
+ @list.insert(i, s).uniq!
12
+ self
13
+ end
14
+
15
+ def unshift(s)
16
+ @list.unshift(s).uniq!
17
+ self
18
+ end
19
+
20
+ def push(s)
21
+ @list.push(s).uniq!
22
+ self
23
+ end
24
+
25
+ def delete(s)
26
+ @list.delete_if { |e| e == s }
27
+ self
28
+ end
29
+
30
+ def find(s)
31
+ i = @list.index(s)
32
+ i.nil? ? nil : i + 1
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ module SeedList
2
+ module Model
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def seed(assoc_name)
7
+ assoc_name = assoc_name.to_s
8
+
9
+ eval "serialize :#{assoc_name}_seed_list, SeedList::List"
10
+
11
+ assoc_name.classify.constantize.class_eval <<-CODE
12
+ after_create do |p|
13
+ p.#{self.name.downcase}.#{assoc_name}_seed_list.push(p.id)
14
+ p.#{self.name.downcase}.save
15
+ end
16
+
17
+ after_destroy do |p|
18
+ p.#{self.name.downcase}.#{assoc_name}_seed_list.delete(p.id)
19
+ p.#{self.name.downcase}.save
20
+ end
21
+
22
+ def seed
23
+ #{self.name.downcase}.#{assoc_name}_seed_list.find(id)
24
+ end
25
+
26
+ def seed=(n)
27
+ #{self.name.downcase}.#{assoc_name}_seed_list.move(id, n)
28
+ #{self.name.downcase}.save
29
+ end
30
+ CODE
31
+
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+
38
+ ActiveRecord::Base.send :include, SeedList::Model
@@ -0,0 +1,59 @@
1
+ # Strategy classes are responsible for matching up players against each other
2
+ # in the first round of a bracket. A strategy is chosen for each tournament by the host.
3
+ #
4
+ # Player objects have a numeric property #seed, which is set at creation
5
+ # and may be reordered by the host. These positions are ranked by skill from
6
+ # best (1) to worst (max).
7
+ #
8
+ # When the Bracket is generated, the players are sorted in accordance with the
9
+ # chosen strategy logic.
10
+ module SeedList
11
+ module Strategy
12
+ class Base
13
+ attr_accessor :players
14
+ def initialize(players); @players = players; end
15
+ def seed; raise 'Abstract method called'; end
16
+ end
17
+
18
+ # Players matched against each other at random. A player's seed position is
19
+ # completely irrelevant.
20
+ class Knockout < Base
21
+ def seed
22
+ @players.shuffle
23
+ end
24
+ end
25
+
26
+ # Best matched against worst, second best against second worst, and so on.
27
+ # Optimized for serious players and viewer entertainment.
28
+ class Playoff < Base
29
+ def seed
30
+ input, output = @players.clone, []
31
+ input.size.times { |i| output << (i.even? ? input.shift : input.pop) }
32
+ output
33
+ end
34
+ end
35
+
36
+ # TODO This strategy is implemented incorrectly, with an associated pending test.
37
+ # Best matched against worst, second best against second worst, and so on.
38
+ # Ensures that if the higher seed wins, he will always face someone from the
39
+ # lower half in the next round.
40
+ class MLGPlayoff < Base
41
+ def seed
42
+ input, sequence, pairs, output = @players.clone, [], [], []
43
+ input.size.times { |i| sequence << (i.even? ? input.shift : input.pop) }
44
+ loop { pairs << sequence.shift(2); break if sequence.empty? }
45
+ pairs.size.times { |i| output << (i.even? ? pairs.shift : pairs.pop) }
46
+ output.flatten
47
+ end
48
+ end
49
+
50
+ # Matched by similar skill straight through; best on the top, worst on the bottom.
51
+ # Optimized for friendly tournaments with diversely skilled players (to prevent casual
52
+ # players from being knocked out right away).
53
+ class Amateur < Base
54
+ def seed
55
+ @players.sort { |a,b| a.seed <=> b.seed }
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,3 @@
1
+ module SeedList
2
+ VERSION = "0.0.1"
3
+ end
data/lib/seed_list.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'seed_list/version'
2
+ require 'seed_list/list'
3
+ require 'seed_list/model'
4
+ require 'seed_list/strategy'
5
+
6
+ module SeedList
7
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :seed_list do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seed_list
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Logan Koester
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: &6890660 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.6
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *6890660
25
+ - !ruby/object:Gem::Dependency
26
+ name: sqlite3
27
+ requirement: &6889020 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *6889020
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec-rails
38
+ requirement: &6887580 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *6887580
47
+ - !ruby/object:Gem::Dependency
48
+ name: capybara
49
+ requirement: &7428560 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *7428560
58
+ - !ruby/object:Gem::Dependency
59
+ name: guard-rspec
60
+ requirement: &7427160 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *7427160
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-spork
71
+ requirement: &7426500 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *7426500
80
+ - !ruby/object:Gem::Dependency
81
+ name: factory_girl_rails
82
+ requirement: &7425200 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *7425200
91
+ - !ruby/object:Gem::Dependency
92
+ name: pry-rails
93
+ requirement: &7423820 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *7423820
102
+ description: SeedList is designed for Rails-powered tournament engines that need to
103
+ persist a 1-indexed ordered list of players (ranked low-to-high by skill or past
104
+ performance) and then match them up appropriately in the first round of a bracket.
105
+ email:
106
+ - lkoester@majorleaguegaming.com
107
+ executables: []
108
+ extensions: []
109
+ extra_rdoc_files: []
110
+ files:
111
+ - lib/seed_list/strategy.rb
112
+ - lib/seed_list/list.rb
113
+ - lib/seed_list/version.rb
114
+ - lib/seed_list/model.rb
115
+ - lib/tasks/seed_list_tasks.rake
116
+ - lib/seed_list.rb
117
+ - MIT-LICENSE
118
+ - Rakefile
119
+ - README.md
120
+ homepage: https://github.com/agoragames/seed_list
121
+ licenses: []
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ segments:
133
+ - 0
134
+ hash: 1687580428413640907
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ! '>='
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ segments:
142
+ - 0
143
+ hash: 1687580428413640907
144
+ requirements: []
145
+ rubyforge_project:
146
+ rubygems_version: 1.8.17
147
+ signing_key:
148
+ specification_version: 3
149
+ summary: Seed management for tournament brackets
150
+ test_files: []