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:
shishberg 2021-07-10 10:23:47 +10:00 committed by GitHub
parent 98f7148ccb
commit 08ad5728db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 0 deletions

View file

@ -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",
];

View file

@ -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);

View file

@ -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
View 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;
}

View file

@ -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."
}
]