Description:
added test pair assignment, requests new input, downloads input
Commit status:
[Not Reviewed]
References:
Diff options:
Comments:
0 Commit comments
0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
r213:805be1d05f2d - - 13 files changed: 178 inserted, 5 deleted
@@ -0,0 +1,5 | |||
|
1 | + class TestPairAssignment < ActiveRecord::Base | |
|
2 | + belongs_to :user | |
|
3 | + belongs_to :test_pair | |
|
4 | + belongs_to :problem | |
|
5 | + end |
@@ -0,0 +1,9 | |||
|
1 | + class AddNumberToTestPair < ActiveRecord::Migration | |
|
2 | + def self.up | |
|
3 | + add_column 'test_pairs', 'number', :integer | |
|
4 | + end | |
|
5 | + | |
|
6 | + def self.down | |
|
7 | + remove_column 'test_pairs', 'number' | |
|
8 | + end | |
|
9 | + end |
@@ -0,0 +1,16 | |||
|
1 | + class CreateTestPairAssignments < ActiveRecord::Migration | |
|
2 | + def self.up | |
|
3 | + create_table :test_pair_assignments do |t| | |
|
4 | + t.integer "user_id" | |
|
5 | + t.integer "problem_id" | |
|
6 | + t.integer "test_pair_id" | |
|
7 | + t.integer "test_pair_number" | |
|
8 | + t.integer "request_number" | |
|
9 | + t.timestamps | |
|
10 | + end | |
|
11 | + end | |
|
12 | + | |
|
13 | + def self.down | |
|
14 | + drop_table :test_pair_assignments | |
|
15 | + end | |
|
16 | + end |
@@ -0,0 +1,9 | |||
|
1 | + class AddSubmittedToTestPairAssignment < ActiveRecord::Migration | |
|
2 | + def self.up | |
|
3 | + add_column 'test_pair_assignments', 'submitted', :boolean | |
|
4 | + end | |
|
5 | + | |
|
6 | + def self.down | |
|
7 | + remove_column 'test_pair_assignments', 'submitted' | |
|
8 | + end | |
|
9 | + end |
@@ -0,0 +1,7 | |||
|
1 | + # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html | |
|
2 | + | |
|
3 | + # one: | |
|
4 | + # column: value | |
|
5 | + # | |
|
6 | + # two: | |
|
7 | + # column: value |
@@ -0,0 +1,8 | |||
|
1 | + require 'test_helper' | |
|
2 | + | |
|
3 | + class TestPairAssignmentTest < ActiveSupport::TestCase | |
|
4 | + # Replace this with your real tests. | |
|
5 | + test "the truth" do | |
|
6 | + assert true | |
|
7 | + end | |
|
8 | + end |
@@ -167,24 +167,55 | |||
|
167 | 167 | |
|
168 | 168 | def announcements |
|
169 | 169 | if params.has_key? 'recent' |
|
170 | 170 | prepare_announcements(params[:recent]) |
|
171 | 171 | else |
|
172 | 172 | prepare_announcements |
|
173 | 173 | end |
|
174 | 174 | render(:partial => 'announcement', |
|
175 | 175 | :collection => @announcements, |
|
176 | 176 | :locals => {:announcement_effect => true}) |
|
177 | 177 | end |
|
178 | 178 | |
|
179 | + # actions for Code Jom | |
|
180 | + def new_input | |
|
181 | + problem = Problem.find(params[:id]) | |
|
182 | + user = User.find(session[:user_id]) | |
|
183 | + if user.can_request_new_test_pair_for? problem | |
|
184 | + assignment = user.get_new_test_pair_assignment_for problem | |
|
185 | + assignment.save | |
|
186 | + | |
|
187 | + send_data(assignment.test_pair.input, | |
|
188 | + { :filename => "#{problem.name}-#{assignment.request_number}.in", | |
|
189 | + :type => 'text/plain' }) | |
|
190 | + else | |
|
191 | + flash[:notice] = 'You cannot request new input now.' | |
|
192 | + redirect_to :action => 'list' | |
|
193 | + end | |
|
194 | + end | |
|
195 | + | |
|
196 | + def download | |
|
197 | + problem = Problem.find(params[:id]) | |
|
198 | + user = User.find(session[:user_id]) | |
|
199 | + recent_assignment = user.get_recent_test_pair_assignment_for problem | |
|
200 | + if recent_assignment != nil | |
|
201 | + send_data(recent_assignment.test_pair.input, | |
|
202 | + { :filename => "#{problem.name}-#{recent_assignment.request_number}.in", | |
|
203 | + :type => 'text/plain' }) | |
|
204 | + else | |
|
205 | + flash[:notice] = 'You have not request for any input data for this problem.' | |
|
206 | + redirect_to :action => 'list' | |
|
207 | + end | |
|
208 | + end | |
|
209 | + | |
|
179 | 210 | protected |
|
180 | 211 | |
|
181 | 212 | def prepare_announcements(recent=nil) |
|
182 | 213 | if Configuration.show_tasks_to?(@user) |
|
183 | 214 | @announcements = Announcement.find_published(true) |
|
184 | 215 | else |
|
185 | 216 | @announcements = Announcement.find_published |
|
186 | 217 | end |
|
187 | 218 | if recent!=nil |
|
188 | 219 | recent_id = recent.to_i |
|
189 | 220 | @announcements = @announcements.find_all { |a| a.id > recent_id } |
|
190 | 221 | end |
@@ -1,24 +1,39 | |||
|
1 | 1 | class Problem < ActiveRecord::Base |
|
2 | 2 | |
|
3 | 3 | belongs_to :description |
|
4 | 4 | has_many :test_pairs, :dependent => :delete_all |
|
5 | 5 | |
|
6 | 6 | validates_presence_of :name |
|
7 | 7 | validates_format_of :name, :with => /^\w+$/ |
|
8 | 8 | validates_presence_of :full_name |
|
9 | 9 | |
|
10 | 10 | DEFAULT_TIME_LIMIT = 1 |
|
11 | 11 | DEFAULT_MEMORY_LIMIT = 32 |
|
12 | 12 | |
|
13 | + def test_pair_count | |
|
14 | + @test_pair_count ||= test_pairs.size | |
|
15 | + end | |
|
16 | + | |
|
17 | + def uses_random_test_pair? | |
|
18 | + test_pair_count != 0 | |
|
19 | + end | |
|
20 | + | |
|
21 | + def random_test_pair(forbidden_numbers=nil) | |
|
22 | + begin | |
|
23 | + test_num = 1 + rand(test_pair_count) | |
|
24 | + end while forbidden_numbers!=nil and forbidden_numbers.include? test_num | |
|
25 | + test_pairs.find_by_number test_num | |
|
26 | + end | |
|
27 | + | |
|
13 | 28 | def self.find_available_problems |
|
14 | 29 | find(:all, :conditions => {:available => true}, :order => "date_added DESC") |
|
15 | 30 | end |
|
16 | 31 | |
|
17 | 32 | def self.create_from_import_form_params(params, old_problem=nil) |
|
18 | 33 | problem = old_problem || Problem.new |
|
19 | 34 | import_params = Problem.extract_params_and_check(params, problem) |
|
20 | 35 | |
|
21 | 36 | if not problem.valid? |
|
22 | 37 | return problem, 'Error importing' |
|
23 | 38 | end |
|
24 | 39 |
@@ -1,3 +1,9 | |||
|
1 | + # TestPair stores an input-solution pair for a problem. This is used | |
|
2 | + # in a certain "test-pair"-type problem for the CodeJom competition | |
|
3 | + # which follows the Google Code Jam format, i.e., a participant only | |
|
4 | + # submits a solution to a single random input that the participant | |
|
5 | + # requested. This input-solution pair is a TestPair. | |
|
6 | + | |
|
1 | 7 | class TestPair < ActiveRecord::Base |
|
2 | 8 | belongs_to :problem |
|
3 | 9 | end |
@@ -7,24 +7,26 | |||
|
7 | 7 | has_many :test_requests, :order => "submitted_at DESC" |
|
8 | 8 | |
|
9 | 9 | has_many :messages, |
|
10 | 10 | :class_name => "Message", |
|
11 | 11 | :foreign_key => "sender_id", |
|
12 | 12 | :order => 'created_at DESC' |
|
13 | 13 | |
|
14 | 14 | has_many :replied_messages, |
|
15 | 15 | :class_name => "Message", |
|
16 | 16 | :foreign_key => "receiver_id", |
|
17 | 17 | :order => 'created_at DESC' |
|
18 | 18 | |
|
19 | + has_many :test_pair_assignments, :dependent => :delete_all | |
|
20 | + | |
|
19 | 21 | belongs_to :site |
|
20 | 22 | belongs_to :country |
|
21 | 23 | |
|
22 | 24 | named_scope :activated_users, :conditions => {:activated => true} |
|
23 | 25 | |
|
24 | 26 | validates_presence_of :login |
|
25 | 27 | validates_uniqueness_of :login |
|
26 | 28 | validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/ |
|
27 | 29 | validates_length_of :login, :within => 3..30 |
|
28 | 30 | |
|
29 | 31 | validates_presence_of :full_name |
|
30 | 32 | validates_length_of :full_name, :minimum => 1 |
@@ -58,24 +60,66 | |||
|
58 | 60 | def authenticated?(password) |
|
59 | 61 | if self.activated |
|
60 | 62 | hashed_password == User.encrypt(password,self.salt) |
|
61 | 63 | else |
|
62 | 64 | false |
|
63 | 65 | end |
|
64 | 66 | end |
|
65 | 67 | |
|
66 | 68 | def admin? |
|
67 | 69 | self.roles.detect {|r| r.name == 'admin' } |
|
68 | 70 | end |
|
69 | 71 | |
|
72 | + # These are methods related to test pairs | |
|
73 | + | |
|
74 | + def get_test_pair_assignments_for(problem) | |
|
75 | + test_pair_assignments.find_all { |a| a.problem_id == problem.id } | |
|
76 | + end | |
|
77 | + | |
|
78 | + def get_recent_test_pair_assignment_for(problem) | |
|
79 | + assignments = get_test_pair_assignments_for problem | |
|
80 | + if assignments.length == 0 | |
|
81 | + return nil | |
|
82 | + else | |
|
83 | + recent = assignments[0] | |
|
84 | + assignments.each do |a| | |
|
85 | + recent = a if a.request_number > recent.request_number | |
|
86 | + end | |
|
87 | + return recent | |
|
88 | + end | |
|
89 | + end | |
|
90 | + | |
|
91 | + def can_request_new_test_pair_for?(problem) | |
|
92 | + recent = get_recent_test_pair_assignment_for problem | |
|
93 | + return (recent == nil or recent.submitted) | |
|
94 | + end | |
|
95 | + | |
|
96 | + def get_new_test_pair_assignment_for(problem) | |
|
97 | + previous_assignment_numbers = | |
|
98 | + get_test_pair_assignments_for(problem).collect {|a| a.test_pair_number } | |
|
99 | + test_pair = problem.random_test_pair(previous_assignment_numbers) | |
|
100 | + if test_pair | |
|
101 | + assignment = TestPairAssignment.new(:user => self, | |
|
102 | + :problem => problem, | |
|
103 | + :test_pair => test_pair, | |
|
104 | + :test_pair_number => test_pair.number, | |
|
105 | + :request_number => | |
|
106 | + previous_assignment_numbers.length + 1, | |
|
107 | + :submitted => false) | |
|
108 | + return assignment | |
|
109 | + else | |
|
110 | + return nil | |
|
111 | + end | |
|
112 | + end | |
|
113 | + | |
|
70 | 114 | def email_for_editing |
|
71 | 115 | if self.email==nil |
|
72 | 116 | "(unknown)" |
|
73 | 117 | elsif self.email=='' |
|
74 | 118 | "(blank)" |
|
75 | 119 | else |
|
76 | 120 | self.email |
|
77 | 121 | end |
|
78 | 122 | end |
|
79 | 123 | |
|
80 | 124 | def email_for_editing=(e) |
|
81 | 125 | self.email=e |
@@ -1,18 +1,26 | |||
|
1 | 1 | <tr class="info-<%= (problem_counter%2==0) ? "even" : "odd" %>"> |
|
2 | 2 | <td> |
|
3 | 3 | <%= "#{problem_counter+1}" %> |
|
4 | 4 | </td> |
|
5 | 5 | <td> |
|
6 | 6 | <%= "#{problem.full_name} (#{problem.name})" %> |
|
7 | 7 | <%= link_to "[#{t 'main.problem_desc'}]", problem.url, :popup => true if (problem.url!=nil) and (problem.url!='') %> |
|
8 | 8 | </td> |
|
9 | 9 | <td align="center"> |
|
10 | 10 | <%= @prob_submissions[problem_counter][:count] %> |
|
11 | 11 | </td> |
|
12 | 12 | <td> |
|
13 | - <%= render :partial => 'submission_short', | |
|
14 | - :locals => { | |
|
15 | - :submission => @prob_submissions[problem_counter][:submission], | |
|
16 | - :problem_name => problem.name }%> | |
|
13 | + <span id="problem-form-<%= problem.id %>"> | |
|
14 | + <% form_tag "new_input/#{problem.id}", :method => :post do -%> | |
|
15 | + <input type="submit" value="New input"/> | |
|
16 | + <% end -%> | |
|
17 | + <% form_tag "download/#{problem.id}", :method => :post do -%> | |
|
18 | + <input type="submit" value="Download input"/> | |
|
19 | + <% end -%> | |
|
20 | + <% form_tag "submit_solution/#{problem.id}", :method => :post do -%> | |
|
21 | + <input type="file"> | |
|
22 | + <input type="submit" value="Submit solution"/> | |
|
23 | + <% end -%> | |
|
24 | + </span> | |
|
17 | 25 | </td> |
|
18 | 26 | </tr> |
@@ -1,24 +1,24 | |||
|
1 | 1 | # This file is auto-generated from the current state of the database. Instead of editing this file, |
|
2 | 2 | # please use the migrations feature of Active Record to incrementally modify your database, and |
|
3 | 3 | # then regenerate this schema definition. |
|
4 | 4 | # |
|
5 | 5 | # Note that this schema.rb definition is the authoritative source for your database schema. If you need |
|
6 | 6 | # to create the application database on another system, you should be using db:schema:load, not running |
|
7 | 7 | # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations |
|
8 | 8 | # you'll amass, the slower it'll run and the greater likelihood for issues). |
|
9 | 9 | # |
|
10 | 10 | # It's strongly recommended to check this file into your version control system. |
|
11 | 11 | |
|
12 |
- ActiveRecord::Schema.define(:version => 2010011 |
|
|
12 | + ActiveRecord::Schema.define(:version => 20100118174404) do | |
|
13 | 13 | |
|
14 | 14 | create_table "announcements", :force => true do |t| |
|
15 | 15 | t.string "author" |
|
16 | 16 | t.text "body" |
|
17 | 17 | t.boolean "published" |
|
18 | 18 | t.datetime "created_at" |
|
19 | 19 | t.datetime "updated_at" |
|
20 | 20 | t.boolean "frontpage", :default => false |
|
21 | 21 | t.boolean "contest_only", :default => false |
|
22 | 22 | t.string "title" |
|
23 | 23 | end |
|
24 | 24 | |
@@ -146,30 +146,42 | |||
|
146 | 146 | end |
|
147 | 147 | |
|
148 | 148 | add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true |
|
149 | 149 | add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id" |
|
150 | 150 | |
|
151 | 151 | create_table "tasks", :force => true do |t| |
|
152 | 152 | t.integer "submission_id" |
|
153 | 153 | t.datetime "created_at" |
|
154 | 154 | t.integer "status" |
|
155 | 155 | t.datetime "updated_at" |
|
156 | 156 | end |
|
157 | 157 | |
|
158 | + create_table "test_pair_assignments", :force => true do |t| | |
|
159 | + t.integer "user_id" | |
|
160 | + t.integer "problem_id" | |
|
161 | + t.integer "test_pair_id" | |
|
162 | + t.integer "test_pair_number" | |
|
163 | + t.integer "request_number" | |
|
164 | + t.datetime "created_at" | |
|
165 | + t.datetime "updated_at" | |
|
166 | + t.boolean "submitted" | |
|
167 | + end | |
|
168 | + | |
|
158 | 169 | create_table "test_pairs", :force => true do |t| |
|
159 | 170 | t.integer "problem_id" |
|
160 | 171 | t.text "input" |
|
161 | 172 | t.text "solution" |
|
162 | 173 | t.datetime "created_at" |
|
163 | 174 | t.datetime "updated_at" |
|
175 | + t.integer "number" | |
|
164 | 176 | end |
|
165 | 177 | |
|
166 | 178 | create_table "test_requests", :force => true do |t| |
|
167 | 179 | t.integer "user_id" |
|
168 | 180 | t.integer "problem_id" |
|
169 | 181 | t.integer "submission_id" |
|
170 | 182 | t.string "input_file_name" |
|
171 | 183 | t.string "output_file_name" |
|
172 | 184 | t.string "running_stat" |
|
173 | 185 | t.integer "status" |
|
174 | 186 | t.datetime "updated_at" |
|
175 | 187 | t.datetime "submitted_at" |
@@ -90,26 +90,29 | |||
|
90 | 90 | |
|
91 | 91 | return testdata_filename |
|
92 | 92 | end |
|
93 | 93 | |
|
94 | 94 | def import_test_pairs(dirname) |
|
95 | 95 | test_num = 1 |
|
96 | 96 | while FileTest.exists? "#{dirname}/#{test_num}.in" |
|
97 | 97 | in_filename = "#{dirname}/#{test_num}.in" |
|
98 | 98 | sol_filename = "#{dirname}/#{test_num}.sol" |
|
99 | 99 | |
|
100 | 100 | break if not FileTest.exists? sol_filename |
|
101 | 101 | |
|
102 | + puts "#{dirname}" | |
|
103 | + | |
|
102 | 104 | test_pair = TestPair.new(:input => open(in_filename).read, |
|
103 | 105 | :solution => open(sol_filename).read, |
|
106 | + :number => test_num, | |
|
104 | 107 | :problem => @problem) |
|
105 | 108 | break if not test_pair.save |
|
106 | 109 | |
|
107 | 110 | test_num += 1 |
|
108 | 111 | end |
|
109 | 112 | return test_num > 1 |
|
110 | 113 | end |
|
111 | 114 | |
|
112 | 115 | def import_problem_description(dirname) |
|
113 | 116 | html_files = Dir["#{dirname}/*.html"] |
|
114 | 117 | markdown_files = Dir["#{dirname}/*.md"] + Dir["#{dirname}/*.markdown"] |
|
115 | 118 | if (html_files.length != 0) or (markdown_files.length != 0) |
You need to be logged in to leave comments.
Login now