rating系统(测试

This commit is contained in:
masnn committed 2020-06-07 15:38:38 +08:00
1 parent 508f5644c3
commit 4aa1c9fe1f
7 files changed
+131 -5

No files matched your search

+11
View File
@@ -8,6 +8,17 @@ process.stdin.on('data', async (input) => {
console.warn(e);
}
});
process.on('unhandledRejection', (e) => console.log(e));
global.onDestory = [];
async function terminate() {
for (const task of global.onDestory) {
// eslint-disable-next-line no-await-in-loop
await task();
}
process.exit(0);
}
process.on('SIGINT', terminate);
require('./loader').load().catch((e) => {
console.error(e);
-1
View File
@@ -81,7 +81,6 @@ class SystemSettingHandler extends SystemHandler {
const s = setting.SYSTEM_SETTINGS_BY_KEY[`${key}.${sub}`];
if (s) {
if (s.ui === 'number') args[key][sub] = Number(args[key][sub]);
console.log(s);
subtasks.push(system.set(`${key}.${sub}`, args[key][sub]));
}
}
-1
View File
@@ -25,7 +25,6 @@ class RecordListHandler extends RecordHandler {
];
}
const rdocs = await record.getMany(domainId, q, { _id: -1 }, page, await system.get('RECORD_PER_PAGE'));
console.log(rdocs);
const [udict, pdict] = await Promise.all([
user.getList(domainId, rdocs.map((rdoc) => rdoc.uid)),
problem.getList(domainId, rdocs.map((rdoc) => rdoc.pid), false),
+88
View File
@@ -0,0 +1,88 @@
class User {
constructor(rank, old, handle = 0) {
this.rank = rank;
this.old = old;
this.seed = 1;
this.handle = handle.toString();
}
}
class RatingCalculator {
constructor(users) {
this.users = [];
for (const user of users) {
this.users.push(new User(user.rank, user.old, user.uid));
}
}
// eslint-disable-next-line class-methods-use-this
calP(a, b) {
return 1 / (1 + 10 ** ((b.old - a.old) / 400));
}
getExSeed(rating, ownUser) {
const exUser = new User(0.0, rating);
let result = 1;
for (const user of this.users) {
if (user !== ownUser) result += this.calP(user, exUser);
}
return result;
}
calRating(rank, user) {
let left = 1;
let right = 8000;
while (right - left > 1) {
const mid = Math.floor((left + right) / 2);
if (this.getExSeed(mid, user) < rank) right = mid;
else left = mid;
}
return left;
}
calculate() {
// Calculate seed
for (let i = 0; i < this.users.length; i++) {
this.users[i].seed = 1;
for (let j = 0; j < this.users.length; j++) {
if (i !== j) {
this.users[i].seed += this.calP(this.users[j], this.users[i]);
}
}
}
// Calculate initial delta and sum_delta
let sumDelta = 0;
for (const user of this.users) {
user.delta = (this.calRating(Math.sqrt(user.rank * user.seed), user) - user.old) / 2;
sumDelta += user.delta;
}
// Calculate first inc
let inc = Math.floor(-sumDelta / this.users.length) - 1;
for (const user of this.users) user.delta += inc;
// Calculate second inc
this.users = this.users.sort((a, b) => b.old - a.old);
const s = Math.min(
this.users.length,
Math.floor(4 * Math.round(Math.sqrt(this.users.length))),
);
let sumS = 0;
for (let i = 0; i < s; i++) {
sumS += this.users[i].delta;
}
inc = Math.min(Math.max(Math.floor(-sumS / s), -10), 0);
// Calculate new rating
for (const user of this.users) {
user.delta += inc;
user.new = user.old + user.delta;
}
this.users = this.users.sort((a, b) => a.rank - b.rank);
return this.users;
}
}
function calculate(users) {
const calculator = new RatingCalculator(users);
return calculator.calculate();
}
module.exports = calculate;
+8 -2
View File
@@ -263,10 +263,16 @@ async function load() {
const notfound = require('./handler/notfound');
await notfound.apply();
for (const i in global.Hydro.service) {
if (global.Hydro.service[i].postInit) await global.Hydro.service[i].postInit();
if (global.Hydro.service[i].postInit) {
try {
await global.Hydro.service[i].postInit();
} catch (e) {
console.error(e);
}
}
}
const builtinScript = [
'install', 'uninstall',
'install', 'uninstall', 'rating',
];
for (const i of builtinScript) require(`./script/${i}`);
await script();
+2 -1
View File
@@ -271,7 +271,6 @@ function getStatus(domainId, tid, uid, type = document.TYPE_CONTEST) {
async function getListStatus(domainId, uid, tids, type = document.TYPE_CONTEST) {
const r = {};
console.log(tids);
// eslint-disable-next-line no-await-in-loop
for (const tid of tids) r[tid] = await getStatus(domainId, tid, uid, type);
return r;
@@ -392,11 +391,13 @@ async function recalcStatus(domainId, tid, type) {
}
return await Promise.all(tasks);
}
global.Hydro.model.contest = module.exports = {
RULES,
ContestHandlerMixin,
add,
getListStatus,
getMultiStatus,
attend,
edit,
get,
+22
View File
@@ -0,0 +1,22 @@
const { ObjectID } = require('bson');
const contest = require('../model/contest');
const user = require('../model/user');
const rating = require('../lib/rating');
async function run({ domainId, contestId }) {
contestId = new ObjectID(contestId);
const tdoc = await contest.get(domainId, contestId);
const tsdocs = await contest.getMultiStatus(domainId, { docId: contestId })
.sort(contest.RULES[tdoc.rule].statusSort).toArray();
const udict = await user.getList(domainId, tsdocs.map((tsdoc) => tsdoc.uid));
const rankedTsdocs = contest.RULES[tdoc.rule].rank(tsdocs);
const users = [];
for (const result of rankedTsdocs) {
users.push({ ...result[1], rank: result[0], old: udict[result[1].uid].rating || 1500 });
}
console.log(users);
const rated = rating(users);
console.log(rated);
}
global.Hydro.script.rating = module.exports = { run };