Description:
import original files
git-svn-id: http://theory.cpe.ku.ac.th/grader/cli/trunk/scripts@12 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Diff options:
Comments:
0 Commit comments
0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
r0:5402b79c9e92 - - 12 files changed: 845 inserted, 0 deleted
@@ -0,0 +1,14 | |||||
|
|
1 | + | ||
|
|
2 | + PROBLEMS_DIR = "/home/jittat/grader/ev" | ||
|
|
3 | + | ||
|
|
4 | + USER_RESULT_DIR = "/home/jittat/grader/result" | ||
|
|
5 | + | ||
|
|
6 | + TALKATIVE = true | ||
|
|
7 | + | ||
|
|
8 | + def report_comment(comment) | ||
|
|
9 | + if comment.chomp =~ /^P+$/ # all P's | ||
|
|
10 | + 'passed' | ||
|
|
11 | + else | ||
|
|
12 | + 'failed' | ||
|
|
13 | + end | ||
|
|
14 | + end |
@@ -0,0 +1,10 | |||||
|
|
1 | + | ||
|
|
2 | + PROBLEMS_DIR = "/home/jittat/grader/ev" | ||
|
|
3 | + | ||
|
|
4 | + USER_RESULT_DIR = "/home/jittat/grader/result" | ||
|
|
5 | + | ||
|
|
6 | + TALKATIVE = true | ||
|
|
7 | + | ||
|
|
8 | + def report_comment(comment) | ||
|
|
9 | + comment.chomp | ||
|
|
10 | + end |
@@ -0,0 +1,6 | |||||
|
|
1 | + | ||
|
|
2 | + # Rails app directory | ||
|
|
3 | + RAILS_APP_DIR = "/home/jittat/web_grader" | ||
|
|
4 | + | ||
|
|
5 | + # load the required environment file | ||
|
|
6 | + require "env_#{GRADER_ENV}.rb" |
@@ -0,0 +1,109 | |||||
|
|
1 | + #!/usr/bin/ruby | ||
|
|
2 | + | ||
|
|
3 | + def talk(str) | ||
|
|
4 | + if TALKATIVE | ||
|
|
5 | + puts str | ||
|
|
6 | + end | ||
|
|
7 | + end | ||
|
|
8 | + | ||
|
|
9 | + def execute(command, error_message="") | ||
|
|
10 | + if not system(command) | ||
|
|
11 | + puts "ERROR: #{error_message}" | ||
|
|
12 | + exit(127) | ||
|
|
13 | + end | ||
|
|
14 | + end | ||
|
|
15 | + | ||
|
|
16 | + def save_source(submission,dir,fname) | ||
|
|
17 | + f = File.open("#{dir}/#{fname}","w") | ||
|
|
18 | + f.write(submission.source) | ||
|
|
19 | + f.close | ||
|
|
20 | + end | ||
|
|
21 | + | ||
|
|
22 | + def call_judge(problem_home,language,problem_out_dir,fname) | ||
|
|
23 | + ENV['PROBLEM_HOME'] = problem_home | ||
|
|
24 | + Dir.chdir problem_out_dir | ||
|
|
25 | + cmd = "#{problem_home}/script/judge #{language} #{fname}" | ||
|
|
26 | + # puts "CMD: #{cmd}" | ||
|
|
27 | + system(cmd) | ||
|
|
28 | + end | ||
|
|
29 | + | ||
|
|
30 | + def read_result(test_result_dir) | ||
|
|
31 | + cmp_msg_fname = "#{test_result_dir}/compiler_message" | ||
|
|
32 | + cmp_msg = File.open(cmp_msg_fname).read | ||
|
|
33 | + | ||
|
|
34 | + result_fname = "#{test_result_dir}/result" | ||
|
|
35 | + comment_fname = "#{test_result_dir}/comment" | ||
|
|
36 | + if FileTest.exist?(result_fname) | ||
|
|
37 | + result = File.open(result_fname).readline.to_i | ||
|
|
38 | + comment = File.open(comment_fname).readline.chomp | ||
|
|
39 | + return {:points => result, | ||
|
|
40 | + :comment => comment, | ||
|
|
41 | + :cmp_msg => cmp_msg} | ||
|
|
42 | + else | ||
|
|
43 | + return {:points => 0, | ||
|
|
44 | + :comment => 'compile error', | ||
|
|
45 | + :cmp_msg => cmp_msg} | ||
|
|
46 | + end | ||
|
|
47 | + end | ||
|
|
48 | + | ||
|
|
49 | + def save_result(submission,result) | ||
|
|
50 | + submission.graded_at = Time.now | ||
|
|
51 | + submission.points = result[:points] | ||
|
|
52 | + submission.grader_comment = report_comment(result[:comment]) | ||
|
|
53 | + submission.compiler_message = result[:cmp_msg] | ||
|
|
54 | + submission.save | ||
|
|
55 | + end | ||
|
|
56 | + | ||
|
|
57 | + def grade(submission_id) | ||
|
|
58 | + sub = Submission.find(submission_id) | ||
|
|
59 | + user = sub.user | ||
|
|
60 | + problem = sub.problem | ||
|
|
61 | + | ||
|
|
62 | + language = sub.language.name | ||
|
|
63 | + lang_ext = sub.language.ext | ||
|
|
64 | + # FIX THIS | ||
|
|
65 | + talk 'some hack on language' | ||
|
|
66 | + if language == 'cpp' | ||
|
|
67 | + language = 'c++' | ||
|
|
68 | + end | ||
|
|
69 | + | ||
|
|
70 | + user_dir = "#{USER_RESULT_DIR}/#{user.login}" | ||
|
|
71 | + Dir.mkdir(user_dir) if !FileTest.exist?(user_dir) | ||
|
|
72 | + | ||
|
|
73 | + problem_out_dir = "#{user_dir}/#{problem.name}" | ||
|
|
74 | + Dir.mkdir(problem_out_dir) if !FileTest.exist?(problem_out_dir) | ||
|
|
75 | + | ||
|
|
76 | + problem_home = "#{PROBLEMS_DIR}/#{problem.name}" | ||
|
|
77 | + source_name = "#{problem.name}.#{lang_ext}" | ||
|
|
78 | + | ||
|
|
79 | + save_source(sub,problem_out_dir,source_name) | ||
|
|
80 | + call_judge(problem_home,language,problem_out_dir,source_name) | ||
|
|
81 | + save_result(sub,read_result("#{problem_out_dir}/test-result")) | ||
|
|
82 | + end | ||
|
|
83 | + | ||
|
|
84 | + # reading environment | ||
|
|
85 | + GRADER_ENV = 'exam' | ||
|
|
86 | + if ARGV.length > 1 | ||
|
|
87 | + GRADER_ENV = ARGV[1] | ||
|
|
88 | + end | ||
|
|
89 | + require "environment.rb" | ||
|
|
90 | + | ||
|
|
91 | + #main program | ||
|
|
92 | + | ||
|
|
93 | + talk 'Reading rails environment' | ||
|
|
94 | + | ||
|
|
95 | + RAILS_ENV = 'development' | ||
|
|
96 | + require RAILS_APP_DIR + '/config/environment' | ||
|
|
97 | + | ||
|
|
98 | + current_dir = `pwd` | ||
|
|
99 | + | ||
|
|
100 | + talk 'Grader queue' | ||
|
|
101 | + task = Task.find(:first, :order => 'created_at') | ||
|
|
102 | + if task!=nil | ||
|
|
103 | + grade(task.submission_id) | ||
|
|
104 | + task.destroy | ||
|
|
105 | + else | ||
|
|
106 | + puts "No job" | ||
|
|
107 | + end | ||
|
|
108 | + | ||
|
|
109 | + |
@@ -0,0 +1,89 | |||||
|
|
1 | + #!/usr/bin/ruby | ||
|
|
2 | + | ||
|
|
3 | + # import_problem: | ||
|
|
4 | + # * creates a directory for a problem in the current directory, | ||
|
|
5 | + # * copy standard scripts | ||
|
|
6 | + # * copy testdata in the old format and create standard testcase config file | ||
|
|
7 | + | ||
|
|
8 | + require 'erb' | ||
|
|
9 | + | ||
|
|
10 | + def input_filename(dir,i) | ||
|
|
11 | + "#{dir}/input-#{i}.txt" | ||
|
|
12 | + end | ||
|
|
13 | + | ||
|
|
14 | + def answer_filename(dir,i) | ||
|
|
15 | + "#{dir}/answer-#{i}.txt" | ||
|
|
16 | + end | ||
|
|
17 | + | ||
|
|
18 | + def copy_testcase(importing_test_dir,dir,i) | ||
|
|
19 | + system("cp #{importing_test_dir}/#{i}.in #{input_filename(dir,i)}") | ||
|
|
20 | + system("cp #{importing_test_dir}/#{i}.sol #{answer_filename(dir,i)}") | ||
|
|
21 | + end | ||
|
|
22 | + | ||
|
|
23 | + def process_options(options) | ||
|
|
24 | + i = 3 | ||
|
|
25 | + while i<ARGV.length | ||
|
|
26 | + if ARGV[i]=='-t' | ||
|
|
27 | + options[:time_limit] = ARGV[i+1].to_i if ARGV.length>i+1 | ||
|
|
28 | + i += 1 | ||
|
|
29 | + end | ||
|
|
30 | + if ARGV[i]=='-m' | ||
|
|
31 | + options[:mem_limit] = ARGV[i+1].to_i if ARGV.length>i+1 | ||
|
|
32 | + i += 1 | ||
|
|
33 | + end | ||
|
|
34 | + i += 1 | ||
|
|
35 | + end | ||
|
|
36 | + end | ||
|
|
37 | + | ||
|
|
38 | + GRADER_DIR = "/home/jittat/grader/grader_ng" | ||
|
|
39 | + | ||
|
|
40 | + # print usage | ||
|
|
41 | + if ARGV.length < 3 | ||
|
|
42 | + puts "using: import_task problem importing_testcase_dir number_of_testcase [options]" | ||
|
|
43 | + exit(127) | ||
|
|
44 | + end | ||
|
|
45 | + | ||
|
|
46 | + # processing arguments | ||
|
|
47 | + problem = ARGV[0] | ||
|
|
48 | + testcase_dir = ARGV[1] | ||
|
|
49 | + num_testcases = ARGV[2].to_i | ||
|
|
50 | + | ||
|
|
51 | + options = {:time_limit => 1, :mem_limit => 16} | ||
|
|
52 | + process_options(options) | ||
|
|
53 | + | ||
|
|
54 | + # start working | ||
|
|
55 | + puts "creating directories" | ||
|
|
56 | + | ||
|
|
57 | + system("mkdir #{problem}") | ||
|
|
58 | + system("mkdir #{problem}/script") | ||
|
|
59 | + system("mkdir #{problem}/test_cases") | ||
|
|
60 | + system("cp #{GRADER_DIR}/std-script/* #{problem}/script") | ||
|
|
61 | + | ||
|
|
62 | + puts "copying testcases" | ||
|
|
63 | + | ||
|
|
64 | + 1.upto(num_testcases) do |i| | ||
|
|
65 | + system("mkdir #{problem}/test_cases/#{i}") | ||
|
|
66 | + copy_testcase("#{testcase_dir}","#{problem}/test_cases/#{i}",i) | ||
|
|
67 | + end | ||
|
|
68 | + | ||
|
|
69 | + | ||
|
|
70 | + # generating all_tests.cfg | ||
|
|
71 | + puts "generating testcase config file" | ||
|
|
72 | + | ||
|
|
73 | + template = %q{ | ||
|
|
74 | + problem do | ||
|
|
75 | + num_tests <%= num_testcases %> | ||
|
|
76 | + full_score <%= num_testcases*10 %> | ||
|
|
77 | + time_limit_each <%= options[:time_limit] %> | ||
|
|
78 | + mem_limit_each <%= options[:mem_limit] %> | ||
|
|
79 | + score_each 10 | ||
|
|
80 | + end | ||
|
|
81 | + } | ||
|
|
82 | + | ||
|
|
83 | + all_test_cfg = ERB.new(template) | ||
|
|
84 | + | ||
|
|
85 | + cfg_file = File.open("#{problem}/test_cases/all_test.cfg","w") | ||
|
|
86 | + cfg_file.puts all_test_cfg.result | ||
|
|
87 | + cfg_file.close | ||
|
|
88 | + | ||
|
|
89 | + puts "done" |
new file 100755 | |||||
binary diff hidden |
@@ -0,0 +1,59 | |||||
|
|
1 | + #!/usr/bin/ruby | ||
|
|
2 | + | ||
|
|
3 | + problem_home = ENV['PROBLEM_HOME'] | ||
|
|
4 | + require "#{problem_home}/script/test_dsl.rb" | ||
|
|
5 | + | ||
|
|
6 | + if ARGV.length < 2 | ||
|
|
7 | + puts "Usage: check <language> <test-number> [<output-file>]" | ||
|
|
8 | + exit(0) | ||
|
|
9 | + end | ||
|
|
10 | + | ||
|
|
11 | + language = ARGV[0] | ||
|
|
12 | + test_num = ARGV[1].to_i | ||
|
|
13 | + if ARGV.length >= 3 | ||
|
|
14 | + output_file_name = ARGV[2] | ||
|
|
15 | + else | ||
|
|
16 | + output_file_name = "output.txt" | ||
|
|
17 | + end | ||
|
|
18 | + | ||
|
|
19 | + load "#{problem_home}/test_cases/all_tests.cfg" | ||
|
|
20 | + problem = Problem.get_instance | ||
|
|
21 | + | ||
|
|
22 | + output_file = File.new(output_file_name, "r") | ||
|
|
23 | + answer_file = File.new("#{problem_home}/test_cases/#{test_num}/answer-#{test_num}.txt") | ||
|
|
24 | + result_file = File.new("check_result", "w") | ||
|
|
25 | + | ||
|
|
26 | + output_file_content = output_file.read | ||
|
|
27 | + answer_file_content = answer_file.read | ||
|
|
28 | + | ||
|
|
29 | + report_correct = lambda { | ||
|
|
30 | + result_file.write "Correct\n" | ||
|
|
31 | + result_file.write problem.get_score(test_num) | ||
|
|
32 | + result_file.write "\n" | ||
|
|
33 | + result_file.close | ||
|
|
34 | + exit(0) | ||
|
|
35 | + } | ||
|
|
36 | + | ||
|
|
37 | + report_wrong = lambda { | ||
|
|
38 | + result_file.write "Incorrect\n" | ||
|
|
39 | + result_file.write "0\n" | ||
|
|
40 | + result_file.close | ||
|
|
41 | + exit(0) | ||
|
|
42 | + } | ||
|
|
43 | + | ||
|
|
44 | + ################## | ||
|
|
45 | + # Your code here # | ||
|
|
46 | + ################## | ||
|
|
47 | + num_pattern = /^[0-9]*/ | ||
|
|
48 | + if (output_file_content =~ num_pattern) == nil | ||
|
|
49 | + report_wrong.call | ||
|
|
50 | + end | ||
|
|
51 | + | ||
|
|
52 | + output_i = output_file_content.to_i | ||
|
|
53 | + answer_i = answer_file_content.to_i | ||
|
|
54 | + | ||
|
|
55 | + if output_i == answer_i | ||
|
|
56 | + report_correct.call | ||
|
|
57 | + else | ||
|
|
58 | + report_wrong.call | ||
|
|
59 | + end |
@@ -0,0 +1,102 | |||||
|
|
1 | + #!/bin/sh | ||
|
|
2 | + | ||
|
|
3 | + ############################## | ||
|
|
4 | + # | ||
|
|
5 | + # Standard Compile Script | ||
|
|
6 | + # | ||
|
|
7 | + # Supported compilers: | ||
|
|
8 | + # gcc, g++, and gpc. | ||
|
|
9 | + # | ||
|
|
10 | + ############################## | ||
|
|
11 | + | ||
|
|
12 | + export C_COMPILER=/usr/bin/gcc | ||
|
|
13 | + export CPLUSPLUS_COMPILER=/usr/bin/g++ | ||
|
|
14 | + export PASCAL_COMPILER=/usr/bin/gpc | ||
|
|
15 | + | ||
|
|
16 | + export C_OPTIONS="-O2 -Wall" | ||
|
|
17 | + export CPLUSPLUS_OPTIONS="-O2 -Wall" | ||
|
|
18 | + export PASCAL_OPTIONS="-O2 -Wall" | ||
|
|
19 | + | ||
|
|
20 | + # Check for the correct number of arguments. Otherwise, print usage. | ||
|
|
21 | + if [ $# -eq 0 -o $# -gt 4 ] | ||
|
|
22 | + then | ||
|
|
23 | + echo "Usage: $0 <language> [<source-file>] [<output-file>] [<message-file>]" | ||
|
|
24 | + echo | ||
|
|
25 | + echo "<source-file> is defaulted to \"source\"." | ||
|
|
26 | + echo "<output-file> is defaulted to \"a.out\"." | ||
|
|
27 | + echo "<message-file> is defaulted to \"compiler_message\"." | ||
|
|
28 | + echo | ||
|
|
29 | + exit 127 | ||
|
|
30 | + fi | ||
|
|
31 | + | ||
|
|
32 | + # Retrieve the arguments. | ||
|
|
33 | + if [ $# -ge 1 ] | ||
|
|
34 | + then | ||
|
|
35 | + export PROG_LANG=$1 | ||
|
|
36 | + echo "programming language: ${PROG_LANG}" | ||
|
|
37 | + fi | ||
|
|
38 | + | ||
|
|
39 | + if [ $# -ge 2 ] | ||
|
|
40 | + then | ||
|
|
41 | + export SOURCE_FILE=$2 | ||
|
|
42 | + else | ||
|
|
43 | + export SOURCE_FILE=source | ||
|
|
44 | + fi | ||
|
|
45 | + echo " source file: $SOURCE_FILE" | ||
|
|
46 | + | ||
|
|
47 | + if [ $# -ge 3 ] | ||
|
|
48 | + then | ||
|
|
49 | + export OUTPUT_FILE=$3 | ||
|
|
50 | + else | ||
|
|
51 | + export OUTPUT_FILE=a.out | ||
|
|
52 | + fi | ||
|
|
53 | + echo " output file: $OUTPUT_FILE" | ||
|
|
54 | + | ||
|
|
55 | + if [ $# -eq 4 ] | ||
|
|
56 | + then | ||
|
|
57 | + export MESSAGE_FILE=$4 | ||
|
|
58 | + else | ||
|
|
59 | + export MESSAGE_FILE=compiler_message | ||
|
|
60 | + fi | ||
|
|
61 | + echo " message file: $MESSAGE_FILE" | ||
|
|
62 | + | ||
|
|
63 | + echo | ||
|
|
64 | + | ||
|
|
65 | + # Remove any remaining output files or message files. | ||
|
|
66 | + rm -Rf $OUTPUT_FILE | ||
|
|
67 | + rm -Rf $MESSAGE_FILE | ||
|
|
68 | + | ||
|
|
69 | + # Check if the source file exists before attempt compiling. | ||
|
|
70 | + if [ ! -f $SOURCE_FILE ] | ||
|
|
71 | + then | ||
|
|
72 | + echo "ERROR: The source file does not exist!" | ||
|
|
73 | + echo "ERROR: The source file did not exist." > $MESSAGE_FILE | ||
|
|
74 | + exit 127 | ||
|
|
75 | + fi | ||
|
|
76 | + | ||
|
|
77 | + # Compile. | ||
|
|
78 | + if [ $PROG_LANG = "c" ] | ||
|
|
79 | + then | ||
|
|
80 | + $C_COMPILER $C_OPTIONS -o $OUTPUT_FILE $SOURCE_FILE 2>$MESSAGE_FILE | ||
|
|
81 | + elif [ $PROG_LANG = "c++" ] | ||
|
|
82 | + then | ||
|
|
83 | + $CPLUSPLUS_COMPILER $CPLUSPLUS_OPTIONS -o $OUTPUT_FILE $SOURCE_FILE 2>$MESSAGE_FILE | ||
|
|
84 | + elif [ $PROG_LANG = "pascal" ] | ||
|
|
85 | + then | ||
|
|
86 | + $PASCAL_COMPILER $PASCAL_OPTIONS -o $OUTPUT_FILE $SOURCE_FILE 2>$MESSAGE_FILE | ||
|
|
87 | + else | ||
|
|
88 | + echo "ERROR: Invalid language specified!" | ||
|
|
89 | + echo "ERROR: Invalid language specified!" > $MESSAGE_FILE | ||
|
|
90 | + exit 127 | ||
|
|
91 | + fi | ||
|
|
92 | + | ||
|
|
93 | + # Report success or failure. | ||
|
|
94 | + if [ -f $OUTPUT_FILE ] | ||
|
|
95 | + then | ||
|
|
96 | + echo "Compilation was successful!" | ||
|
|
97 | + else | ||
|
|
98 | + echo "ERROR: Something was wrong during the compilation!" | ||
|
|
99 | + echo "Dumping compiler message:" | ||
|
|
100 | + echo | ||
|
|
101 | + cat $MESSAGE_FILE | ||
|
|
102 | + fi No newline at end of file |
@@ -0,0 +1,65 | |||||
|
|
1 | + #!/usr/bin/ruby | ||
|
|
2 | + | ||
|
|
3 | + def char_comment(comment) | ||
|
|
4 | + if comment =~ /[iI]ncorrect/ | ||
|
|
5 | + '-' | ||
|
|
6 | + elsif comment =~ /[Cc]orrect/ | ||
|
|
7 | + 'P' | ||
|
|
8 | + elsif comment =~ /[Tt]ime/ | ||
|
|
9 | + 'T' | ||
|
|
10 | + else | ||
|
|
11 | + '?' | ||
|
|
12 | + end | ||
|
|
13 | + end | ||
|
|
14 | + | ||
|
|
15 | + problem_home = ENV['PROBLEM_HOME'] | ||
|
|
16 | + require "#{problem_home}/script/test_dsl.rb" | ||
|
|
17 | + load "#{problem_home}/test_cases/all_tests.cfg" | ||
|
|
18 | + problem = Problem.get_instance | ||
|
|
19 | + | ||
|
|
20 | + if problem.well_formed? == false | ||
|
|
21 | + puts "The problem specification is not well formed." | ||
|
|
22 | + exit(127) | ||
|
|
23 | + end | ||
|
|
24 | + | ||
|
|
25 | + all_score = 0 | ||
|
|
26 | + all_comment = '' | ||
|
|
27 | + (1..(problem.runs.length-1)).each do |k| | ||
|
|
28 | + run = problem.runs[k] | ||
|
|
29 | + run_score = 0 | ||
|
|
30 | + run_comment = '' | ||
|
|
31 | + run.tests.each do |test_num| | ||
|
|
32 | + result_file_name = "#{test_num}/result" | ||
|
|
33 | + if not File.exists?(result_file_name) | ||
|
|
34 | + puts "Cannot find the file #{test_num}/result!" | ||
|
|
35 | + exit(127) | ||
|
|
36 | + end | ||
|
|
37 | + | ||
|
|
38 | + result_file = File.new(result_file_name, "r") | ||
|
|
39 | + result_file_lines = result_file.readlines | ||
|
|
40 | + run_score = run_score + result_file_lines[1].to_i | ||
|
|
41 | + run_comment += char_comment(result_file_lines[0]) | ||
|
|
42 | + result_file.close | ||
|
|
43 | + end | ||
|
|
44 | + | ||
|
|
45 | + run_result_file = File.new("result-#{k}", "w") | ||
|
|
46 | + run_result_file.write run_score | ||
|
|
47 | + run_result_file.write "\n" | ||
|
|
48 | + run_result_file.close | ||
|
|
49 | + | ||
|
|
50 | + run_comment_file = File.new("comment-#{k}", "w") | ||
|
|
51 | + run_comment_file.write "#{run_comment}\n" | ||
|
|
52 | + run_comment_file.close | ||
|
|
53 | + | ||
|
|
54 | + all_score = all_score + run_score | ||
|
|
55 | + all_comment += run_comment | ||
|
|
56 | + end | ||
|
|
57 | + | ||
|
|
58 | + result_file = File.new("result", "w") | ||
|
|
59 | + result_file.write all_score | ||
|
|
60 | + result_file.write "\n" | ||
|
|
61 | + result_file.close | ||
|
|
62 | + | ||
|
|
63 | + comment_file = File.new("comment", "w") | ||
|
|
64 | + comment_file.write "#{all_comment}\n" | ||
|
|
65 | + comment_file.close |
@@ -0,0 +1,114 | |||||
|
|
1 | + #!/usr/bin/ruby | ||
|
|
2 | + | ||
|
|
3 | + problem_home = ENV['PROBLEM_HOME'] | ||
|
|
4 | + | ||
|
|
5 | + def execute(command, error_message="") | ||
|
|
6 | + if not system(command) | ||
|
|
7 | + puts "ERROR: #{error_message}" | ||
|
|
8 | + exit(127) | ||
|
|
9 | + end | ||
|
|
10 | + end | ||
|
|
11 | + | ||
|
|
12 | + # ARGV[0] --- language | ||
|
|
13 | + # ARGV[1] --- program source file | ||
|
|
14 | + # ARGV[2] --- test result directory | ||
|
|
15 | + # ARGV[3] --- sandbox directory | ||
|
|
16 | + | ||
|
|
17 | + if ARGV.length < 2 || ARGV.length > 4 | ||
|
|
18 | + puts "Usage: judge <language> <program-source> [<test-result-directory>] [<sandbox-directory>]" | ||
|
|
19 | + puts " <sandbox-directory> is defaulted to ./sandbox" | ||
|
|
20 | + puts " <test-result-directory> is defaulted to ./test-result" | ||
|
|
21 | + puts "WARNING: The judge script will forcefully create the (implicitly and explicitly) specified directories and remove anything inside it." | ||
|
|
22 | + exit(127) | ||
|
|
23 | + end | ||
|
|
24 | + | ||
|
|
25 | + language = ARGV[0] | ||
|
|
26 | + if language != "c" && language != "c++" && language != "pascal" | ||
|
|
27 | + puts "You specified a language that is not supported." | ||
|
|
28 | + exit(127) | ||
|
|
29 | + end | ||
|
|
30 | + | ||
|
|
31 | + source_file = ARGV[1] | ||
|
|
32 | + if File.exist?(source_file) == false | ||
|
|
33 | + puts "The source file does not exist." | ||
|
|
34 | + exit(127) | ||
|
|
35 | + end | ||
|
|
36 | + | ||
|
|
37 | + puts "Making test result and sandbox directories..." | ||
|
|
38 | + | ||
|
|
39 | + current_dir = `pwd` | ||
|
|
40 | + current_dir.strip! | ||
|
|
41 | + | ||
|
|
42 | + if ARGV.length >= 3 | ||
|
|
43 | + test_result_dir = ARGV[2] | ||
|
|
44 | + else | ||
|
|
45 | + test_result_dir = "#{current_dir}/test-result" | ||
|
|
46 | + end | ||
|
|
47 | + puts "Test result directory: #{test_result_dir}" | ||
|
|
48 | + system("rm -Rf #{test_result_dir}") | ||
|
|
49 | + execute("mkdir #{test_result_dir}", "Cannot make directory #{test_result_dir}.") | ||
|
|
50 | + | ||
|
|
51 | + if ARGV.length >= 4 | ||
|
|
52 | + sandbox_dir = ARGV[3] | ||
|
|
53 | + else | ||
|
|
54 | + sandbox_dir = "#{current_dir}/sandbox" | ||
|
|
55 | + end | ||
|
|
56 | + puts "Sandbox directory: #{sandbox_dir}" | ||
|
|
57 | + system("rm -Rf #{sandbox_dir}") | ||
|
|
58 | + execute("mkdir #{sandbox_dir}", "Cannot make directory #{sandbox_dir}") | ||
|
|
59 | + | ||
|
|
60 | + # Compile | ||
|
|
61 | + puts | ||
|
|
62 | + puts "Compiling..." | ||
|
|
63 | + execute("cp #{source_file} #{sandbox_dir}", "Cannot copy the source file to #{sandbox_dir}") | ||
|
|
64 | + begin | ||
|
|
65 | + Dir.chdir sandbox_dir | ||
|
|
66 | + rescue | ||
|
|
67 | + puts "ERROR: Cannot change directory to #{sandbox_dir}." | ||
|
|
68 | + exit(127) | ||
|
|
69 | + end | ||
|
|
70 | + execute("#{problem_home}/script/compile #{language} #{source_file}", "Compilation error!") | ||
|
|
71 | + compile_message = `cat compiler_message` | ||
|
|
72 | + compile_message.strip! | ||
|
|
73 | + execute("mv compiler_message #{test_result_dir}", "Cannot move the compiler message to #{test_result_dir}.") | ||
|
|
74 | + if compile_message != "" | ||
|
|
75 | + puts "Cannot compile the source code. See message in #{test_result_dir}/compile_message" | ||
|
|
76 | + exit(127) | ||
|
|
77 | + else | ||
|
|
78 | + execute("mv a.out #{test_result_dir}", "Cannot move the compiled program to #{test_result_dir}") | ||
|
|
79 | + system("rm -Rf #{sandbox_dir}/*") | ||
|
|
80 | + end | ||
|
|
81 | + | ||
|
|
82 | + require "#{problem_home}/script/test_dsl.rb" | ||
|
|
83 | + load "#{problem_home}/test_cases/all_tests.cfg" | ||
|
|
84 | + problem = Problem.get_instance | ||
|
|
85 | + | ||
|
|
86 | + if problem.well_formed? == false | ||
|
|
87 | + puts "The problem specification is not well formed." | ||
|
|
88 | + exit(127) | ||
|
|
89 | + end | ||
|
|
90 | + | ||
|
|
91 | + # Doing the testing. | ||
|
|
92 | + (1..(problem.num_tests)).each do |test_num| | ||
|
|
93 | + puts | ||
|
|
94 | + execute("cp #{test_result_dir}/a.out #{sandbox_dir}", "Cannot copy the compiled program into #{sandbox_dir}") | ||
|
|
95 | + execute("#{problem_home}/script/run #{language} #{test_num}", "Error occured during execution of the run script") | ||
|
|
96 | + execute("mkdir #{test_result_dir}/#{test_num}", "Cannot create directory #{test_result_dir}/#{test_num}") | ||
|
|
97 | + execute("mv #{sandbox_dir}/result #{test_result_dir}/#{test_num}", "Cannot copy the result file into #{test_result_dir}/#{test_num}") | ||
|
|
98 | + execute("mv #{sandbox_dir}/comment #{test_result_dir}/#{test_num}", "Cannot copy the comment file into #{test_result_dir}/#{test_num}") | ||
|
|
99 | + execute("rm -Rf #{sandbox_dir}/*", "Cannot clear #{sandbox_dir}") | ||
|
|
100 | + end | ||
|
|
101 | + | ||
|
|
102 | + # Grade | ||
|
|
103 | + puts | ||
|
|
104 | + puts "Grading..." | ||
|
|
105 | + begin | ||
|
|
106 | + Dir.chdir test_result_dir | ||
|
|
107 | + rescue | ||
|
|
108 | + puts "ERROR: Cannot change directory to #{test_result_dir}." | ||
|
|
109 | + exit(127) | ||
|
|
110 | + end | ||
|
|
111 | + execute("#{problem_home}/script/grade", "An error occured during grading!") | ||
|
|
112 | + | ||
|
|
113 | + puts | ||
|
|
114 | + puts "All done!" |
@@ -0,0 +1,99 | |||||
|
|
1 | + #!/usr/bin/ruby | ||
|
|
2 | + | ||
|
|
3 | + if ARGV.length < 2 || ARGV.length > 3 | ||
|
|
4 | + puts "Usage: run <language> <test-num> [<program-name>]" | ||
|
|
5 | + exit(127) | ||
|
|
6 | + end | ||
|
|
7 | + | ||
|
|
8 | + language = ARGV[0] | ||
|
|
9 | + test_num = ARGV[1].to_i | ||
|
|
10 | + if ARGV.length > 2 | ||
|
|
11 | + program_name = ARGV[2] | ||
|
|
12 | + else | ||
|
|
13 | + program_name = "a.out" | ||
|
|
14 | + end | ||
|
|
15 | + | ||
|
|
16 | + problem_home = ENV['PROBLEM_HOME'] | ||
|
|
17 | + require "#{problem_home}/script/test_dsl.rb" | ||
|
|
18 | + load "#{problem_home}/test_cases/all_tests.cfg" | ||
|
|
19 | + problem = Problem.get_instance | ||
|
|
20 | + | ||
|
|
21 | + if problem.well_formed? == false | ||
|
|
22 | + puts "The problem specification is not well formed." | ||
|
|
23 | + exit(127) | ||
|
|
24 | + end | ||
|
|
25 | + | ||
|
|
26 | + # Check if the test number is okay. | ||
|
|
27 | + if test_num <= 0 || test_num > problem.num_tests | ||
|
|
28 | + puts "You have specified a wrong test number." | ||
|
|
29 | + exit(127) | ||
|
|
30 | + end | ||
|
|
31 | + | ||
|
|
32 | + ##################################### | ||
|
|
33 | + # Set the relavant file names here. # | ||
|
|
34 | + ##################################### | ||
|
|
35 | + | ||
|
|
36 | + input_file_name = "#{problem_home}/test_cases/#{test_num}/input-#{test_num}.txt" | ||
|
|
37 | + | ||
|
|
38 | + ##################################### | ||
|
|
39 | + | ||
|
|
40 | + time_limit = problem.get_time_limit test_num | ||
|
|
41 | + mem_limit = problem.get_mem_limit(test_num) * 1024 | ||
|
|
42 | + | ||
|
|
43 | + # Copy the input file. | ||
|
|
44 | + #`cp #{problem_home}/test_cases/#{test_num}/#{input_file_name} .` | ||
|
|
45 | + | ||
|
|
46 | + # Run the program. | ||
|
|
47 | + run_command = "/usr/bin/time -f \"%E\" 2>run_result #{problem_home}/script/box -a 2 -f -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name}" | ||
|
|
48 | + puts "Running test #{test_num}..." | ||
|
|
49 | + puts run_command | ||
|
|
50 | + puts | ||
|
|
51 | + system(run_command) | ||
|
|
52 | + | ||
|
|
53 | + # Create the result file. | ||
|
|
54 | + result_file = File.new("result", "w") | ||
|
|
55 | + comment_file = File.new("comment", "w") | ||
|
|
56 | + | ||
|
|
57 | + # Check if the program actually produced any output. | ||
|
|
58 | + run_result_file = File.new("run_result", "r") | ||
|
|
59 | + run_result = run_result_file.readlines | ||
|
|
60 | + run_result_file.close | ||
|
|
61 | + time_elapsed = run_result[run_result.length-1] | ||
|
|
62 | + | ||
|
|
63 | + report = lambda{ |status, points, comment| | ||
|
|
64 | + result_file.write status.strip | ||
|
|
65 | + result_file.write "\n" | ||
|
|
66 | + result_file.write points.to_s.strip | ||
|
|
67 | + result_file.write "\n" | ||
|
|
68 | + result_file.write time_elapsed.strip | ||
|
|
69 | + result_file.write "\n" | ||
|
|
70 | + result_file.close | ||
|
|
71 | + `rm run_result` | ||
|
|
72 | + `rm output.txt` | ||
|
|
73 | + | ||
|
|
74 | + comment_file.write comment | ||
|
|
75 | + comment_file.close | ||
|
|
76 | + | ||
|
|
77 | + puts | ||
|
|
78 | + puts "Done!" | ||
|
|
79 | + exit(0) | ||
|
|
80 | + } | ||
|
|
81 | + | ||
|
|
82 | + if run_result[0][0,2] != "OK" | ||
|
|
83 | + puts "There was a runtime error." | ||
|
|
84 | + report.call(run_result[0], 0, "No comment.\n") | ||
|
|
85 | + end | ||
|
|
86 | + | ||
|
|
87 | + # Run 'check' to evaluate the output. | ||
|
|
88 | + #puts "There was no runtime error. Proceed to checking the output." | ||
|
|
89 | + check_command = "#{problem_home}/script/check #{language} #{test_num}" | ||
|
|
90 | + puts "Checking the output..." | ||
|
|
91 | + puts check_command | ||
|
|
92 | + if not system(check_command) | ||
|
|
93 | + exit(127) | ||
|
|
94 | + end | ||
|
|
95 | + | ||
|
|
96 | + check_file = File.new("check_result", "r") | ||
|
|
97 | + check_file_lines = check_file.readlines | ||
|
|
98 | + | ||
|
|
99 | + report.call(check_file_lines[0], check_file_lines[1], "No comment.\n") |
@@ -0,0 +1,178 | |||||
|
|
1 | + class DSLNode | ||
|
|
2 | + def DSLNode.scalar_attr(*names) | ||
|
|
3 | + names.each do |name| | ||
|
|
4 | + define_method name do |*a| | ||
|
|
5 | + if a.length == 0 | ||
|
|
6 | + instance_variable_get( "@#{name}" ) | ||
|
|
7 | + else | ||
|
|
8 | + instance_variable_set( "@#{name}", a[0] ) | ||
|
|
9 | + end | ||
|
|
10 | + end | ||
|
|
11 | + end | ||
|
|
12 | + end | ||
|
|
13 | + | ||
|
|
14 | + def DSLNode.array_attr(*names) | ||
|
|
15 | + names.each do |name| | ||
|
|
16 | + define_method name do |*a| | ||
|
|
17 | + if a.length == 0 | ||
|
|
18 | + instance_variable_get( "@#{name}" ) | ||
|
|
19 | + else | ||
|
|
20 | + instance_variable_set( "@#{name}", a ) | ||
|
|
21 | + end | ||
|
|
22 | + end | ||
|
|
23 | + end | ||
|
|
24 | + end | ||
|
|
25 | + end | ||
|
|
26 | + | ||
|
|
27 | + class Problem < DSLNode | ||
|
|
28 | + def initialize | ||
|
|
29 | + @runs = [] | ||
|
|
30 | + @tests = [] | ||
|
|
31 | + end | ||
|
|
32 | + | ||
|
|
33 | + def Problem.getter(name, plural_name, each_name) | ||
|
|
34 | + eval "def get_#{name}(index) \n \ | ||
|
|
35 | + if defined?(@tests) and @tests[index] != nil \n \ | ||
|
|
36 | + if @tests[index].#{name} != nil \n \ | ||
|
|
37 | + return @tests[index].#{name} \n \ | ||
|
|
38 | + end \n \ | ||
|
|
39 | + end \n \ | ||
|
|
40 | + \n \ | ||
|
|
41 | + (1..@runs.length-1).each do |i| \n \ | ||
|
|
42 | + run = @runs[i] \n \ | ||
|
|
43 | + k = run.tests.index(index) \n \ | ||
|
|
44 | + if k == nil \n \ | ||
|
|
45 | + next \n \ | ||
|
|
46 | + end \n \ | ||
|
|
47 | + \n \ | ||
|
|
48 | + if run.#{plural_name} != nil && run.#{plural_name}[k] != nil \n \ | ||
|
|
49 | + return run.#{plural_name}[k] \n \ | ||
|
|
50 | + end \n \ | ||
|
|
51 | + \n \ | ||
|
|
52 | + if run.#{each_name} != nil \n \ | ||
|
|
53 | + return run.#{each_name} \n \ | ||
|
|
54 | + end \n \ | ||
|
|
55 | + end \n \ | ||
|
|
56 | + \n \ | ||
|
|
57 | + if @#{each_name} != nil \n \ | ||
|
|
58 | + return @#{each_name} \n \ | ||
|
|
59 | + else \n \ | ||
|
|
60 | + raise 'The problem is malformed (possibly in more than one way)!' \n \ | ||
|
|
61 | + end \n \ | ||
|
|
62 | + end" | ||
|
|
63 | + end | ||
|
|
64 | + | ||
|
|
65 | + scalar_attr :num_tests, :full_score, :score_each, :time_limit_each, :mem_limit_each | ||
|
|
66 | + array_attr :runs, :tests | ||
|
|
67 | + getter "score", "scores", "score_each" | ||
|
|
68 | + getter "mem_limit", "mem_limits", "mem_limit_each" | ||
|
|
69 | + getter "time_limit", "time_limits", "time_limit_each" | ||
|
|
70 | + | ||
|
|
71 | + def run(index, &block) | ||
|
|
72 | + new_run = Run.new | ||
|
|
73 | + new_run.instance_eval &block | ||
|
|
74 | + @runs[index] = new_run | ||
|
|
75 | + end | ||
|
|
76 | + | ||
|
|
77 | + def test(index, &block) | ||
|
|
78 | + new_test = Test.new | ||
|
|
79 | + new_test.instance_eval &block | ||
|
|
80 | + @tests[index] = new_test | ||
|
|
81 | + end | ||
|
|
82 | + | ||
|
|
83 | + def read_test(index) | ||
|
|
84 | + filename = ENV['PROBLEM_HOME'] + "/test_cases/#{index}/test.cfg" | ||
|
|
85 | + if File.exists?(filename) | ||
|
|
86 | + @tests[index] ||= Test.new | ||
|
|
87 | + content = File.read(filename) | ||
|
|
88 | + @tests[index].instance_eval content | ||
|
|
89 | + end | ||
|
|
90 | + end | ||
|
|
91 | + | ||
|
|
92 | + def Problem.set_instance(prob) | ||
|
|
93 | + @instance = prob | ||
|
|
94 | + end | ||
|
|
95 | + | ||
|
|
96 | + def Problem.get_instance | ||
|
|
97 | + return @instance | ||
|
|
98 | + end | ||
|
|
99 | + | ||
|
|
100 | + def well_formed? | ||
|
|
101 | + # Check if run 1 to run @runs.length are present. | ||
|
|
102 | + (1..(@runs.length-1)).each do |i| | ||
|
|
103 | + if @runs[i] == nil | ||
|
|
104 | + puts "run #{i} is not present" | ||
|
|
105 | + return false | ||
|
|
106 | + end | ||
|
|
107 | + end | ||
|
|
108 | + | ||
|
|
109 | + # Check if all tests are in one and only one run. | ||
|
|
110 | + test_present = [] | ||
|
|
111 | + (1..(@num_tests)).each do |i| | ||
|
|
112 | + test_present[i] = false | ||
|
|
113 | + end | ||
|
|
114 | + (1..(@runs.length-1)).each do |j| | ||
|
|
115 | + run = @runs[j] | ||
|
|
116 | + run.tests.each do |t| | ||
|
|
117 | + if test_present[t] == false | ||
|
|
118 | + test_present[t] = true | ||
|
|
119 | + else | ||
|
|
120 | + puts "test #{t} is present in more than one run" | ||
|
|
121 | + return false | ||
|
|
122 | + end | ||
|
|
123 | + end | ||
|
|
124 | + end | ||
|
|
125 | + (1..(@num_tests)).each do |i| | ||
|
|
126 | + if test_present[i] == false | ||
|
|
127 | + puts "test #{i} is not present" | ||
|
|
128 | + return false | ||
|
|
129 | + end | ||
|
|
130 | + end | ||
|
|
131 | + | ||
|
|
132 | + # Check if we can find the score, mem limit, and time limit for all tests. | ||
|
|
133 | + (1..(@num_tests)).each do |i| | ||
|
|
134 | + begin | ||
|
|
135 | + get_score i | ||
|
|
136 | + rescue | ||
|
|
137 | + puts "cannot get score for test #{i}" | ||
|
|
138 | + return false | ||
|
|
139 | + end | ||
|
|
140 | + | ||
|
|
141 | + begin | ||
|
|
142 | + get_mem_limit i | ||
|
|
143 | + rescue | ||
|
|
144 | + puts "cannot get mem limit for test #{i}" | ||
|
|
145 | + return false | ||
|
|
146 | + end | ||
|
|
147 | + | ||
|
|
148 | + begin | ||
|
|
149 | + get_time_limit i | ||
|
|
150 | + rescue | ||
|
|
151 | + puts "cannot get time limit for test #{i}" | ||
|
|
152 | + return false | ||
|
|
153 | + end | ||
|
|
154 | + end | ||
|
|
155 | + | ||
|
|
156 | + return true | ||
|
|
157 | + end | ||
|
|
158 | + end | ||
|
|
159 | + | ||
|
|
160 | + class Run < DSLNode | ||
|
|
161 | + scalar_attr :score_each, :time_limit_each, :mem_limit_each | ||
|
|
162 | + array_attr :tests, :scores, :time_limits, :mem_limits | ||
|
|
163 | + end | ||
|
|
164 | + | ||
|
|
165 | + class Test < DSLNode | ||
|
|
166 | + scalar_attr :score, :time_limit, :mem_limit | ||
|
|
167 | + end | ||
|
|
168 | + | ||
|
|
169 | + def problem(&blk) | ||
|
|
170 | + prob = Problem.new | ||
|
|
171 | + prob.instance_eval &blk | ||
|
|
172 | + Problem.set_instance prob | ||
|
|
173 | + p = Problem.get_instance | ||
|
|
174 | + (1..(p.num_tests)).each do |i| | ||
|
|
175 | + p.read_test i | ||
|
|
176 | + end | ||
|
|
177 | + p.well_formed? | ||
|
|
178 | + end |
You need to be logged in to leave comments.
Login now