diff --git a/app/controllers/problems_controller.rb b/app/controllers/problems_controller.rb
--- a/app/controllers/problems_controller.rb
+++ b/app/controllers/problems_controller.rb
@@ -150,11 +150,26 @@
def stat
@problem = Problem.find(params[:id])
- if !@problem.available
+ unless @problem.available or session[:admin]
redirect_to :controller => 'main', :action => 'list'
- else
- @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
+ return
end
+ @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
+
+ #stat summary
+ range =65
+ @histogram = { data: Array.new(range,0), summary: {} }
+ @histogram[:data] = Array.new(range,0)
+ user = Hash.new(0)
+ @submissions.find_each do |sub|
+ d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
+ @histogram[:data][d.to_i] += 1 if d < range
+ user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
+ end
+ @histogram[:summary][:max] = [@histogram[:data].max,1].max
+
+ @summary = { attempt: user.count, solve: 0 }
+ user.each_value { |v| @summary[:solve] += 1 if v == 1 }
end
def manage
@@ -257,4 +272,7 @@
problems
end
+ def get_problems_stat
+ end
+
end
diff --git a/app/controllers/report_controller.rb b/app/controllers/report_controller.rb
--- a/app/controllers/report_controller.rb
+++ b/app/controllers/report_controller.rb
@@ -105,91 +105,88 @@
end
end
- if @problem
- #aggregrate by language
- @by_lang = {}
- Submission.where(problem_id: @problem.id).find_each do |sub|
- lang = Language.find_by_id(sub.language_id)
- next unless lang
- next unless sub.points >= @problem.full_score
+ return unless @problem
+
+ @by_lang = {} #aggregrate by language
- #initialize
- unless @by_lang.has_key?(lang.pretty_name)
- @by_lang[lang.pretty_name] = {
- runtime: { avail: false, value: 2**30-1 },
- memory: { avail: false, value: 2**30-1 },
- length: { avail: false, value: 2**30-1 },
- first: { avail: false, value: DateTime.new(3000,1,1) }
- }
- end
+ range =65
+ @histogram = { data: Array.new(range,0), summary: {} }
+ @histogram[:data] = Array.new(range,0)
+ @summary = {count: 0, solve: 0, attempt: 0}
+ user = Hash.new(0)
+ Submission.where(problem_id: @problem.id).find_each do |sub|
+ #histogram
+ d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
+ @histogram[:data][d.to_i] += 1 if d < range
- if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
- @by_lang[lang.pretty_name][:runtime] = {
- avail: true,
- user_id: sub.user_id,
- value: sub.max_runtime,
- sub_id: sub.id
- }
- end
+ @summary[:count] += 1
+ user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
- if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
- @by_lang[lang.pretty_name][:memory] = {
- avail: true,
- user_id: sub.user_id,
- value: sub.peak_memory,
- sub_id: sub.id
- }
- end
+ lang = Language.find_by_id(sub.language_id)
+ next unless lang
+ next unless sub.points >= @problem.full_score
- if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
- !sub.user.admin?
- @by_lang[lang.pretty_name][:first] = {
- avail: true,
- user_id: sub.user_id,
- value: sub.submitted_at,
- sub_id: sub.id
- }
- end
+ #initialize
+ unless @by_lang.has_key?(lang.pretty_name)
+ @by_lang[lang.pretty_name] = {
+ runtime: { avail: false, value: 2**30-1 },
+ memory: { avail: false, value: 2**30-1 },
+ length: { avail: false, value: 2**30-1 },
+ first: { avail: false, value: DateTime.new(3000,1,1) }
+ }
+ end
- if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
- @by_lang[lang.pretty_name][:length] = {
- avail: true,
- user_id: sub.user_id,
- value: sub.effective_code_length,
- sub_id: sub.id
- }
- end
- end
-
- #process user_id
- @by_lang.each do |lang,prop|
- prop.each do |k,v|
- v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
- end
+ if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
+ @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
end
- #sum into best
- if @by_lang and @by_lang.first
- @best = @by_lang.first[1].clone
- @by_lang.each do |lang,prop|
- if @best[:runtime][:value] >= prop[:runtime][:value]
- @best[:runtime] = prop[:runtime]
- @best[:runtime][:lang] = lang
- end
- if @best[:memory][:value] >= prop[:memory][:value]
- @best[:memory] = prop[:memory]
- @best[:memory][:lang] = lang
- end
- if @best[:length][:value] >= prop[:length][:value]
- @best[:length] = prop[:length]
- @best[:length][:lang] = lang
- end
- if @best[:first][:value] >= prop[:first][:value]
- @best[:first] = prop[:first]
- @best[:first][:lang] = lang
- end
+ if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
+ @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
+ end
+
+ if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
+ !sub.user.admin?
+ @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
+ end
+
+ if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
+ @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
+ end
+ end
+
+ #process user_id
+ @by_lang.each do |lang,prop|
+ prop.each do |k,v|
+ v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
+ end
+ end
+
+ #sum into best
+ if @by_lang and @by_lang.first
+ @best = @by_lang.first[1].clone
+ @by_lang.each do |lang,prop|
+ if @best[:runtime][:value] >= prop[:runtime][:value]
+ @best[:runtime] = prop[:runtime]
+ @best[:runtime][:lang] = lang
+ end
+ if @best[:memory][:value] >= prop[:memory][:value]
+ @best[:memory] = prop[:memory]
+ @best[:memory][:lang] = lang
+ end
+ if @best[:length][:value] >= prop[:length][:value]
+ @best[:length] = prop[:length]
+ @best[:length][:lang] = lang
+ end
+ if @best[:first][:value] >= prop[:first][:value]
+ @best[:first] = prop[:first]
+ @best[:first][:lang] = lang
end
end
end
+
+ @histogram[:summary][:max] = [@histogram[:data].max,1].max
+ @summary[:attempt] = user.count
+ user.each_value { |v| @summary[:solve] += 1 if v == 1 }
end
+
end
diff --git a/app/models/problem.rb b/app/models/problem.rb
--- a/app/models/problem.rb
+++ b/app/models/problem.rb
@@ -54,6 +54,13 @@
def self.download_file_basedir
return "#{Rails.root}/data/tasks"
end
+
+ def get_submission_stat
+ result = Hash.new
+ #total number of submission
+ result[:total_sub] = Submission.where(problem_id: self.id).count
+ result[:attempted_user] = Submission.where(problem_id: self.id).group_by(:user_id)
+ end
protected
diff --git a/app/views/application/_bar_graph.html.haml b/app/views/application/_bar_graph.html.haml
new file mode 100644
--- /dev/null
+++ b/app/views/application/_bar_graph.html.haml
@@ -0,0 +1,44 @@
+- param = {} unless param
+- graph_height = param[:graph_height] || 100
+- bar_width = param[:bar_width] || 14
+- graph_width = (bar_width * histogram[:data].count) + 20
+:css
+ .hist_bar {
+ width: #{bar_width-1}px;
+ position: absolute;
+ background-color: lightblue;
+ }
+ .hist_fill {
+ width: #{bar_width-1}px;
+ position: absolute;
+ background-color: #eee;
+ }
+ .hist_text {
+ position: absolute;
+ font-size:5px;
+ }
+
+%div{style: "position: relative; width: #{graph_width}px; height: 150px; background-color:#fff;" }
+ //draw background
+ - histogram[:data].each_index do |i|
+ - height = histogram[:data][i] * graph_height / histogram[:summary][:max]
+ - top = graph_height - height
+ - left = graph_width - (i+1)*bar_width
+ %div.hist_fill{style: "top: 0px; height: #{graph_height - height}px; left: #{left}px;" }
+ // draw horizontal line
+ - line = 3
+ - line.times do |i|
+ - top = graph_height - graph_height * (i+0.5)/ line
+ %div{style: "position:absolute;width: #{graph_width-21}px;height: 1px;left: 20px;top:#{top}px;background-color: #333;"}
+ %div.hist_text{style: "position:absolute;left: 0px;top:#{top-6}px"}
+ =((i+0.5) * histogram[:summary][:max] / line).to_i
+ // draw the actual bar and text
+ - @histogram[:data].each_index do |i|
+ - height = histogram[:data][i] * graph_height / histogram[:summary][:max]
+ - top = graph_height - height
+ - left = graph_width - (i+1)*bar_width
+ %div.hist_bar{style: "top: #{top}px; height: #{height}px; left: #{left}px; dae: #{histogram[:data][i]}" }
+ - if i % 7 == 1
+ %div.hist_text{style: "top:#{graph_height + 5}px;left: #{left}px;"} #{(Time.zone.today - i.day).strftime('%-d')}
+ - if (Time.now.in_time_zone - i.day).day == 15
+ %div.hist_text{style: "top:#{graph_height + 15}px;left: #{left}px;"} #{(Time.zone.today - i.day).strftime('%b')}
diff --git a/app/views/problems/stat.html.haml b/app/views/problems/stat.html.haml
--- a/app/views/problems/stat.html.haml
+++ b/app/views/problems/stat.html.haml
@@ -6,6 +6,23 @@
%h1 Problem stat: #{@problem.name}
%h2 Overview
+
+%table.info
+ %thead
+ %tr.info-head
+ %th Stat
+ %th Value
+ %tbody
+ %tr{class: cycle('info-even','info-odd')}
+ %td Submissions
+ %td= @submissions.count
+ %tr{class: cycle('info-even','info-odd')}
+ %td Solved/Attempted User
+ %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
+
+%h2 Submissions Count
+= render partial: 'application/bar_graph', locals: { histogram: @histogram }
+
%h2 Submissions
- if @submissions and @submissions.count > 0
%table.info#main_table
diff --git a/app/views/report/_task_hof.html.haml b/app/views/report/_task_hof.html.haml
--- a/app/views/report/_task_hof.html.haml
+++ b/app/views/report/_task_hof.html.haml
@@ -2,47 +2,66 @@
.hof_user { color: orangered; font-style: italic; }
.hof_language { color: green; font-style: italic; }
.hof_value { color: deeppink;font-style: italic; }
+ .info_param { font-weight: bold;text-align: right; }
-%h2 Overall of #{Problem.find(params[:id]).full_name}
+%h1 (#{Problem.find(params[:id]).name}) #{Problem.find(params[:id]).full_name}
+
+%h2 Problem Stat
+%table.info
+ %thead
+ %tr.info-head
+ %th Stat
+ %th Value
+ %tbody
+ %tr{class: cycle('info-even','info-odd')}
+ %td.info_param Submissions
+ %td= @summary[:count]
+ %tr{class: cycle('info-even','info-odd')}
+ %td.info_param Solved/Attempted User
+ %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
+ - if @best
+ %tr{class: cycle('info-even','info-odd')}
+ %td.info_param Best Runtime
+ %td
+ by #{link_to @best[:runtime][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
+ using #{@best[:runtime][:lang]}
+ with #{@best[:runtime][:value] * 1000} milliseconds
+ at submission
+ = link_to("#" + @best[:runtime][:sub_id].to_s, controller: 'graders', action: 'submission', id:@best[:runtime][:sub_id])
+
+ %tr{class: cycle('info-even','info-odd')}
+ %td.info_param Best Memory Usage
+ %td
+ by #{link_to @best[:memory][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
+ using #{@best[:memory][:lang]}
+ with #{number_with_delimiter(@best[:memory][:value])} kbytes
+ at submission
+ = link_to("#" + @best[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id:@best[:memory][:sub_id])
+
+ %tr{class: cycle('info-even','info-odd')}
+ %td.info_param Shortest Code
+ %td
+ by #{link_to @best[:length][:user], controller:'users', action:'profile', id:@best[:length][:user_id]}
+ using #{@best[:length][:lang]}
+ with #{@best[:length][:value]} bytes
+ at submission
+ = link_to("#" + @best[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:length][:sub_id])
+
+ %tr{class: cycle('info-even','info-odd')}
+ %td.info_param First solver
+ %td
+ #{link_to @best[:first][:user], controller:'users', action:'profile', id:@best[:first][:user_id]} is the first solver
+ using #{@best[:first][:lang]}
+ on #{@best[:first][:value]}
+ at submission
+ = link_to("#" + @best[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:first][:sub_id])
+
+
+%p
+ This counts only for submission with 100% score
+ Right now, java is excluded from memory usage competition. (Because it always uses 2GB memory...)
- if @best
- %b Best Runtime:
- by #{link_to @best[:runtime][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
- using #{@best[:runtime][:lang]}
- with #{@best[:runtime][:value] * 1000} milliseconds
- at submission
- = link_to("#" + @best[:runtime][:sub_id].to_s, controller: 'graders', action: 'submission', id:@best[:runtime][:sub_id])
- %br/
-
- %b Best Memory Usage:
- by #{link_to @best[:memory][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
- using #{@best[:memory][:lang]}
- with #{number_with_delimiter(@best[:memory][:value])} kbytes
- at submission
- = link_to("#" + @best[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id:@best[:memory][:sub_id])
- %br/
-
- %b Shortest Code:
- by #{link_to @best[:length][:user], controller:'users', action:'profile', id:@best[:length][:user_id]}
- using #{@best[:length][:lang]}
- with #{@best[:length][:value]} bytes
- at submission
- = link_to("#" + @best[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:length][:sub_id])
- %br/
-
- %b First solver:
- #{link_to @best[:first][:user], controller:'users', action:'profile', id:@best[:first][:user_id]} is the first solver
- using #{@best[:first][:lang]}
- on #{@best[:first][:value]}
- at submission
- = link_to("#" + @best[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:first][:sub_id])
- %br/
-
-
- %p
- This counts only for submission with 100% score
- Right now, java is excluded from memory usage competition. (Because it always uses 2GB memory...)
-
%h2 By language
%table.info
@@ -75,5 +94,3 @@
= "(#{value[:first][:value]} @"
= "#{link_to("#" + value[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:first][:sub_id])} )".html_safe
-- else
- %h3 No submissions
diff --git a/app/views/report/problem_hof.html.haml b/app/views/report/problem_hof.html.haml
--- a/app/views/report/problem_hof.html.haml
+++ b/app/views/report/problem_hof.html.haml
@@ -6,7 +6,7 @@
/ %h1 All-Time Hall of Fame
-%h1 Tasks Hall of Fame
+%h1 Hall of Fame
.task-menu
Tasks
%br/
@@ -18,5 +18,6 @@
Please select a problem.
- else
=render partial: 'task_hof'
+ %h2 Submission History
+ =render partial: 'application/bar_graph', locals: { histogram: @histogram }
-