tournament-system 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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