change e testcase table UI and add CPP validator

This commit is contained in:
cuom1999 2020-03-17 00:11:03 -06:00
parent 0ff312e3ba
commit f74f8b6e05
15 changed files with 803 additions and 181 deletions

View file

@ -2,10 +2,7 @@
{% block body %}
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><style>body {
max-width: 980px;
border: 1px solid #ddd;
outline: 1300px solid #fff;
margin: 16px auto;
margin: 0;
}
body .markdown-body
@ -1079,28 +1076,13 @@ body .markdown-body
<p>Additionally, if the <code>check</code> method has the flag <code>run_on_error</code> set, it will be run against the submission&rsquo;s output, even if it receives an IR/TLE/RTE/MLE verdict.
The only built-in checker that has this flag set is the <code>linecount</code> checker.</p>
<h2 id="return">Return:<a class="headerlink" href="#return" title="Permanent link"></a></h2>
<p><code>True</code> for correct output, <code>False</code> for incorrect one</p>
<p><code>check</code> can return either a <code>CheckerResult</code> object (<code>from dmoj.result import CheckerResult</code>), or a boolean (<code>case_passed_bool</code>).
A <code>CheckerResult</code> can be instantiated through <code>CheckerResult(case_passed_bool, points_awarded, feedback='')</code>.</p>
<h2 id="sample-checker">Sample Checker:<a class="headerlink" href="#sample-checker" title="Permanent link"></a></h2>
<p>Here is the checker for the problem: Print 2 integers having sum equal to n (n is read from input).</p>
<div class="codehilite"><pre><span class="k">def</span> <span class="nf">check</span><span class="p">(</span><span class="n">process_output</span><span class="p">,</span> <span class="n">judge_output</span><span class="p">,</span> <span class="n">judge_input</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="c1"># process the input</span>
<span class="n">input_arr</span> <span class="o">=</span> <span class="n">judge_input</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
<span class="k">assert</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">input_arr</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">input_arr</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<iframe src="https://pastebin.com/embed_iframe/UvuchwbQ" style="border:none;width:100%;height:40em;"></iframe>
<span class="c1"># process the contestant&#39;s output</span>
<span class="n">output_arr</span> <span class="o">=</span> <span class="n">process_output</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
</article></body></html>
<span class="k">if</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">output_arr</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">2</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">False</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">output_arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]),</span> <span class="nb">int</span><span class="p">(</span><span class="n">output_arr</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">False</span>
<span class="k">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">==</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">True</span>
<span class="k">return</span> <span class="bp">False</span>
</pre></div></article></body></html>
{% endblock body %}

View file

@ -95,21 +95,29 @@
}).change();
}
function checker_custom($checker, $custom_checker) {
$tr = $custom_checker.parent().parent();
(function toggle_custom() {
let $custom_checker = $('#id_problem-data-custom_checker')
let $checker = $('#id_problem-data-checker')
let $validator = $('#id_problem-data-custom_validator')
$tr_checker = $custom_checker.parent().parent();
$tr_validator = $validator.parent().parent()
$td = $checker.parent();
var $sample = $("<a/>",{
text: "Sample Checker",
text: "{{_('Instruction')}}",
style: "margin-left:3em;",
target: "_blank",
href: "{{url('custom_checker_sample')}}"
}).appendTo($td);
$checker.change(function () {
$tr.toggle($checker.val().startsWith('custom')).change();
$tr_checker.toggle($checker.val() == 'custom').change();
$tr_validator.toggle($checker.val() == 'customval').change();
$sample.toggle($checker.val().startsWith('custom')).change();
}).change();
}
})();
function swap_row($a, $b) {
var $a_order = $a.find('input[id$=order]'), $b_order = $b.find('input[id$=order]');
@ -123,8 +131,7 @@
}
checker_precision($('#id_problem-data-checker'));
checker_custom($('#id_problem-data-checker'), $('#id_problem-data-custom_checker'));
$table.on('add-row', function (e, $tr) {
var $order = $tr.find('input').filter('[id$=order]').attr('type', 'hidden').val(++order);
$order.after($('<span>', {'class': 'order'}).text($order.val()))
@ -306,26 +313,6 @@
$("input[name$='DELETE']").attr('checked', false);
}
});
var $controls = $('#column-visible');
var problem = $controls.attr('data-problem');
$controls.find('input').change(function () {
var $this = $(this), suffix = $this.attr('data-suffix'), checked = $this.is(':checked');
$table.find('.' + suffix.replace(/_/g, '-')).toggle(checked);
localStorage.setItem('data-visible:' + problem + ':' + suffix, checked ? '1' : '0')
}).each(function () {
var $this = $(this), suffix = $this.attr('data-suffix'), filled = false;
filled = localStorage.getItem('data-visible:' + problem + ':' + suffix);
if (filled !== null)
filled = filled == '1';
else {
filled = false;
$table.find('[id$=' + suffix + ']').each(function () {
filled |= !!$(this).val();
});
}
$this.prop('checked', filled).trigger('change');
});
}).change();
</script>
{% endblock %}
@ -451,29 +438,7 @@
</a>
</td>
</table>
<div id="column-visible" data-problem="{{ problem.code }}">
<strong>{{ _('Show columns:') }}</strong>
<label>
<input type="checkbox" data-suffix="output_prefix">
{{ _('Output prefix') }}
</label>
<label>
<input type="checkbox" data-suffix="output_limit">
{{ _('Output limit') }}
</label>
<label>
<input type="checkbox" data-suffix="checker">
{{ _('Checker') }}
</label>
<label>
<input type="checkbox" data-suffix="generator_args">
{{ _('Generator args') }}
</label>
<label>
<input type="checkbox" id="delete-all">
{{ _('Delete all') }}
</label>
</div>
<input type="submit" value="{{ _('Apply!') }}" class="button" id="submit-button">
<table id="case-table" class="table">
<thead>
<tr>
@ -483,12 +448,10 @@
<th>{{ _('Output file') }}</th>
<th>{{ _('Points') }}</th>
<th>{{ _('Pretest?') }}</th>
<th class="output-prefix">{{ _('Output prefix') }}</th>
<th class="output-limit">{{ _('Output limit') }}</th>
<th class="checker">{{ _('Checker') }}</th>
<th class="generator-args">{{ _('Generator args') }}</th>
{% if cases_formset.can_delete %}
<th>{{ _('Delete?') }}
<th>{{ _('Delete?') }}
<br>
<input type="checkbox" name="delete-all" id="delete-all">
</th>
{% endif %}
</tr>
@ -517,25 +480,15 @@
</td>
<td>{{ form.points.errors }}{{ form.points }}</td>
<td>{{ form.is_pretest.errors }}{{ form.is_pretest }}</td>
<td class="output-prefix">{{ form.output_prefix.errors }}{{ form.output_prefix }}</td>
<td class="output-limit">{{ form.output_limit.errors }}{{ form.output_limit }}</td>
<td class="checker">
{{ form.checker.errors }}{{ form.checker }}{{ form.checker_args.errors }}{{ form.checker_args }}
</td>
<td class="generator-args">{{ form.generator_args.errors }}{{ form.generator_args }}
<a href="javascript:void(0)" class="edit-generator-args">
<i class="fa fa-pencil"></i>
{{ _('Edit') }}
</a>
</td>
{% if cases_formset.can_delete %}
<td>{{ form.DELETE }}</td>
<td>{{ form.DELETE }}
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
<input type="submit" value="{{ _('Submit!') }}" class="button" id="submit-button">
<input type="submit" value="{{ _('Apply!') }}" class="button" id="submit-button">
<a id="add-case-row" href="#"><i class="fa fa-plus"></i> {{ _('Add new case') }}</a>
</form>
<div style="display: none" class="generator-args-editor"><textarea></textarea><a class="button">Save</a></div>

View file

@ -38,7 +38,7 @@
</div>
{% endif %}
<br>
<hr class="half-hr">
<hr>
<br>
<div class="source-wrap">
<table>

View file

@ -17,7 +17,7 @@
{% if submission.error %}
<h3>{{ _('Compilation Warnings') }}</h3>
<pre>{{ submission.error|ansi2html }}</pre>
<hr class="half-hr"><br>
<hr><br>
{% endif %}
{% if is_pretest %}
<h3>{{ _('Pretest Execution Results') }}</h3>
@ -33,7 +33,48 @@
<br>
<div class="batch-cases">
{% endif %}
<table>{% for case in batch.cases %}
<table id="testcases-table">
{% if submission.is_graded %}
{% if submission.result != 'AB' %}
<thead>
<tr id="overall-row" class="case-row overall-result-{{submission.result}}">
<td><span class="col-title">{{_('Overall: ')}}</span>
{% if request.in_contest and submission.contest_or_none %}
{% with contest=submission.contest_or_none %}
({{ _('%(points)s/%(total)s points', points=contest.points|roundfloat(3),
total=contest.problem.points|floatformat(-1)) }})
{% endwith %}
{% else %}
{{ _('%(points)s/%(total)s', points=submission.points|roundfloat(3),
total=submission.problem.points|floatformat(-1)) }}
{% endif %}
</td>
<td><span class="case-{{submission.result}}">{{submission.long_status}}</span></td>
<td><span class="col-title">{{_('Point: ')}}</span>
{{ submission.case_points|floatformat(0) }}/{{ submission.case_total|floatformat(0) }}
</td>
<td><span class="col-title">{{_('Time: ')}}</span>
{% if submission.result == "TLE" %}
<span>---</span>
{% else %}
<span title="{{ submission.time }}s">{{ (submission.time * 1000)|floatformat(0) }} ms</span>
{% endif %}
</td>
<td><span class="col-title">{{_('Memory: ')}}</span>{{ submission.memory|kbdetailformat }}</td>
</tr>
</thead>
{% endif %}
{% endif %}
{% for case in batch.cases %}
<tr id="{{ case.id }}" class="case-row toggle closed">
<td>
{%- if ((prefix_length is none or prefix_length > 0) or (request.user.is_superuser)) -%}
@ -50,26 +91,25 @@
<td>
<span title="{{ case.long_status }}" class="case-{{ case.status }}">
{%- if case.status == 'SC' %}&mdash;{% else %}{{ case.status }}{% endif -%}
{%- if case.status == 'SC' %}&mdash;{% else %}{{ case.long_status }}{% endif -%}
</span>
{%- if case.feedback %}&nbsp;({{ case.feedback }}){% endif -%}
</td>
{% if not batch.id %}
<td><span class="col-title">{{_('Point')}}: </span> {{ case.points|floatformat(0) }}/{{ case.total|floatformat(0) }}</td>
{% endif %}
<td>
{%- if case.status != 'SC' -%}
{%- if case.status == 'TLE' -%}
[&gt;<span>{{ time_limit|floatformat(3) }}s,</span>
<span><span class="col-title">{{_('Time')}}: &gt;</span>{{ (time_limit * 1000)|floatformat(0) }} ms</span>
{%- else -%}
[<span title="{{ case.time }}s">{{ case.time|floatformat(3) }}s,</span>
<span title="{{ case.time }}s"><span class="col-title">{{_('Time')}}: </span>{{ (case.time * 1000)|floatformat(0) }} ms</span>
{%- endif -%}
{%- endif -%}
</td>
<td>{% if case.status != 'SC' %}{{ case.memory|kbdetailformat }}]{% endif %}</td>
{% if not batch.id %}
<td>({{ case.points|floatformat(0) }}/{{ case.total|floatformat(0) }})</td>
{% endif %}
<td>{% if case.status != 'SC' %}<span class="col-title">{{_('Memory')}}: </span> {{ case.memory|kbdetailformat }}{% endif %}</td>
</tr>
{% if ((prefix_length is none or prefix_length > 0) or (request.user.is_superuser)) %}
@ -79,20 +119,22 @@
{% set curr_data = cases_data[case.case] %}
<strong>{{ _('Input:') }}</strong>
<pre class="case-output">{{ curr_data['input']|linebreaksbr }}</pre>
<strong>{{ _('Your output:') }}</strong>
<strong>{{ _('Output:') }}</strong>
<pre class="case-output">{{ case.output|linebreaksbr }}</pre>
<strong>{{ _('Answer:') }}</strong>
<pre class="case-output">{{ curr_data['answer']|linebreaksbr }}</pre>
{% if case.extended_feedback or case.feedback %}
<strong>{{ _('Judge feedback:') }}</strong>
{% if case.feedback %}
<pre class="case-output">{{ case.feedback|linebreaksbr }}</pre>
{% endif %}
{% if case.extended_feedback %}
<pre class="case-output">{{ case.extended_feedback|linebreaksbr }}</pre>
{% endif %}
{% endif %}
</div>
</td>
{% if case.extended_feedback %}
<td colspan="5" class="case-ext-feedback">
<div class="case-info">
<strong>{{ _('Judge feedback') }}</strong>
<pre class="case-output">{{ case.extended_feedback|linebreaksbr }}</pre>
</div>
</td>
{% endif %}
</tr>
{% endif %}
{% endfor %}
@ -104,29 +146,6 @@
{% if submission.is_graded %}
<br>
{% if submission.result != "AB" %}
<b>{{ _('Resources:') }}</b>
{% if submission.result == "TLE" %}
<span>---,</span>
{% else %}
<span title="{{ submission.time }}s">{{ submission.time|floatformat(3) }}s,</span>
{% endif %}
{{ submission.memory|kbdetailformat }}
<br>
{% if is_pretest %}
<b>{{ _('Final pretest score:') }}</b>
{% else %}
<b>{{ _('Final score:') }}</b>
{% endif %}
{{ submission.case_points|floatformat(0) }}/{{ submission.case_total|floatformat(0) }}
{% if request.in_contest and submission.contest_or_none %}
{% with contest=submission.contest_or_none %}
({{ _('%(points)s/%(total)s points', points=contest.points|roundfloat(3),
total=contest.problem.points|floatformat(-1)) }})
{% endwith %}
{% else %}
({{ _('%(points)s/%(total)s points', points=submission.points|roundfloat(3),
total=submission.problem.points|floatformat(-1)) }})
{% endif %}
{% if is_pretest and submission.result == "AC" %}
<br>
<i>{{ _('Passing pretests does not guarantee a full score on system tests.') }}</i>

View file

@ -72,7 +72,7 @@
{% endif %}
<br>
<hr class="half-hr">
<hr>
<br>
<div id="test-cases">{% include "submission/status-testcases.html" %}</div>
@ -81,7 +81,7 @@
{% if request.user == submission.user.user or perms.judge.abort_any_submission %}
<div id="abort-button">
<br>
<hr class="half-hr">
<hr>
<br>
<form action="{{ url('submission_abort', submission.id) }}" method="post">
{% csrf_token %}