Double toucher sans coup évident : un toucher simple ; tests navigateur adaptés aux raccourcis

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Pierre MARTIN
2026-11-12 10:26:30 +01:00
co-authored by Claude Opus 5.5
parent 0aec6cb7b1
commit 094f535c84
2 changed files with 66 additions and 34 deletions
+55 -32
View File
@@ -1719,45 +1719,44 @@ export function startApp(options: AppOptions): void {
}
/**
* Double toucher : joue le coup évident (le domaine le cherche, le
* moteur le juge) commencé au premier toucher, si le joueur n'a rien
* fait d'autre entre-temps. Le premier toucher a pu faire partir le
* Double toucher (charte, 1i) : joue le coup évident (le domaine le
* cherche, le moteur le juge) qui commence par le pion touché, depuis
* l'état du premier toucher. Ce premier toucher a pu faire partir le
* pion tout de suite (une seule case d'arrivée) : il ne reste alors que
* la suite du coup. Sinon, rien : le double toucher vaut un toucher.
* la suite du coup. Sans coup évident, le second toucher n'est qu'un
* toucher : touchers rapides sur une même pile (un double, par exemple)
* et pion repris (touché deux fois : plus rien de choisi).
* L'appelant a pris l'écran (busy) : le moteur est seul à travailler.
*/
async function playObvious(tap: ObviousTap): Promise<void> {
await whenIdle();
const g = game;
if (g !== tap.game || busy || g.state.phase !== "moving") {
return;
}
const now = g.pendingHalfMoves;
const now = g?.pendingHalfMoves ?? [];
const same = (a: HalfMove | undefined, b: HalfMove | undefined) =>
a !== undefined && b !== undefined && a.from === b.from && a.to === b.to;
if (now.length < tap.pending.length || !tap.pending.every((h, i) => same(h, now[i]))) {
return;
}
// Demandé seulement maintenant : un toucher simple ne coûte rien au
// moteur.
busy = true;
render();
let obvious: HalfMove[] | null = null;
try {
obvious = await g.obviousMove(pointOf(tap.place), tap.pending);
} catch {
obvious = null;
let rest: HalfMove[] = [];
if (
g === tap.game &&
g.state.phase === "moving" &&
now.length >= tap.pending.length &&
tap.pending.every((h, i) => same(h, now[i]))
) {
// Demandé seulement maintenant : un toucher simple ne coûte rien
// au moteur.
const obvious = await g.obviousMove(pointOf(tap.place), tap.pending).catch(() => null);
const done = now.slice(tap.pending.length);
if (obvious !== null && done.every((h, i) => same(h, obvious[i]))) {
rest = obvious.slice(done.length);
}
}
busy = false;
const done = now.slice(tap.pending.length);
const rest = obvious?.slice(done.length) ?? [];
const unchanged =
game === g &&
g.pendingHalfMoves.length === now.length &&
done.every((h, i) => same(h, obvious?.[i]));
if (!unchanged || rest.length === 0) {
if (game !== g || g === null) {
render();
return;
}
if (rest.length === 0) {
tapPlace(tap.place);
return;
}
void act(async (g) => {
info = "";
const before = (await g.displayedBoard()).computer.bar;
@@ -2673,12 +2672,18 @@ export function startApp(options: AppOptions): void {
: { game: current, place, pending: [...current.pendingHalfMoves] },
);
if (second !== null) {
void playObvious(second);
doubleTapped(second);
return;
}
if (busy) {
return;
if (!busy) {
tapPlace(place);
}
});
/** Un toucher simple sur un endroit du plateau : le pion choisi va sur
* cette case d'arrivée ; ou ce pion part tout de suite, s'il n'a qu'une
* case d'arrivée ; ou il est choisi (touché de nouveau : plus rien). */
function tapPlace(place: Place): void {
keyTarget = null;
const halfMove = selected === null ? undefined : targets.get(selected)?.get(place);
if (halfMove !== undefined) {
@@ -2695,7 +2700,25 @@ export function startApp(options: AppOptions): void {
shownMove = null; // toucher un pion : le coup de l'ordinateur s'efface
}
render();
});
}
/** Le second toucher d'un double toucher : l'écran le prend tout de
* suite (réponse immédiate), ou dès qu'il a fini l'effet du premier. */
function doubleTapped(tap: ObviousTap): void {
const claim = () => {
if (busy) {
return;
}
busy = true;
render();
void playObvious(tap);
};
if (busy) {
void whenIdle().then(claim);
} else {
claim();
}
}
/**
* Le plateau au clavier (interaction.md) : les flèches gauche et droite