题目难度自动计算

This commit is contained in:
undefined committed 2020-08-08 14:28:17 +08:00
1 parent 37d449d42f
commit 16108993cf
10 files changed
+112 -28

No files matched your search

+1 -1
View File
@@ -27,7 +27,7 @@
"globby": "^11.0.1", "globby": "^11.0.1",
"jest": "^26.2.2", "jest": "^26.2.2",
"latest-version": "^5.1.0", "latest-version": "^5.1.0",
"ora": "^4.0.5", "ora": "^5.0.0",
"semver": "^7.3.2", "semver": "^7.3.2",
"ts-jest": "^26.1.4", "ts-jest": "^26.1.4",
"typescript": "^3.9.7" "typescript": "^3.9.7"
-2
View File
@@ -4,6 +4,4 @@ SETTINGS_PRIVACY.allowRegisteredUsers
model.setting.ui.name model.setting.ui.name
pdoc.secretConfig? pdoc.secretConfig?
message.markAsRead message.markAsRead
批量导入用户
domain_join_application domain_join_application
problem.difficulty_setting
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "2.12.5", "version": "2.12.6",
"bin": "bin/hydrooj.js", "bin": "bin/hydrooj.js",
"main": "dist/loader.js", "main": "dist/loader.js",
"typings": "dist/loader.d.ts", "typings": "dist/loader.d.ts",
@@ -35,7 +35,7 @@
"mongodb": "^3.5.9", "mongodb": "^3.5.9",
"nodemailer": "^6.4.10", "nodemailer": "^6.4.10",
"nunjucks": "^3.2.2", "nunjucks": "^3.2.2",
"prismjs": "^1.20.0", "prismjs": "^1.21.0",
"proxy-agent": "^3.1.1", "proxy-agent": "^3.1.1",
"ps-list": "^7.2.0", "ps-list": "^7.2.0",
"serialize-javascript": "^4.0.0", "serialize-javascript": "^4.0.0",
+1 -1
View File
@@ -26,7 +26,7 @@ export const builtinHandler = [
]; ];
export const builtinScript = [ export const builtinScript = [
'rating', 'register', 'problemStat', 'blacklist', 'deleteUser', 'rating', 'difficulty', 'problemStat', 'blacklist', 'deleteUser',
'upgrade0_1', 'upgrade0_1',
]; ];
+3
View File
@@ -165,6 +165,7 @@ class SystemSettingHandler extends SystemHandler {
class SystemUserImportHandler extends SystemHandler { class SystemUserImportHandler extends SystemHandler {
async get() { async get() {
this.response.body.users = []; this.response.body.users = [];
this.response.body.path.push(['manage_user_import']);
this.response.template = 'manage_user_import.html'; this.response.template = 'manage_user_import.html';
} }
@@ -188,7 +189,9 @@ class SystemUserImportHandler extends SystemHandler {
} }
} else messages.push(`Line ${i + 1}: Input invalid.`); } else messages.push(`Line ${i + 1}: Input invalid.`);
} }
messages.push(`${udocs.length} users found.`);
await Promise.all(tasks); await Promise.all(tasks);
this.response.body.path.push(['manage_user_import']);
this.response.body.users = udocs; this.response.body.users = udocs;
this.response.body.messages = messages; this.response.body.messages = messages;
} }
+12 -1
View File
@@ -369,12 +369,23 @@ class ProblemSettingsHandler extends ProblemManageHandler {
@param('hidden', Types.Boolean) @param('hidden', Types.Boolean)
@param('category', Types.String, true, null, parseCategory) @param('category', Types.String, true, null, parseCategory)
@param('tag', Types.String, true, null, parseCategory) @param('tag', Types.String, true, null, parseCategory)
@param('difficultySetting', Types.UnsignedInt)
@param('difficultyAdmin', Types.UnsignedInt, true)
async postSetting( async postSetting(
domainId: string, pid: string | number, hidden = false, domainId: string, pid: string | number, hidden = false,
category: string[] = [], tag: string[] = [], category: string[] = [], tag: string[] = [],
difficultySetting: string, difficultyAdmin: number,
) { ) {
const pdoc = await problem.get(domainId, pid); const pdoc = await problem.get(domainId, pid);
await problem.edit(domainId, pdoc.docId, { hidden, category, tag }); if (!problem.SETTING_DIFFICULTY_RANGE[difficultySetting]) {
throw new ValidationError('difficultySetting');
}
if (!difficultyAdmin) difficultyAdmin = null;
else if (difficultyAdmin < 1 || difficultyAdmin > 9) throw new ValidationError('difficultyAdmin');
await problem.edit(domainId, pdoc.docId, {
hidden, category, tag, difficultySetting, difficultyAdmin,
});
await global.Hydro.script.difficulty.run({ domainId, pid }, console.log);
this.back(); this.back();
} }
} }
+5 -1
View File
@@ -135,11 +135,15 @@ export interface Pdoc {
nAccept: number, nAccept: number,
tag: string[], tag: string[],
category: string[], category: string[],
difficulty: number,
data?: ProblemData, data?: ProblemData,
hidden: boolean, hidden: boolean,
config: ProblemConfig, config: ProblemConfig,
acMsg?: string, acMsg?: string,
difficulty?: number,
difficultyAlgo?: number,
difficultyAdmin?: number,
difficultySetting?: number,
} }
export type Pdict = NumericDictionary<Pdoc>; export type Pdict = NumericDictionary<Pdoc>;
+15
View File
@@ -10,6 +10,16 @@ import {
import { ProblemNotFoundError } from '../error'; import { ProblemNotFoundError } from '../error';
import * as testdataConfig from '../lib/testdataConfig'; import * as testdataConfig from '../lib/testdataConfig';
export const SETTING_DIFFICULTY_ALGORITHM = 0;
export const SETTING_DIFFICULTY_ADMIN = 1;
export const SETTING_DIFFICULTY_AVERAGE = 2;
export const SETTING_DIFFICULTY_RANGE = [
[SETTING_DIFFICULTY_ALGORITHM, 'Use algorithm calculated'],
[SETTING_DIFFICULTY_ADMIN, 'Use admin specificed'],
[SETTING_DIFFICULTY_AVERAGE, 'Use average of above'],
];
export const pdocHidden: Pdoc = { export const pdocHidden: Pdoc = {
_id: new ObjectID(), _id: new ObjectID(),
domainId: 'system', domainId: 'system',
@@ -152,6 +162,11 @@ export async function setTestdata(domainId: string, _id: number, filePath: strin
} }
global.Hydro.model.problem = { global.Hydro.model.problem = {
SETTING_DIFFICULTY_ADMIN,
SETTING_DIFFICULTY_ALGORITHM,
SETTING_DIFFICULTY_AVERAGE,
SETTING_DIFFICULTY_RANGE,
pdocHidden, pdocHidden,
add, add,
inc, inc,
+73
View File
@@ -0,0 +1,73 @@
import { Pdoc } from '../interface';
import * as problem from '../model/problem';
export const description = 'Create a new user';
const _CACHE_INFO = {
last_s: 0.0,
last_y: 0,
values: [0.0],
};
function _LOGP(x: number) {
const sqrt_2_pi = 2.506628274631000502415765284811; // Sqrt[Pi]
return (2 * Math.exp(-1.0 * (Math.log(x) ** 2) * 2)) / x / sqrt_2_pi;
}
function _integrate_ensure_cache(y: number) {
let last_y = _CACHE_INFO.last_y;
if (y <= last_y) return _CACHE_INFO;
let s = _CACHE_INFO.last_s;
const dx = 0.1;
const dT = 2;
let x0 = (last_y / dT) * dx;
while (y > last_y) {
x0 += dx;
s += _LOGP(x0) * dx;
for (let i = 1; i <= dT; i++) _CACHE_INFO.values.push(s);
last_y += dT;
}
_CACHE_INFO.last_y = last_y;
_CACHE_INFO.last_s = s;
return _CACHE_INFO;
}
_integrate_ensure_cache(1000000);
function _integrate(y: number) {
_integrate_ensure_cache(y);
return _CACHE_INFO.values[y];
}
function difficultyAlgorithm(nSubmit: number, nAccept: number) {
if (!nSubmit) return null;
const s = _integrate(nSubmit);
const ac_rate = nAccept / nSubmit;
const ans = Math.round(10.0 - 1.30 * s * 10.0 * ac_rate);
return Math.max(ans, 1);
}
function _get_difficulty(pdoc: Pdoc, calculatedDifficulty: number) {
const setting = pdoc.difficultySetting;
if (setting === problem.SETTING_DIFFICULTY_ALGORITHM) return calculatedDifficulty;
if (setting === problem.SETTING_DIFFICULTY_ADMIN) return pdoc.difficultyAdmin;
if (setting === problem.SETTING_DIFFICULTY_AVERAGE && pdoc.difficultyAdmin !== null) {
return Math.round((calculatedDifficulty + pdoc.difficultyAdmin) / 2);
} return calculatedDifficulty;
}
export async function run({
domainId, pid,
}) {
const pdoc = await problem.get(domainId, pid);
const difficultyAlgo = difficultyAlgorithm(pdoc.nSubmit, pdoc.nAccept);
const difficulty = _get_difficulty(pdoc, difficultyAlgo);
return await problem.edit(domainId, pdoc.docId, { difficulty, difficultyAlgo });
}
export const validate = {
domainId: { $type: 'string' },
pid: { $type: 'number' },
};
global.Hydro.script.difficulty = { run, description, validate };
-20
View File
@@ -1,20 +0,0 @@
import * as user from '../model/user';
export const description = 'Create a new user';
export async function run({
uname, password, mail, uid,
}) {
if (uid) uid = parseInt(uid, 10);
if (uid && Number.isNaN(uid)) throw new Error('uid');
uid = await user.create(mail, uname, password, uid);
return uid;
}
export const validate = {
uname: { $type: 'string' },
password: { $type: 'string' },
mail: { $type: 'string' },
};
global.Hydro.script.register = { run, description, validate };