Prompts : le niveau du joueur seulement à partir de 20 décisions, son taux d'erreur dans le seul bilan

Recette de 1f (F3). En dessous de 20 décisions analysées, le prompt dit
« Je débute au backgammon. ». Test du seuil ; outil prompt-sample pour
relire des prompts remplis par le moteur. Plan de 1f clos.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Pierre MARTIN
2026-11-11 21:52:23 +01:00
co-authored by Claude Opus 5.5
parent f509f8746e
commit f2df1b2e7f
10 changed files with 143 additions and 71 deletions
+27 -16
View File
@@ -14,6 +14,7 @@
// au moteur la position à décrire.
import {
type ErrorRate,
gameTurns,
levelOfErrorRate,
type ReviewedDecision,
@@ -85,14 +86,25 @@ export function plyText(ply: Ply): string {
return `analyse à ${ply} ${ply > 1 ? "plis" : "pli"}`;
}
/** Le niveau du joueur d'après son erreur par décision dans une partie
* (comme le bilan) ; « pas encore mesuré » sans décision comptée. */
export function playerLevel(journal: GameJournal | null): string {
const rate = journal === null ? null : summarizeAnalysis(journal).player.errorRate;
if (rate === null || rate.decisions === 0) {
return "pas encore mesuré (aucune de mes décisions n'a encore été analysée)";
/** Nombre de décisions analysées à partir duquel le niveau du joueur se
* dit dans un prompt : en dessous, l'erreur par décision dit peu de chose. */
export const LEVEL_MIN_DECISIONS = 20;
/** Ce que le joueur dit de lui-même dans un prompt : son niveau, d'après
* son erreur par décision mesurée par GNU Backgammon, s'il est mesuré sur
* au moins LEVEL_MIN_DECISIONS décisions ; sinon, qu'il débute (pas encore
* d'historique des parties : étape 1h). Jamais le taux lui-même, qui n'est
* que dans le bilan. */
export function playerSentence(rate: Pick<ErrorRate, "decisions" | "level"> | null): string {
if (rate === null || rate.decisions < LEVEL_MIN_DECISIONS) {
return "Je débute au backgammon.";
}
return `${LEVEL_NAMES[rate.level]}, d'après mon erreur par décision dans ma partie, mesurée par GNU Backgammon (${formatEquity(-rate.perDecision)} sur ${plural(rate.decisions, "décision", "décisions")})`;
return `Je suis un joueur de niveau ${LEVEL_NAMES[rate.level]}.`;
}
/** playerSentence, sur les décisions d'une partie. */
function playerOf(journal: GameJournal | null): string {
return playerSentence(journal === null ? null : summarizeAnalysis(journal).player.errorRate);
}
/** Les repères de la position, communs à tous les gabarits. */
@@ -130,7 +142,7 @@ export function decisionPrompt(
): Prompt {
const common = {
...positionValues(data.position),
niveau: playerLevel(data.journal),
joueur: playerOf(data.journal),
niveau_eval: plyText(data.advice.ply),
appreciation: masterWords(phrases, data.advice).word,
};
@@ -309,7 +321,7 @@ export function summaryPrompt(
const toReview = summary.toReview;
return fillPrompt(templates.summary, {
...positionValues(data.position),
niveau: playerLevel(data.journal),
joueur: playerOf(data.journal),
niveau_eval: plyText(summaryPly(data.journal, toReview)),
ordinateur: computerLevelName(data.journal),
resultat: resultText(data.journal),
@@ -381,7 +393,7 @@ export function conceptPrompt(templates: PromptTemplates, data: ConceptPromptDat
: "";
return fillPrompt(templates.concept, {
...positionValues(example.position),
niveau: playerLevel(data.journal),
joueur: playerOf(data.journal),
niveau_eval: plyText(example.ply),
concept: `« ${data.term} »${english}`,
definition: data.brief,
@@ -439,24 +451,23 @@ export function exercisesPrompt(
if (worst === undefined) {
throw new Error("exercices : aucune erreur dans ces parties");
}
// Le niveau, sur toutes les décisions de ces parties.
let total = 0;
let decisions = 0;
const rates = data.journals.map((journal) => {
for (const journal of data.journals) {
const rate = summarizeAnalysis(journal).player.errorRate;
total += rate.total;
decisions += rate.decisions;
return `${formatEquity(-rate.perDecision)} (${LEVEL_NAMES[rate.level]})`;
});
const perDecision = decisions > 0 ? total / decisions : 0;
}
const level = levelOfErrorRate(decisions > 0 ? total / decisions : 0);
const listed = mistakes
.slice(0, MAX_ERRORS)
.map((m) => mistakeLine(phrases, m, `Partie ${m.game}, coup ${m.turn}`));
return fillPrompt(templates.exercises, {
...positionValues(data.position),
niveau: `${LEVEL_NAMES[levelOfErrorRate(perDecision)]}, d'après mon erreur par décision sur ces parties, mesurée par GNU Backgammon (${formatEquity(-perDecision)} sur ${plural(decisions, "décision", "décisions")})`,
joueur: playerSentence({ decisions, level }),
niveau_eval: plyText(worst.advice.ply),
parties: String(data.journals.length),
taux_parties: rates.join(", "),
erreurs: listed.join("\n"),
position_titre: `La plus coûteuse (partie ${worst.game}, coup ${worst.turn}) : la position avant ma décision`,
});