Skip to content

Commit 4eb174b

Browse files
committed
Improved likelyhood algo
1 parent a79c0b1 commit 4eb174b

File tree

2 files changed

+45
-31
lines changed

2 files changed

+45
-31
lines changed

src/japanese/exercises/kana-typer/KanaTyper.tsx

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const game = makeAutoObservable({
3434
saveInLocalStorage: false,
3535
kanaLikelyhood: {} as { [key: string]: number },
3636
kanaLikelyhoodCorrectDecrease: 1,
37-
kanaLikelyhoodWrongIncrease: 5,
37+
kanaLikelyhoodWrongIncrease: 10,
3838
hintDelayMs: 4000,
3939

4040
reset(): void {
@@ -61,21 +61,16 @@ const game = makeAutoObservable({
6161
kana.typed = currentText.trim().toLowerCase();
6262
kana.correct = kana.typed === kana.expected;
6363

64-
if (kana.correct) {
65-
const existingLikelyhood = this.kanaLikelyhood[kana.kana];
66-
if (
67-
!existingLikelyhood ||
68-
existingLikelyhood <= this.kanaLikelyhoodCorrectDecrease
69-
) {
70-
delete this.kanaLikelyhood[kana.kana];
71-
} else {
72-
this.kanaLikelyhood[kana.kana] -= this.kanaLikelyhoodCorrectDecrease;
73-
}
74-
} else {
75-
this.kanaLikelyhood[kana.kana] =
76-
(this.kanaLikelyhood[kana.kana] || 0) +
77-
this.kanaLikelyhoodWrongIncrease;
78-
}
64+
const likelyhoodDiff = kana.correct
65+
? -this.kanaLikelyhoodCorrectDecrease
66+
: this.kanaLikelyhoodWrongIncrease;
67+
68+
const undakutened = KanaUtils.fromHandakuten(
69+
KanaUtils.fromDakuten(kana.kana),
70+
);
71+
72+
this.kanaLikelyhood[undakutened] =
73+
(this.kanaLikelyhood[undakutened] || 0) + likelyhoodDiff;
7974

8075
this.currentInput = "";
8176
this.currentIdx++;
@@ -129,26 +124,24 @@ const game = makeAutoObservable({
129124

130125
if (!this.enabledKanas.length) return result;
131126

132-
const pool = new Set([...this.enabledKanas]);
127+
const minLikelyhood = this.enabledKanas
128+
.map((k) => this.kanaLikelyhood[k] || 0)
129+
.reduce((result, next) => Math.min(next, result), 0);
133130

134-
if (this.dakuten) {
135-
for (const dakuten of [...pool.values()].map(KanaUtils.toDakuten))
136-
pool.add(dakuten);
137-
}
131+
const pool = this.enabledKanas.flatMap((k) =>
132+
k.repeat((this.kanaLikelyhood[k] || 1) - minLikelyhood).split(""),
133+
);
138134

139-
if (this.handakuten) {
140-
for (const handakuten of [...pool.values()].map(KanaUtils.toHandakuten))
141-
pool.add(handakuten);
142-
}
135+
console.log(minLikelyhood, this.kanaLikelyhood, pool);
143136

144-
const poolArr = Array.from(pool);
137+
for (let i = 0; i < 10; i++) {
138+
const kanaCandidate = pool.random()!;
145139

146-
for (const [kana, times] of Object.entries(this.kanaLikelyhood)) {
147-
poolArr.push(...kana.repeat(times).split(""));
148-
}
140+
const drawPool = [kanaCandidate];
141+
if (this.dakuten) drawPool.push(KanaUtils.toDakuten(kanaCandidate));
142+
if (this.handakuten) drawPool.push(KanaUtils.toHandakuten(kanaCandidate));
149143

150-
for (let i = 0; i < 10; i++) {
151-
const selectedKana = poolArr[Math.floor(Math.random() * poolArr.length)];
144+
const selectedKana = drawPool.random()!;
152145

153146
const expectedInput = KanaUtils.toRomaji(selectedKana);
154147

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
declare global {
2+
interface Array<T> {
3+
/**
4+
* Returns a random element of the array or undefined if empty.
5+
* @returns The a random element of the array, or undefined if the array is empty.
6+
*/
7+
random(): T | undefined;
8+
}
9+
}
10+
11+
Object.defineProperty(Array.prototype, "random", {
12+
value: function <T1>(this: Array<T1>) {
13+
if (!this.length) return undefined;
14+
15+
const idx = Math.floor(Math.random() * this.length);
16+
17+
return this[idx];
18+
},
19+
});
20+
21+
export {};

0 commit comments

Comments
 (0)