seed_list 0.0.1

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/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: []