diff options
author | Luke Shumaker <shumakl@purdue.edu> | 2014-04-22 15:50:21 -0400 |
---|---|---|
committer | Luke Shumaker <shumakl@purdue.edu> | 2014-04-22 15:50:21 -0400 |
commit | 9d226fcd27b6c2470edf718ad36a262348891470 (patch) | |
tree | bb17fce921d0017b6e9111bd81edc194c07f61d3 | |
parent | 136b86453000aa6ad3a099efb96d85232eb2eeb5 (diff) |
re-factor for tournament_stage's and separate scheduling modules
-rw-r--r-- | app/controllers/matches_controller.rb | 6 | ||||
-rw-r--r-- | app/controllers/tournaments_controller.rb | 9 | ||||
-rw-r--r-- | app/models/tournament.rb | 31 | ||||
-rw-r--r-- | app/models/tournament_stage.rb | 26 | ||||
-rw-r--r-- | app/views/matches/index.html.erb | 80 | ||||
-rw-r--r-- | config/routes.rb | 10 | ||||
-rw-r--r-- | lib/scheduling/elimination.rb | 55 | ||||
-rw-r--r-- | lib/scheduling/elimination.svg.erb | 72 |
8 files changed, 176 insertions, 113 deletions
diff --git a/app/controllers/matches_controller.rb b/app/controllers/matches_controller.rb index d7a8b99..e95f24a 100644 --- a/app/controllers/matches_controller.rb +++ b/app/controllers/matches_controller.rb @@ -8,12 +8,6 @@ class MatchesController < ApplicationController # GET /tournaments/1/matches # GET /tournaments/1/matches.json def index - @matches = @tournament.matches - # depth of SVG tree - @depth = Math.log2(@matches.count).floor+1; - # height of SVG - @height = 200 * 2**Math.log2(@matches.count).floor + 100; - @h_sector = 2**(@depth-1)+1 end # For compatability with the router assumptions made by ApplicationController#check_permission diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb index b6f911f..4b0e1af 100644 --- a/app/controllers/tournaments_controller.rb +++ b/app/controllers/tournaments_controller.rb @@ -96,10 +96,13 @@ class TournamentsController < ApplicationController when "start" check_permission(:edit, @tournament) @tournament.status = 1 - @tournament.save + ok = + @tournament.save && + @tournament.tournament_stages.create(scheduling: "elimination") && + @tournament.tournament_stages.first.create_matches respond_to do |format| - if @tournament.setup - format.html { redirect_to @tournament, notice: 'You have joined this tournament.' } + if ok + format.html { redirect_to @tournament, notice: 'You have started this tournament.' } format.json { head :no_content } else format.html { redirect_to @tournament, notice: "You don't have permission to start this tournament." } diff --git a/app/models/tournament.rb b/app/models/tournament.rb index 822e641..e21ccb1 100644 --- a/app/models/tournament.rb +++ b/app/models/tournament.rb @@ -1,15 +1,15 @@ class Tournament < ActiveRecord::Base belongs_to :game - has_many :matches + has_many :tournament_stages has_many :settings_raw, class_name: "TournamentSetting" has_and_belongs_to_many :players, class_name: "User", association_foreign_key: "player_id", join_table: "players_tournaments" has_and_belongs_to_many :hosts, class_name: "User", association_foreign_key: "host_id", join_table: "hosts_tournaments" - def matches_ordered + def stages_ordered h = {} i = 1 - matches.order(:id).each do |m| - h[i] = m + self.tournament_stages.order(:id).each do |s| + h[i] = s i += 1 end return h @@ -86,27 +86,4 @@ class Tournament < ActiveRecord::Base players.delete(user) end end - - def setup - num_teams = (self.players.count/self.min_players_per_team).floor - num_matches = num_teams - 1 - for i in 1..num_matches - self.matches.create(name: "Match #{i}", status: 0, submitted_peer_evaluations: 0) - end - match_num = num_matches-1 - team_num = 0 - #for each grouping of min_players_per_team - players.each_slice(min_players_per_team) do |players| - - #if the match is full, move to the next match, otherwise move to the next team - if (team_num == min_teams_per_match) - match_num -= 1 - team_num = 0 - else - team_num += 1 - end - #create a new team in the current match - self.matches[match_num].teams.push(Team.create(users: players)) - end - end end diff --git a/app/models/tournament_stage.rb b/app/models/tournament_stage.rb index 205c8cc..a24d7b9 100644 --- a/app/models/tournament_stage.rb +++ b/app/models/tournament_stage.rb @@ -1,3 +1,29 @@ class TournamentStage < ActiveRecord::Base belongs_to :tournament + has_many :matches + + def matches_ordered + h = {} + i = 1 + self.matches.order(:id).each do |m| + h[i] = m + i += 1 + end + return h + end + + def create_matches + set_scheduling + @scheduling.create_matches + end + + def to_svg + set_scheduling + return @scheduling.graph(self) + end + + private + def set_scheduling + @scheduling ||= "Scheduling::#{self.scheduling}".constantize.new(self) + end end diff --git a/app/views/matches/index.html.erb b/app/views/matches/index.html.erb index 03427d8..cebabb3 100644 --- a/app/views/matches/index.html.erb +++ b/app/views/matches/index.html.erb @@ -32,80 +32,6 @@ <br> -<div id="match-tree"> - <SVG version="1.1" - baseProfile="full" - width="100%" height="<%= @height = [@height, 500].max %>" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink"> - <% lastrx = 0 - lastry = 0 - lastrh = 0 - lastrw = 0 %> - <defs> - <radialGradient id="gradMatch" cx="50%" cy="50%" r="80%" fx="80%" fy="80%"> - <stop offset="0%" style="stop-color:#ffd281; - stop-opacity:0" /> - <stop offset="100%" style="stop-color:#ccc;stop-opacity:1" /> - </radialGradient> - </defs> - <script type="text/ecmascript"><![CDATA[ - function redirect(i){ - window.location.replace("<%= request.original_url %>"+"/"+i); - } - ]]> - </script> - - <% (1..@matches.count).each do |i| %> - <g id="svg-match-<%= i %>" onclick="redirect(<%= @matches[i-1].id %>)" cursor="pointer"> - <rect height="<%= rh = 100/(2**(@depth-1)+1) - 5 %>%" - width="<%= rw = 100/(@depth+1) - 5 %>%" - x="<%= rx = 50/(@depth+1) + 100/(@depth+1)*(@depth-(Math.log2(i).floor+1)) %>%" - y="<%= ry = ( 100/(2**(Math.log2(i).floor)+1) + rh * 1.1 * (2**Math.log2(i).ceil-i)) %>%" - fill="url(#gradMatch)" - rx="5px" - stroke-width="2" - <% case @matches[i-1].status %> - <% when 0 %> - <% if @matches[i-1].teams.count < @tournament.min_teams_per_match %> - stroke="red" - fill-opacity="0.6" - <% else %> - stroke="green" - <% end %> - <% when 1 %> - stroke="orange" - <% when 2 %> - stroke="yellow" - <% when 3 %> - stroke="grey" - <% end %> - /> - <rect width="<%= rw-5 %>%" height="<%= rh/4 %>%" x="<%= rx + 2.5 %>%" y="<%= ry + rh/6 %>%" fill="<%= @matches[i-1].teams.first and @matches[i-1].teams.first.users.include?(current_user) ? "#BCED91" : "white" %>" /> - <text x="<%= rx + rw/4 %>%" y="<%= ry + rh/3 %>%" font-size="<%= rh %>"> - <% if @matches[i-1].teams.first %> - Team <%= @matches[i-1].teams.first.id %> - <% end %> - </text> - <text x="<%= rx + 1.3*rw/3 %>%" y="<%= ry + 5.2*rh/9 %>%" font-size="<%= rh %>"> VS </text> - - <rect width="<%= rw-5 %>%" height="<%= rh/4 %>%" x="<%= rx + 2.5 %>%" y="<%= ry + 3*rh/5 %>%" fill="<%= @matches[i-1].teams[1] and @matches[i-1].teams[1].users.include?(current_user) ? "#BCED91" : "white" %>" /> - <text x="<%= rx + rw/4 %>%" y="<%= ry + 4*rh/5 %>%" font-size="<%= rh %>"> - <% if @matches[i-1].teams[1] %> - Team <%= @matches[i-1].teams[1].id %> - <% end %> - </text> - <% if i > 1 %> - <line x1="<%= rx+rw %>%" y1="<%= ry+rh/2 %>%" x2="<%= lastrx %>%" y2="<%= lastry+lastrh/2 %>%" stroke="black" stroke-width="2" > - <% end %> - <% if Math.log2(i+1) == Math.log2(i+1).ceil %> - <% lastrx = rx - lastry = ry - lastrh = rh - lastrw = rw %> - <% end %> - </g> - - <% end %> -</SVG> -</div> +<% @tournament.stages_ordered.each do |stage| %> + <div class="graph"><%= stage.to_svg %></div> +<% end %> diff --git a/config/routes.rb b/config/routes.rb index 8ec4432..f94bd2f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -25,7 +25,17 @@ Leaguer::Application.routes.draw do root to: 'static#homepage' get '/testsvg', to: 'static#test' +end +Leaguer::Application.routes.named_routes.module.module_eval do + def match_path(match, options={}) + tournament_match_path(match.tournament_stage.tournament, match, options) + end + def match_url(match, options={}) + tournament_match_url(match.tournament_stage.tournament, match, options) + end +end +if false # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". diff --git a/lib/scheduling/elimination.rb b/lib/scheduling/elimination.rb new file mode 100644 index 0000000..519d08a --- /dev/null +++ b/lib/scheduling/elimination.rb @@ -0,0 +1,55 @@ +module Scheduling + class Elimination + + def initialize(tournament_stage) + @tournament_stage = tournament_stage + end + + def tournament_stage + @tournament_stage + end + def tournament + self.tournament_stage.tournament + end + + def create_matches + num_teams = (self.tournament.players.count/self.tournament.min_players_per_team).floor + num_matches = num_teams - 1 + for i in 1..num_matches + self.tournament_stage.matches.create(status: 0, submitted_peer_evaluations: 0) + end + match_num = num_matches-1 + team_num = 0 + # for each grouping of min_players_per_team + self.tournament.players.each_slice(min_players_per_team) do |team_members| + # if the match is full, move to the next match, otherwise move to the next team + if (team_num == min_teams_per_match) + match_num -= 1 + team_num = 0 + else + team_num += 1 + end + # create a new team in the current match + self.tournament_stage.matches[match_num].teams.push(Team.create(users: team_members)) + end + end + + def match_finished(match) + matches = match.tournament_stage.matches_ordered + cur_match_num = matches.invert[match] + unless cur_match_num == 1 + match.winner.matches.push(matches[cur_match_num/2]) + end + end + + def graph + require 'erb' + erb_filename = File.join(File.dirname(__FILE__), 'elimination.svg.erb') + + erb = ERB.new(File.read(erb_filename)) + erb.filename = erb_filename + return erb.result + end + + end +end diff --git a/lib/scheduling/elimination.svg.erb b/lib/scheduling/elimination.svg.erb new file mode 100644 index 0000000..91b8f6a --- /dev/null +++ b/lib/scheduling/elimination.svg.erb @@ -0,0 +1,72 @@ +<% + +matches = @tournament_stage.matches_ordered +# depth of SVG tree +depth = Math.log2(matches.count).floor+1; +# height of SVG +height = 200 * 2**Math.log2(matches.count).floor + 100; +lastrx = 0 +lastry = 0 +lastrh = 0 +lastrw = 0 + +%><svg version="1.1" baseProfile="full" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="100%" height="<%= height = [height, 500].max %>"> + <% %> + <defs> + <radialGradient id="gradMatch" cx="50%" cy="50%" r="80%" fx="80%" fy="80%"> + <stop offset="0%" style="stop-color:#ffd281; stop-opacity:0" /> + <stop offset="100%" style="stop-color:#ccc;stop-opacity:1" /> + </radialGradient> + </defs> + <% (1..matches.count).each do |i| %> + <a id="svg-match-<%= i %>" xlink:href="<%= match_path(matches[i-1]) %>"> + <rect height="<%= rh = 100/(2**(depth-1)+1) - 5 %>%" + width="<%= rw = 100/(depth+1) - 5 %>%" + x="<%= rx = 50/(depth+1) + 100/(depth+1)*(depth-(Math.log2(i).floor+1)) %>%" + y="<%= ry = ( 100/(2**(Math.log2(i).floor)+1) + rh * 1.1 * (2**Math.log2(i).ceil-i)) %>%" + fill="url(#gradMatch)" + rx="5px" + stroke-width="2" + <% case matches[i-1].status %> + <% when 0 %> + <% if matches[i-1].teams.count < @tournament_stage.tournament.min_teams_per_match %> + stroke="red" + fill-opacity="0.6" + <% else %> + stroke="green" + <% end %> + <% when 1 %> + stroke="orange" + <% when 2 %> + stroke="yellow" + <% when 3 %> + stroke="grey" + <% end %> /> + <rect width="<%= rw-5 %>%" height="<%= rh/4 %>%" x="<%= rx + 2.5 %>%" y="<%= ry + rh/6 %>%" fill="<%= matches[i-1].teams.first and matches[i-1].teams.first.users.include?(current_user) ? "#BCED91" : "white" %>" /> + <text x="<%= rx + rw/4 %>%" y="<%= ry + rh/3 %>%" font-size="<%= rh %>"> + <% if matches[i-1].teams.first %> + Team <%= matches[i-1].teams.first.id %> + <% end %> + </text> + <text x="<%= rx + 1.3*rw/3 %>%" y="<%= ry + 5.2*rh/9 %>%" font-size="<%= rh %>"> VS </text> + <rect width="<%= rw-5 %>%" height="<%= rh/4 %>%" x="<%= rx + 2.5 %>%" y="<%= ry + 3*rh/5 %>%" fill="<%= matches[i-1].teams[1] and matches[i-1].teams[1].users.include?(current_user) ? "#BCED91" : "white" %>" /> + <text x="<%= rx + rw/4 %>%" y="<%= ry + 4*rh/5 %>%" font-size="<%= rh %>"> + <% if matches[i-1].teams[1] %> + Team <%= matches[i-1].teams[1].id %> + <% end %> + </text> + <% if i > 1 %> + <line x1="<%= rx+rw %>%" y1="<%= ry+rh/2 %>%" x2="<%= lastrx %>%" y2="<%= lastry+lastrh/2 %>%" stroke="black" stroke-width="2" > + <% end %> + <% if Math.log2(i+1) == Math.log2(i+1).ceil %> + <% lastrx = rx + lastry = ry + lastrh = rh + lastrw = rw %> + <% end %> + </a> + <% end %> +</svg> |