mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
core&ui: add problem_config
Co-authored-by: undefined <i@undefined.moe>
This commit is contained in:
1 parent
0b71b089e0
commit
1f498484d2
20 files changed
+1128
-159
No files matched your search
@@ -2,158 +2,11 @@ import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import yaml from 'js-yaml';
|
||||
import { max, sum } from 'lodash';
|
||||
import readYamlCases, { convertIniConfig } from '@hydrooj/utils/lib/cases';
|
||||
import readYamlCases, { convertIniConfig, readCasesFromFiles, readSubtasksFromFiles } from '@hydrooj/utils/lib/cases';
|
||||
import { changeErrorType } from '@hydrooj/utils/lib/utils';
|
||||
import { getConfig } from './config';
|
||||
import { FormatError, SystemError } from './error';
|
||||
import { ensureFile, parseMemoryMB, parseTimeMS } from './utils';
|
||||
|
||||
interface Re0 {
|
||||
reg: RegExp,
|
||||
output: ((a: RegExpExecArray) => string)[],
|
||||
id: (a: RegExpExecArray) => number,
|
||||
}
|
||||
|
||||
interface Re1 extends Re0 {
|
||||
subtask: (a: RegExpExecArray) => number,
|
||||
}
|
||||
|
||||
const RE0: Re0[] = [
|
||||
{
|
||||
reg: /^([^\d]*)(\d+).(in|txt)$/,
|
||||
output: [
|
||||
(a) => `${a[1] + a[2]}.out`,
|
||||
(a) => `${a[1] + a[2]}.ans`,
|
||||
(a) => `${a[1] + a[2]}.out`.replace(/input/g, 'output'),
|
||||
(a) => (a[1].includes('input') ? `${a[1] + a[2]}.txt`.replace(/input/g, 'output') : null),
|
||||
],
|
||||
id: (a) => +a[2],
|
||||
},
|
||||
{
|
||||
reg: /^([^\d]*)\.in(\d+)$/,
|
||||
output: [
|
||||
(a) => `${a[1]}.ou${a[2]}`,
|
||||
(a) => `${a[1]}.ou${a[2]}`.replace(/input/g, 'output'),
|
||||
],
|
||||
id: (a) => +a[2],
|
||||
},
|
||||
];
|
||||
const RE1: Re1[] = [
|
||||
{
|
||||
reg: /^([^\d]*)([0-9]+)([-_])([0-9]+).in$/,
|
||||
output: [(a) => `${a[1] + a[2]}${a[3]}${a[4]}.out`],
|
||||
subtask: (a) => +a[2],
|
||||
id: (a) => +a[4],
|
||||
},
|
||||
];
|
||||
|
||||
async function read0(folder: string, files: string[], checkFile, cfg) {
|
||||
const cases = [];
|
||||
for (const file of files) {
|
||||
for (const REG of RE0) {
|
||||
if (REG.reg.test(file)) {
|
||||
const data = REG.reg.exec(file);
|
||||
const c = { input: file, output: '', id: REG.id(data) };
|
||||
for (const func of REG.output) {
|
||||
if (cfg.noOutputFile) c.output = '/dev/null';
|
||||
else c.output = func(data);
|
||||
if (c.output && (c.output === '/dev/null' || fs.existsSync(path.resolve(folder, c.output)))) {
|
||||
cases.push(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cases.sort((a, b) => (a.id - b.id));
|
||||
const extra = cases.length - (100 % cases.length);
|
||||
const config = {
|
||||
count: 0,
|
||||
subtasks: [{
|
||||
time: parseTimeMS(cfg.time || '1s'),
|
||||
memory: parseMemoryMB(cfg.memory || '256m'),
|
||||
type: 'sum',
|
||||
cases: [],
|
||||
score: Math.floor(100 / cases.length),
|
||||
}],
|
||||
};
|
||||
for (let i = 0; i < extra; i++) {
|
||||
config.count++;
|
||||
config.subtasks[0].cases.push({
|
||||
id: config.count,
|
||||
input: checkFile(cases[i].input),
|
||||
output: checkFile(cases[i].output),
|
||||
});
|
||||
}
|
||||
if (extra < cases.length) {
|
||||
config.subtasks.push({
|
||||
time: parseTimeMS(cfg.time || '1s'),
|
||||
memory: parseMemoryMB(cfg.memory || '256m'),
|
||||
type: 'sum',
|
||||
cases: [],
|
||||
score: Math.floor(100 / cases.length) + 1,
|
||||
});
|
||||
for (let i = extra; i < cases.length; i++) {
|
||||
config.count++;
|
||||
config.subtasks[1].cases.push({
|
||||
id: config.count,
|
||||
input: checkFile(cases[i].input),
|
||||
output: checkFile(cases[i].output),
|
||||
});
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
async function read1(folder: string, files: string[], checkFile, cfg, rst) {
|
||||
const subtask = {};
|
||||
for (const s of rst.subtasks) if (s.id) subtask[s.id] = s;
|
||||
const subtasks = [];
|
||||
for (const file of files) {
|
||||
for (const REG of RE1) {
|
||||
if (REG.reg.test(file)) {
|
||||
const data = REG.reg.exec(file);
|
||||
const sid = REG.subtask(data);
|
||||
const c = { input: file, output: '', id: REG.id(data) };
|
||||
for (const func of REG.output) {
|
||||
if (cfg.noOutputFile) c.output = '/dev/null';
|
||||
else c.output = func(data);
|
||||
if (c.output === '/dev/null' || fs.existsSync(path.resolve(folder, c.output))) {
|
||||
if (!subtask[sid]) {
|
||||
subtask[sid] = {
|
||||
time: parseTimeMS(cfg.time || '1s'),
|
||||
memory: parseMemoryMB(cfg.memory || '256m'),
|
||||
type: 'min',
|
||||
cases: [c],
|
||||
};
|
||||
} else if (!subtask[sid].cases) subtask[sid].cases = [c];
|
||||
else subtask[sid].cases.push(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const i in subtask) {
|
||||
subtask[i].cases.sort((a, b) => (a.id - b.id));
|
||||
subtasks.push(subtask[i]);
|
||||
}
|
||||
const base = Math.floor(100 / subtasks.length);
|
||||
const extra = subtasks.length - (100 % subtasks.length);
|
||||
const config = { count: 0, subtasks };
|
||||
const keys = Object.keys(subtask);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (i >= extra) subtask[keys[i]].score = base + 1;
|
||||
else subtask[keys[i]].score = base;
|
||||
for (const j of subtask[keys[i]].cases) {
|
||||
config.count++;
|
||||
j.input = checkFile(j.input);
|
||||
j.output = checkFile(j.output);
|
||||
j.id = config.count;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
import { ensureFile, parseMemoryMB } from './utils';
|
||||
|
||||
async function readAutoCases(folder: string, { next }, cfg, rst) {
|
||||
const config = {
|
||||
@@ -174,8 +27,8 @@ async function readAutoCases(folder: string, { next }, cfg, rst) {
|
||||
const outputs = await fs.readdir(path.resolve(folder, 'output'));
|
||||
files.push(...outputs.map((i) => `output/${i}`));
|
||||
}
|
||||
let result = await read0(folder, files, checkFile, cfg);
|
||||
if (!result.count) result = await read1(folder, files, checkFile, cfg, rst);
|
||||
let result = await readCasesFromFiles(files, checkFile, cfg);
|
||||
if (!result.count) result = await readSubtasksFromFiles(files, checkFile, cfg, rst);
|
||||
Object.assign(config, result);
|
||||
if (cfg.isSelfSubmission) next({ message: { message: 'Found {0} testcases.', params: [config.count] } });
|
||||
} catch (e) {
|
||||
|
||||
Reference in new issue
Block a user