Implement projected time
This commit is contained in:
@@ -26,9 +26,7 @@ class CompletionsController < ApplicationController
|
||||
@completion = Completion.new(completion_params)
|
||||
@completion.contest_id = @contest.id
|
||||
if @completion.save
|
||||
if @completion.display_time_from_start.present?
|
||||
extend_completions!(@completion.contestant)
|
||||
end
|
||||
extend_completions!(@completion.contestant)
|
||||
if @contestant && !params[:completion].key?(:message_id)
|
||||
redirect_to edit_contest_contestant_path(@contest, @contestant), notice: t("completions.new.notice")
|
||||
else
|
||||
|
||||
@@ -9,24 +9,38 @@ module CompletionsConcern
|
||||
end
|
||||
|
||||
def display_time(time)
|
||||
if time == nil
|
||||
return ""
|
||||
end
|
||||
h = time / 3600
|
||||
m = (time % 3600) / 60
|
||||
s = (time % 3600) % 60
|
||||
if h > 0
|
||||
return h.to_s + ":" + pad(m) + ":" + pad(s)
|
||||
elsif m > 0
|
||||
return m.to_s + ":" + pad(s)
|
||||
end
|
||||
s.to_s
|
||||
m.to_s + ":" + pad(s)
|
||||
end
|
||||
|
||||
def extend_completions!(contestant)
|
||||
current_time_from_start = 0
|
||||
contestant.completions.order(:time_seconds).each do |completion|
|
||||
completion.update(display_time_from_start: display_time(completion.time_seconds),
|
||||
display_relative_time: display_time(completion.time_seconds - current_time_from_start))
|
||||
current_time_from_start = completion.time_seconds
|
||||
completions = contestant.completions
|
||||
puzzles = contestant.contest.puzzles
|
||||
if puzzles.length > 1
|
||||
current_time_from_start = 0
|
||||
completions.order(:time_seconds).each do |completion|
|
||||
completion.update(display_time_from_start: display_time(completion.time_seconds),
|
||||
display_relative_time: display_time(completion.time_seconds - current_time_from_start))
|
||||
current_time_from_start = completion.time_seconds
|
||||
end
|
||||
contestant.update(display_time: display_time(current_time_from_start), time_seconds: current_time_from_start)
|
||||
elsif puzzles.length == 1 && completions.length >= 1
|
||||
if completions[0].remaining_pieces != nil
|
||||
contestant.update(
|
||||
display_time: "#{display_time(completions[0].time_seconds)} - #{puzzles[0].pieces - completions[0].remaining_pieces}p",
|
||||
time_seconds: completions[0].projected_time
|
||||
)
|
||||
else
|
||||
contestant.update(display_time: display_time(completions[0].time_seconds), time_seconds: completions[0].time_seconds)
|
||||
end
|
||||
end
|
||||
contestant.update(display_time: display_time(current_time_from_start), time_seconds: current_time_from_start)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -160,6 +160,7 @@ class ContestsController < ApplicationController
|
||||
contestant = Contestant.create(contest: @contest, name: @offline.name, offline: @offline)
|
||||
Completion.create(contest: @contest,
|
||||
contestant: contestant,
|
||||
offline: @offline,
|
||||
puzzle: @contest.puzzles[0],
|
||||
completed: @offline.completed,
|
||||
display_time_from_start: dp,
|
||||
|
||||
@@ -7,14 +7,15 @@ module ContestsHelper
|
||||
end
|
||||
|
||||
def display_time(time)
|
||||
if time == nil
|
||||
return ""
|
||||
end
|
||||
h = time / 3600
|
||||
m = (time % 3600) / 60
|
||||
s = (time % 3600) % 60
|
||||
if h > 0
|
||||
return h.to_s + ":" + pad(m) + ":" + pad(s)
|
||||
elsif m > 0
|
||||
return m.to_s + ":" + pad(s)
|
||||
end
|
||||
"0:" + pad(s)
|
||||
m.to_s + ":" + pad(s)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
# display_relative_time :string
|
||||
# display_time_from_start :string
|
||||
# missing_pieces :integer
|
||||
# projected_time :integer
|
||||
# remaining_pieces :integer
|
||||
# time_seconds :integer
|
||||
# created_at :datetime not null
|
||||
@@ -36,11 +37,12 @@ class Completion < ApplicationRecord
|
||||
belongs_to :puzzle
|
||||
belongs_to :message, optional: true
|
||||
|
||||
before_save :add_time_seconds, if: -> { display_time_from_start.present? }
|
||||
before_save :nullify_display_time
|
||||
before_save :clean_pieces
|
||||
has_one :offline, dependent: :destroy
|
||||
|
||||
validates :display_time_from_start, presence: true, format: { with: /\A(((\d\d|\d):\d\d|\d\d|\d):\d\d|\d\d|\d)\z/ }, if: -> { completed }
|
||||
before_save :clean_pieces
|
||||
before_save :compute_projected_time
|
||||
|
||||
validates :display_time_from_start, presence: true, format: { with: /\A(((\d\d|\d):\d\d|\d\d|\d):\d\d|\d\d|\d)\z/ }
|
||||
validates :remaining_pieces, presence: true, if: -> { !completed }
|
||||
validates :contestant_id, uniqueness: { scope: :puzzle }, if: -> { contest.puzzles.size == 1 }
|
||||
validates :puzzle_id, uniqueness: { scope: :contestant }, if: -> { contest.puzzles.size > 1 }
|
||||
@@ -53,21 +55,18 @@ class Completion < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def nullify_display_time
|
||||
if self.remaining_pieces
|
||||
self.display_time_from_start = nil
|
||||
self.display_relative_time = nil
|
||||
end
|
||||
end
|
||||
|
||||
def add_time_seconds
|
||||
arr = display_time_from_start.split(":")
|
||||
if arr.size == 3
|
||||
self.time_seconds = arr[0].to_i * 3600 + arr[1].to_i * 60 + arr[2].to_i
|
||||
elsif arr.size == 2
|
||||
self.time_seconds = arr[0].to_i * 60 + arr[1].to_i
|
||||
elsif arr.size == 1
|
||||
self.time_seconds = arr[0].to_i
|
||||
if display_time_from_start.present?
|
||||
arr = display_time_from_start.split(":")
|
||||
if arr.size == 3
|
||||
self.time_seconds = arr[0].to_i * 3600 + arr[1].to_i * 60 + arr[2].to_i
|
||||
elsif arr.size == 2
|
||||
self.time_seconds = arr[0].to_i * 60 + arr[1].to_i
|
||||
elsif arr.size == 1
|
||||
self.time_seconds = arr[0].to_i
|
||||
end
|
||||
else
|
||||
self.time_seconds = 1
|
||||
end
|
||||
end
|
||||
|
||||
@@ -78,4 +77,16 @@ class Completion < ApplicationRecord
|
||||
self.missing_pieces = nil
|
||||
end
|
||||
end
|
||||
|
||||
def compute_projected_time
|
||||
add_time_seconds
|
||||
if self.completed
|
||||
self.projected_time = self.time_seconds
|
||||
elsif self.offline.present?
|
||||
assembled_time = self.time_seconds
|
||||
assembled_pieces = self.puzzle.pieces - self.remaining_pieces
|
||||
pieces_per_second = assembled_pieces.to_f / assembled_time.to_f
|
||||
self.projected_time = assembled_time + Integer(self.remaining_pieces.to_f / pieces_per_second)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
#
|
||||
# Table name: contestants
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# display_time :string
|
||||
# email :string
|
||||
# name :string
|
||||
# time_seconds :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# contest_id :integer not null
|
||||
# id :integer not null, primary key
|
||||
# display_time :string
|
||||
# email :string
|
||||
# name :string
|
||||
# projected_time :string
|
||||
# time_seconds :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# contest_id :integer not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
@@ -22,7 +23,7 @@
|
||||
class Contestant < ApplicationRecord
|
||||
belongs_to :contest
|
||||
has_many :completions, dependent: :destroy
|
||||
has_one :offline
|
||||
has_one :offline, dependent: :destroy
|
||||
has_and_belongs_to_many :categories
|
||||
|
||||
before_validation :initialize_time_seconds_if_empty
|
||||
|
||||
@@ -12,22 +12,26 @@
|
||||
# submitted :boolean
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# completion_id :integer
|
||||
# contest_id :integer not null
|
||||
# contestant_id :integer
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_offlines_on_completion_id (completion_id)
|
||||
# index_offlines_on_contest_id (contest_id)
|
||||
# index_offlines_on_contestant_id (contestant_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# completion_id (completion_id => completions.id)
|
||||
# contest_id (contest_id => contests.id)
|
||||
# contestant_id (contestant_id => contestants.id)
|
||||
#
|
||||
class Offline < ApplicationRecord
|
||||
belongs_to :contest
|
||||
belongs_to :contestant, optional: true
|
||||
belongs_to :completion, optional: true
|
||||
|
||||
has_many_attached :images
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
table.table.table-striped.table-hover
|
||||
thead
|
||||
tr
|
||||
th scope="col"
|
||||
= t("activerecord.attributes.completion.completed")
|
||||
- if @contest.puzzles.size > 1
|
||||
th scope="col"
|
||||
= t("activerecord.attributes.completion.display_time_from_start")
|
||||
@@ -44,6 +46,8 @@
|
||||
- else
|
||||
th scope="col"
|
||||
= t("activerecord.attributes.completion.display_time")
|
||||
th scope="col"
|
||||
= t("activerecord.attributes.completion.projected_time")
|
||||
th scope="col"
|
||||
= t("activerecord.attributes.completion.missing_pieces")
|
||||
th scope="col"
|
||||
@@ -54,10 +58,19 @@
|
||||
- @completions.each do |completion|
|
||||
tr scope="row"
|
||||
td
|
||||
= completion.display_time_from_start
|
||||
- if completion.completed
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check-square" viewBox="0 0 16 16">
|
||||
<path d="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/>
|
||||
<path d="M10.97 4.97a.75.75 0 0 1 1.071 1.05l-3.992 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425z"/>
|
||||
</svg>
|
||||
td
|
||||
= display_time(completion.time_seconds)
|
||||
- if @contest.puzzles.size > 1
|
||||
td
|
||||
= completion.display_relative_time
|
||||
- else
|
||||
td
|
||||
= display_time(completion.projected_time)
|
||||
td
|
||||
= completion.missing_pieces
|
||||
td
|
||||
|
||||
@@ -47,11 +47,11 @@ css:
|
||||
td
|
||||
= contestant.completions.where(remaining_pieces: nil).length
|
||||
td style="position: relative"
|
||||
- if index > 0 && contestant.time_seconds > 0 && contestant.completions.where(remaining_pieces: nil).size > 0
|
||||
.relative-time style="position:absolute; margin: 1px 0 0 64px; font-size: 14px; color: grey"
|
||||
- if index > 0 && contestant.time_seconds > 0 && contestant.completions.where(completed: true).size > 0
|
||||
.relative-time style="position:absolute; margin: 1px 0 0 100px; font-size: 14px; color: grey"
|
||||
|> +
|
||||
= display_time(contestant.time_seconds - @contestants[index - 1].time_seconds)
|
||||
= contestant.completions.size > 0 && contestant.completions[-1].remaining_pieces ? "#{contestant.completions.map{|completion| completion.puzzle.pieces}.sum - contestant.completions[-1].remaining_pieces}p" : contestant.display_time
|
||||
= contestant.display_time
|
||||
.col-1
|
||||
.col-5
|
||||
- @contest.puzzles.each do |puzzle|
|
||||
|
||||
Reference in New Issue
Block a user