mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-11-08 05:03:39 +08:00
checking if result funboxes are unique
checking if result funboxes are compatible with each other
This commit is contained in:
parent
f8f80fbeb0
commit
2e7179df8e
2 changed files with 168 additions and 6 deletions
|
|
@ -20,7 +20,7 @@ import Logger from "../../utils/logger";
|
|||
import "dotenv/config";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import MonkeyError from "../../utils/error";
|
||||
import { isTestTooShort } from "../../utils/validation";
|
||||
import { areFunboxesCompatible, isTestTooShort } from "../../utils/validation";
|
||||
import {
|
||||
implemented as anticheatImplemented,
|
||||
validateResult,
|
||||
|
|
@ -36,7 +36,7 @@ import { getDailyLeaderboard } from "../../utils/daily-leaderboards";
|
|||
import AutoRoleList from "../../constants/auto-roles";
|
||||
import * as UserDAL from "../../dal/user";
|
||||
import { buildMonkeyMail } from "../../utils/monkey-mail";
|
||||
import FunboxesMetadata from "../../constants/funbox";
|
||||
import FunboxList from "../../constants/funbox-list";
|
||||
import _ from "lodash";
|
||||
import * as WeeklyXpLeaderboard from "../../services/weekly-xp-leaderboard";
|
||||
import { UAParser } from "ua-parser-js";
|
||||
|
|
@ -175,6 +175,17 @@ export async function addResult(
|
|||
}
|
||||
}
|
||||
|
||||
if (result.funbox) {
|
||||
const funboxes = result.funbox.split("#");
|
||||
if (funboxes.length !== _.uniq(funboxes).length) {
|
||||
throw new MonkeyError(400, "Duplicate funboxes");
|
||||
}
|
||||
}
|
||||
|
||||
if (!areFunboxesCompatible(result.funbox)) {
|
||||
throw new MonkeyError(400, "Impossible funbox combination");
|
||||
}
|
||||
|
||||
try {
|
||||
result.keySpacingStats = {
|
||||
average:
|
||||
|
|
@ -625,9 +636,8 @@ async function calculateXp(
|
|||
}
|
||||
|
||||
if (funboxBonusConfiguration > 0) {
|
||||
const resultFunboxes = _.uniq(funbox.split("#"));
|
||||
const funboxModifier = _.sumBy(resultFunboxes, (funboxName) => {
|
||||
const funbox = FunboxesMetadata[funboxName as string];
|
||||
const funboxModifier = _.sumBy(funbox.split("#"), (funboxName) => {
|
||||
const funbox = FunboxList.find((f) => f.name === funboxName);
|
||||
const difficultyLevel = funbox?.difficultyLevel ?? 0;
|
||||
return Math.max(difficultyLevel * funboxBonusConfiguration, 0);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import _ from "lodash";
|
||||
import { replaceHomoglyphs } from "../constants/homoglyphs";
|
||||
import { profanities, regexProfanities } from "../constants/profanities";
|
||||
import { matchesAPattern, sanitizeString } from "./misc";
|
||||
import { intersect, matchesAPattern, sanitizeString } from "./misc";
|
||||
import { default as FunboxList } from "../constants/funbox-list";
|
||||
|
||||
export function inRange(value: number, min: number, max: number): boolean {
|
||||
return value >= min && value <= max;
|
||||
|
|
@ -105,3 +106,154 @@ export function isTestTooShort(result: MonkeyTypes.CompletedEvent): boolean {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function areFunboxesCompatible(funboxesString: string): boolean {
|
||||
const funboxes = funboxesString.split("#").filter((f) => f !== "none");
|
||||
|
||||
const funboxesToCheck = FunboxList.filter((f) => funboxes.includes(f.name));
|
||||
|
||||
console.log(funboxesToCheck);
|
||||
console.log(funboxes);
|
||||
|
||||
const allFunboxesAreValid = funboxesToCheck.length === funboxes.length;
|
||||
const oneWordModifierMax =
|
||||
funboxesToCheck.filter(
|
||||
(f) =>
|
||||
f.frontendFunctions?.includes("getWord") ||
|
||||
f.frontendFunctions?.includes("pullSection") ||
|
||||
f.frontendFunctions?.includes("withWords")
|
||||
).length <= 1;
|
||||
const layoutUsability =
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "changesLayout")
|
||||
).length === 0 ||
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "ignoresLayout" || fp === "usesLayout")
|
||||
).length === 0;
|
||||
const oneNospaceOrToPushMax =
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "nospace" || fp.startsWith("toPush"))
|
||||
).length <= 1;
|
||||
const oneChangesWordsVisibilityMax =
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "changesWordsVisibility")
|
||||
).length <= 1;
|
||||
const oneFrequencyChangesMax =
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "changesWordsFrequency")
|
||||
).length <= 1;
|
||||
const noFrequencyChangesConflicts =
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "changesWordsFrequency")
|
||||
).length === 0 ||
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "ignoresLanguage")
|
||||
).length === 0;
|
||||
const capitalisationChangePosibility =
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "noLetters")
|
||||
).length === 0 ||
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "changesCapitalisation")
|
||||
).length === 0;
|
||||
const noConflictsWithSymmetricChars =
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "conflictsWithSymmetricChars")
|
||||
).length === 0 ||
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "symmetricChars")
|
||||
).length === 0;
|
||||
const canSpeak =
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "speaks" || fp === "unspeakable")
|
||||
).length <= 1;
|
||||
const hasLanguageToSpeak =
|
||||
funboxesToCheck.filter((f) => f.properties?.find((fp) => fp === "speaks"))
|
||||
.length === 0 ||
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.properties?.find((fp) => fp === "ignoresLanguage")
|
||||
).length === 0;
|
||||
const oneToPushOrPullSectionMax =
|
||||
funboxesToCheck.filter(
|
||||
(f) =>
|
||||
f.properties?.find((fp) => fp.startsWith("toPush:")) ||
|
||||
f.frontendFunctions?.includes("pullSection")
|
||||
).length <= 1;
|
||||
const oneApplyCSSMax =
|
||||
funboxesToCheck.filter((f) => f.frontendFunctions?.includes("applyCSS"))
|
||||
.length <= 1;
|
||||
const onePunctuateWordMax =
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.frontendFunctions?.includes("punctuateWord")
|
||||
).length <= 1;
|
||||
const oneCharCheckerMax =
|
||||
funboxesToCheck.filter((f) =>
|
||||
f.frontendFunctions?.includes("isCharCorrect")
|
||||
).length <= 1;
|
||||
const oneCharReplacerMax =
|
||||
funboxesToCheck.filter((f) => f.frontendFunctions?.includes("getWordHtml"))
|
||||
.length <= 1;
|
||||
const allowedConfig = {} as Record<string, string[] | boolean[]>;
|
||||
let noConfigConflicts = true;
|
||||
for (const f of funboxesToCheck) {
|
||||
if (!f.frontendForcedConfig) continue;
|
||||
for (const key in f.frontendForcedConfig) {
|
||||
if (allowedConfig[key]) {
|
||||
if (
|
||||
intersect<string | boolean>(
|
||||
allowedConfig[key],
|
||||
f.frontendForcedConfig[key],
|
||||
true
|
||||
).length === 0
|
||||
) {
|
||||
noConfigConflicts = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
allowedConfig[key] = f.frontendForcedConfig[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(allowedConfig);
|
||||
|
||||
console.log(
|
||||
allFunboxesAreValid,
|
||||
oneWordModifierMax,
|
||||
layoutUsability,
|
||||
oneNospaceOrToPushMax,
|
||||
oneChangesWordsVisibilityMax,
|
||||
oneFrequencyChangesMax,
|
||||
noFrequencyChangesConflicts,
|
||||
capitalisationChangePosibility,
|
||||
noConflictsWithSymmetricChars,
|
||||
canSpeak,
|
||||
hasLanguageToSpeak,
|
||||
oneToPushOrPullSectionMax,
|
||||
oneApplyCSSMax,
|
||||
onePunctuateWordMax,
|
||||
oneCharCheckerMax,
|
||||
oneCharReplacerMax,
|
||||
noConfigConflicts
|
||||
);
|
||||
|
||||
return (
|
||||
allFunboxesAreValid &&
|
||||
oneWordModifierMax &&
|
||||
layoutUsability &&
|
||||
oneNospaceOrToPushMax &&
|
||||
oneChangesWordsVisibilityMax &&
|
||||
oneFrequencyChangesMax &&
|
||||
noFrequencyChangesConflicts &&
|
||||
capitalisationChangePosibility &&
|
||||
noConflictsWithSymmetricChars &&
|
||||
canSpeak &&
|
||||
hasLanguageToSpeak &&
|
||||
oneToPushOrPullSectionMax &&
|
||||
oneApplyCSSMax &&
|
||||
onePunctuateWordMax &&
|
||||
oneCharCheckerMax &&
|
||||
oneCharReplacerMax &&
|
||||
noConfigConflicts
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue