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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 658d99ded4876bcc1c1ec78dbb38066d3dfae06a
4
- data.tar.gz: 9a11ee1ed63be549fc09d2c6f40165a316188949
3
+ metadata.gz: 2e2feaf11e43d4582382ab6702fee535a796e00c
4
+ data.tar.gz: 79c8750797f63e42658afcbbc05b240308801209
5
5
  SHA512:
6
- metadata.gz: c355fa4f8edfeb89e524b613cf98e66ab551f3cfe773690a039d3d7996342eab2556e151a69fc775226d11a0819cbe7660685b985f1576fcf44998a6642113f8
7
- data.tar.gz: d5abd06fb557db3adf12c9de53d19fbfa7097c198d0b637a6a4a7a37b1ea9826ec08cabe8a1944609c2b5a3db35e67c320f7a512f41aa4fce11a4e9fa8643f60
6
+ metadata.gz: 11128da929528638694f487a17aa28baa25fc4dd090ea88b7a378553f3894ffcd8c3c8c4c30f30cff2388dbf6d71872e74532e4ecf6c1e891051ac280483f1de
7
+ data.tar.gz: 8991877ed078ae29d705d630fb8fad9a828f52264b6546109ff74fbf6e460fce6599516318a13598177251ded7c0bf3e895aa729046b7985e6df66586a8884b9
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Build Status](https://travis-ci.org/ozfortress/tournament-system.svg?branch=master)](https://travis-ci.org/ozfortress/tournament-system)
4
4
  [![Coverage Status](https://coveralls.io/repos/github/ozfortress/tournament-system/badge.svg?branch=master)](https://coveralls.io/github/ozfortress/tournament-system?branch=master)
5
5
  [![Gem Version](https://badge.fury.io/rb/tournament-system.svg)](https://badge.fury.io/rb/tournament-system)
6
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](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 the 3rd round of a single elimination tournament
79
- Tournament::SingleElimination.generate driver, round: 2
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, guesses round automatically
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
 
@@ -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
- groups = teams.each_slice(2)
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
- top_half = groups.map { |pair| pair[0] }
13
- bottom_half = groups.map { |pair| pair[1] }
18
+ private
14
19
 
15
- if top_half.length > 2
16
- top_half = seed top_half
17
- bottom_half = seed bottom_half
18
- end
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
- top_half + bottom_half
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 = options[:round] || raise('Missing option :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.matches_for_round(round - 1)
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
- # Insert the padding after the top half of the total number of teams
34
- total = 2**total_rounds_for_teams(teams)
35
- half = total / 2
47
+ required = 2**total_rounds_for_teams(teams)
48
+ padding = required - teams.length
36
49
 
37
- padding = total - teams.length
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 = group_keys[index - 1]
47
+ new_key = new_keys[-1]
48
48
  groups[new_key] += group
49
49
  end
50
50
  # Leave larger groups the way they are
@@ -18,6 +18,7 @@ module Tournament
18
18
 
19
19
  private
20
20
 
21
+ # Match the top half with the bottom half
21
22
  def dutch_pairing(teams)
22
23
  half = teams.length / 2
23
24
  top = teams[0...half]
@@ -1,3 +1,3 @@
1
1
  module Tournament
2
- VERSION = '0.1.1'.freeze
2
+ VERSION = '0.1.2'.freeze
3
3
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  lib = File.expand_path('../lib', __FILE__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'tournament-system'
5
+ require 'tournament/version'
6
6
 
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = 'tournament-system'
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.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-18 00:00:00.000000000 Z
11
+ date: 2017-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler