mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 17:38:19 +08:00
judge: use case.score & normalizeSubtask API
This commit is contained in:
1 parent
310189bc4d
commit
539a1c44ce
14 files changed
+231
-201
No files matched your search
@@ -38,14 +38,14 @@ const subtasksKey = [
|
||||
|
||||
const casesKey = ['time', 'memory', 'input', 'output'];
|
||||
|
||||
function configYamlFormat(config: ProblemConfigFile) {
|
||||
export function configYamlFormat(config: ProblemConfigFile) {
|
||||
const formatConfig: ProblemConfigFile = {};
|
||||
configKey.forEach((key) => {
|
||||
if (config[key] !== undefined) {
|
||||
if (key === 'subType' && ['single', 'multi'].includes(config[key]) && config.type !== 'submit_answer') return;
|
||||
if (key === 'checker_type' && config.type !== 'default') return;
|
||||
if (key === 'checker'
|
||||
&& (['default', 'strict'].includes(formatConfig.checker_type) || formatConfig.checker_type === undefined)) return;
|
||||
&& (['default', 'strict'].includes(formatConfig.checker_type) || !formatConfig.checker_type)) return;
|
||||
if (key === 'interactor' && config.type !== 'interactive') return;
|
||||
if (key === 'subtasks') {
|
||||
formatConfig[key] = [];
|
||||
@@ -62,7 +62,7 @@ function configYamlFormat(config: ProblemConfigFile) {
|
||||
formatConfig[key] = [];
|
||||
config[key].forEach((caseItem) => {
|
||||
const formatCase: TestCaseConfig = {
|
||||
time: 1000, memory: 256, input: '', output: '',
|
||||
time: '1000ms', memory: '256MB', input: '', output: '',
|
||||
};
|
||||
casesKey.forEach((caseKey) => {
|
||||
if (caseItem[caseKey] !== undefined) formatCase[caseKey] = caseItem[caseKey];
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useSelector, useDispatch } from 'react-redux';
|
||||
import { SubtaskConfig } from 'hydrooj/src/interface';
|
||||
import { parseTimeMS, parseMemoryMB } from '@hydrooj/utils/lib/common';
|
||||
import CustomSelectAutoComplete from '../autocomplete/components/CustomSelectAutoComplete';
|
||||
import { FormItem, ManagedInput } from './BasicForm';
|
||||
import { FormItem } from './BasicForm';
|
||||
import { RootState } from './reducer';
|
||||
import { CasesTable } from './TestCasesTable';
|
||||
|
||||
@@ -71,7 +71,7 @@ export function SubtasksTable({ index }) {
|
||||
{['id', 'score'].map((key) => (
|
||||
<td key={key}>
|
||||
<input
|
||||
value={subtask[key] || ''}
|
||||
value={subtask[key] ?? ''}
|
||||
onChange={dispatcher(key)}
|
||||
type="number"
|
||||
className="textbox"
|
||||
@@ -80,7 +80,7 @@ export function SubtasksTable({ index }) {
|
||||
))}
|
||||
<td>
|
||||
<select
|
||||
value={subtask.type || ''}
|
||||
value={subtask.type ?? 'min'}
|
||||
onChange={dispatcher('type')}
|
||||
className="select"
|
||||
>
|
||||
@@ -116,20 +116,48 @@ export function SubtasksTable({ index }) {
|
||||
);
|
||||
}
|
||||
|
||||
function GlobalTaskConfig() {
|
||||
const time = useSelector((state: RootState) => state.config.time);
|
||||
const memory = useSelector((state: RootState) => state.config.memory);
|
||||
const dispatch = useDispatch();
|
||||
const dispatcher = (key: string, suffix = '') => (ev: React.ChangeEvent<HTMLInputElement | HTMLSelectElement> | number) => {
|
||||
let value = typeof ev !== 'object' ? ev : ev.currentTarget?.value;
|
||||
if (value === 0) value = '';
|
||||
if (value && suffix) value += suffix;
|
||||
dispatch({ type: 'CONFIG_FORM_UPDATE', key, value });
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<FormItem columns={6} label="Time">
|
||||
<NumericInput
|
||||
rightElement={<Tag minimal>ms</Tag>}
|
||||
value={time ? parseTimeMS(time).toString() : ''}
|
||||
placeholder={parseTimeMS('1000ms').toString()}
|
||||
onValueChange={dispatcher('time', 'ms')}
|
||||
buttonPosition="none"
|
||||
fill
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem columns={6} label="Memory">
|
||||
<NumericInput
|
||||
rightElement={<Tag minimal>MB</Tag>}
|
||||
value={memory ? parseMemoryMB(memory).toString() : ''}
|
||||
placeholder={parseMemoryMB('256m').toString()}
|
||||
onValueChange={dispatcher('memory', 'MB')}
|
||||
buttonPosition="none"
|
||||
fill
|
||||
/>
|
||||
</FormItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function TaskConfig() {
|
||||
const len = useSelector((state: RootState) => state.config.subtasks?.length);
|
||||
return (
|
||||
<FormItem columns={12} label="Task Settings">
|
||||
<div className="row">
|
||||
<FormItem columns={4} label="Time">
|
||||
<ManagedInput placeholder="Time" formKey="time" />
|
||||
</FormItem>
|
||||
<FormItem columns={4} label="Memory">
|
||||
<ManagedInput placeholder="Memory" formKey="memory" />
|
||||
</FormItem>
|
||||
<FormItem columns={4} label="Score">
|
||||
<ManagedInput placeholder="Score" formKey="score" />
|
||||
</FormItem>
|
||||
<GlobalTaskConfig />
|
||||
<FormItem columns={12} label="TestCases" disableLabel>
|
||||
{len && [...Array(len).keys()].map((i) => <SubtasksTable index={i} key={i} />)}
|
||||
</FormItem>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import yaml from 'js-yaml';
|
||||
import type { ProblemConfigFile } from 'hydrooj/src/interface';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { parseMemoryMB, parseTimeMS } from '@hydrooj/utils/lib/common';
|
||||
|
||||
type State = ProblemConfigFile & { __loaded: boolean };
|
||||
|
||||
@@ -25,23 +26,20 @@ export default function reducer(state = { type: 'default', __loaded: false } as
|
||||
}
|
||||
case 'CONFIG_AUTOCASES_UPDATE': {
|
||||
const next = { ...state };
|
||||
const autocases = action.value;
|
||||
if (autocases.subtasks.length === 0) next.subtasks = [];
|
||||
const { subtasks } = action;
|
||||
for (const subtask of subtasks) {
|
||||
if (subtask.time === parseTimeMS(state.time || '1s')) delete subtask.time;
|
||||
if (subtask.memory === parseMemoryMB(state.memory || '256m')) delete subtask.memory;
|
||||
if (subtask.time) subtask.time += 'ms';
|
||||
if (subtask.memory) subtask.memory += 'MB';
|
||||
}
|
||||
if (subtasks.length === 0) next.subtasks = [];
|
||||
else {
|
||||
next.subtasks = autocases.subtasks.map((subtask) => (
|
||||
next.subtasks = subtasks.map((subtask) => (
|
||||
{ ...subtask, ...{ cases: subtask.cases.map((i) => ({ input: i.input, output: i.output })) } }));
|
||||
}
|
||||
return next;
|
||||
}
|
||||
case 'CONFIG_SUBTASKS_SWITCH': {
|
||||
const next = { ...state };
|
||||
next.subtasks = next.cases.map((k, v) => ({
|
||||
id: v, time: k.time, memory: k.memory, cases: [{ input: k.input, output: k.output }],
|
||||
}));
|
||||
if (!next.subtasks.length) next.subtasks.push({ id: 0 });
|
||||
delete next.cases;
|
||||
return next;
|
||||
}
|
||||
case 'CONFIG_SUBTASK_UPDATE': {
|
||||
const subtasks = cloneDeep(state.subtasks);
|
||||
const subsubtasks = cloneDeep(state.subtasks[action.id]);
|
||||
|
||||
@@ -52,8 +52,7 @@
|
||||
transition: outline-color 0.2s, border-color 0.2s
|
||||
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1)
|
||||
box-shadow: none
|
||||
input::placeholder
|
||||
color: inherit
|
||||
|
||||
|
||||
.data-table
|
||||
tr
|
||||
@@ -68,4 +67,7 @@
|
||||
background: transparent
|
||||
|
||||
.hover-row.status-bar
|
||||
display: none
|
||||
display: none
|
||||
|
||||
input::placeholder
|
||||
color: rgba(95,107,124,.6)!important
|
||||
@@ -7,10 +7,10 @@ import yaml from 'js-yaml';
|
||||
import Notification from 'vj/components/notification';
|
||||
import Dialog, { ConfirmDialog } from 'vj/components/dialog/index';
|
||||
import download from 'vj/components/zipDownloader';
|
||||
import {
|
||||
size, readSubtasksFromFiles, parseTimeMS, parseMemoryMB,
|
||||
} from '@hydrooj/utils/lib/common';
|
||||
import { size, readSubtasksFromFiles } from '@hydrooj/utils/lib/common';
|
||||
import tpl from 'vj/utils/tpl';
|
||||
import { SubtaskType } from 'hydrooj/src/interface';
|
||||
import { configYamlFormat } from 'vj/components/problemconfig/ProblemConfigEditor';
|
||||
|
||||
async function handleSection(ev: JQuery.ClickEvent<Document, undefined, any, any>, type: string) {
|
||||
const $section = $(ev.currentTarget).closest('.section--problem-sidebar-testdata');
|
||||
@@ -146,7 +146,7 @@ const page = new NamedPage('problem_config', () => {
|
||||
}
|
||||
|
||||
async function uploadConfig(config: object) {
|
||||
const configYaml = yaml.dump(config);
|
||||
const configYaml = yaml.dump(configYamlFormat(config));
|
||||
Notification.info(i18n('Saving file...'));
|
||||
const data = new FormData();
|
||||
data.append('filename', 'config.yaml');
|
||||
@@ -179,20 +179,20 @@ const page = new NamedPage('problem_config', () => {
|
||||
// TODO set yaml schema
|
||||
const state = store.getState();
|
||||
if (!state.config.__loaded) return;
|
||||
if (state.config.subtasks || state.config.cases) return;
|
||||
if (state.config.cases) {
|
||||
const score = state.config.score * state.config.cases.length;
|
||||
state.config.subtasks = [{ type: 'sum' as SubtaskType, score: score && score < 100 ? score : 100, cases: state.config.cases }];
|
||||
delete state.config.cases;
|
||||
delete state.config.score;
|
||||
}
|
||||
if (state.config.subtasks) return;
|
||||
const testdata = (state.testdata || []).map((i) => i.name);
|
||||
const checkFile = (file: string) => (testdata.includes(file) ? file : null);
|
||||
unsubscribe();
|
||||
const value = readSubtasksFromFiles(testdata, checkFile, state.config, {});
|
||||
for (const subtask of value.subtasks) {
|
||||
if (subtask.time === parseTimeMS(state.config.time || '1s')) delete subtask.time;
|
||||
if (subtask.memory === parseMemoryMB(state.config.memory || '256m')) delete subtask.memory;
|
||||
if (subtask.time) subtask.time += 'ms';
|
||||
if (subtask.memory) subtask.memory += 'MB';
|
||||
}
|
||||
const subtasks = readSubtasksFromFiles(testdata, checkFile, state.config);
|
||||
store.dispatch({
|
||||
type: 'CONFIG_AUTOCASES_UPDATE',
|
||||
value,
|
||||
subtasks,
|
||||
});
|
||||
});
|
||||
render(
|
||||
|
||||
Reference in new issue
Block a user