mirror of
https://github.com/ENSL/ensl.org.git
synced 2024-11-15 01:11:23 +00:00
Init ladder prototype. Challenge stuff is still mostly broken.
This commit is contained in:
parent
fcf8f2111d
commit
ce812b8f17
11 changed files with 185 additions and 104 deletions
|
@ -18,10 +18,13 @@ class ChallengesController < ApplicationController
|
|||
end
|
||||
|
||||
def new
|
||||
#No new challenges for now.
|
||||
raise AccessError
|
||||
@challenge = Challenge.new
|
||||
@challenge.user = cuser
|
||||
@challenge.contester2 = Contester.active.find params[:id]
|
||||
@challenge.get_contester1
|
||||
contest = @challenge.contester2.contest
|
||||
@challenge.contester1 = @challenge.user.active_contesters.of_contest(contest).first
|
||||
raise AccessError unless @challenge.can_create? cuser
|
||||
end
|
||||
|
||||
|
@ -62,7 +65,8 @@ class ChallengesController < ApplicationController
|
|||
def destroy
|
||||
raise AccessError unless @challenge.can_destroy? cuser
|
||||
@challenge.destroy
|
||||
return_to
|
||||
#return_to FIX ME from challenge side
|
||||
render text: t(:challenges_cleared)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -22,6 +22,9 @@ class ContestersController < ApplicationController
|
|||
@contester = Contester.new params[:contester]
|
||||
@contester.user = cuser
|
||||
raise AccessError unless @contester.can_create? cuser
|
||||
if @contester.contest.contest_type == Contest::TYPE_LADDER
|
||||
@contester.score = @contester.contest.contesters.active.count + 1
|
||||
end
|
||||
|
||||
if @contester.save
|
||||
flash[:notice] = t(:contests_join)
|
||||
|
@ -34,9 +37,20 @@ class ContestersController < ApplicationController
|
|||
|
||||
def update
|
||||
raise AccessError unless @contester.can_update? cuser
|
||||
|
||||
if @contester.contest.contest_type == Contest::TYPE_LADDER
|
||||
old_rank = @contester.score
|
||||
new_rank = params[:contester][:score].to_i
|
||||
raise Error, t(:rank_invalid) unless new_rank > 0 and
|
||||
new_rank <= @contester.contest.contesters.active.count
|
||||
if old_rank != new_rank
|
||||
@contester.contest.update_ranks(@contester, old_rank, new_rank)
|
||||
end
|
||||
end
|
||||
|
||||
if @contester.update_attributes params[:contester]
|
||||
flash[:notice] = t(:contests_contester_update)
|
||||
redirect_to @contester
|
||||
redirect_to @contester.contest
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
|
|
|
@ -36,7 +36,7 @@ class Challenge < ActiveRecord::Base
|
|||
|
||||
attr_protected :id, :updated_at, :created_at, :default_time, :user_id, :status
|
||||
|
||||
validates_presence_of :contester1, :contester2, :server, :map1
|
||||
validates_presence_of :contester1, :contester2
|
||||
validates_presence_of :map2, :on => :update
|
||||
#validates_datetime :match_time, :default_time
|
||||
#validates_length_of [:details, :response], :maximum => 255, :allow_blank => true, :allow_nil => true
|
||||
|
@ -111,102 +111,102 @@ class Challenge < ActiveRecord::Base
|
|||
|
||||
def validate_teams
|
||||
if contester1.team == contester2.team
|
||||
errors.add_to_base I18n.t(:challenges_yourself)
|
||||
errors.add :base, I18n.t(:challenges_yourself)
|
||||
end
|
||||
if contester1.contest != contester2.contest
|
||||
errors.add_to_base I18n.t(:challenges_opponent_contest)
|
||||
errors.add :base, I18n.t(:challenges_opponent_contest)
|
||||
end
|
||||
if !contester2.active or !contester2.team.active
|
||||
errors.add_to_base I18n.t(:challenges_opponent_inactive)
|
||||
errors.add :base, I18n.t(:challenges_opponent_inactive)
|
||||
end
|
||||
if !contester1.active or !contester1.team.active
|
||||
errors.add_to_base I18n.t(:challenges_inactive)
|
||||
errors.add :base, I18n.t(:challenges_inactive)
|
||||
end
|
||||
end
|
||||
|
||||
def validate_contest
|
||||
if contester1.contest.end.past? or contester1.contest.status == Contest::STATUS_CLOSED
|
||||
errors.add_to_base I18n.t(:contests_closed)
|
||||
errors.add :base, I18n.t(:contests_closed)
|
||||
end
|
||||
if contester1.contest.contest_type != Contest::TYPE_LADDER and !match
|
||||
errors.add_to_base I18n.t(:contests_notladder)
|
||||
errors.add :base, I18n.t(:contests_notladder)
|
||||
end
|
||||
end
|
||||
|
||||
def validate_mandatory
|
||||
return unless mandatory
|
||||
# return unless mandatory
|
||||
|
||||
if contester2.score < contester1.score
|
||||
errors.add_to_base I18n.t(:challenges_mandatory)
|
||||
end
|
||||
if Challenge.pending.count(:conditions => \
|
||||
["contester1_id = ? AND contester2_id = ? AND mandatory = true AND default_time < UTC_TIMESTAMP()",
|
||||
contester1.id, contester2.id]) > 0
|
||||
errors.add_to_base I18n.t(:challenges_mandatory_handled)
|
||||
end
|
||||
if Match.of_contester(contester2).on_week(match_time).count > 0
|
||||
errors.add_to_base I18n.t(:challenges_opponent_week)
|
||||
end
|
||||
if Challenge.of_contester(contester2).mandatory.on_week(match_time).count > 0
|
||||
errors.add_to_base I18n.t(:challenges_opponent_mandatory_week)
|
||||
end
|
||||
if Challenge.of_contester(contester2).mandatory.on_week(default_time).count > 0
|
||||
errors.add_to_base I18n.t(:challenges_opponent_mandatory_week_defaulttime)
|
||||
end
|
||||
if Match.of_contester(contester2).around(default_time).count > 0
|
||||
errors.add_to_base I18n.t(:challenges_opponent_defaulttime)
|
||||
end
|
||||
# if contester2.score < contester1.score
|
||||
# errors.add :base, I18n.t(:challenges_mandatory)
|
||||
# end
|
||||
# if Challenge.pending.count(:conditions => \
|
||||
# ["contester1_id = ? AND contester2_id = ? AND mandatory = true AND default_time < UTC_TIMESTAMP()",
|
||||
# contester1.id, contester2.id]) > 0
|
||||
# errors.add :base, I18n.t(:challenges_mandatory_handled)
|
||||
# end
|
||||
# if Match.of_contester(contester2).on_week(match_time).count > 0
|
||||
# errors.add :base, I18n.t(:challenges_opponent_week)
|
||||
# end
|
||||
# if Challenge.of_contester(contester2).mandatory.on_week(match_time).count > 0
|
||||
# errors.add :base, I18n.t(:challenges_opponent_mandatory_week)
|
||||
# end
|
||||
# if Challenge.of_contester(contester2).mandatory.on_week(default_time).count > 0
|
||||
# errors.add :base, I18n.t(:challenges_opponent_mandatory_week_defaulttime)
|
||||
# end
|
||||
# if Match.of_contester(contester2).around(default_time).count > 0
|
||||
# errors.add :base, I18n.t(:challenges_opponent_defaulttime)
|
||||
# end
|
||||
end
|
||||
|
||||
def validate_match_time
|
||||
if (match_time-get_margin).past?
|
||||
if get_margin > 86400
|
||||
errors.add_to_base I18n.t(:matches_time1) + get_margin / 60 / 60 / 24 + I18n.t(:matches_time2)
|
||||
else
|
||||
errors.add_to_base I18n.t(:matches_time1) + get_margin / 60 + I18n.t(:matches_time3)
|
||||
end
|
||||
end
|
||||
if Challenge.of_contester(contester2).around(match_time).pending.count > 0
|
||||
errors.add_to_base I18n.t(:challenges_opponent_specifictime)
|
||||
end
|
||||
if Match.of_contester(contester2).around(match_time).count > 0
|
||||
errors.add_to_base I18n.t(:challenges_opponent_match_specifictime)
|
||||
end
|
||||
if match_time > contester1.contest.end
|
||||
errors.add_to_base I18n.t(:contests_end)
|
||||
end
|
||||
# if (match_time-get_margin).past?
|
||||
# if get_margin > 86400
|
||||
# errors.add :base, I18n.t(:matches_time1) + get_margin / 60 / 60 / 24 + I18n.t(:matches_time2)
|
||||
# else
|
||||
# errors.add :base, I18n.t(:matches_time1) + get_margin / 60 + I18n.t(:matches_time3)
|
||||
# end
|
||||
# end
|
||||
# if Challenge.of_contester(contester2).around(match_time).pending.count > 0
|
||||
# errors.add :base, I18n.t(:challenges_opponent_specifictime)
|
||||
# end
|
||||
# if Match.of_contester(contester2).around(match_time).count > 0
|
||||
# errors.add :base, I18n.t(:challenges_opponent_match_specifictime)
|
||||
# end
|
||||
# if match_time > contester1.contest.end
|
||||
# errors.add :base, I18n.t(:contests_end)
|
||||
# end
|
||||
end
|
||||
|
||||
def validate_server
|
||||
unless server and server.official
|
||||
errors.add_to_base I18n.t(:servers_notavailable)
|
||||
end
|
||||
unless server.is_free match_time
|
||||
errors.add_to_base I18n.t(:servers_notfree_specifictime)
|
||||
end
|
||||
if !server.is_free default_time
|
||||
errors.add_to_base I18n.t(:servers_notfree_defaulttime)
|
||||
end
|
||||
# unless server and server.official
|
||||
# errors.add :base, I18n.t(:servers_notavailable)
|
||||
# end
|
||||
# unless server.is_free match_time
|
||||
# errors.add :base, I18n.t(:servers_notfree_specifictime)
|
||||
# end
|
||||
# if !server.is_free default_time
|
||||
# errors.add :base, I18n.t(:servers_notfree_defaulttime)
|
||||
# end
|
||||
end
|
||||
|
||||
def validate_map1
|
||||
unless contester1.contest.maps.exists?(map1)
|
||||
errors.add_to_base I18n.t(:contests_map_notavailable)
|
||||
errors.add :base, I18n.t(:contests_map_notavailable)
|
||||
end
|
||||
end
|
||||
|
||||
def validate_map2
|
||||
unless contester2.contest.maps.exists?(map2)
|
||||
errors.add_to_base I18n.t(:contests_map_notavailable)
|
||||
errors.add :base, I18n.t(:contests_map_notavailable)
|
||||
end
|
||||
end
|
||||
|
||||
def validate_status
|
||||
if mandatory and ![STATUS_ACCEPTED, STATUS_DEFAULT, STATUS_FORFEIT].include? status
|
||||
errors.add_to_base I18n.t(:challenges_mandatory_invalidresult)
|
||||
errors.add :base, I18n.t(:challenges_mandatory_invalidresult)
|
||||
end
|
||||
unless statuses.include? status
|
||||
errors.add_to_base I18n.t(:challenges_mandatory_invalidresult)
|
||||
errors.add :base, I18n.t(:challenges_mandatory_invalidresult)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -251,10 +251,10 @@ class Challenge < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def can_update? cuser
|
||||
cuser and (contester2.team.is_leader? cuser or cuser.admin?) and status == STATUS_PENDING and autodefault.future?
|
||||
cuser and (contester2.team.is_leader? cuser or cuser.admin?) and status == STATUS_PENDING# and autodefault.future?
|
||||
end
|
||||
|
||||
def can_destroy? cuser
|
||||
cuser and (contester1.team.is_leader? cuser or cuser.admin?) and status == STATUS_PENDING and autodefault.future?
|
||||
cuser and (contester1.team.is_leader? cuser or cuser.admin?) and status == STATUS_PENDING# and autodefault.future?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -107,23 +107,27 @@ class Contest < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def elo_score score1, score2, diff, level = self.modulus_base, weight = self.weight, moduluses = [self.modulus_even, self.modulus_3to1, self.modulus_4to0]
|
||||
points = (score2-score1).abs
|
||||
modulus = moduluses[0].to_f if points <= 1
|
||||
modulus = moduluses[1].to_f if points == 2
|
||||
modulus = moduluses[2].to_f if points >= 3
|
||||
if score1 == score2
|
||||
result = 0.5
|
||||
elsif score1 > score2
|
||||
result = 1.0
|
||||
elsif score2 > score1
|
||||
result = 0.0
|
||||
def update_ranks contester, old_rank, new_rank
|
||||
if old_rank < new_rank
|
||||
Contester.update_all(["score = score -1, trend = ?", Contester::TREND_UP],
|
||||
["contest_id = ? and score > ? and score <= ?",
|
||||
self.id, old_rank, new_rank])
|
||||
contester.trend = Contester::TREND_DOWN
|
||||
elsif old_rank > new_rank
|
||||
Contester.update_all(["score = score + 1, trend = ?", Contester::TREND_DOWN],
|
||||
["contest_id = ? and score < ? and score >= ?",
|
||||
self.id, old_rank, new_rank])
|
||||
contester.trend = Contester::TREND_UP
|
||||
end
|
||||
prob = 1.0/(10**(diff.to_f/weight.to_f)+1.0)
|
||||
total = (level.to_f*modulus*(result-prob)).round
|
||||
return total
|
||||
contester.score = new_rank
|
||||
end
|
||||
|
||||
def ladder_ranks_unique?
|
||||
c = Contester.where({:contest_id => self.id})
|
||||
c.uniq.pluck(:score).count == c.count
|
||||
end
|
||||
|
||||
|
||||
def can_create? cuser
|
||||
cuser and cuser.admin?
|
||||
end
|
||||
|
|
|
@ -27,6 +27,8 @@ class Contester < ActiveRecord::Base
|
|||
attr_accessor :user
|
||||
|
||||
scope :active, :include => :team, :conditions => {"contesters.active" => true}
|
||||
# ranked is used for ladder. lower score the higher the rank
|
||||
scope :ranked, :select => "contesters.*", :order => "score ASC, win DESC, loss ASC"
|
||||
scope :ordered, :select => "contesters.*, (score + extra) AS total_score", :order => "total_score DESC, score DESC, win DESC, loss ASC"
|
||||
scope :chronological, :order => "created_at DESC"
|
||||
scope :of_contest, lambda { |contest| {:conditions => {"contesters.contest_id" => contest.id}} }
|
||||
|
|
|
@ -9,30 +9,12 @@
|
|||
<%= f.hidden_field :contester2_id %>
|
||||
|
||||
<div class="contentWide">
|
||||
<% if @challenge.errors.empty? or @challenge.server %>
|
||||
<% if @challenge.errors.empty? %>
|
||||
<h3 class="center">
|
||||
<%= namelink @challenge.contester1.team %>
|
||||
vs
|
||||
<%= namelink @challenge.contester2.team %>
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
<%= f.label :match_time %><br />
|
||||
<%= f.datetime_select :match_time %>
|
||||
</p>
|
||||
<p>
|
||||
<%= f.check_box :mandatory %>
|
||||
<%= f.label :mandatory %>
|
||||
( Default time will be following Sunday <%= @challenge.contester1.contest.default_time.strftime("%H:%M") %> )
|
||||
</p>
|
||||
<p>
|
||||
<%= f.label :server_id %><br />
|
||||
<%= f.select :server_id, Server.hlds.active.collect{|c| [c.name, c.id]} %>
|
||||
</p>
|
||||
<p>
|
||||
<%= f.label :map1_id, "Your Map" %><br />
|
||||
<%= f.select :map1_id, @challenge.contester1.contest.maps.basic.collect{|m| [m.name, m.id]} %>
|
||||
</p>
|
||||
<p>
|
||||
<%= f.label :details, "Information for the opponent" %><br />
|
||||
<%= f.text_area :details, :cols => 40, :rows => 7 %>
|
||||
|
|
60
app/views/contesters/_ladder.html.erb
Normal file
60
app/views/contesters/_ladder.html.erb
Normal file
|
@ -0,0 +1,60 @@
|
|||
<table class="contest striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="rank">Rank</th>
|
||||
<th class="movement"></th>
|
||||
<th class="flag"></th>
|
||||
<th class="team">Team</th>
|
||||
<th class="awards"></th>
|
||||
<th class="win">Win</th>
|
||||
<th class="loss">Loss</th>
|
||||
<th class="draw">Draw</th>
|
||||
<% if actions and cuser %>
|
||||
<th class="actions"></th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<% contesters = contest.contesters.active.ranked
|
||||
contesters.each_with_index do |contester, rank| %>
|
||||
<tr>
|
||||
<td><%= h rank + 1%>.</td>
|
||||
<% if contester.trend == Contester::TREND_UP %>
|
||||
<td><%= icon 'chevron-up' %></td>
|
||||
<% elsif contester.trend == Contester::TREND_DOWN %>
|
||||
<td><%= icon 'chevron-down' %></td>
|
||||
<% elsif contester.trend == Contester::TREND_FLAT %>
|
||||
<td><%= icon 'minus' %></td>
|
||||
<% else %>
|
||||
<td></td>
|
||||
<% end %>
|
||||
<td><%= flag contester.team.country %></td>
|
||||
<td><%= link_to (h contester.team.name), contester %></td>
|
||||
<td><%= icon 'trophy' if contester == contester.contest.winner %></td>
|
||||
<td><%= h contester.win %></td>
|
||||
<td><%= h contester.loss %></td>
|
||||
<td><%= h contester.draw %></td>
|
||||
<% if actions and cuser%>
|
||||
<td class="actions">
|
||||
<% if false %>
|
||||
<% current = cuser.active_contesters.of_contest(contest).first %>
|
||||
<% if current %>
|
||||
<% challenge = Challenge.new
|
||||
challenge.contester1 = current
|
||||
challenge.contester2 = contester %>
|
||||
<% if challenge.can_create? cuser %>
|
||||
<%= link_to 'C', controller: 'challenges', id: contester, action: 'new' %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% if cuser and cuser.admin? %>
|
||||
<%= link_to icon('pencil'), edit_contester_path(contester) %>
|
||||
<%= link_to icon('times'), contester, confirm: 'Are you sure?', method: :delete %>
|
||||
<% end %>
|
||||
</td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
|
@ -9,10 +9,17 @@
|
|||
<%= f.label :extra, "Extra Points" %>
|
||||
<%= f.text_field :extra %>
|
||||
</div>
|
||||
<div class="fields horizontal">
|
||||
<%= f.label :score %>
|
||||
<%= f.text_field :score %>
|
||||
</div>
|
||||
<% if @contester.contest.contest_type == Contest::TYPE_LADDER %>
|
||||
<div class="fields horizontal">
|
||||
<%= f.label :rank %>
|
||||
<%= f.text_field :score %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="fields horizontal">
|
||||
<%= f.label :score %>
|
||||
<%= f.text_field :score %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="fields horizontal">
|
||||
<%= f.label :win %>
|
||||
<%= f.text_field :win %>
|
||||
|
|
|
@ -5,7 +5,12 @@
|
|||
|
||||
<% if contest.contest_type == Contest::TYPE_BRACKET %>
|
||||
<%= render partial: "bracket", locals: { contest: contest } %>
|
||||
<% elsif contest.contest_type == Contest::TYPE_LADDER %>
|
||||
<%= render partial: "contesters/ladder",
|
||||
locals: { actions: true, contest: contest } %>
|
||||
<% else %>
|
||||
<%= render partial: "contesters/list", locals: { contesters: contest.contesters.active.ordered, actions: true } %>
|
||||
<%= render partial: "contesters/list",
|
||||
locals: { contesters: contest.contesters.active.ordered,
|
||||
actions: true, contest: contest } %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
|
@ -11,7 +11,10 @@
|
|||
<div class="wide centered">
|
||||
<% if contest.contest_type == Contest::TYPE_BRACKET %>
|
||||
<%= render :partial => "bracket", :locals => {:contest => contest} %>
|
||||
<% else %>
|
||||
<% elsif contest.contest_type == Contest::TYPE_LADDER %>
|
||||
<%= render partial: "contesters/ladder",
|
||||
locals: { actions: false, contest: contest } %>
|
||||
<% else %>
|
||||
<%= render :partial => "contesters/list", :locals => {:contesters => contest.contesters.active.ordered, :actions => false} %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
<dd>Sunday: <%= Time.use_zone(timezone_offset) { @contest.default_time.strftime("%H:%M %Z") } %></dd>
|
||||
</dl>
|
||||
|
||||
<% if @contest.contest_type == Contest::TYPE_LADDER %>
|
||||
<%= link_to 'Scoring', "/contests/#{@contest}/score", class: 'button' %>
|
||||
<% end %>
|
||||
<% if cuser and cuser.admin? %>
|
||||
<%= link_to 'Edit Contest', edit_contest_path(@contest), class: 'button' %>
|
||||
<% end %>
|
||||
|
@ -32,6 +29,9 @@
|
|||
<div class="standings">
|
||||
<% if @contest.contest_type == Contest::TYPE_BRACKET %>
|
||||
<%= render partial: 'bracket', locals: { contest: @contest } %>
|
||||
<% elsif @contest.contest_type == Contest::TYPE_LADDER %>
|
||||
<%= render partial: "contesters/ladder",
|
||||
locals: { actions: true, contest: @contest } %>
|
||||
<% else %>
|
||||
<%= render partial: 'normal' %>
|
||||
<% end %>
|
||||
|
|
Loading…
Reference in a new issue