mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-10-08 22:50:00 +08:00
Add weakspot mode. (#1606) by shishberg
* Add weakspot mode. This keeps track of a per-character "weakness" score, basically a moving average of the spacing duration with a penalty for incorrect letters. The weakspot funbox mode uses this to bias towards words with lots of weak letters. * Comment about keeping weaknessScores * Move weakspot to its own module. * prettier
This commit is contained in:
parent
98f7148ccb
commit
08ad5728db
5 changed files with 59 additions and 0 deletions
|
@ -168,6 +168,7 @@ const refactoredSrc = [
|
|||
"./src/js/test/layout-emulator.js",
|
||||
"./src/js/test/poetry.js",
|
||||
"./src/js/test/today-tracker.js",
|
||||
"./src/js/test/weak-spot.js",
|
||||
"./src/js/replay.js",
|
||||
];
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import * as Focus from "./focus";
|
|||
import * as ShiftTracker from "./shift-tracker";
|
||||
import * as Replay from "./replay.js";
|
||||
import * as MonkeyPower from "./monkey-power";
|
||||
import * as WeakSpot from "./weak-spot";
|
||||
|
||||
$("#wordsInput").keypress((event) => {
|
||||
event.preventDefault();
|
||||
|
@ -660,6 +661,7 @@ function handleAlpha(event) {
|
|||
);
|
||||
}
|
||||
}
|
||||
WeakSpot.updateScore(nextCharInWord, thisCharCorrect);
|
||||
|
||||
if (thisCharCorrect) {
|
||||
Sound.playClick(Config.playSoundOnClick);
|
||||
|
|
|
@ -32,6 +32,7 @@ import * as Replay from "./replay.js";
|
|||
import * as MonkeyPower from "./monkey-power";
|
||||
import * as Poetry from "./poetry.js";
|
||||
import * as TodayTracker from "./today-tracker";
|
||||
import * as WeakSpot from "./weak-spot";
|
||||
|
||||
let glarsesMode = false;
|
||||
|
||||
|
@ -573,6 +574,8 @@ export async function init() {
|
|||
UpdateConfig.setPunctuation(false, true);
|
||||
UpdateConfig.setNumbers(false, true);
|
||||
randomWord = Misc.getASCII();
|
||||
} else if (Config.funbox === "weakspot") {
|
||||
randomWord = WeakSpot.getWord(wordset);
|
||||
}
|
||||
|
||||
if (Config.punctuation) {
|
||||
|
|
48
src/js/test/weak-spot.js
Normal file
48
src/js/test/weak-spot.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
import * as TestStats from "./test-stats";
|
||||
|
||||
const adjustRate = 0.02;
|
||||
const wordSamples = 20;
|
||||
|
||||
// TODO: base these on WPM or something instead of constants
|
||||
const defaultScore = 500;
|
||||
const incorrectPenalty = 5000;
|
||||
|
||||
let scores = {};
|
||||
|
||||
export function updateScore(char, isCorrect) {
|
||||
let score = 0.0;
|
||||
const timings = TestStats.keypressTimings.spacing.array;
|
||||
if (timings.length > 0) {
|
||||
score += timings[timings.length - 1];
|
||||
}
|
||||
if (!isCorrect) {
|
||||
score += incorrectPenalty;
|
||||
}
|
||||
if (!(char in scores)) {
|
||||
scores[char] = defaultScore;
|
||||
}
|
||||
// Keep an exponential moving average of the score over time.
|
||||
scores[char] = score * adjustRate + scores[char] * (1 - adjustRate);
|
||||
}
|
||||
|
||||
export function getWord(wordset) {
|
||||
let highScore;
|
||||
let randomWord;
|
||||
for (let i = 0; i < wordSamples; i++) {
|
||||
let newWord = wordset[Math.floor(Math.random() * wordset.length)];
|
||||
let newScore = score(newWord);
|
||||
if (i == 0 || newScore > highScore) {
|
||||
randomWord = newWord;
|
||||
highScore = newScore;
|
||||
}
|
||||
}
|
||||
return randomWord;
|
||||
}
|
||||
|
||||
function score(word) {
|
||||
let total = 0.0;
|
||||
for (const c of word) {
|
||||
total += c in scores ? scores[c] : defaultScore;
|
||||
}
|
||||
return total / word.length;
|
||||
}
|
|
@ -108,6 +108,11 @@
|
|||
"name": "poetry",
|
||||
"type": "script",
|
||||
"info": "Practice typing some beautiful prose."
|
||||
},
|
||||
{
|
||||
"name": "weakspot",
|
||||
"type": "script",
|
||||
"info": "Focus on slow and mistyped letters."
|
||||
}
|
||||
]
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue