Skip to content

Commit 3bad4a1

Browse files
authored
Update useDescriptionGenerator.ts
1 parent c37b421 commit 3bad4a1

1 file changed

Lines changed: 77 additions & 64 deletions

File tree

Lines changed: 77 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
1-
import { Chess } from "chess.js";
1+
import { Chess } from 'chess.js'
22

3-
type StockfishEvals = Record<string, number>; // UCI → eval (white-positive)
4-
type MaiaEvals = Record<string, number[]>; // UCI → 9-length probability array
3+
type StockfishEvals = Record<string, number> // UCI → eval (white-positive)
4+
type MaiaEvals = Record<string, number[]> // UCI → 9-length probability array
55

6-
const A = 1, B = 0.8, EPS = 0.08;
6+
const A = 1
7+
const B = 0.8
8+
const EPS = 0.08 // 8 %
79

8-
const winRate = (p: number) => 1 / (1 + Math.exp(-(p - A) / B));
9-
const wdl = (p: number) => { const w = winRate(p), l = winRate(-p); return { w, d: 1 - w - l }; };
10+
const winRate = (p: number) => 1 / (1 + Math.exp(-(p - A) / B))
11+
const wdl = (p: number) => {
12+
const w = winRate(p)
13+
const l = winRate(-p)
14+
return { w, d: 1 - w - l }
15+
}
1016

1117
const legalMovesUci = (fen: string) => {
12-
const c = new Chess(fen);
13-
const s = new Set<string>();
14-
c.moves({ verbose: true }).forEach(m => s.add(m.from + m.to + (m.promotion ?? "")));
15-
return s;
16-
};
18+
const c = new Chess(fen)
19+
const s = new Set<string>()
20+
c
21+
.moves({ verbose: true })
22+
.forEach(m => s.add(m.from + m.to + (m.promotion ?? '')))
23+
return s
24+
}
1725

1826
export function describePosition(
1927
fen: string,
@@ -22,91 +30,96 @@ export function describePosition(
2230
whiteToMove: boolean,
2331
eps = EPS
2432
): string {
25-
const legal = legalMovesUci(fen);
26-
const moves = Object.keys(sf).filter(m => legal.has(m));
27-
if (!moves.length) return "No legal moves available.";
33+
const legal = legalMovesUci(fen)
34+
const moves = Object.keys(sf).filter(m => legal.has(m))
35+
if (!moves.length) return 'No legal moves available.'
2836

29-
const seval: Record<string, number> = {};
30-
moves.forEach(m => seval[m] = (whiteToMove ? 1 : -1) * sf[m]);
37+
const seval: Record<string, number> = {}
38+
moves.forEach(m => {
39+
seval[m] = (whiteToMove ? 1 : -1) * sf[m]
40+
})
3141

32-
const opt = moves.reduce((a, b) => seval[a] > seval[b] ? a : b);
33-
const { w: wOpt, d: dOpt } = wdl(seval[opt]);
42+
const opt = moves.reduce((a, b) => (seval[a] > seval[b] ? a : b))
43+
const { w: wOpt, d: dOpt } = wdl(seval[opt])
3444

3545
const good = moves.filter(m => {
36-
const { w, d } = wdl(seval[m]);
37-
return Math.abs(w - wOpt) <= eps && Math.abs(d - dOpt) <= eps;
38-
});
46+
const { w, d } = wdl(seval[m])
47+
return Math.abs(w - wOpt) <= eps && Math.abs(d - dOpt) <= eps
48+
})
3949

40-
const nGood = good.length;
50+
const nGood = good.length
4151
const abundance =
42-
nGood === 1 ? "only one move"
43-
: nGood === 2 ? "two moves"
44-
: "several moves";
52+
nGood === 1 ? 'only one move' : nGood === 2 ? 'two moves' : 'several moves'
4553

46-
const avgGood = good.reduce((s, m) => s + seval[m], 0) / nGood;
54+
const avgGood = good.reduce((s, m) => s + seval[m], 0) / nGood
4755

48-
let outcome: string;
49-
if (avgGood > 2.5) outcome = "to cleanly win";
50-
else if (avgGood > 1.0) outcome = "to win";
51-
else if (avgGood > 0.35) outcome = "for an advantage";
52-
else if (avgGood >= -0.35) outcome = "to keep the balance";
53-
else if (avgGood >= -1.0) outcome = "to hold the position";
54-
else outcome = "to stay in the game";
56+
let outcome: string
57+
if (avgGood > 2.5) outcome = 'to cleanly win'
58+
else if (avgGood > 1.0) outcome = 'to win'
59+
else if (avgGood > 0.35) outcome = 'for an advantage'
60+
else if (avgGood >= -0.35) outcome = 'to keep the balance'
61+
else if (avgGood >= -1.0) outcome = 'to hold the position'
62+
else outcome = 'to stay in the game'
5563

56-
let setLevels = 0, optLevels = 0, temptLevels = 0;
64+
let setLevels = 0
65+
let optLevels = 0
66+
let temptLevels = 0
5767

5868
for (let lvl = 0; lvl < 9; lvl++) {
5969
const probs = moves
6070
.map(m => [maia[m]?.[lvl] ?? 0, m] as [number, string])
61-
.sort((a, b) => b[0] - a[0]);
71+
.sort((a, b) => b[0] - a[0])
6272

63-
const [p1, m1] = probs[0];
64-
const [p2, m2] = probs[1] ?? [0, ""];
65-
const [p3, m3] = probs[2] ?? [0, ""];
73+
const [p1, m1] = probs[0]
74+
const [p2, m2] = probs[1] ?? [0, '']
75+
const [p3, m3] = probs[2] ?? [0, '']
6676

67-
const inGood = good.includes(m1);
68-
if (inGood) setLevels++;
69-
if (m1 === opt) optLevels++;
77+
const inGood = good.includes(m1)
78+
if (inGood) setLevels++
79+
if (m1 === opt) optLevels++
7080

71-
const nearTop = (prob: number) => (p1 - prob) <= eps;
81+
const nearTop = (prob: number) => p1 - prob <= eps
7282
const tempting =
73-
inGood && (
74-
(m2 && !good.includes(m2) && nearTop(p2)) ||
75-
(m3 && !good.includes(m3) && nearTop(p3))
76-
);
83+
inGood &&
84+
((m2 && !good.includes(m2) && nearTop(p2)) ||
85+
(m3 && !good.includes(m3) && nearTop(p3)))
7786

78-
if (tempting) temptLevels++;
87+
if (tempting) temptLevels++
7988
}
8089

81-
const tier = (k: number) => k <= 2 ? 0 : k <= 6 ? 1 : 2;
82-
const setTier = tier(setLevels);
83-
const optTier = tier(optLevels);
90+
const tier = (k: number) => (k <= 2 ? 0 : k <= 6 ? 1 : 2)
91+
const setTier = tier(setLevels)
92+
const optTier = tier(optLevels)
8493

8594
const phrSet =
86-
setTier === 0 ? "hard for players to find"
87-
: setTier === 1 ? "findable for skilled players"
88-
: "straightforward for players across skill levels to find";
95+
setTier === 0
96+
? 'hard for players to find'
97+
: setTier === 1
98+
? 'findable for skilled players'
99+
: 'straightforward for players across skill levels to find'
89100

90101
let phrBest =
91-
optTier === 0 ? "hard for players to find"
92-
: optTier === 1 ? "findable for skilled players"
93-
: "straightforward for players across skill levels to find";
102+
optTier === 0
103+
? 'hard for players to find'
104+
: optTier === 1
105+
? 'findable for skilled players'
106+
: 'straightforward for players across skill levels to find'
94107

95-
if (optTier === 1) phrBest = "only " + phrBest;
108+
if (optTier === 1) phrBest = 'only ' + phrBest
96109

97-
const verb = nGood === 1 ? "is" : "are";
98-
const pron = nGood === 1 ? "it is" : "they are";
110+
const verb = nGood === 1 ? 'is' : 'are'
111+
const pron = nGood === 1 ? 'it is' : 'they are'
99112

100-
const hasTempting = setLevels > 0 && temptLevels > setLevels / 2;
101-
const temptText = hasTempting ? " There are also tempting alternatives." : "";
113+
const hasTempting = setLevels > 0 && temptLevels > setLevels / 2
114+
const temptText = hasTempting ? ' There are also tempting alternatives.' : ''
102115

103116
if (nGood === 1) {
104-
return `There ${verb} ${abundance} ${outcome}, and ${pron} ${phrSet}.${temptText}`;
117+
return `There ${verb} ${abundance} ${outcome}, and ${pron} ${phrSet}.${temptText}`
105118
}
106119

107120
if (optTier < setTier) {
108-
return `There ${verb} ${abundance} ${outcome}, and ${pron} ${phrSet}, but the best move is ${phrBest}.${temptText}`;
121+
return `There ${verb} ${abundance} ${outcome}, and ${pron} ${phrSet}, but the best move is ${phrBest}.${temptText}`
109122
}
110123

111-
return `There ${verb} ${abundance} ${outcome}, and ${pron} ${phrSet}.${temptText}`;
124+
return `There ${verb} ${abundance} ${outcome}, and ${pron} ${phrSet}.${temptText}`
112125
}

0 commit comments

Comments
 (0)