Description:
grades contest submissions
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r385:865ba2aed5c0 - - 3 files changed: 73 inserted, 25 deleted

@@ -0,0 +1,47
1 + #!/usr/bin/env ruby
2 +
3 + APP_PATH = File.expand_path('../../config/application', __FILE__)
4 + require File.expand_path('../../config/boot', __FILE__)
5 + require APP_PATH
6 +
7 + # set Rails.env here if desired
8 + Rails.application.require_environment!
9 +
10 + def main
11 + if ARGV.length != 1
12 + puts "Usage: contest_grade_prob.rb [problem_name]"
13 + exit(0)
14 + end
15 +
16 + problem_name = ARGV[0]
17 + problem = Problem.where(:name => problem_name).first
18 + if !problem
19 + puts "Problem not found"
20 + exit(0)
21 + end
22 +
23 + problem.full_score = 100
24 + problem.save
25 +
26 + test_pair = TestPair.get_for(problem, true)
27 +
28 + User.all.each do |u|
29 + puts "#{u.login}:"
30 + submissions = Submission.find_all_by_user_problem(u.id, problem.id)
31 + submissions.each do |sub|
32 + result = test_pair.grade(sub.output)
33 + result2 = test_pair.grade(sub.source)
34 + if result2[:score] > result[:score]
35 + result = result2
36 + puts "Use source field (#{sub.id})"
37 + end
38 +
39 + full_score = result[:full_score]
40 + sub.points = result[:score]*100 / full_score
41 + sub.grader_comment = result[:msg]
42 + sub.save
43 + end
44 + end
45 + end
46 +
47 + main
@@ -193,228 +193,204
193 if !FileTest.exists?(out_filename)
193 if !FileTest.exists?(out_filename)
194 flash[:notice] = 'Output not found.'
194 flash[:notice] = 'Output not found.'
195 redirect_to :action => 'list' and return
195 redirect_to :action => 'list' and return
196 end
196 end
197
197
198 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
198 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
199 response.headers['Content-Type'] = "application/force-download"
199 response.headers['Content-Type'] = "application/force-download"
200 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
200 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
201 response.headers["X-Sendfile"] = out_filename
201 response.headers["X-Sendfile"] = out_filename
202 response.headers['Content-length'] = File.size(out_filename)
202 response.headers['Content-length'] = File.size(out_filename)
203 render :nothing => true
203 render :nothing => true
204 else
204 else
205 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
205 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
206 end
206 end
207 end
207 end
208
208
209 def error
209 def error
210 @user = User.find(session[:user_id])
210 @user = User.find(session[:user_id])
211 end
211 end
212
212
213 # announcement refreshing and hiding methods
213 # announcement refreshing and hiding methods
214
214
215 def announcements
215 def announcements
216 if params.has_key? 'recent'
216 if params.has_key? 'recent'
217 prepare_announcements(params[:recent])
217 prepare_announcements(params[:recent])
218 else
218 else
219 prepare_announcements
219 prepare_announcements
220 end
220 end
221 render(:partial => 'announcement',
221 render(:partial => 'announcement',
222 :collection => @announcements,
222 :collection => @announcements,
223 :locals => {:announcement_effect => true})
223 :locals => {:announcement_effect => true})
224 end
224 end
225
225
226 def confirm_contest_start
226 def confirm_contest_start
227 user = User.find(session[:user_id])
227 user = User.find(session[:user_id])
228 if request.method == 'POST'
228 if request.method == 'POST'
229 user.update_start_time
229 user.update_start_time
230 redirect_to :action => 'list'
230 redirect_to :action => 'list'
231 else
231 else
232 @contests = user.contests
232 @contests = user.contests
233 @user = user
233 @user = user
234 end
234 end
235 end
235 end
236
236
237 # thailandoi contests
237 # thailandoi contests
238
238
239 def verifying_testcase
239 def verifying_testcase
240 problem = Problem.find(params[:id])
240 problem = Problem.find(params[:id])
241 if !problem.available
241 if !problem.available
242 flash[:notice] = 'Error: problem is not available'
242 flash[:notice] = 'Error: problem is not available'
243 redirect_to :action => 'list'
243 redirect_to :action => 'list'
244 else
244 else
245 test_pair = TestPair.get_for(problem, false)
245 test_pair = TestPair.get_for(problem, false)
246 send_data(test_pair.input,
246 send_data(test_pair.input,
247 {:filename => problem.name + '-verifying-input.txt',
247 {:filename => problem.name + '-verifying-input.txt',
248 :type => 'text/plain'})
248 :type => 'text/plain'})
249 end
249 end
250 end
250 end
251
251
252 def testcase
252 def testcase
253 problem = Problem.find(params[:id])
253 problem = Problem.find(params[:id])
254 if !problem.available
254 if !problem.available
255 flash[:notice] = 'Error: problem is not available'
255 flash[:notice] = 'Error: problem is not available'
256 redirect_to :action => 'list'
256 redirect_to :action => 'list'
257 else
257 else
258 test_pair = TestPair.get_for(problem, true)
258 test_pair = TestPair.get_for(problem, true)
259
259
260 user = User.find(session[:user_id])
260 user = User.find(session[:user_id])
261 assignment = user.get_test_pair_assignment_for(problem)
261 assignment = user.get_test_pair_assignment_for(problem)
262
262
263 if !assignment
263 if !assignment
264 assignment = TestPairAssignment.create_for(user, problem, test_pair)
264 assignment = TestPairAssignment.create_for(user, problem, test_pair)
265 assignment.save
265 assignment.save
266 end
266 end
267
267
268 send_data(test_pair.input,
268 send_data(test_pair.input,
269 {:filename => problem.name + '-input.txt',
269 {:filename => problem.name + '-input.txt',
270 :type => 'text/plain'})
270 :type => 'text/plain'})
271 end
271 end
272 end
272 end
273
273
274 def verifying_submit
274 def verifying_submit
275 user = User.find(session[:user_id])
275 user = User.find(session[:user_id])
276 problem_id = params[:id]
276 problem_id = params[:id]
277 problem = Problem.find(problem_id)
277 problem = Problem.find(problem_id)
278
278
279 if !problem or !problem.available
279 if !problem or !problem.available
280 flash[:notice] = 'Error: problem is not available'
280 flash[:notice] = 'Error: problem is not available'
281 redirect_to :action => 'list' and return
281 redirect_to :action => 'list' and return
282 end
282 end
283
283
284 @current_problem = problem
284 @current_problem = problem
285 test_pair = TestPair.get_for(problem, false)
285 test_pair = TestPair.get_for(problem, false)
286 if (params['output_file']) and (params['output_file']!='')
286 if (params['output_file']) and (params['output_file']!='')
287 output = params['output_file'].read
287 output = params['output_file'].read
288
288
289 - @grading_result = grade(output, test_pair.solution)
289 + @grading_result = test_pair.grade(output)
290 prepare_list_information
290 prepare_list_information
291 render :action => 'list' and return
291 render :action => 'list' and return
292 else
292 else
293 flash[:notice] = 'Error: output file errors'
293 flash[:notice] = 'Error: output file errors'
294 prepare_list_information
294 prepare_list_information
295 render :action => 'list' and return
295 render :action => 'list' and return
296 end
296 end
297 end
297 end
298
298
299 protected
299 protected
300
300
301 - def grade(output, solution)
302 - out_items = output.split("\n")
303 - sol_items = solution.split("\n")
304 - res = ''
305 - f = 0
306 - s = 0
307 - sol_items.length.times do |i|
308 - f += 1
309 - si = sol_items[i].chomp
310 - if out_items[i]
311 - oi = out_items[i].chomp
312 - else
313 - oi = ''
314 - end
315 - if oi == si
316 - res = res + 'P'
317 - s += 1
318 - else
319 - res = res + '-'
320 - end
321 - end
322 - return { :score => s, :full_score => f, :msg => res }
323 - end
324 -
325 def prepare_announcements(recent=nil)
301 def prepare_announcements(recent=nil)
326 if GraderConfiguration.show_tasks_to?(@user)
302 if GraderConfiguration.show_tasks_to?(@user)
327 @announcements = Announcement.find_published(true)
303 @announcements = Announcement.find_published(true)
328 else
304 else
329 @announcements = Announcement.find_published
305 @announcements = Announcement.find_published
330 end
306 end
331 if recent!=nil
307 if recent!=nil
332 recent_id = recent.to_i
308 recent_id = recent.to_i
333 @announcements = @announcements.find_all { |a| a.id > recent_id }
309 @announcements = @announcements.find_all { |a| a.id > recent_id }
334 end
310 end
335 end
311 end
336
312
337 def prepare_timeout_information(problems)
313 def prepare_timeout_information(problems)
338 @submission_timeouts = {}
314 @submission_timeouts = {}
339 problems.each do |problem|
315 problems.each do |problem|
340 assignment = @user.get_test_pair_assignment_for(problem)
316 assignment = @user.get_test_pair_assignment_for(problem)
341 if assignment == nil
317 if assignment == nil
342 timeout = nil
318 timeout = nil
343 else
319 else
344 if (assignment.expired?) or (assignment.submitted)
320 if (assignment.expired?) or (assignment.submitted)
345 timeout = 0
321 timeout = 0
346 else
322 else
347 timeout = assignment.created_at + TEST_ASSIGNMENT_EXPIRATION_DURATION - Time.new.gmtime
323 timeout = assignment.created_at + TEST_ASSIGNMENT_EXPIRATION_DURATION - Time.new.gmtime
348 end
324 end
349 end
325 end
350 @submission_timeouts[problem.id] = timeout
326 @submission_timeouts[problem.id] = timeout
351 end
327 end
352 end
328 end
353
329
354 def prepare_list_information
330 def prepare_list_information
355 @user = User.find(session[:user_id])
331 @user = User.find(session[:user_id])
356 if not GraderConfiguration.multicontests?
332 if not GraderConfiguration.multicontests?
357 @problems = @user.available_problems
333 @problems = @user.available_problems
358 else
334 else
359 @contest_problems = @user.available_problems_group_by_contests
335 @contest_problems = @user.available_problems_group_by_contests
360 @problems = @user.available_problems
336 @problems = @user.available_problems
361 end
337 end
362 @prob_submissions = {}
338 @prob_submissions = {}
363 @problems.each do |p|
339 @problems.each do |p|
364 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
340 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
365 if sub!=nil
341 if sub!=nil
366 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
342 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
367 else
343 else
368 @prob_submissions[p.id] = { :count => 0, :submission => nil }
344 @prob_submissions[p.id] = { :count => 0, :submission => nil }
369 end
345 end
370 end
346 end
371 prepare_announcements
347 prepare_announcements
372 prepare_timeout_information(@problems)
348 prepare_timeout_information(@problems)
373 end
349 end
374
350
375 def check_viewability
351 def check_viewability
376 @user = User.find(session[:user_id])
352 @user = User.find(session[:user_id])
377 if (!GraderConfiguration.show_tasks_to?(@user)) and
353 if (!GraderConfiguration.show_tasks_to?(@user)) and
378 ((action_name=='submission') or (action_name=='submit'))
354 ((action_name=='submission') or (action_name=='submit'))
379 redirect_to :action => 'list' and return
355 redirect_to :action => 'list' and return
380 end
356 end
381 end
357 end
382
358
383 def prepare_grading_result(submission)
359 def prepare_grading_result(submission)
384 if GraderConfiguration.task_grading_info.has_key? submission.problem.name
360 if GraderConfiguration.task_grading_info.has_key? submission.problem.name
385 grading_info = GraderConfiguration.task_grading_info[submission.problem.name]
361 grading_info = GraderConfiguration.task_grading_info[submission.problem.name]
386 else
362 else
387 # guess task info from problem.full_score
363 # guess task info from problem.full_score
388 cases = submission.problem.full_score / 10
364 cases = submission.problem.full_score / 10
389 grading_info = {
365 grading_info = {
390 'testruns' => cases,
366 'testruns' => cases,
391 'testcases' => cases
367 'testcases' => cases
392 }
368 }
393 end
369 end
394 @test_runs = []
370 @test_runs = []
395 if grading_info['testruns'].is_a? Integer
371 if grading_info['testruns'].is_a? Integer
396 trun_count = grading_info['testruns']
372 trun_count = grading_info['testruns']
397 trun_count.times do |i|
373 trun_count.times do |i|
398 @test_runs << [ read_grading_result(@user.login,
374 @test_runs << [ read_grading_result(@user.login,
399 submission.problem.name,
375 submission.problem.name,
400 submission.id,
376 submission.id,
401 i+1) ]
377 i+1) ]
402 end
378 end
403 else
379 else
404 grading_info['testruns'].keys.sort.each do |num|
380 grading_info['testruns'].keys.sort.each do |num|
405 run = []
381 run = []
406 testrun = grading_info['testruns'][num]
382 testrun = grading_info['testruns'][num]
407 testrun.each do |c|
383 testrun.each do |c|
408 run << read_grading_result(@user.login,
384 run << read_grading_result(@user.login,
409 submission.problem.name,
385 submission.problem.name,
410 submission.id,
386 submission.id,
411 c)
387 c)
412 end
388 end
413 @test_runs << run
389 @test_runs << run
414 end
390 end
415 end
391 end
416 end
392 end
417
393
418 def grading_result_dir(user_name, problem_name, submission_id, case_num)
394 def grading_result_dir(user_name, problem_name, submission_id, case_num)
419 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
395 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
420 end
396 end
@@ -1,8 +1,33
1 class TestPair < ActiveRecord::Base
1 class TestPair < ActiveRecord::Base
2 belongs_to :problem
2 belongs_to :problem
3
3
4 def self.get_for(problem, is_private)
4 def self.get_for(problem, is_private)
5 return TestPair.where(:problem_id => problem.id,
5 return TestPair.where(:problem_id => problem.id,
6 :is_private => is_private).first
6 :is_private => is_private).first
7 end
7 end
8 +
9 + def grade(output)
10 + out_items = output.split("\n")
11 + sol_items = solution.split("\n")
12 + res = ''
13 + f = 0
14 + s = 0
15 + sol_items.length.times do |i|
16 + f += 1
17 + si = sol_items[i].chomp
18 + if out_items[i]
19 + oi = out_items[i].chomp
20 + else
21 + oi = ''
22 + end
23 + if oi == si
24 + res = res + 'P'
25 + s += 1
26 + else
27 + res = res + '-'
28 + end
29 + end
30 + return { :score => s, :full_score => f, :msg => res }
31 + end
32 +
8 end
33 end
You need to be logged in to leave comments. Login now