Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Guardfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme

guard :rspec do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }

# Rails example
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
watch('config/routes.rb') { "spec/routing" }
watch('app/controllers/application_controller.rb') { "spec/controllers" }

# Capybara features specs
watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }

# Turnip features and steps
watch(%r{^spec/acceptance/(.+)\.feature$})
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
end

5 changes: 4 additions & 1 deletion bracket_tree.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Gem::Specification.new do |s|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]

s.add_development_dependency "rspec"
s.add_dependency 'activesupport'

s.add_development_dependency "rspec", '2.99'
s.add_development_dependency "guard-rspec"
s.add_development_dependency "rake"
end
1 change: 1 addition & 0 deletions lib/bracket_tree.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require 'bracket_tree/template'
require 'bracket_tree/templates/double_elimination'
require 'bracket_tree/templates/single_elimination'
require 'bracket_tree/templates/single_elimination_generator'

module BracketTree
end
Empty file.
1 change: 1 addition & 0 deletions lib/bracket_tree/templates/single_elimination/1024.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/bracket_tree/templates/single_elimination/256.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/bracket_tree/templates/single_elimination/512.json

Large diffs are not rendered by default.

99 changes: 99 additions & 0 deletions lib/bracket_tree/templates/single_elimination_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
require 'active_support/all'
require 'json'

module BracketTree
module Template
class SingleEliminationGenerator
attr_reader :seats, :matches, :starting_seats, :slots

def initialize(slots)
@slots = slots
@matches = []
@seats = []
@starting_seats = (1..slots*2).select { |n| n.odd? }
end

def build
build_matches
populate_matches
populate_seats
end

def to_hash
{
:matches => matches.flatten,
:seats => seats,
:starting_seats => starting_seats
}
end

def to_json
to_hash.to_json
end

def matches_for_row(n)
if n == 1
slots / 2
else
matches_for_row(n - 1) / 2
end
end

def build_matches
if matches.empty?
i = 1
while matches_for_row(i) > 0
row = []
matches_for_row(i).times do
row << {:seats => nil, :winner_to => nil, :loser_to => nil}
end
matches << row
i += 1
end
end
end

def matches_row(n)
matches[n]
end

def populate_matches
step = nil
populate_first_row_matches
matches.each_with_index do |row, level|
next_row_groups = row.inject Array.new do |arr, match|
arr << match[:winner_to]
end.in_groups_of(2)
next_matches = matches[level+1]
if next_matches
next_matches.each_with_index do |match, i|
match[:seats] = next_row_groups[i]
if i.zero?
step = (match[:seats][1] - match[:seats][0]) / 2
end
match[:winner_to] = match[:seats][1] - step
end
end
end
matches.last.last[:winner_to] = nil
end

def populate_first_row_matches
starting_seats.in_groups_of(2).each_with_index do |arr, i|
step ||= (arr[1] - arr[0])/2
matches_row(0)[i][:seats] = arr
matches_row(0)[i][:winner_to] = arr[1] - step
end
end

def populate_seats
matches_seats = matches.map {|arr| arr.map {|a| a[:seats]}}
ordered_seats = slots < 32 ? matches_seats.reverse.map {|a| a.reverse} : matches_seats.reverse
flat_seats = ordered_seats.flatten
first_seat = flat_seats.first*2
all_seats = flat_seats.unshift first_seat
@seats = all_seats.map {|n| {:position => n} }
end
end
end
end
Empty file.
164 changes: 164 additions & 0 deletions spec/single_elimination_json_generator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
require 'pry'
require 'spec_helper'

module BracketTree
module Template
describe SingleEliminationGenerator do
def hash_from_single_elimination_json(n)
filename = "../../lib/bracket_tree/templates/single_elimination/#{n}.json"
JSON.parse File.read(File.expand_path filename, __FILE__), :symbolize_names => true
end

context 'with 16 slots' do
subject { SingleEliminationGenerator.new(16) }

before { subject.build_matches }

it 'builds 15 matches' do
subject.matches.flatten.size.should == 15
end

it 'has 16 starting seats' do
subject.starting_seats.size.should == 16
end

it 'has 8 matches in the first row' do
subject.matches_row(0).size.should == 8
end

describe '#matches_for_row' do
it 'is in sequence 8,4,2,0' do
subject.matches_for_row(1).should == 8
subject.matches_for_row(2).should == 4
subject.matches_for_row(3).should == 2
subject.matches_for_row(4).should == 1
end
end

describe '#populate_first_row_matches' do
before { subject.populate_first_row_matches }

it 'builds first match with expected values' do
first_match = {:seats => [1,3], :winner_to => 2, :loser_to => nil}
subject.matches_row(0).first.should == first_match
end

it 'builds last match with expected values' do
last_match = {:seats => [29,31], :winner_to => 30, :loser_to => nil}
subject.matches_row(0).last.should == last_match
end
end

describe '#populate_matches' do
before { subject.populate_matches }

it 'builds ninth match with expected values' do
ninth_match = {:seats => [2,6], :winner_to => 4, :loser_to => nil}
subject.matches_row(1).first.should == ninth_match
end

it 'builds last match with expected values' do
last_match = {:seats => [8,24], :winner_to => nil, :loser_to => nil}
subject.matches.last.first.should == last_match
end
end

describe '#populate_seats' do
subject { SingleEliminationGenerator.new(16) }

it 'builds seats as expected' do
subject.populate_matches
subject.populate_seats
subject.seats[1].should == {:position => 8}
end
end

describe '#to_hash' do
context 'when building a 8 seats tree' do
subject { SingleEliminationGenerator.new(8) }
let(:expected) { hash_from_single_elimination_json 8 }

it 'builds expected json 8' do
subject.build
subject.to_hash.should == expected.symbolize_keys
end
end

context 'when building a 16 seats tree' do
subject { SingleEliminationGenerator.new 16 }
let(:expected) { hash_from_single_elimination_json 16 }

it 'builds expected json 16' do
subject.build
subject.to_hash.should == expected.symbolize_keys
end
end

context 'when building a 32 seats tree' do
subject { SingleEliminationGenerator.new 32 }
let(:expected) { hash_from_single_elimination_json 32 }

it 'builds expected json 32' do
subject.build
subject.to_hash.should == expected.symbolize_keys
end
end

context 'when building a 64 seats tree' do
subject { SingleEliminationGenerator.new 64 }
let(:expected) { hash_from_single_elimination_json 64 }

it 'builds expected json 64' do
subject.build
subject.to_hash.should == expected.symbolize_keys
end
end

context 'when building a 128 seats tree' do
subject { SingleEliminationGenerator.new 128 }
let(:expected) { hash_from_single_elimination_json 128 }

it 'builds expected json 128' do
subject.build
result = subject.to_hash
result[:matches].should == expected[:matches]
result[:starting_seats].should == expected[:starting_seats]
end

it 'has problems with seats' do
subject.build
subject.to_hash[:seats].should == expected[:seats]
end
end

context 'when building a 256 seats tree' do
subject { SingleEliminationGenerator.new 256 }

it 'builds the json' do
subject.build
subject.to_json.should_not raise_error
end
end

context 'when building a 512 seats tree' do
subject { SingleEliminationGenerator.new 512 }

it 'builds the json' do
subject.build
subject.to_json.should_not raise_error
end
end

context 'when building a 1024 seats tree' do
subject { SingleEliminationGenerator.new 1024 }

it 'builds the json' do
subject.build
subject.to_json.should_not raise_error
end
end
end
end
end
end
end