Recette 1h : « aucune gagnée », résultat avec gammon et videau
Le résultat d'une partie dit d'où viennent ses points (« Perdue, gammon, videau à 2, 4 points ») ; la valeur du videau vient du journal rejoué. Les « Perdue, 2 points » des captures étaient des parties simples perdues avec un videau à 2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c2c5d13651
commit
06cc20fb1b
@@ -12,8 +12,8 @@
|
||||
// n'a pas encore de taux ; l'application l'analyse en arrière-plan.
|
||||
|
||||
import type { Level } from "../game/engine.js";
|
||||
import type { GameJournal } from "../game/events.js";
|
||||
import type { GameResult } from "../game/state.js";
|
||||
import { currentLine, type GameJournal } from "../game/events.js";
|
||||
import { type GameResult, replay } from "../game/state.js";
|
||||
import { type ErrorRate, readyForSummary, summarizeAnalysis } from "./game-analysis.js";
|
||||
|
||||
/** Les parties prises en compte au plus : les plus récentes. Au-delà, la
|
||||
@@ -43,6 +43,8 @@ export interface ProgressionEntry {
|
||||
readonly startedAt: number;
|
||||
readonly level: Level;
|
||||
readonly result: GameResult | null;
|
||||
/** La valeur du videau à la fin de la partie (1 : jamais doublé). */
|
||||
readonly cube: number;
|
||||
readonly errorRate: ErrorRate | null;
|
||||
}
|
||||
|
||||
@@ -56,6 +58,7 @@ export function progressionEntries(games: readonly FinishedGame[]): ProgressionE
|
||||
startedAt: game.startedAt,
|
||||
level: game.level,
|
||||
result: game.result,
|
||||
cube: replay(currentLine(game.journal)).cube.value,
|
||||
errorRate: readyForSummary(game.journal)
|
||||
? summarizeAnalysis(game.journal).player.errorRate
|
||||
: null,
|
||||
|
||||
@@ -43,7 +43,7 @@ export const HOME_TEXTS = {
|
||||
progress: (played: number, won: number) =>
|
||||
played === 0
|
||||
? "aucune partie jouée"
|
||||
: `${plural(played, "partie jouée", "parties jouées")} · ${plural(won, "gagnée", "gagnées")}`,
|
||||
: `${plural(played, "partie jouée", "parties jouées")} · ${won === 0 ? "aucune gagnée" : plural(won, "gagnée", "gagnées")}`,
|
||||
/** La ligne de progression, lien vers l'écran de progression (1h). */
|
||||
progressLink: (line: string) => `Votre progression : ${line}`,
|
||||
footer: "Né à l'Atelier du Huit, à Cugnaux. Logiciel libre, sans publicité ni mise.",
|
||||
|
||||
@@ -31,15 +31,24 @@ export const PROGRESSION_TEXTS = {
|
||||
`Le maître analyse ${plural(n, "partie", "parties")} : ${n > 1 ? "elles apparaîtront" : "elle apparaîtra"} ici une fois ${n > 1 ? "analysées" : "analysée"}.`,
|
||||
exercises: "Demander des exercices à une IA",
|
||||
listTitle: "Vos parties",
|
||||
/** Le résultat court : « Gagnée, 1 point », « Perdue, gammon, 2 points »
|
||||
* (jamais « partie simple »). */
|
||||
result: (result: GameResult | null) => {
|
||||
/** Le résultat court, qui dit d'où viennent les points : « Gagnée,
|
||||
* 1 point », « Perdue, gammon, 2 points », « Perdue, videau à 2,
|
||||
* 2 points », « Perdue, gammon, videau à 2, 4 points » (jamais
|
||||
* « partie simple »). cube : la valeur du videau à la fin de la
|
||||
* partie. */
|
||||
result: (result: GameResult | null, cube: number) => {
|
||||
if (result === null) {
|
||||
return "Partie terminée";
|
||||
}
|
||||
const who = result.winner === "player" ? "Gagnée" : "Perdue";
|
||||
const kind = result.kind === "single" ? "" : `${RESULT_KIND[result.kind]}, `;
|
||||
return `${who}, ${kind}${plural(result.points, "point", "points")}`;
|
||||
const parts = [result.winner === "player" ? "Gagnée" : "Perdue"];
|
||||
if (result.kind !== "single") {
|
||||
parts.push(RESULT_KIND[result.kind]);
|
||||
}
|
||||
if (cube > 1) {
|
||||
parts.push(`videau à ${cube}`);
|
||||
}
|
||||
parts.push(plural(result.points, "point", "points"));
|
||||
return parts.join(", ");
|
||||
},
|
||||
level: (name: string) => `contre ${name}`,
|
||||
rateLabel: "taux d'erreur",
|
||||
|
||||
@@ -125,6 +125,7 @@ export function createProgressionView(options: ProgressionViewOptions): Progress
|
||||
entries: data.entries.map((e) => [
|
||||
e.id,
|
||||
e.result,
|
||||
e.cube,
|
||||
e.level,
|
||||
e.errorRate?.perDecision ?? null,
|
||||
]),
|
||||
@@ -222,7 +223,7 @@ export function createProgressionView(options: ProgressionViewOptions): Progress
|
||||
li.className = "progression-item";
|
||||
li.dataset.id = entry.id;
|
||||
const date = PROGRESSION_TEXTS.date(entry.startedAt);
|
||||
const result = PROGRESSION_TEXTS.result(entry.result);
|
||||
const result = PROGRESSION_TEXTS.result(entry.result, entry.cube);
|
||||
// Une ligne, un seul lien : le bilan (l'analyse s'ouvre depuis
|
||||
// lui), chevron à droite.
|
||||
const game = element(li, "a", { className: "progression-game" });
|
||||
|
||||
@@ -38,6 +38,8 @@ import {
|
||||
mistakeThemes,
|
||||
} from "../src/domain/prompts/prompts.js";
|
||||
import { PROMPT_FILES, parsePromptTemplate } from "../src/domain/prompts/templates.js";
|
||||
import { HOME_TEXTS } from "../src/ui/home-texts.js";
|
||||
import { PROGRESSION_TEXTS } from "../src/ui/progression-texts.js";
|
||||
import { parseRoute, routeHash } from "../src/ui/router.js";
|
||||
import { loadPhrases } from "./support/advice.js";
|
||||
import { loadNodeEngine } from "./support/node-engine.js";
|
||||
@@ -86,6 +88,25 @@ test("l'adresse #/progression et celle de « Créer des exercices »", () => {
|
||||
assert.equal(routeHash({ screen: "progression", ai: true }), "#/progression/ia");
|
||||
});
|
||||
|
||||
test("le résultat d'une partie dit d'où viennent les points : gammon, videau", () => {
|
||||
const result = PROGRESSION_TEXTS.result;
|
||||
const lost = (kind: "single" | "gammon" | "backgammon", points: number) =>
|
||||
({ winner: "computer", kind, points }) as const;
|
||||
assert.equal(result({ winner: "player", kind: "single", points: 1 }, 1), "Gagnée, 1 point");
|
||||
assert.equal(result(lost("single", 1), 1), "Perdue, 1 point");
|
||||
assert.equal(result(lost("gammon", 2), 1), "Perdue, gammon, 2 points");
|
||||
assert.equal(result(lost("single", 2), 2), "Perdue, videau à 2, 2 points");
|
||||
assert.equal(result(lost("gammon", 4), 2), "Perdue, gammon, videau à 2, 4 points");
|
||||
assert.equal(result(lost("backgammon", 12), 4), "Perdue, backgammon, videau à 4, 12 points");
|
||||
assert.equal(result(null, 1), "Partie terminée");
|
||||
});
|
||||
|
||||
test("la ligne de l'accueil : « aucune gagnée », comme « aucune leçon terminée »", () => {
|
||||
assert.equal(HOME_TEXTS.progress(3, 0), "3 parties jouées · aucune gagnée");
|
||||
assert.equal(HOME_TEXTS.progress(3, 1), "3 parties jouées · 1 gagnée");
|
||||
assert.equal(HOME_TEXTS.progress(0, 0), "aucune partie jouée");
|
||||
});
|
||||
|
||||
test("le taux d'erreur s'écrit en millièmes, comme les mEMG de GNU Backgammon", () => {
|
||||
assert.equal(errorRateMillis(0.0142), 14);
|
||||
assert.equal(errorRateMillis(0.0075), 8);
|
||||
|
||||
@@ -308,6 +308,7 @@ const shown = await page.evaluate(() => ({
|
||||
id: li.dataset.id,
|
||||
summary: li.querySelector(".progression-game").getAttribute("href"),
|
||||
links: li.querySelectorAll("a, button").length,
|
||||
result: li.querySelector(".progression-text strong").textContent,
|
||||
chevron: li.querySelector(".progression-game > svg.icon") !== null,
|
||||
rate: li.querySelector(".progression-rate")?.dataset.rate,
|
||||
})),
|
||||
@@ -348,7 +349,7 @@ check(
|
||||
`exercices : ${shown.exercises} « ${shown.exercisesText} »`,
|
||||
);
|
||||
await capture("2-trois-parties");
|
||||
log(`courbe : ${shown.dots.map((d) => d.rate).join(", ")} ; « ${shown.summary} »`);
|
||||
log(`courbe : ${shown.dots.map((d) => d.rate).join(", ")} ; « ${shown.summary} » ; résultats : ${shown.items.map((i) => i.result).join(" | ")}`);
|
||||
|
||||
// Une ligne ouvre le bilan ; le fermer ramène à la progression.
|
||||
await page.click(`#progression-list .progression-item[data-id="${games[0].id}"] .progression-game`);
|
||||
|
||||
Reference in New Issue
Block a user