tournament-system 0.1.1 → 0.1.2
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/README.md +5 -8
- data/lib/tournament/driver.rb +8 -5
- data/lib/tournament/seeder/single_bracket.rb +23 -8
- data/lib/tournament/single_elimination.rb +27 -8
- data/lib/tournament/swiss/common.rb +1 -1
- data/lib/tournament/swiss/dutch.rb +1 -0
- data/lib/tournament/version.rb +1 -1
- data/tournament-system.gemspec +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e2feaf11e43d4582382ab6702fee535a796e00c
|
4
|
+
data.tar.gz: 79c8750797f63e42658afcbbc05b240308801209
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11128da929528638694f487a17aa28baa25fc4dd090ea88b7a378553f3894ffcd8c3c8c4c30f30cff2388dbf6d71872e74532e4ecf6c1e891051ac280483f1de
|
7
|
+
data.tar.gz: 8991877ed078ae29d705d630fb8fad9a828f52264b6546109ff74fbf6e460fce6599516318a13598177251ded7c0bf3e895aa729046b7985e6df66586a8884b9
|
data/README.md
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
[](https://travis-ci.org/ozfortress/tournament-system)
|
4
4
|
[](https://coveralls.io/github/ozfortress/tournament-system?branch=master)
|
5
5
|
[](https://badge.fury.io/rb/tournament-system)
|
6
|
+
[](http://www.rubydoc.info/github/ozfortress/tournament-system/master)
|
6
7
|
|
7
8
|
This is a simple gem that implements numerous tournament systems.
|
8
9
|
|
@@ -39,10 +40,6 @@ class Driver < Tournament::Driver
|
|
39
40
|
...
|
40
41
|
end
|
41
42
|
|
42
|
-
def matches_for_round(round)
|
43
|
-
...
|
44
|
-
end
|
45
|
-
|
46
43
|
def seeded_teams
|
47
44
|
...
|
48
45
|
end
|
@@ -75,14 +72,14 @@ instance:
|
|
75
72
|
```ruby
|
76
73
|
driver = Driver.new
|
77
74
|
|
78
|
-
# Generate
|
79
|
-
Tournament::SingleElimination.generate driver
|
75
|
+
# Generate a round of a single elimination tournament
|
76
|
+
Tournament::SingleElimination.generate driver
|
80
77
|
|
81
|
-
# Generate a round for a round robin tournament
|
78
|
+
# Generate a round for a round robin tournament
|
82
79
|
Tournament::RoundRobin.generate driver
|
83
80
|
|
84
81
|
# Generate a round for a swiss system tournament
|
85
|
-
# with Dutch pairings (default) with a minimum pair size of 6
|
82
|
+
# with Dutch pairings (default) with a minimum pair size of 6 (default 4)
|
86
83
|
Tournament::Swiss.generate driver, pairer: Tournament::Swiss::Dutch,
|
87
84
|
pair_options: { min_pair_size: 6 }
|
88
85
|
|
data/lib/tournament/driver.rb
CHANGED
@@ -3,6 +3,14 @@ module Tournament
|
|
3
3
|
#
|
4
4
|
# To use any tournament system implemented in this gem, simply subclass this
|
5
5
|
# class and implement the interface functions.
|
6
|
+
#
|
7
|
+
# The interface is designed to be useable with arbitrary data,
|
8
|
+
# meaning that as long as your data is consistent it will work with this gem.
|
9
|
+
# Be it Ruby on Rails Models or simply integers.
|
10
|
+
#
|
11
|
+
# Certain tournament systems will not make use of certain parts of this
|
12
|
+
# interface. You can for example leave out `#get_team_score` if you're not
|
13
|
+
# using the Swiss tournament system.
|
6
14
|
# :reek:UnusedParameters
|
7
15
|
class Driver
|
8
16
|
# rubocop:disable Lint/UnusedMethodArgument
|
@@ -12,11 +20,6 @@ module Tournament
|
|
12
20
|
raise 'Not Implemented'
|
13
21
|
end
|
14
22
|
|
15
|
-
# Get the matches played for a particular round
|
16
|
-
def matches_for_round(round)
|
17
|
-
raise 'Not Implemented'
|
18
|
-
end
|
19
|
-
|
20
23
|
# Get the teams playing with their initial seedings
|
21
24
|
def seeded_teams
|
22
25
|
raise 'Not Implemented'
|
@@ -7,17 +7,32 @@ module Tournament
|
|
7
7
|
extend self
|
8
8
|
|
9
9
|
def seed(teams)
|
10
|
-
|
10
|
+
unless (Math.log2(teams.length) % 1).zero?
|
11
|
+
raise ArgumentError, 'Need power-of-2 teams'
|
12
|
+
end
|
13
|
+
|
14
|
+
teams = teams.map.with_index { |team, index| SeedTeam.new(team, index) }
|
15
|
+
seed_bracket(teams).map(&:team)
|
16
|
+
end
|
11
17
|
|
12
|
-
|
13
|
-
bottom_half = groups.map { |pair| pair[1] }
|
18
|
+
private
|
14
19
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
# Structure for wrapping a team with it's seed index
|
21
|
+
SeedTeam = Struct.new(:team, :index)
|
22
|
+
|
23
|
+
# Recursively seed the top half of the teams
|
24
|
+
# and match teams reversed by index to the bottom half
|
25
|
+
def seed_bracket(teams)
|
26
|
+
return teams if teams.length <= 2
|
27
|
+
|
28
|
+
top_half, bottom_half = teams.each_slice(teams.length / 2).to_a
|
29
|
+
top_half = seed top_half
|
30
|
+
|
31
|
+
top_half.map do |team|
|
32
|
+
match = bottom_half[-team.index - 1]
|
19
33
|
|
20
|
-
|
34
|
+
[team, match]
|
35
|
+
end.flatten
|
21
36
|
end
|
22
37
|
end
|
23
38
|
end
|
@@ -4,12 +4,12 @@ module Tournament
|
|
4
4
|
extend self
|
5
5
|
|
6
6
|
def generate(driver, options = {})
|
7
|
-
round =
|
7
|
+
round = guess_round(driver)
|
8
8
|
|
9
9
|
teams = if driver.matches.empty?
|
10
10
|
seed_teams driver.seeded_teams, options
|
11
11
|
else
|
12
|
-
last_matches = driver
|
12
|
+
last_matches = previous_round_matches driver, round
|
13
13
|
get_match_winners driver, last_matches
|
14
14
|
end
|
15
15
|
|
@@ -20,6 +20,20 @@ module Tournament
|
|
20
20
|
total_rounds_for_teams(driver.seeded_teams)
|
21
21
|
end
|
22
22
|
|
23
|
+
def guess_round(driver)
|
24
|
+
rounds = total_rounds(driver)
|
25
|
+
teams_count = 2**rounds
|
26
|
+
matches_count = driver.matches.length
|
27
|
+
|
28
|
+
# Make sure we don't have too many matches
|
29
|
+
raise ArgumentError, 'Too many matches' unless teams_count > matches_count
|
30
|
+
|
31
|
+
round = rounds - Math.log2(teams_count - matches_count)
|
32
|
+
# Make sure we don't have some weird number of matches
|
33
|
+
raise ArgumentError, 'Invalid number of matches' unless (round % 1).zero?
|
34
|
+
round.to_i
|
35
|
+
end
|
36
|
+
|
23
37
|
private
|
24
38
|
|
25
39
|
def seed_teams(teams, options)
|
@@ -30,13 +44,11 @@ module Tournament
|
|
30
44
|
end
|
31
45
|
|
32
46
|
def padd_teams(teams)
|
33
|
-
|
34
|
-
|
35
|
-
half = total / 2
|
47
|
+
required = 2**total_rounds_for_teams(teams)
|
48
|
+
padding = required - teams.length
|
36
49
|
|
37
|
-
padding
|
38
|
-
|
39
|
-
teams[0...half] + [nil] * padding + teams[half...teams.length]
|
50
|
+
# Insert the padding at the bottom to give top teams byes
|
51
|
+
teams + [nil] * padding
|
40
52
|
end
|
41
53
|
|
42
54
|
def total_rounds_for_teams(teams)
|
@@ -49,6 +61,13 @@ module Tournament
|
|
49
61
|
matches.map { |match| driver.get_match_winner(match) }
|
50
62
|
end
|
51
63
|
|
64
|
+
def previous_round_matches(driver, round)
|
65
|
+
rounds_left = total_rounds(driver) - round - 1
|
66
|
+
previous_matches_count = 2**rounds_left
|
67
|
+
|
68
|
+
driver.matches[-previous_matches_count, previous_matches_count]
|
69
|
+
end
|
70
|
+
|
52
71
|
def create_matches(driver, teams)
|
53
72
|
teams.each_slice(2) do |slice|
|
54
73
|
next if slice.all?(&:nil?)
|
@@ -44,7 +44,7 @@ module Tournament
|
|
44
44
|
groups[new_key] = group + groups[new_key]
|
45
45
|
# If there isn't, merge into the adjacent greater group
|
46
46
|
else
|
47
|
-
new_key =
|
47
|
+
new_key = new_keys[-1]
|
48
48
|
groups[new_key] += group
|
49
49
|
end
|
50
50
|
# Leave larger groups the way they are
|
data/lib/tournament/version.rb
CHANGED
data/tournament-system.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tournament-system
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Schaaf
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-04-
|
11
|
+
date: 2017-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|