mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-27 13:45:27 -05:00
Recalculate skills script
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
"cy:run": "npx cypress run",
|
||||
"test:unit": "uvu -r tsm -r tsconfig-paths/register -i cypress",
|
||||
"tests": "npm run lint:styles && npm run lint:ts && npm run prettier:check && npm run typecheck && npm run test:unit",
|
||||
"matches": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/matchesWithoutDetails.ts"
|
||||
"recalculate-skills": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/recalculateSkills.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^5.0.3",
|
||||
|
||||
82
scripts/recalculateSkills.ts
Normal file
82
scripts/recalculateSkills.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Prisma, PrismaClient } from "@prisma/client";
|
||||
import { rating } from "openskill";
|
||||
import { adjustSkills } from "~/core/mmr/utils";
|
||||
import { groupsToWinningAndLosingPlayerIds } from "~/core/play/utils";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
type SkillWithDetails = {
|
||||
mu: number;
|
||||
sigma: number;
|
||||
userId: string;
|
||||
matchId: string;
|
||||
};
|
||||
type UserId = string;
|
||||
type CurrentSkills = Record<UserId, Pick<SkillWithDetails, "mu" | "sigma">>;
|
||||
|
||||
async function main() {
|
||||
const matches = (await allMatches()).filter((m) =>
|
||||
m.stages.some((s) => s.winnerGroupId)
|
||||
);
|
||||
|
||||
const newSkills: SkillWithDetails[] = [];
|
||||
const currentSkills: CurrentSkills = {};
|
||||
|
||||
for (const match of matches) {
|
||||
const adjustedSkills = adjustSkills({
|
||||
skills: skillsPerUser({
|
||||
currentSkills,
|
||||
userIds: match.groups.flatMap((g) =>
|
||||
g.members.flatMap((m) => m.memberId)
|
||||
),
|
||||
}),
|
||||
playerIds: groupsToWinningAndLosingPlayerIds({
|
||||
groups: match.groups.map((g) => ({
|
||||
id: g.id,
|
||||
members: g.members.map((m) => ({ user: { id: m.memberId } })),
|
||||
})),
|
||||
winnerGroupIds: match.stages.flatMap((s) =>
|
||||
s.winnerGroupId ? [s.winnerGroupId] : []
|
||||
),
|
||||
}),
|
||||
});
|
||||
|
||||
newSkills.push(...adjustedSkills.map((s) => ({ ...s, matchId: match.id })));
|
||||
|
||||
for (const skill of adjustedSkills) {
|
||||
const { userId, ...rest } = skill;
|
||||
currentSkills[userId] = rest;
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.$transaction([
|
||||
prisma.skill.deleteMany({}),
|
||||
prisma.skill.createMany({ data: newSkills }),
|
||||
]);
|
||||
}
|
||||
|
||||
export type AllMatches = Prisma.PromiseReturnType<typeof allMatches>;
|
||||
function allMatches() {
|
||||
return prisma.lfgGroupMatch.findMany({
|
||||
include: { stages: true, groups: { include: { members: true } } },
|
||||
orderBy: { createdAt: "asc" },
|
||||
});
|
||||
}
|
||||
|
||||
function skillsPerUser({
|
||||
currentSkills,
|
||||
userIds,
|
||||
}: {
|
||||
currentSkills: CurrentSkills;
|
||||
userIds: string[];
|
||||
}): Omit<SkillWithDetails, "matchId">[] {
|
||||
return userIds.map((id) => {
|
||||
const skill = currentSkills[id] ? currentSkills[id] : rating();
|
||||
return { userId: id, ...skill };
|
||||
});
|
||||
}
|
||||
|
||||
main()
|
||||
// eslint-disable-next-line no-console
|
||||
.then(() => console.log("done"))
|
||||
.catch((e) => console.error(e));
|
||||
Reference in New Issue
Block a user