brackets 0.0.0 → 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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +67 -0
- data/Guardfile +47 -0
- data/brackets.gemspec +17 -0
- data/lib/brackets.rb +8 -0
- data/lib/brackets/match.rb +19 -0
- data/lib/brackets/tournament.rb +76 -0
- data/lib/brackets/util/boolean_counter.rb +13 -0
- data/spec/brackets/tournament_spec.rb +113 -0
- data/spec/brackets/util/boolean_counter_spec.rb +22 -0
- data/spec/spec_helper.rb +7 -0
- metadata +15 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c83d7fafb937ee94ed9ae54cefa98cb2ed830c4
|
4
|
+
data.tar.gz: 990b94f69f4e57cb5ecb43804fefbe7cb1565e1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8187f943dbc8be7e3c96501966e2f506637fa5f1814308224018ea864409758454589cd98d14621a766d2eba4bbca7970c6cc58bb40b5a84873d4a49703b8146
|
7
|
+
data.tar.gz: 53213ef11e8cc68488f95be647d9bd373b6b74e9c1985cbbc93e4b544966a5ebed66ac2a104cd965a99d98afdc41da5e53247adc36a07a3bf894750fbb0063f7
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
brackets (0.0.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
coderay (1.1.0)
|
10
|
+
diff-lcs (1.2.5)
|
11
|
+
ffi (1.9.10)
|
12
|
+
formatador (0.2.5)
|
13
|
+
guard (2.13.0)
|
14
|
+
formatador (>= 0.2.4)
|
15
|
+
listen (>= 2.7, <= 4.0)
|
16
|
+
lumberjack (~> 1.0)
|
17
|
+
nenv (~> 0.1)
|
18
|
+
notiffany (~> 0.0)
|
19
|
+
pry (>= 0.9.12)
|
20
|
+
shellany (~> 0.0)
|
21
|
+
thor (>= 0.18.1)
|
22
|
+
guard-compat (1.2.1)
|
23
|
+
guard-rspec (4.5.0)
|
24
|
+
guard (~> 2.1)
|
25
|
+
guard-compat (~> 1.1)
|
26
|
+
rspec (>= 2.99.0, < 4.0)
|
27
|
+
listen (3.0.4)
|
28
|
+
rb-fsevent (>= 0.9.3)
|
29
|
+
rb-inotify (>= 0.9)
|
30
|
+
lumberjack (1.0.9)
|
31
|
+
method_source (0.8.2)
|
32
|
+
nenv (0.2.0)
|
33
|
+
notiffany (0.0.8)
|
34
|
+
nenv (~> 0.1)
|
35
|
+
shellany (~> 0.0)
|
36
|
+
pry (0.10.3)
|
37
|
+
coderay (~> 1.1.0)
|
38
|
+
method_source (~> 0.8.1)
|
39
|
+
slop (~> 3.4)
|
40
|
+
rb-fsevent (0.9.6)
|
41
|
+
rb-inotify (0.9.5)
|
42
|
+
ffi (>= 0.5.0)
|
43
|
+
rspec (3.3.0)
|
44
|
+
rspec-core (~> 3.3.0)
|
45
|
+
rspec-expectations (~> 3.3.0)
|
46
|
+
rspec-mocks (~> 3.3.0)
|
47
|
+
rspec-core (3.3.2)
|
48
|
+
rspec-support (~> 3.3.0)
|
49
|
+
rspec-expectations (3.3.1)
|
50
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
51
|
+
rspec-support (~> 3.3.0)
|
52
|
+
rspec-mocks (3.3.2)
|
53
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
54
|
+
rspec-support (~> 3.3.0)
|
55
|
+
rspec-support (3.3.0)
|
56
|
+
shellany (0.0.1)
|
57
|
+
slop (3.6.0)
|
58
|
+
thor (0.19.1)
|
59
|
+
|
60
|
+
PLATFORMS
|
61
|
+
ruby
|
62
|
+
|
63
|
+
DEPENDENCIES
|
64
|
+
brackets!
|
65
|
+
guard-rspec
|
66
|
+
pry
|
67
|
+
rspec
|
data/Guardfile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
5
|
+
# directories %w(app lib config test spec features)
|
6
|
+
|
7
|
+
## Uncomment to clear the screen before every task
|
8
|
+
# clearing :on
|
9
|
+
|
10
|
+
## Guard internally checks for changes in the Guardfile and exits.
|
11
|
+
## If you want Guard to automatically start up again, run guard in a
|
12
|
+
## shell loop, e.g.:
|
13
|
+
##
|
14
|
+
## $ while bundle exec guard; do echo "Restarting Guard..."; done
|
15
|
+
##
|
16
|
+
## Note: if you are using the `directories` clause above and you are not
|
17
|
+
## watching the project directory ('.'), then you will want to move
|
18
|
+
## the Guardfile to a watched dir and symlink it back, e.g.
|
19
|
+
#
|
20
|
+
# $ mkdir config
|
21
|
+
# $ mv Guardfile config/
|
22
|
+
# $ ln -s config/Guardfile .
|
23
|
+
#
|
24
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
25
|
+
|
26
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
27
|
+
# rspec may be run, below are examples of the most common uses.
|
28
|
+
# * bundler: 'bundle exec rspec'
|
29
|
+
# * bundler binstubs: 'bin/rspec'
|
30
|
+
# * spring: 'bin/rspec' (This will use spring if running and you have
|
31
|
+
# installed the spring binstubs per the docs)
|
32
|
+
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
33
|
+
# * 'just' rspec: 'rspec'
|
34
|
+
|
35
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
36
|
+
require "guard/rspec/dsl"
|
37
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
38
|
+
|
39
|
+
# RSpec files
|
40
|
+
rspec = dsl.rspec
|
41
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
42
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
43
|
+
watch(rspec.spec_files)
|
44
|
+
|
45
|
+
# Ruby files
|
46
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
47
|
+
end
|
data/brackets.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'brackets'
|
5
|
+
s.version = '0.0.1'
|
6
|
+
s.date = '2015-11-08'
|
7
|
+
s.summary = "A gem to generate tournament brackets"
|
8
|
+
s.description = "A gem to generate tournament brackets"
|
9
|
+
s.authors = ["Vitor HP Bittencourt"]
|
10
|
+
s.email = 'vitorhp2@gmail.com'
|
11
|
+
|
12
|
+
s.files = `git ls-files`.split("\n")
|
13
|
+
s.test_files = `git ls-files -- test/*`.split("\n")
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
s.homepage = 'http://rubygems.org/gems/brackets'
|
16
|
+
s.license = 'MIT'
|
17
|
+
end
|
data/lib/brackets.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Brackets
|
2
|
+
class Match
|
3
|
+
attr_reader :winner, :deph, :number, :red, :blue
|
4
|
+
|
5
|
+
def initialize(deph = 0, number, red, blue)
|
6
|
+
@red, @blue, @deph, @number = red, blue, deph, number
|
7
|
+
|
8
|
+
@winner = blue.nil? ? red : nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def placeholder?
|
12
|
+
@red.nil? && @blue.nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"-"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Brackets
|
2
|
+
class Tournament
|
3
|
+
def initialize(counter = Brackets::Util::BooleanCounter.new)
|
4
|
+
@counter = counter
|
5
|
+
end
|
6
|
+
|
7
|
+
def generate(competitors)
|
8
|
+
generate_rounds(generate_first_round(competitors))
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def generate_first_round(competitors)
|
14
|
+
c = competitors.dup
|
15
|
+
|
16
|
+
if c.size == 1
|
17
|
+
[build_match(1, [c.first, nil])]
|
18
|
+
else
|
19
|
+
placeholder_matches = generate_placeholder_matches(c)
|
20
|
+
exceeding_matches = generate_exceeding_matches(c)
|
21
|
+
normal_matches = c.each_slice(2).map do |slice|
|
22
|
+
build_match(1, slice)
|
23
|
+
end
|
24
|
+
|
25
|
+
placeholder_matches.concat(exceeding_matches).concat(normal_matches)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def generate_rounds(round, deph = 2)
|
30
|
+
if round.size == 1
|
31
|
+
round
|
32
|
+
else
|
33
|
+
matches = round.select{|m| m.deph == deph - 1 }.each_slice(2).map do |slice|
|
34
|
+
build_match(deph, slice)
|
35
|
+
end
|
36
|
+
|
37
|
+
round.concat(generate_rounds(matches, deph + 1))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_match(deph = 0, competitors)
|
42
|
+
red, blue = competitors
|
43
|
+
|
44
|
+
Match.new(deph, @counter.next_if(deph > 0, nil), red, blue)
|
45
|
+
end
|
46
|
+
|
47
|
+
def generate_exceeding_matches(competitors)
|
48
|
+
matches = exceeding_number_of_players_for(competitors.size).times.map do
|
49
|
+
build_match(0, competitors.slice!(0, 2))
|
50
|
+
end
|
51
|
+
|
52
|
+
exceeding_player_matches = matches.map do
|
53
|
+
build_match(1, [competitors.slice!(0)])
|
54
|
+
end
|
55
|
+
|
56
|
+
matches.concat(exceeding_player_matches)
|
57
|
+
end
|
58
|
+
|
59
|
+
def generate_placeholder_matches(competitors)
|
60
|
+
placeholder_matches_count = power_of_two_after(competitors.size) - competitors.size
|
61
|
+
|
62
|
+
placeholder_matches_count.times.map do
|
63
|
+
build_match(0, [nil, nil])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def power_of_two_after(x, pow = 1)
|
68
|
+
2 ** pow >= x ? 2 ** pow : power_of_two_after(x, pow + 1)
|
69
|
+
end
|
70
|
+
|
71
|
+
def exceeding_number_of_players_for(size, pow = 1)
|
72
|
+
2 ** pow > size ? size - (2 ** (pow - 1)) : exceeding_number_of_players_for(size, pow + 1)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Brackets
|
2
|
+
describe Tournament do
|
3
|
+
let(:anakin) { double("anakin") }
|
4
|
+
let(:obiwan) { double("obiwan") }
|
5
|
+
let(:maul) { double("maul") }
|
6
|
+
let(:mace) { double("mace") }
|
7
|
+
let(:yoda) { double("yoda") }
|
8
|
+
let(:shaak) { double("shaak") }
|
9
|
+
let(:kit) { double("kit") }
|
10
|
+
let(:plo) { double("plo") }
|
11
|
+
|
12
|
+
describe "#generate_round" do
|
13
|
+
|
14
|
+
subject { Tournament.new.generate(competitors) }
|
15
|
+
|
16
|
+
let(:competitors) { [anakin, obiwan, maul, mace] }
|
17
|
+
|
18
|
+
it "numbers the matches sequentially" do
|
19
|
+
expect(subject.map(&:number)).to eq([1, 2, 3])
|
20
|
+
end
|
21
|
+
|
22
|
+
context "with one participant" do
|
23
|
+
let(:competitors) { [anakin] }
|
24
|
+
|
25
|
+
it "generates one match with the only participant being the winner" do
|
26
|
+
expect(subject.length).to eq(1)
|
27
|
+
expect(subject.first).to be_a(Match)
|
28
|
+
expect(subject.first.winner).to eq(anakin)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with two competitors" do
|
33
|
+
let(:competitors) { [anakin, obiwan] }
|
34
|
+
|
35
|
+
it "generates one match with no winner" do
|
36
|
+
expect(subject.length).to eq(1)
|
37
|
+
expect(subject.first).to be_a(Match)
|
38
|
+
expect(subject.first.winner).to be(nil)
|
39
|
+
expect(subject.first.red).to be(anakin)
|
40
|
+
expect(subject.first.blue).to be(obiwan)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when number of competitors is a power of two" do
|
45
|
+
let(:competitors) { [yoda, mace, anakin, obiwan] }
|
46
|
+
|
47
|
+
it "generates matches from subsequent rounds" do
|
48
|
+
expect(subject.size).to eq(3)
|
49
|
+
expect(subject.last.red).to be_a(Match)
|
50
|
+
expect(subject.last.blue).to be_a(Match)
|
51
|
+
expect(subject.last.red.red).to be(yoda)
|
52
|
+
expect(subject.last.red.blue).to be(mace)
|
53
|
+
expect(subject.last.blue.red).to be(anakin)
|
54
|
+
expect(subject.last.blue.blue).to be(obiwan)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when number of competitors is not a power of two" do
|
59
|
+
let(:competitors) { [yoda, mace, anakin, obiwan, maul] }
|
60
|
+
|
61
|
+
it "puts the exceeding competitors against winners of the first round" do
|
62
|
+
expect(subject.select{ |m| m.deph == 0 }.size).to eq(4)
|
63
|
+
expect(subject.select{ |m| m.deph == 1 }.size).to eq(2)
|
64
|
+
expect(subject.select{ |m| m.deph == 2 }.size).to eq(1)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# context "with three competitors" do
|
71
|
+
# # TODO: Special case of three competitors
|
72
|
+
# subject { Tournament.new.generate_round([anakin, obiwan, maul], 0, 1) }
|
73
|
+
|
74
|
+
# it "generates three matches" do
|
75
|
+
# expect(subject.length).to eq(3)
|
76
|
+
# end
|
77
|
+
|
78
|
+
# it "has no winners on the first match" do
|
79
|
+
# expect(subject.first.winner).to eq(nil)
|
80
|
+
# end
|
81
|
+
|
82
|
+
# it "has a winner on the second match because there's only one guy" do
|
83
|
+
# expect(subject[1].winner).not_to eq(nil)
|
84
|
+
# end
|
85
|
+
|
86
|
+
# it "generates a final match with one participant from the second match", focus: true do
|
87
|
+
# expect(subject.last.red).to eq(nil)
|
88
|
+
# expect(subject.last.blue).not_to eq(nil)
|
89
|
+
# end
|
90
|
+
|
91
|
+
# it "sets deph of match accordingly" do
|
92
|
+
# expect(subject.first.deph).to eq(0)
|
93
|
+
# expect(subject[1].deph).to eq(0)
|
94
|
+
# expect(subject.last.deph).to eq(1)
|
95
|
+
# end
|
96
|
+
|
97
|
+
# it "numbers the matches sequentially" do
|
98
|
+
# expect(subject.first.number).to eq(1)
|
99
|
+
# expect(subject[1].number).to eq(2)
|
100
|
+
# expect(subject.last.number).to eq(3)
|
101
|
+
# end
|
102
|
+
# end
|
103
|
+
|
104
|
+
# context "when number of competitors is not a power of two" do
|
105
|
+
# subject { Tournament.new.generate_round([yoda, mace, anakin, obiwan, maul], 1, 1) }
|
106
|
+
|
107
|
+
# it "moves the remaining competitors to the second round" do
|
108
|
+
# expect(subject.size).to eq(4)
|
109
|
+
# end
|
110
|
+
# end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Brackets::Util
|
2
|
+
describe BooleanCounter do
|
3
|
+
describe "#next_if" do
|
4
|
+
it "advances the counter when the param is true" do
|
5
|
+
expect(subject.next_if(true)).to eq(1)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "keeps advancing if called multiple times" do
|
9
|
+
subject.next_if(true)
|
10
|
+
expect(subject.next_if(true)).to eq(2)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "noes not advance the value when the param evals to false" do
|
14
|
+
expect(subject.next_if(false)).to eq(0)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns the given value when param evals to false" do
|
18
|
+
expect(subject.next_if(false, "Nothing")).to eq("Nothing")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brackets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vitor HP Bittencourt
|
@@ -15,7 +15,20 @@ email: vitorhp2@gmail.com
|
|
15
15
|
executables: []
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
18
|
-
files:
|
18
|
+
files:
|
19
|
+
- ".gitignore"
|
20
|
+
- ".rspec"
|
21
|
+
- Gemfile
|
22
|
+
- Gemfile.lock
|
23
|
+
- Guardfile
|
24
|
+
- brackets.gemspec
|
25
|
+
- lib/brackets.rb
|
26
|
+
- lib/brackets/match.rb
|
27
|
+
- lib/brackets/tournament.rb
|
28
|
+
- lib/brackets/util/boolean_counter.rb
|
29
|
+
- spec/brackets/tournament_spec.rb
|
30
|
+
- spec/brackets/util/boolean_counter_spec.rb
|
31
|
+
- spec/spec_helper.rb
|
19
32
|
homepage: http://rubygems.org/gems/brackets
|
20
33
|
licenses:
|
21
34
|
- MIT
|