chesspal 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/README.md +99 -2
  2. package/dist/cli/chat-hook.d.ts +2 -0
  3. package/dist/cli/chat-hook.js +33 -0
  4. package/dist/cli/cli.d.ts +2 -0
  5. package/dist/cli/cli.js +28 -0
  6. package/dist/cli/command-line.d.ts +7 -0
  7. package/dist/cli/command-line.js +177 -0
  8. package/dist/commands/agents.d.ts +26 -0
  9. package/dist/commands/agents.js +72 -0
  10. package/dist/commands/ai-move.d.ts +28 -0
  11. package/dist/commands/ai-move.js +85 -0
  12. package/dist/commands/ai-say.d.ts +22 -0
  13. package/dist/commands/ai-say.js +58 -0
  14. package/dist/commands/analyse-game.d.ts +65 -0
  15. package/dist/commands/analyse-game.js +265 -0
  16. package/dist/commands/annotate-game.d.ts +39 -0
  17. package/dist/commands/annotate-game.js +131 -0
  18. package/dist/commands/answer-lines.d.ts +28 -0
  19. package/dist/commands/answer-lines.js +144 -0
  20. package/dist/commands/clock.d.ts +15 -0
  21. package/dist/commands/clock.js +45 -0
  22. package/dist/commands/coach.d.ts +45 -0
  23. package/dist/commands/coach.js +344 -0
  24. package/dist/commands/context.d.ts +67 -0
  25. package/dist/commands/context.js +37 -0
  26. package/dist/commands/delete-game.d.ts +7 -0
  27. package/dist/commands/delete-game.js +30 -0
  28. package/dist/commands/delete-review.d.ts +8 -0
  29. package/dist/commands/delete-review.js +34 -0
  30. package/dist/commands/draw-offer.d.ts +10 -0
  31. package/dist/commands/draw-offer.js +43 -0
  32. package/dist/commands/drawings.d.ts +13 -0
  33. package/dist/commands/drawings.js +25 -0
  34. package/dist/commands/end-game.d.ts +23 -0
  35. package/dist/commands/end-game.js +67 -0
  36. package/dist/commands/export-game.d.ts +14 -0
  37. package/dist/commands/export-game.js +27 -0
  38. package/dist/commands/game-summary.d.ts +78 -0
  39. package/dist/commands/game-summary.js +102 -0
  40. package/dist/commands/index.d.ts +18 -0
  41. package/dist/commands/index.js +64 -0
  42. package/dist/commands/init.d.ts +15 -0
  43. package/dist/commands/init.js +73 -0
  44. package/dist/commands/lead-input.d.ts +8 -0
  45. package/dist/commands/lead-input.js +21 -0
  46. package/dist/commands/levels.d.ts +9 -0
  47. package/dist/commands/levels.js +25 -0
  48. package/dist/commands/look.d.ts +31 -0
  49. package/dist/commands/look.js +64 -0
  50. package/dist/commands/new-game.d.ts +68 -0
  51. package/dist/commands/new-game.js +218 -0
  52. package/dist/commands/opening-book.d.ts +13 -0
  53. package/dist/commands/opening-book.js +84 -0
  54. package/dist/commands/page-link.d.ts +11 -0
  55. package/dist/commands/page-link.js +28 -0
  56. package/dist/commands/past-games.d.ts +11 -0
  57. package/dist/commands/past-games.js +47 -0
  58. package/dist/commands/play-move.d.ts +37 -0
  59. package/dist/commands/play-move.js +94 -0
  60. package/dist/commands/player-move.d.ts +13 -0
  61. package/dist/commands/player-move.js +51 -0
  62. package/dist/commands/player-say.d.ts +5 -0
  63. package/dist/commands/player-say.js +16 -0
  64. package/dist/commands/ponder.d.ts +52 -0
  65. package/dist/commands/ponder.js +179 -0
  66. package/dist/commands/position.d.ts +14 -0
  67. package/dist/commands/position.js +130 -0
  68. package/dist/commands/profiles.d.ts +69 -0
  69. package/dist/commands/profiles.js +163 -0
  70. package/dist/commands/registry.d.ts +59 -0
  71. package/dist/commands/registry.js +62 -0
  72. package/dist/commands/say.d.ts +16 -0
  73. package/dist/commands/say.js +84 -0
  74. package/dist/commands/speech.d.ts +8 -0
  75. package/dist/commands/speech.js +20 -0
  76. package/dist/commands/status.d.ts +35 -0
  77. package/dist/commands/status.js +128 -0
  78. package/dist/commands/study-games.d.ts +5 -0
  79. package/dist/commands/study-games.js +40 -0
  80. package/dist/commands/study.d.ts +38 -0
  81. package/dist/commands/study.js +106 -0
  82. package/dist/commands/view.d.ts +14 -0
  83. package/dist/commands/view.js +125 -0
  84. package/dist/core/board-text.d.ts +7 -0
  85. package/dist/core/board-text.js +18 -0
  86. package/dist/core/book.json +1 -0
  87. package/dist/core/clock.d.ts +45 -0
  88. package/dist/core/clock.js +109 -0
  89. package/dist/core/facts.d.ts +55 -0
  90. package/dist/core/facts.js +175 -0
  91. package/dist/core/game.d.ts +95 -0
  92. package/dist/core/game.js +352 -0
  93. package/dist/core/illegal.d.ts +19 -0
  94. package/dist/core/illegal.js +141 -0
  95. package/dist/core/index.d.ts +20 -0
  96. package/dist/core/index.js +12 -0
  97. package/dist/core/lead.d.ts +15 -0
  98. package/dist/core/lead.js +40 -0
  99. package/dist/core/levels.d.ts +20 -0
  100. package/dist/core/levels.js +33 -0
  101. package/dist/core/material.d.ts +9 -0
  102. package/dist/core/material.js +12 -0
  103. package/dist/core/moods.d.ts +21 -0
  104. package/dist/core/moods.js +45 -0
  105. package/dist/core/openings.d.ts +35 -0
  106. package/dist/core/openings.js +98 -0
  107. package/dist/core/openings.json +1 -0
  108. package/dist/core/pgn.d.ts +10 -0
  109. package/dist/core/pgn.js +213 -0
  110. package/dist/core/profile.d.ts +117 -0
  111. package/dist/core/profile.js +232 -0
  112. package/dist/core/record.d.ts +21 -0
  113. package/dist/core/record.js +25 -0
  114. package/dist/core/review.d.ts +80 -0
  115. package/dist/core/review.js +146 -0
  116. package/dist/games/ai-model.d.ts +5 -0
  117. package/dist/games/ai-model.js +15 -0
  118. package/dist/games/analysis.d.ts +12 -0
  119. package/dist/games/analysis.js +26 -0
  120. package/dist/games/archive.d.ts +63 -0
  121. package/dist/games/archive.js +242 -0
  122. package/dist/games/chat-start.d.ts +16 -0
  123. package/dist/games/chat-start.js +26 -0
  124. package/dist/games/coach.d.ts +57 -0
  125. package/dist/games/coach.js +144 -0
  126. package/dist/games/current-game.d.ts +56 -0
  127. package/dist/games/current-game.js +134 -0
  128. package/dist/games/files.d.ts +9 -0
  129. package/dist/games/files.js +53 -0
  130. package/dist/games/index.d.ts +11 -0
  131. package/dist/games/index.js +12 -0
  132. package/dist/games/plans.d.ts +9 -0
  133. package/dist/games/plans.js +23 -0
  134. package/dist/games/table-talk.d.ts +12 -0
  135. package/dist/games/table-talk.js +25 -0
  136. package/dist/games/talk.d.ts +36 -0
  137. package/dist/games/talk.js +131 -0
  138. package/dist/games/thoughts.d.ts +15 -0
  139. package/dist/games/thoughts.js +60 -0
  140. package/dist/home/data-folder.d.ts +12 -0
  141. package/dist/home/data-folder.js +55 -0
  142. package/dist/home/index.d.ts +2 -0
  143. package/dist/home/index.js +3 -0
  144. package/dist/home/open-folder.d.ts +2 -0
  145. package/dist/home/open-folder.js +14 -0
  146. package/dist/host-files/agents.d.ts +20 -0
  147. package/dist/host-files/agents.js +53 -0
  148. package/dist/host-files/host-files.d.ts +15 -0
  149. package/dist/host-files/host-files.js +182 -0
  150. package/dist/host-files/index.d.ts +2 -0
  151. package/dist/host-files/index.js +3 -0
  152. package/dist/index.d.ts +2 -0
  153. package/dist/index.js +3 -0
  154. package/dist/page/app/anchor.js +88 -0
  155. package/dist/page/app/app.js +458 -0
  156. package/dist/page/app/keys.js +94 -0
  157. package/dist/page/app/phase.js +30 -0
  158. package/dist/page/app/served.js +73 -0
  159. package/dist/page/avatars/avatars.js +19 -0
  160. package/dist/page/avatars/beanie.webp +0 -0
  161. package/dist/page/avatars/beard.webp +0 -0
  162. package/dist/page/avatars/bun.webp +0 -0
  163. package/dist/page/avatars/cat.webp +0 -0
  164. package/dist/page/avatars/curls.webp +0 -0
  165. package/dist/page/avatars/glasses.webp +0 -0
  166. package/dist/page/avatars/moustache.webp +0 -0
  167. package/dist/page/avatars/owl.webp +0 -0
  168. package/dist/page/avatars/short-hair.webp +0 -0
  169. package/dist/page/avatars/silver-bob.webp +0 -0
  170. package/dist/page/avatars/thought.js +10 -0
  171. package/dist/page/avatars/torretta.js +38 -0
  172. package/dist/page/base.css +160 -0
  173. package/dist/page/board/board.css +959 -0
  174. package/dist/page/board/board.js +125 -0
  175. package/dist/page/board/explain.js +58 -0
  176. package/dist/page/board/marks.js +160 -0
  177. package/dist/page/board/motion.js +71 -0
  178. package/dist/page/board/pointer.js +239 -0
  179. package/dist/page/board/squares.js +26 -0
  180. package/dist/page/dialogs/analyses.js +195 -0
  181. package/dist/page/dialogs/dialog.js +26 -0
  182. package/dist/page/dialogs/dialogs.css +1228 -0
  183. package/dist/page/dialogs/new-game.js +42 -0
  184. package/dist/page/dialogs/profiles.js +152 -0
  185. package/dist/page/dialogs/search.js +31 -0
  186. package/dist/page/dialogs/settings.js +42 -0
  187. package/dist/page/dialogs/studied.js +39 -0
  188. package/dist/page/dialogs/study.js +51 -0
  189. package/dist/page/game/badges.js +50 -0
  190. package/dist/page/game/browse.js +17 -0
  191. package/dist/page/game/card-fold.js +40 -0
  192. package/dist/page/game/column.js +51 -0
  193. package/dist/page/game/ending.js +73 -0
  194. package/dist/page/game/game.css +577 -0
  195. package/dist/page/game/move-list.js +72 -0
  196. package/dist/page/game/opening-book.js +14 -0
  197. package/dist/page/game/plies.js +82 -0
  198. package/dist/page/game/result-tile.js +14 -0
  199. package/dist/page/helps/helps.css +689 -0
  200. package/dist/page/helps/helps.js +220 -0
  201. package/dist/page/helps/view.js +127 -0
  202. package/dist/page/layout/fold-tab.js +11 -0
  203. package/dist/page/layout/folds.js +43 -0
  204. package/dist/page/layout/header.js +28 -0
  205. package/dist/page/layout/layout.css +834 -0
  206. package/dist/page/lead/lead.js +82 -0
  207. package/dist/page/lead/view.js +38 -0
  208. package/dist/page/main.js +8 -0
  209. package/dist/page/pieces/CREDITS.md +19 -0
  210. package/dist/page/pieces/capablanca-small.svg +20 -0
  211. package/dist/page/pieces/capablanca.svg +22 -0
  212. package/dist/page/pieces/nitida-small.svg +20 -0
  213. package/dist/page/pieces/nitida.svg +21 -0
  214. package/dist/page/pieces/pieces.js +28 -0
  215. package/dist/page/pieces/torretta-small.svg +20 -0
  216. package/dist/page/pieces/torretta.svg +21 -0
  217. package/dist/page/players/card.js +56 -0
  218. package/dist/page/players/clock-time.js +12 -0
  219. package/dist/page/players/model-name.js +20 -0
  220. package/dist/page/profile/profile.js +99 -0
  221. package/dist/page/profile/settings.js +77 -0
  222. package/dist/page/sounds/capture.ogg +0 -0
  223. package/dist/page/sounds/check.ogg +0 -0
  224. package/dist/page/sounds/draw.ogg +0 -0
  225. package/dist/page/sounds/flag.ogg +0 -0
  226. package/dist/page/sounds/mate.ogg +0 -0
  227. package/dist/page/sounds/move.ogg +0 -0
  228. package/dist/page/sounds/offer.ogg +0 -0
  229. package/dist/page/sounds/resign.ogg +0 -0
  230. package/dist/page/sounds/sounds.js +105 -0
  231. package/dist/page/style.css +9 -0
  232. package/dist/page/talk/talk.css +958 -0
  233. package/dist/page/talk/talk.js +165 -0
  234. package/dist/page/talk/voice.js +38 -0
  235. package/dist/page/text.js +711 -0
  236. package/dist/page/theme.css +292 -0
  237. package/dist/profiles/avatar.d.ts +23 -0
  238. package/dist/profiles/avatar.js +84 -0
  239. package/dist/profiles/front-matter.d.ts +9 -0
  240. package/dist/profiles/front-matter.js +33 -0
  241. package/dist/profiles/index.d.ts +3 -0
  242. package/dist/profiles/index.js +5 -0
  243. package/dist/profiles/profiles.d.ts +69 -0
  244. package/dist/profiles/profiles.js +254 -0
  245. package/dist/profiles/settings.d.ts +12 -0
  246. package/dist/profiles/settings.js +46 -0
  247. package/dist/server/bell.d.ts +68 -0
  248. package/dist/server/bell.js +225 -0
  249. package/dist/server/caller.d.ts +21 -0
  250. package/dist/server/caller.js +132 -0
  251. package/dist/server/mcp.d.ts +13 -0
  252. package/dist/server/mcp.js +207 -0
  253. package/dist/server/page/analyses.d.ts +23 -0
  254. package/dist/server/page/analyses.js +65 -0
  255. package/dist/server/page/files.d.ts +5 -0
  256. package/dist/server/page/files.js +92 -0
  257. package/dist/server/page/game.d.ts +6 -0
  258. package/dist/server/page/game.js +381 -0
  259. package/dist/server/page/http.d.ts +29 -0
  260. package/dist/server/page/http.js +68 -0
  261. package/dist/server/page/page.d.ts +41 -0
  262. package/dist/server/page/page.js +229 -0
  263. package/dist/server/page/profiles.d.ts +19 -0
  264. package/dist/server/page/profiles.js +215 -0
  265. package/dist/version.d.ts +2 -0
  266. package/dist/version.js +3 -0
  267. package/instructions/analysis.md +4 -0
  268. package/instructions/analyst-agent.md +8 -0
  269. package/instructions/analyst.md +4 -0
  270. package/instructions/coach.md +11 -0
  271. package/instructions/opponent.md +15 -0
  272. package/instructions/ponder.md +9 -0
  273. package/package.json +66 -5
@@ -0,0 +1,72 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
2
+ import { useEffect, useRef } from "preact/hooks";
3
+ import { Figurine } from "../pieces/pieces.js";
4
+ import { BadgeIcon, NoteIcon } from "./badges.js";
5
+ import { FoldButton, useCardFold } from "./card-fold.js";
6
+ /**
7
+ * The moves numbered in pairs, the one the board shows marked (`shown`, how many moves it shows), and the result once the game is over; a click on a move
8
+ * shows it. The list keeps its last move in sight, and the one shown while the player looks back.
9
+ */
10
+ export function MoveList({ plies, result, shown, onShow, text }) {
11
+ const list = useRef(null);
12
+ const [folded, toggleFold] = useCardFold("moves");
13
+ const rows = rowsOf(plies);
14
+ const current = plies[shown - 1];
15
+ useEffect(() => {
16
+ list.current?.scrollTo({ top: list.current.scrollHeight });
17
+ }, [plies.length]);
18
+ // Only the list scrolls to the move shown: the page under the board stays where the player has it.
19
+ useEffect(() => keepInSight(list.current), [shown]);
20
+ // The cards above it change height with the position, the helps' card above all: the list follows, its move still in sight.
21
+ useEffect(() => {
22
+ const element = list.current;
23
+ if (element === null) {
24
+ return;
25
+ }
26
+ const observer = new ResizeObserver(() => keepInSight(element));
27
+ observer.observe(element);
28
+ return () => observer.disconnect();
29
+ }, []);
30
+ const move = (ply) => _jsx(Move, { ply: ply, current: ply !== undefined && ply === current, onShow: () => onShow(plies.indexOf(ply) + 1), text: text });
31
+ // The card's title with its icon, a score sheet, as the other cards of the column, which folds the card to it (Stefano); only the list under it
32
+ // scrolls, and it stays in the page while folded, so that it keeps its move in sight.
33
+ return (_jsxs("section", { class: `card moves-card${folded ? " folded" : ""}`, "aria-label": text.moves, children: [_jsx("h3", { class: "card-title", children: _jsxs(FoldButton, { folded: folded, onFold: toggleFold, text: text, children: [_jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M6 3H15L19 7V21H6ZM15 3V7H19M9 11H16M9 14.5H16M9 18H13" }) }), text.moves] }) }), _jsxs("div", { ref: list, class: "moves", hidden: folded, children: [_jsx("ol", { children: rows.map(({ number, white, black }) => (_jsxs("li", { children: [_jsxs("span", { class: "number", children: [number, "."] }), move(white), move(black)] }, number))) }), result === undefined ? null : _jsx("p", { class: "result", children: result })] })] }));
34
+ }
35
+ /** The buttons that step through the moves: to the start, back, forward, and to the game as it is; each one off where it could not go. */
36
+ export function Steps({ shown, total, onStep, text }) {
37
+ const button = (step, path, off) => (_jsx("button", { type: "button", title: text.steps[step], "aria-label": text.steps[step], disabled: off, onClick: () => onStep(step), children: _jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: path }) }) }));
38
+ return (_jsxs("nav", { class: "steps card", "aria-label": text.moves, children: [button("first", "M7 6V18M17 6L11 12L17 18", shown === 0), button("back", "M14.5 6L8.5 12L14.5 18", shown === 0), button("forward", "M9.5 6L15.5 12L9.5 18", shown === total), button("last", "M17 6V18M7 6L13 12L7 18", shown === total)] }));
39
+ }
40
+ /** A move in SAN with each piece's letter drawn as its figure, the same in every language (D-50), and a capture's x in grey, so the squares stand out. */
41
+ export function Figurines({ san, side }) {
42
+ return (_jsx(_Fragment, { children: san.split(/([KQRBNx])/).map((part, index) => index % 2 === 0 ? part : part === "x" ? _jsx("span", { class: "takes", children: "x" }, index) : _jsx(Figurine, { letter: part, side: side }, index)) }));
43
+ }
44
+ function Move({ ply, current, onShow, text }) {
45
+ if (ply === undefined) {
46
+ return _jsx("span", { children: "\u2026" });
47
+ }
48
+ // A screen reader reads the move in SAN and the AI's badge by its name; the eye sees each piece's letter as its figure, and the badge's disc (D-69).
49
+ return (_jsxs("button", { type: "button", class: current ? "ply current" : "ply", "aria-current": current ? "step" : undefined, onClick: onShow, children: [_jsx("span", { class: "visually-hidden", children: ply.review?.badge === undefined ? ply.san : `${ply.san}, ${text.badges[ply.review.badge]}` }), _jsx("span", { "aria-hidden": "true", children: _jsx(Figurines, { san: ply.san, side: ply.side }) }), ply.review?.badge !== undefined ? _jsx(BadgeIcon, { badge: ply.review.badge }) : ply.review?.note !== undefined ? _jsx(NoteIcon, {}) : null] }));
50
+ }
51
+ /** Scrolls the list, and only the list, as little as it takes to show its current move. */
52
+ function keepInSight(list) {
53
+ const box = list?.getBoundingClientRect();
54
+ const move = list?.querySelector(".current")?.getBoundingClientRect();
55
+ if (box === undefined || move === undefined) {
56
+ return;
57
+ }
58
+ list.scrollTop += Math.min(0, move.top - box.top) + Math.max(0, move.bottom - box.bottom);
59
+ }
60
+ /** The plies in rows of one number: White's move and Black's. */
61
+ function rowsOf(plies) {
62
+ const rows = [];
63
+ for (const ply of plies) {
64
+ let row = rows.at(-1);
65
+ if (row?.number !== ply.number) {
66
+ row = { number: ply.number };
67
+ rows.push(row);
68
+ }
69
+ row[ply.side] = ply;
70
+ }
71
+ return rows;
72
+ }
@@ -0,0 +1,14 @@
1
+ // The book of the openings (D-16), fetched once the game has a move: the page names the opening itself, from the moves it replays.
2
+ import { useEffect, useState } from "preact/hooks";
3
+ let fetched;
4
+ /** The book, once it is needed and has come; undefined before, or when it cannot be had. */
5
+ export function useOpeningBook(needed) {
6
+ const [book, setBook] = useState(undefined);
7
+ useEffect(() => {
8
+ if (needed && book === undefined) {
9
+ fetched ??= fetch("/core/openings.json").then((response) => response.ok ? response.json() : undefined).catch(() => undefined);
10
+ void fetched.then(setBook);
11
+ }
12
+ }, [needed]);
13
+ return book;
14
+ }
@@ -0,0 +1,82 @@
1
+ // The moves of a game as the page shows them: each with its side and number, the comment the player may read and the AI's review; and the words said on
2
+ // the page.
3
+ import { drawingsIn, leadOf, reviewOf } from "../../core/index.js";
4
+ /**
5
+ * The moves of a record, each with its side and number: a game may start from a position where Black moves first. A comment keeps only its words: the
6
+ * commands in it, such as the AI's plan that an ended game shows, and the (=) of a draw offer (D-65), are not for the page.
7
+ */
8
+ export function pliesOf(record) {
9
+ const [, turn, , , , number] = (record.tags.FEN ?? "").split(" ");
10
+ const first = Number(number) || 1;
11
+ const offset = turn === "b" ? 1 : 0;
12
+ return record.moves.map((move, index) => {
13
+ const comment = move.comment?.replace(/\s*\[%[^\]]*\]/g, "").replace(/^\s*\(=\)/, "").trim();
14
+ // The AI's drawings with its own move, with the helps on, come without a badge or a note (D-78).
15
+ const drawings = drawingsIn(move.comment);
16
+ const review = reviewOf(move.comment) ?? (Object.keys(drawings).length === 0 ? undefined : drawings);
17
+ const lead = leadOf(move.comment);
18
+ const ply = {
19
+ san: move.san,
20
+ side: (index + offset) % 2 === 0 ? "white" : "black",
21
+ number: first + Math.floor((index + offset) / 2),
22
+ ...(review === undefined ? {} : { review }),
23
+ ...(lead === undefined ? {} : { lead }),
24
+ };
25
+ return comment === undefined || comment === "" ? ply : { ...ply, comment };
26
+ });
27
+ }
28
+ /** The moves with the coach's judgments on the player's, as the analyst's review shows on them (D-88), and who it saw ahead after the moves it was given (D-90). */
29
+ export function withJudgments(plies, { judgments, leads = [] }) {
30
+ return plies.map((ply, index) => {
31
+ const judgment = judgments.find((one) => one.ply === index + 1);
32
+ const lead = leads.find((one) => one.position === index + 1)?.lead;
33
+ const judged = judgment === undefined
34
+ ? ply
35
+ : { ...ply, review: { ...(judgment.badge === undefined ? {} : { badge: judgment.badge }), ...(judgment.note === undefined ? {} : { note: judgment.note }) } };
36
+ return lead === undefined ? judged : { ...judged, lead };
37
+ });
38
+ }
39
+ /** The moves with the book's badge on the first `book` of them that have no review of the AI's. */
40
+ export function withBook(plies, book) {
41
+ // A move the AI only drew on keeps its drawings beside the book's badge (D-78).
42
+ return book === 0 ? plies : plies.map((ply, index) => index < book && ply.review?.badge === undefined && ply.review?.note === undefined ? { ...ply, review: { ...ply.review, badge: "book" } } : ply);
43
+ }
44
+ /** The moves without the AI's review: during a game with the helps off the player sees neither its judgments nor its drawings (D-78), nor who is ahead (D-90). */
45
+ export function withoutReviews(plies) {
46
+ return plies.map(({ review, lead, ...ply }) => ply);
47
+ }
48
+ /**
49
+ * The coach's judgments the card shows (D-78, D-88): first one whose note was held until the player's last move let it go, however far back its move (Zoe); then the latest, of the player's last move the AI has answered, else of the one before (Zoe and Federico). Only
50
+ * those with a badge of their own or a note.
51
+ */
52
+ export function judgmentsOf(plies, player, { judgments }) {
53
+ const answered = plies.at(-1)?.side === player ? plies.slice(0, -1) : plies;
54
+ const latest = answered.filter((ply) => ply.side === player).slice(-2).reverse().find(judged);
55
+ const released = judgments.filter((judgment) => judgment.released === true).map(({ ply }) => answered[ply - 1])
56
+ .filter((ply) => ply !== undefined && ply !== latest && judged(ply));
57
+ return [...released, ...(latest === undefined ? [] : [latest])];
58
+ }
59
+ /** How long a line of the player's may be: the server's limit (D-54), which a test keeps equal. */
60
+ export const talkLimits = { line: 200 };
61
+ /** How many times the AI has spoken in the game, its comments on its moves and its lines on the page: the page sees it speak when the count grows. */
62
+ export function aiSpoke(plies, ai, talk) {
63
+ return plies.filter((ply) => ply.side === ai && ply.comment !== undefined).length + talk.filter((line) => line.who === "ai").length;
64
+ }
65
+ /** The AI's words in the game going on (D-53), in the order said: its comments on its moves and what it said on the page. */
66
+ export function aiWords(plies, ai, talk) {
67
+ // A comment counts as said just after its move, before what the AI said there; the sort keeps that order.
68
+ const comments = plies.flatMap((ply, index) => ply.side === ai && ply.comment !== undefined ? [{ text: ply.comment, ply: index + 1 }] : []);
69
+ return [...comments, ...talk.filter((line) => line.who === "ai")].sort((one, other) => one.ply - other.ply).map((word) => word.text);
70
+ }
71
+ /** The player's words in the game going on (D-53), in the order said. */
72
+ export function playerWords(talk) {
73
+ return talk.filter((line) => line.who === "player");
74
+ }
75
+ /** How many characters the player has written since the AI's last move, of the 200 they may until its next one (D-54). */
76
+ export function playerSpent(plies, ai, talk) {
77
+ const moved = plies.findLastIndex((ply) => ply.side === ai);
78
+ return talk.filter((line) => line.who === "player" && line.ply > moved).reduce((sum, line) => sum + line.text.length, 0);
79
+ }
80
+ function judged({ review }) {
81
+ return review?.note !== undefined || (review?.badge !== undefined && review.badge !== "book");
82
+ }
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ // The result of a game as a little board: the winner's king standing over the loser's, laid down, or both standing in a draw; the game's card and the
3
+ // list of the analyses show it.
4
+ import { Piece } from "../pieces/pieces.js";
5
+ /** The tile of a game's result, 1-0, 0-1 or 1/2-1/2; a star for a game without one. */
6
+ export function ResultTile({ result }) {
7
+ const winner = result === "1-0" ? "white" : result === "0-1" ? "black" : undefined;
8
+ if (winner !== undefined) {
9
+ return (_jsxs("span", { class: "tile over win", "aria-hidden": "true", children: [_jsx("span", { class: "down", children: _jsx(Piece, { letter: winner === "white" ? "k" : "K" }) }), _jsx("span", { class: "up", children: _jsx(Piece, { letter: winner === "white" ? "K" : "k" }) })] }));
10
+ }
11
+ return result === "1/2-1/2"
12
+ ? (_jsxs("span", { class: "tile over draw", "aria-hidden": "true", children: [_jsx(Piece, { letter: "K" }), _jsx(Piece, { letter: "k" })] }))
13
+ : _jsx("span", { class: "tile open", "aria-hidden": "true", children: "*" });
14
+ }