mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
题目难度自动计算
This commit is contained in:
1 parent
37d449d42f
commit
16108993cf
10 files changed
+112
-28
No files matched your search
+1
-1
@@ -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"
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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",
|
||||||
|
|||||||
@@ -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',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 };
|
||||||
@@ -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 };
|
|
||||||
Reference in new issue
Block a user