chesspal 0.0.1 → 0.1.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.
- package/README.md +136 -2
- package/dist/cli/chat-hook.d.ts +2 -0
- package/dist/cli/chat-hook.js +33 -0
- package/dist/cli/cli.d.ts +2 -0
- package/dist/cli/cli.js +28 -0
- package/dist/cli/command-line.d.ts +8 -0
- package/dist/cli/command-line.js +178 -0
- package/dist/commands/ai-move.d.ts +37 -0
- package/dist/commands/ai-move.js +92 -0
- package/dist/commands/ai-say.d.ts +20 -0
- package/dist/commands/ai-say.js +40 -0
- package/dist/commands/analyse-game.d.ts +61 -0
- package/dist/commands/analyse-game.js +238 -0
- package/dist/commands/annotate-game.d.ts +35 -0
- package/dist/commands/annotate-game.js +78 -0
- package/dist/commands/clock.d.ts +15 -0
- package/dist/commands/clock.js +45 -0
- package/dist/commands/context.d.ts +56 -0
- package/dist/commands/context.js +36 -0
- package/dist/commands/draw-offer.d.ts +10 -0
- package/dist/commands/draw-offer.js +43 -0
- package/dist/commands/drawings.d.ts +15 -0
- package/dist/commands/drawings.js +23 -0
- package/dist/commands/end-game.d.ts +23 -0
- package/dist/commands/end-game.js +64 -0
- package/dist/commands/export-game.d.ts +14 -0
- package/dist/commands/export-game.js +26 -0
- package/dist/commands/game-summary.d.ts +95 -0
- package/dist/commands/game-summary.js +239 -0
- package/dist/commands/index.d.ts +3 -0
- package/dist/commands/index.js +19 -0
- package/dist/commands/init.d.ts +15 -0
- package/dist/commands/init.js +73 -0
- package/dist/commands/levels.d.ts +9 -0
- package/dist/commands/levels.js +25 -0
- package/dist/commands/look.d.ts +31 -0
- package/dist/commands/look.js +61 -0
- package/dist/commands/new-game.d.ts +69 -0
- package/dist/commands/new-game.js +215 -0
- package/dist/commands/opening-book.d.ts +13 -0
- package/dist/commands/opening-book.js +84 -0
- package/dist/commands/page-link.d.ts +11 -0
- package/dist/commands/page-link.js +28 -0
- package/dist/commands/past-games.d.ts +11 -0
- package/dist/commands/past-games.js +47 -0
- package/dist/commands/play-move.d.ts +44 -0
- package/dist/commands/play-move.js +102 -0
- package/dist/commands/player-move.d.ts +17 -0
- package/dist/commands/player-move.js +44 -0
- package/dist/commands/player-say.d.ts +5 -0
- package/dist/commands/player-say.js +16 -0
- package/dist/commands/ponder.d.ts +42 -0
- package/dist/commands/ponder.js +167 -0
- package/dist/commands/position.d.ts +14 -0
- package/dist/commands/position.js +128 -0
- package/dist/commands/profiles.d.ts +60 -0
- package/dist/commands/profiles.js +129 -0
- package/dist/commands/registry.d.ts +54 -0
- package/dist/commands/registry.js +61 -0
- package/dist/commands/say.d.ts +16 -0
- package/dist/commands/say.js +84 -0
- package/dist/commands/status.d.ts +29 -0
- package/dist/commands/status.js +103 -0
- package/dist/commands/study-games.d.ts +5 -0
- package/dist/commands/study-games.js +40 -0
- package/dist/commands/study.d.ts +38 -0
- package/dist/commands/study.js +122 -0
- package/dist/commands/view.d.ts +14 -0
- package/dist/commands/view.js +125 -0
- package/dist/core/board-text.d.ts +7 -0
- package/dist/core/board-text.js +18 -0
- package/dist/core/book.json +1 -0
- package/dist/core/clock.d.ts +45 -0
- package/dist/core/clock.js +109 -0
- package/dist/core/facts.d.ts +55 -0
- package/dist/core/facts.js +175 -0
- package/dist/core/game.d.ts +93 -0
- package/dist/core/game.js +348 -0
- package/dist/core/illegal.d.ts +19 -0
- package/dist/core/illegal.js +141 -0
- package/dist/core/index.d.ts +19 -0
- package/dist/core/index.js +11 -0
- package/dist/core/levels.d.ts +20 -0
- package/dist/core/levels.js +33 -0
- package/dist/core/material.d.ts +9 -0
- package/dist/core/material.js +12 -0
- package/dist/core/moods.d.ts +23 -0
- package/dist/core/moods.js +45 -0
- package/dist/core/openings.d.ts +37 -0
- package/dist/core/openings.js +98 -0
- package/dist/core/openings.json +1 -0
- package/dist/core/pgn.d.ts +10 -0
- package/dist/core/pgn.js +213 -0
- package/dist/core/profile.d.ts +117 -0
- package/dist/core/profile.js +232 -0
- package/dist/core/record.d.ts +21 -0
- package/dist/core/record.js +25 -0
- package/dist/core/review.d.ts +74 -0
- package/dist/core/review.js +126 -0
- package/dist/games/ai-model.d.ts +5 -0
- package/dist/games/ai-model.js +15 -0
- package/dist/games/analysis.d.ts +12 -0
- package/dist/games/analysis.js +26 -0
- package/dist/games/archive.d.ts +42 -0
- package/dist/games/archive.js +168 -0
- package/dist/games/chat-start.d.ts +16 -0
- package/dist/games/chat-start.js +26 -0
- package/dist/games/current-game.d.ts +54 -0
- package/dist/games/current-game.js +128 -0
- package/dist/games/files.d.ts +9 -0
- package/dist/games/files.js +52 -0
- package/dist/games/index.d.ts +10 -0
- package/dist/games/index.js +11 -0
- package/dist/games/plans.d.ts +9 -0
- package/dist/games/plans.js +23 -0
- package/dist/games/table-talk.d.ts +12 -0
- package/dist/games/table-talk.js +25 -0
- package/dist/games/talk.d.ts +40 -0
- package/dist/games/talk.js +131 -0
- package/dist/games/thoughts.d.ts +15 -0
- package/dist/games/thoughts.js +60 -0
- package/dist/home/data-folder.d.ts +12 -0
- package/dist/home/data-folder.js +55 -0
- package/dist/home/index.d.ts +2 -0
- package/dist/home/index.js +3 -0
- package/dist/home/open-folder.d.ts +2 -0
- package/dist/home/open-folder.js +14 -0
- package/dist/host-files/host-files.d.ts +10 -0
- package/dist/host-files/host-files.js +167 -0
- package/dist/host-files/index.d.ts +2 -0
- package/dist/host-files/index.js +3 -0
- package/dist/host-files/ponder-agents.d.ts +12 -0
- package/dist/host-files/ponder-agents.js +40 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/page/app.js +576 -0
- package/dist/page/avatars/beanie.webp +0 -0
- package/dist/page/avatars/beard.webp +0 -0
- package/dist/page/avatars/bun.webp +0 -0
- package/dist/page/avatars/cat.webp +0 -0
- package/dist/page/avatars/curls.webp +0 -0
- package/dist/page/avatars/glasses.webp +0 -0
- package/dist/page/avatars/moustache.webp +0 -0
- package/dist/page/avatars/owl.webp +0 -0
- package/dist/page/avatars/short-hair.webp +0 -0
- package/dist/page/avatars/silver-bob.webp +0 -0
- package/dist/page/avatars.js +16 -0
- package/dist/page/badges.js +50 -0
- package/dist/page/board.js +566 -0
- package/dist/page/browse.js +17 -0
- package/dist/page/clock-time.js +12 -0
- package/dist/page/dialog.js +26 -0
- package/dist/page/ending.js +73 -0
- package/dist/page/explain.js +58 -0
- package/dist/page/fold-tab.js +9 -0
- package/dist/page/folds.js +43 -0
- package/dist/page/game-column.js +44 -0
- package/dist/page/header.js +27 -0
- package/dist/page/helps-view.js +51 -0
- package/dist/page/helps.js +90 -0
- package/dist/page/main.js +8 -0
- package/dist/page/model-name.js +20 -0
- package/dist/page/move-list.js +68 -0
- package/dist/page/new-game-dialog.js +42 -0
- package/dist/page/opening-book.js +14 -0
- package/dist/page/pieces/CREDITS.md +36 -0
- package/dist/page/pieces/cburnett-small.svg +20 -0
- package/dist/page/pieces/cburnett.svg +20 -0
- package/dist/page/pieces/nitida-small.svg +19 -0
- package/dist/page/pieces/nitida.svg +20 -0
- package/dist/page/pieces/torretta-small.svg +19 -0
- package/dist/page/pieces/torretta.svg +19 -0
- package/dist/page/pieces.js +28 -0
- package/dist/page/player-card.js +60 -0
- package/dist/page/plies.js +62 -0
- package/dist/page/profile-dialogs.js +123 -0
- package/dist/page/profile.js +95 -0
- package/dist/page/settings-panel.js +32 -0
- package/dist/page/settings.js +76 -0
- package/dist/page/sounds/capture.ogg +0 -0
- package/dist/page/sounds/check.ogg +0 -0
- package/dist/page/sounds/draw.ogg +0 -0
- package/dist/page/sounds/flag.ogg +0 -0
- package/dist/page/sounds/mate.ogg +0 -0
- package/dist/page/sounds/move.ogg +0 -0
- package/dist/page/sounds/offer.ogg +0 -0
- package/dist/page/sounds/resign.ogg +0 -0
- package/dist/page/sounds.js +105 -0
- package/dist/page/studied.js +14 -0
- package/dist/page/study-dialog.js +58 -0
- package/dist/page/style.css +4398 -0
- package/dist/page/talk.js +172 -0
- package/dist/page/text.js +593 -0
- package/dist/page/torretta.js +38 -0
- package/dist/page/voice.js +38 -0
- package/dist/profiles/avatar.d.ts +23 -0
- package/dist/profiles/avatar.js +84 -0
- package/dist/profiles/front-matter.d.ts +9 -0
- package/dist/profiles/front-matter.js +33 -0
- package/dist/profiles/index.d.ts +3 -0
- package/dist/profiles/index.js +5 -0
- package/dist/profiles/profiles.d.ts +58 -0
- package/dist/profiles/profiles.js +237 -0
- package/dist/profiles/settings.d.ts +12 -0
- package/dist/profiles/settings.js +46 -0
- package/dist/server/analyses.d.ts +17 -0
- package/dist/server/analyses.js +46 -0
- package/dist/server/bell.d.ts +60 -0
- package/dist/server/bell.js +209 -0
- package/dist/server/caller.d.ts +10 -0
- package/dist/server/caller.js +99 -0
- package/dist/server/http.d.ts +16 -0
- package/dist/server/http.js +57 -0
- package/dist/server/mcp.d.ts +14 -0
- package/dist/server/mcp.js +179 -0
- package/dist/server/page.d.ts +46 -0
- package/dist/server/page.js +657 -0
- package/dist/server/profile-routes.d.ts +19 -0
- package/dist/server/profile-routes.js +186 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +3 -0
- package/instructions/analyst.md +8 -0
- package/instructions/opponent.md +15 -0
- package/instructions/ponder.md +9 -0
- package/package.json +66 -5
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
/** The words for the first of the browser's languages the page speaks, else English. */
|
|
2
|
+
export function textFor(languages) {
|
|
3
|
+
const known = languages.map((language) => language.slice(0, 2).toLowerCase()).find((language) => language === "it" || language === "en");
|
|
4
|
+
return known === "it" ? italian : english;
|
|
5
|
+
}
|
|
6
|
+
const englishNames = { K: "king", Q: "queen", R: "rook", B: "bishop", N: "knight", P: "pawn" };
|
|
7
|
+
const italianNames = { K: "re", Q: "donna", R: "torre", B: "alfiere", N: "cavallo", P: "pedone" };
|
|
8
|
+
const english = {
|
|
9
|
+
language: "en",
|
|
10
|
+
flip: "Flip",
|
|
11
|
+
theme: "Light or dark theme",
|
|
12
|
+
sounds: "Sounds",
|
|
13
|
+
voice: "Read the AI's words aloud",
|
|
14
|
+
newGame: "New game",
|
|
15
|
+
offerDraw: "Offer a draw",
|
|
16
|
+
offerDrawWhen: "Offer a draw: on your turn, once each side has moved",
|
|
17
|
+
drawOffered: "You offered a draw",
|
|
18
|
+
acceptDraw: "Accept",
|
|
19
|
+
declineDraw: "Decline",
|
|
20
|
+
declineDrawTitle: "Decline: moving declines it too",
|
|
21
|
+
resign: "Resign",
|
|
22
|
+
resignGame: "Resign this game?",
|
|
23
|
+
settings: "Settings",
|
|
24
|
+
close: "Close",
|
|
25
|
+
look: "Look",
|
|
26
|
+
themeChoice: "Theme",
|
|
27
|
+
themes: { system: "As the system", light: "Light", dark: "Dark" },
|
|
28
|
+
boardSkin: "Board",
|
|
29
|
+
pieceSet: "Pieces",
|
|
30
|
+
pieceColours: "Pieces' colours",
|
|
31
|
+
marksColour: "Arrows and marked squares",
|
|
32
|
+
play: "Play",
|
|
33
|
+
dots: "Dots on the legal moves",
|
|
34
|
+
explain: "Explain the moves refused",
|
|
35
|
+
bookBadges: "Mark the book moves",
|
|
36
|
+
helps: "The AI teaches as you play",
|
|
37
|
+
languageChoice: "Language",
|
|
38
|
+
languages: { auto: "As the browser", it: "Italiano", en: "English" },
|
|
39
|
+
names: {
|
|
40
|
+
nitida: "Nitida",
|
|
41
|
+
torretta: "Torretta",
|
|
42
|
+
cburnett: "cburnett",
|
|
43
|
+
azzurro: "Blue",
|
|
44
|
+
verde: "Green",
|
|
45
|
+
noce: "Walnut",
|
|
46
|
+
ardesia: "Slate",
|
|
47
|
+
grigio: "Grey",
|
|
48
|
+
lavanda: "Lavender",
|
|
49
|
+
ciliegio: "Cherry wood",
|
|
50
|
+
menta: "Mint",
|
|
51
|
+
carta: "Paper",
|
|
52
|
+
classico: "Classic",
|
|
53
|
+
avorio: "Ivory and ebony",
|
|
54
|
+
notte: "Midnight",
|
|
55
|
+
bordeaux: "Burgundy",
|
|
56
|
+
arancione: "Orange",
|
|
57
|
+
rosso: "Red",
|
|
58
|
+
blu: "Blue",
|
|
59
|
+
},
|
|
60
|
+
game: "The game",
|
|
61
|
+
moves: "Moves",
|
|
62
|
+
steps: { first: "Start", back: "Previous move", forward: "Next move", last: "Back to the game" },
|
|
63
|
+
noGame: "No game yet: press + to start one, or ask for one in the chat.",
|
|
64
|
+
saveMoves: "Save the moves (PGN)",
|
|
65
|
+
noGameNow: "No game in progress",
|
|
66
|
+
analysing: "Analysis in progress",
|
|
67
|
+
badges: {
|
|
68
|
+
brilliant: "Brilliant",
|
|
69
|
+
great: "Great move",
|
|
70
|
+
best: "Best move",
|
|
71
|
+
excellent: "Excellent",
|
|
72
|
+
good: "Good",
|
|
73
|
+
book: "Book",
|
|
74
|
+
inaccuracy: "Inaccuracy",
|
|
75
|
+
mistake: "Mistake",
|
|
76
|
+
miss: "Miss",
|
|
77
|
+
blunder: "Blunder",
|
|
78
|
+
},
|
|
79
|
+
reviewBy: (name) => `${name}'s review`,
|
|
80
|
+
drawn: { green: "better", red: "threat", yellow: "another way", blue: "plan" },
|
|
81
|
+
reviewing: (name) => `${name} is going over the game…`,
|
|
82
|
+
you: "You",
|
|
83
|
+
ai: "AI",
|
|
84
|
+
sides: { white: "White", black: "Black" },
|
|
85
|
+
yourTurn: "your move",
|
|
86
|
+
clock: (time, running) => `Clock: ${time}${running ? ", running" : ""}`,
|
|
87
|
+
send: "Send",
|
|
88
|
+
sent: "Sent",
|
|
89
|
+
withMove: "Or move: your words go with it",
|
|
90
|
+
talk: "The talk",
|
|
91
|
+
move: "Move",
|
|
92
|
+
draw: "draw",
|
|
93
|
+
checkmate: "checkmate",
|
|
94
|
+
ended: {
|
|
95
|
+
checkmate: "checkmate",
|
|
96
|
+
stalemate: "stalemate",
|
|
97
|
+
"insufficient material": "insufficient material",
|
|
98
|
+
"threefold repetition": "threefold repetition",
|
|
99
|
+
"fifty moves": "fifty-move rule",
|
|
100
|
+
resignation: "resignation",
|
|
101
|
+
agreement: "agreed",
|
|
102
|
+
time: "on time",
|
|
103
|
+
},
|
|
104
|
+
opening: "Opening",
|
|
105
|
+
outOfBook: "Out of book since move",
|
|
106
|
+
inBook: "In book",
|
|
107
|
+
promoteTo: "Promote to",
|
|
108
|
+
canGo: "a legal move",
|
|
109
|
+
boardLabel: (turn, lastMove) => `Chessboard, ${english.toMove(turn)}${lastMove === undefined ? "" : `, last move ${lastMove}`}`,
|
|
110
|
+
clearChat: (name) => `Before a new game, clear your chat with ${name}: in the window where you opened ${name}, not here, write /clear, then a message such as "new game". A clean chat plays faster.`,
|
|
111
|
+
offline: (name) => `${name} is not connected. Write it a message in the window where you opened ${name}, not in this page's chat: the page connects again by itself.`,
|
|
112
|
+
startClocks: "Start",
|
|
113
|
+
asleep: (name) => `${name} is not listening: write a message, such as "hi", in the window where you opened ${name}, not here. Its clock waits until it answers.`,
|
|
114
|
+
commandHere: (name) => `/clear and the other commands go in the window where you opened ${name}, not here.`,
|
|
115
|
+
refused: {
|
|
116
|
+
"no-game": () => "There is no game going on: press + to start one, or ask for one in the chat.",
|
|
117
|
+
"ai-to-move": () => "Wait for the AI's move.",
|
|
118
|
+
illegal: () => "That move is not legal here.",
|
|
119
|
+
"clear-chat": (most, name) => english.clearChat(name),
|
|
120
|
+
"words-empty": () => "Write something first.",
|
|
121
|
+
"words-spent": () => "You have used up your words for this move: write again after the AI's move.",
|
|
122
|
+
"words-long": (most) => `Write at most ${most} characters.`,
|
|
123
|
+
"words-longer-than-left": (most) => `You have ${most} characters left until the AI's move.`,
|
|
124
|
+
"draw-offered": () => "A draw offer stands already.",
|
|
125
|
+
"draw-none": () => "There is no draw offer to answer.",
|
|
126
|
+
"draw-early": () => "You can offer a draw once each side has made a move.",
|
|
127
|
+
"profile-game": () => english.profile.whilePlaying,
|
|
128
|
+
"game-going": () => "A game is going on: finish it before you bring another to analyse.",
|
|
129
|
+
"pgn-unreadable": () => "Chesspal cannot read this PGN: check you copied the whole game, its tags and its moves.",
|
|
130
|
+
},
|
|
131
|
+
piece: (letter, side) => `${side} ${englishNames[letter]}`,
|
|
132
|
+
taken: (pieces, ahead) => `Pieces taken: ${pieces.length === 0 ? "none" : pieces.join(", ")}${ahead > 0 ? `; ahead by ${ahead}` : ""}`,
|
|
133
|
+
writeTo: (name) => `Write to ${name}…`,
|
|
134
|
+
readBy: (name) => `Read by ${name}`,
|
|
135
|
+
wrote: (name) => `${name} wrote`,
|
|
136
|
+
offers: "offers a draw",
|
|
137
|
+
declines: "declines the draw",
|
|
138
|
+
started: (when) => `started ${when}`,
|
|
139
|
+
lasted: (count) => `${count} ${count === 1 ? "move" : "moves"}`,
|
|
140
|
+
won: (side) => `${side === "white" ? "White" : "Black"} wins`,
|
|
141
|
+
toMove: (side) => `${side === "white" ? "White" : "Black"} to move`,
|
|
142
|
+
verdict: (how, winner) => {
|
|
143
|
+
if (winner !== undefined) {
|
|
144
|
+
return how === undefined ? english.won(winner) : `${capital(english.ended[how])} · ${english.won(winner)}`;
|
|
145
|
+
}
|
|
146
|
+
return how === "agreement" ? "Draw agreed" : how === undefined ? "Draw" : `Draw · ${english.ended[how]}`;
|
|
147
|
+
},
|
|
148
|
+
illegal: (move) => move.reason === "shape" ? englishMoves[move.piece] : englishIllegal[move.reason]({ ...move, by: englishCulprit(move.by) }),
|
|
149
|
+
profile: {
|
|
150
|
+
welcome: "Welcome to Chesspal",
|
|
151
|
+
lead: "One minute, and we play. You can change it all whenever you like.",
|
|
152
|
+
gameMoves: "The game you started stays in your profile.",
|
|
153
|
+
name: "What's your name?",
|
|
154
|
+
namePlaceholder: "Your name",
|
|
155
|
+
gamesIn: "Your games are in",
|
|
156
|
+
openFolder: "Open the folder",
|
|
157
|
+
opened: "Opened",
|
|
158
|
+
noFolder: "It cannot be opened from here: look for it at the path above.",
|
|
159
|
+
documents: "Documents",
|
|
160
|
+
avatar: "Choose a picture",
|
|
161
|
+
ownImage: "Use a picture of yours",
|
|
162
|
+
level: "How do you play?",
|
|
163
|
+
levels: {
|
|
164
|
+
learning: ["I've just learned", "I know the rules, little more"],
|
|
165
|
+
casual: ["I play now and then", "With friends or on my phone"],
|
|
166
|
+
regular: ["I play often", "Online or at a club"],
|
|
167
|
+
tournament: ["I play tournaments", "I have a FIDE rating"],
|
|
168
|
+
},
|
|
169
|
+
rating: "Do you have a rating?",
|
|
170
|
+
optional: "optional",
|
|
171
|
+
ratingPlaceholder: "e.g. 1450",
|
|
172
|
+
ratingLabel: "Rating",
|
|
173
|
+
siteLabel: "Where",
|
|
174
|
+
sites: { "lichess": "on Lichess", "chess.com": "on Chess.com", "fide": "FIDE" },
|
|
175
|
+
start: "Start playing",
|
|
176
|
+
create: "Done",
|
|
177
|
+
newProfile: "Add a player",
|
|
178
|
+
profiles: "Who's playing?",
|
|
179
|
+
eachOwn: "Each player has their own games and settings.",
|
|
180
|
+
changePlayer: "Change player",
|
|
181
|
+
back: "Back",
|
|
182
|
+
changePicture: "Change picture",
|
|
183
|
+
yourPicture: "Your picture: change it",
|
|
184
|
+
avatars: { "short-hair": "Short hair", bun: "Bun", glasses: "Glasses", beanie: "Beanie", beard: "Beard", curls: "Curls", moustache: "Moustache", "silver-bob": "Silver bob", cat: "Cat", owl: "Owl" },
|
|
185
|
+
whilePlaying: "Finish the game, or resign, before changing player.",
|
|
186
|
+
badImage: "That picture won't open: try another photo (the ones from a phone usually work).",
|
|
187
|
+
},
|
|
188
|
+
start: {
|
|
189
|
+
colour: "You play",
|
|
190
|
+
colours: { white: "White", black: "Black", random: "Either" },
|
|
191
|
+
level: "The AI's level",
|
|
192
|
+
levels: {
|
|
193
|
+
beginner: ["Beginner", "Board and legal moves", "The AI sees the board and its legal moves; Chesspal tells it no hanging pieces or threats."],
|
|
194
|
+
club: ["Club", "Plus hanging pieces and threats", "The AI sees the board and tactics; no strategy, no theory."],
|
|
195
|
+
strong: ["Strong", "Plus structure: pawns, files, king", "The AI sees the board, tactics and strategy; no theory."],
|
|
196
|
+
master: ["Master", "As Strong, plus the opening book", "The AI sees the board, tactics, strategy and theory."],
|
|
197
|
+
},
|
|
198
|
+
clock: "Clock",
|
|
199
|
+
clockNote: "minutes each + seconds a move",
|
|
200
|
+
noClock: "None",
|
|
201
|
+
abandons: "The game going on goes to the archive unfinished.",
|
|
202
|
+
start: "Start",
|
|
203
|
+
},
|
|
204
|
+
study: {
|
|
205
|
+
title: "Analyses",
|
|
206
|
+
paste: "Paste the game's PGN",
|
|
207
|
+
file: "or choose a .pgn file",
|
|
208
|
+
note: "The game is kept to study; the AI goes over it with you in the chat.",
|
|
209
|
+
start: "Analyse",
|
|
210
|
+
yours: "Your analyses",
|
|
211
|
+
bring: "Bring a game",
|
|
212
|
+
reviewed: "reviewed",
|
|
213
|
+
unreviewed: "to review",
|
|
214
|
+
moves: (count) => `${count} ${count === 1 ? "move" : "moves"}`,
|
|
215
|
+
download: "Save PGN",
|
|
216
|
+
analyseIt: "Analyse the game",
|
|
217
|
+
analyseLast: "Analyse the last game",
|
|
218
|
+
},
|
|
219
|
+
helpsCard: {
|
|
220
|
+
title: "Helps",
|
|
221
|
+
tactics: "Tactics",
|
|
222
|
+
strategy: "Strategy",
|
|
223
|
+
map: "Map",
|
|
224
|
+
mapHint: "Hold it, or the M key, to see who controls each square; on a phone, a touch turns it on and off",
|
|
225
|
+
hold: "hold",
|
|
226
|
+
attackers: "attackers",
|
|
227
|
+
defenders: "defenders",
|
|
228
|
+
undefended: "no defender",
|
|
229
|
+
cheaper: "a cheaper attacker",
|
|
230
|
+
outnumbered: "more attackers than defenders",
|
|
231
|
+
pinnedTo: (letter) => `pinned to the ${englishNames[letter]}`,
|
|
232
|
+
pinnedBy: (letter) => `by the ${englishNames[letter]}`,
|
|
233
|
+
nothingAtRisk: "No piece at risk, no pins.",
|
|
234
|
+
checks: (side, toMove) => `${side === "white" ? "White" : "Black"}'s checks${toMove ? "" : `, if it were ${side === "white" ? "White" : "Black"}'s move`}`,
|
|
235
|
+
loose: "Pieces neither attacked nor defended",
|
|
236
|
+
white: "White",
|
|
237
|
+
black: "Black",
|
|
238
|
+
rows: {
|
|
239
|
+
isolated: ["Isolated pawns", "A pawn with no pawn of its colour on the files beside it: no pawn can defend it."],
|
|
240
|
+
doubled: ["Doubled pawns", "Two pawns of one colour on the same file."],
|
|
241
|
+
backward: ["Backward pawns", "A pawn left behind the pawns beside it, with the square in front of it attacked by an enemy pawn."],
|
|
242
|
+
passed: ["Passed pawns", "No enemy pawn in front of it, on its file or the files beside it."],
|
|
243
|
+
islands: ["Pawn islands", "Groups of pawns on neighbouring files, apart from each other."],
|
|
244
|
+
halfOpen: ["Half-open files", "Files with enemy pawns and none of one's own."],
|
|
245
|
+
heavyOnFiles: ["Rooks and queens on open files", "Rooks and queens on open or half-open files."],
|
|
246
|
+
onSeventh: ["Rooks and queens on the seventh", "Rooks and queens on the enemy's second rank: the seventh for White, the second for Black."],
|
|
247
|
+
outposts: ["Outposts", "Squares on one's ranks 4 to 6, defended by a pawn, that no enemy pawn can ever attack."],
|
|
248
|
+
bishopPair: ["Bishop pair", "Both bishops still on the board."],
|
|
249
|
+
space: ["Space (squares in the enemy's half)", "How many squares of the enemy's half one's pieces attack."],
|
|
250
|
+
undeveloped: ["Minor pieces not developed", "Knights and bishops still on their first squares."],
|
|
251
|
+
castled: ["Castling", "How it castled; not yet while it still can, no more once the king or the rooks have moved."],
|
|
252
|
+
kingAttacks: ["Enemy attacks around the king", "How many enemy attacks fall on the squares next to the king."],
|
|
253
|
+
},
|
|
254
|
+
yes: "yes",
|
|
255
|
+
notYet: "not yet",
|
|
256
|
+
noMore: "no more",
|
|
257
|
+
phases: { opening: "opening", middlegame: "middlegame", endgame: "endgame" },
|
|
258
|
+
openFiles: (files) => `Open files: ${files}`,
|
|
259
|
+
controlled: (white, black, both) => `Squares only White's ${white}, only Black's ${black}, both ${both}`,
|
|
260
|
+
oppositeBishops: "Bishops of opposite colours",
|
|
261
|
+
repetitions: (times) => `This position has stood ${times} times`,
|
|
262
|
+
fiftyMoves: (halfMoves) => `${halfMoves} half-moves left before the fifty-move draw`,
|
|
263
|
+
insufficient: "Too little material to mate",
|
|
264
|
+
pawnSquare: (pawn, caught) => `The enemy king is ${caught ? "inside" : "outside"} the square of the pawn on ${pawn}`,
|
|
265
|
+
opposition: (side) => `${side === "white" ? "White" : "Black"} has the opposition`,
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
const italian = {
|
|
269
|
+
language: "it",
|
|
270
|
+
flip: "Gira",
|
|
271
|
+
theme: "Tema chiaro o scuro",
|
|
272
|
+
sounds: "Suoni",
|
|
273
|
+
voice: "Leggi ad alta voce le parole dell'AI",
|
|
274
|
+
newGame: "Nuova partita",
|
|
275
|
+
offerDraw: "Proponi patta",
|
|
276
|
+
offerDrawWhen: "Proponi patta: nel tuo turno, dopo una mossa a testa",
|
|
277
|
+
drawOffered: "Hai proposto patta",
|
|
278
|
+
acceptDraw: "Accetta",
|
|
279
|
+
declineDraw: "Rifiuta",
|
|
280
|
+
declineDrawTitle: "Rifiuta: anche muovere rifiuta",
|
|
281
|
+
resign: "Abbandona",
|
|
282
|
+
resignGame: "Abbandonare la partita?",
|
|
283
|
+
settings: "Impostazioni",
|
|
284
|
+
close: "Chiudi",
|
|
285
|
+
look: "Aspetto",
|
|
286
|
+
themeChoice: "Tema",
|
|
287
|
+
themes: { system: "Come il sistema", light: "Chiaro", dark: "Scuro" },
|
|
288
|
+
boardSkin: "Scacchiera",
|
|
289
|
+
pieceSet: "Pezzi",
|
|
290
|
+
pieceColours: "Colori dei pezzi",
|
|
291
|
+
marksColour: "Frecce e case segnate",
|
|
292
|
+
play: "Gioco",
|
|
293
|
+
dots: "Pallini sulle mosse legali",
|
|
294
|
+
explain: "Spiega le mosse vietate",
|
|
295
|
+
bookBadges: "Segna le mosse da libro",
|
|
296
|
+
helps: "L'AI ti insegna mentre giochi",
|
|
297
|
+
languageChoice: "Lingua",
|
|
298
|
+
languages: { auto: "Come il browser", it: "Italiano", en: "English" },
|
|
299
|
+
names: {
|
|
300
|
+
nitida: "Nitida",
|
|
301
|
+
torretta: "Torretta",
|
|
302
|
+
cburnett: "cburnett",
|
|
303
|
+
azzurro: "Azzurro",
|
|
304
|
+
verde: "Verde",
|
|
305
|
+
noce: "Noce",
|
|
306
|
+
ardesia: "Ardesia",
|
|
307
|
+
grigio: "Grigio",
|
|
308
|
+
lavanda: "Lavanda",
|
|
309
|
+
ciliegio: "Ciliegio",
|
|
310
|
+
menta: "Menta",
|
|
311
|
+
carta: "Carta",
|
|
312
|
+
classico: "Classico",
|
|
313
|
+
avorio: "Avorio ed ebano",
|
|
314
|
+
notte: "Blu notte",
|
|
315
|
+
bordeaux: "Bordeaux",
|
|
316
|
+
arancione: "Arancione",
|
|
317
|
+
rosso: "Rosso",
|
|
318
|
+
blu: "Blu",
|
|
319
|
+
},
|
|
320
|
+
game: "La partita",
|
|
321
|
+
moves: "Mosse",
|
|
322
|
+
steps: { first: "Inizio", back: "Mossa precedente", forward: "Mossa successiva", last: "Torna alla partita" },
|
|
323
|
+
noGame: "Nessuna partita: premi + per iniziarne una, o chiedila nella chat.",
|
|
324
|
+
saveMoves: "Scarica le mosse (PGN)",
|
|
325
|
+
noGameNow: "Nessuna partita in corso",
|
|
326
|
+
analysing: "Analisi in corso",
|
|
327
|
+
badges: {
|
|
328
|
+
brilliant: "Geniale",
|
|
329
|
+
great: "Ottima mossa",
|
|
330
|
+
best: "Mossa migliore",
|
|
331
|
+
excellent: "Eccellente",
|
|
332
|
+
good: "Buona",
|
|
333
|
+
book: "Teoria",
|
|
334
|
+
inaccuracy: "Imprecisione",
|
|
335
|
+
mistake: "Errore",
|
|
336
|
+
miss: "Occasione persa",
|
|
337
|
+
blunder: "Errore grave",
|
|
338
|
+
},
|
|
339
|
+
reviewBy: (name) => `Il giudizio di ${name}`,
|
|
340
|
+
drawn: { green: "meglio", red: "minaccia", yellow: "altra via", blue: "piano" },
|
|
341
|
+
reviewing: (name) => `${name} sta analizzando la partita…`,
|
|
342
|
+
you: "Tu",
|
|
343
|
+
ai: "AI",
|
|
344
|
+
sides: { white: "Bianco", black: "Nero" },
|
|
345
|
+
yourTurn: "tocca a te",
|
|
346
|
+
clock: (time, running) => `Orologio: ${time}${running ? ", in corsa" : ""}`,
|
|
347
|
+
send: "Manda",
|
|
348
|
+
sent: "Mandato",
|
|
349
|
+
withMove: "Oppure muovi: parte con la mossa",
|
|
350
|
+
talk: "Conversazione",
|
|
351
|
+
move: "Mossa",
|
|
352
|
+
draw: "patta",
|
|
353
|
+
checkmate: "scacco matto",
|
|
354
|
+
ended: {
|
|
355
|
+
checkmate: "scacco matto",
|
|
356
|
+
stalemate: "stallo",
|
|
357
|
+
"insufficient material": "materiale insufficiente",
|
|
358
|
+
"threefold repetition": "triplice ripetizione",
|
|
359
|
+
"fifty moves": "regola delle 50 mosse",
|
|
360
|
+
resignation: "abbandono",
|
|
361
|
+
agreement: "d'accordo",
|
|
362
|
+
time: "per tempo",
|
|
363
|
+
},
|
|
364
|
+
opening: "Apertura",
|
|
365
|
+
outOfBook: "Fuori teoria dalla mossa",
|
|
366
|
+
inBook: "In teoria",
|
|
367
|
+
promoteTo: "Promuovi a",
|
|
368
|
+
canGo: "mossa possibile",
|
|
369
|
+
boardLabel: (turn, lastMove) => `Scacchiera, ${italian.toMove(turn)}${lastMove === undefined ? "" : `, ultima mossa ${lastMove}`}`,
|
|
370
|
+
clearChat: (name) => `Prima di una nuova partita azzera la conversazione con ${name}: nella finestra dove hai aperto ${name}, non qui, scrivi /clear e poi un messaggio, per esempio "nuova partita". Con la chat pulita l'AI gioca più veloce.`,
|
|
371
|
+
offline: (name) => `${name} è scollegato. Scrivigli un messaggio nella finestra dove hai aperto ${name}, non nella chat di questa pagina: la pagina si ricollega da sola.`,
|
|
372
|
+
startClocks: "Inizia",
|
|
373
|
+
asleep: (name) => `${name} non ti sta ascoltando: scrivi un messaggio, per esempio "ciao", nella finestra dove hai aperto ${name}, non qui. Il suo orologio aspetta che risponda.`,
|
|
374
|
+
commandHere: (name) => `/clear e gli altri comandi vanno scritti nella finestra dove hai aperto ${name}, non qui.`,
|
|
375
|
+
refused: {
|
|
376
|
+
"no-game": () => "Nessuna partita in corso: premi + per iniziarne una, o chiedila nella chat.",
|
|
377
|
+
"ai-to-move": () => "Aspetta la mossa dell'AI.",
|
|
378
|
+
illegal: () => "Questa mossa qui non è legale.",
|
|
379
|
+
"clear-chat": (most, name) => italian.clearChat(name),
|
|
380
|
+
"words-empty": () => "Scrivi prima qualcosa.",
|
|
381
|
+
"words-spent": () => "Hai finito le parole per questa mossa: scrivi di nuovo dopo quella dell'AI.",
|
|
382
|
+
"words-long": (most) => `Scrivi al massimo ${most} caratteri.`,
|
|
383
|
+
"words-longer-than-left": (most) => `Ti restano ${most} caratteri fino alla mossa dell'AI.`,
|
|
384
|
+
"draw-offered": () => "C'è già una proposta di patta.",
|
|
385
|
+
"draw-none": () => "Non c'è una proposta di patta a cui rispondere.",
|
|
386
|
+
"draw-early": () => "Puoi proporre patta dopo una mossa a testa.",
|
|
387
|
+
"profile-game": () => italian.profile.whilePlaying,
|
|
388
|
+
"game-going": () => "C'è una partita in corso: finiscila prima di portarne un'altra da analizzare.",
|
|
389
|
+
"pgn-unreadable": () => "Chesspal non riesce a leggere questo PGN: controlla di aver copiato la partita intera, intestazioni e mosse.",
|
|
390
|
+
},
|
|
391
|
+
// Queen and rook are feminine in Italian.
|
|
392
|
+
piece: (letter, side) => `${italianNames[letter]} ${side === "white" ? (letter === "Q" || letter === "R" ? "bianca" : "bianco") : (letter === "Q" || letter === "R" ? "nera" : "nero")}`,
|
|
393
|
+
taken: (pieces, ahead) => `Pezzi presi: ${pieces.length === 0 ? "nessuno" : pieces.join(", ")}${ahead > 0 ? `; avanti di ${ahead}` : ""}`,
|
|
394
|
+
writeTo: (name) => `Scrivi a ${name}…`,
|
|
395
|
+
readBy: (name) => `Letto da ${name}`,
|
|
396
|
+
wrote: (name) => `${name} ha scritto`,
|
|
397
|
+
offers: "propone patta",
|
|
398
|
+
declines: "rifiuta la patta",
|
|
399
|
+
started: (when) => `iniziata ${when}`,
|
|
400
|
+
lasted: (count) => `${count} ${count === 1 ? "mossa" : "mosse"}`,
|
|
401
|
+
won: (side) => `vince il ${side === "white" ? "Bianco" : "Nero"}`,
|
|
402
|
+
toMove: (side) => `muove il ${side === "white" ? "Bianco" : "Nero"}`,
|
|
403
|
+
verdict: (how, winner) => {
|
|
404
|
+
if (winner !== undefined) {
|
|
405
|
+
return how === undefined ? capital(italian.won(winner)) : `${capital(italian.ended[how])} · ${italian.won(winner)}`;
|
|
406
|
+
}
|
|
407
|
+
return how === "agreement" ? "Patta d'accordo" : how === undefined ? "Patta" : `Patta · ${italian.ended[how]}`;
|
|
408
|
+
},
|
|
409
|
+
illegal: (move) => move.reason === "shape" ? italianMoves[move.piece] : italianIllegal[move.reason]({ ...move, by: italianCulprit(move.by) }),
|
|
410
|
+
profile: {
|
|
411
|
+
welcome: "Ti diamo il benvenuto in Chesspal",
|
|
412
|
+
lead: "Un minuto, e giochiamo. Puoi cambiare tutto quando vuoi.",
|
|
413
|
+
gameMoves: "La partita che hai iniziato resta nel tuo profilo.",
|
|
414
|
+
name: "Come ti chiami?",
|
|
415
|
+
namePlaceholder: "Il tuo nome",
|
|
416
|
+
gamesIn: "Le tue partite stanno in",
|
|
417
|
+
openFolder: "Apri la cartella",
|
|
418
|
+
opened: "Aperta",
|
|
419
|
+
noFolder: "Da qui non si apre: cercala nel percorso scritto qui sopra.",
|
|
420
|
+
documents: "Documenti",
|
|
421
|
+
avatar: "Scegli un'immagine",
|
|
422
|
+
ownImage: "Usa una tua immagine",
|
|
423
|
+
level: "Come giochi?",
|
|
424
|
+
levels: {
|
|
425
|
+
learning: ["Ho appena imparato", "Conosco le regole, poco di più"],
|
|
426
|
+
casual: ["Gioco ogni tanto", "Con amici o sul telefono"],
|
|
427
|
+
regular: ["Gioco spesso", "Online o al circolo"],
|
|
428
|
+
tournament: ["Gioco a torneo", "Ho un punteggio FIDE"],
|
|
429
|
+
},
|
|
430
|
+
rating: "Hai un punteggio?",
|
|
431
|
+
optional: "facoltativo",
|
|
432
|
+
ratingPlaceholder: "es. 1450",
|
|
433
|
+
ratingLabel: "Punteggio",
|
|
434
|
+
siteLabel: "Dove",
|
|
435
|
+
sites: { "lichess": "su Lichess", "chess.com": "su Chess.com", "fide": "FIDE" },
|
|
436
|
+
start: "Inizia a giocare",
|
|
437
|
+
create: "Fatto",
|
|
438
|
+
newProfile: "Aggiungi un giocatore",
|
|
439
|
+
profiles: "Chi gioca?",
|
|
440
|
+
eachOwn: "Ognuno ha le sue partite e le sue impostazioni.",
|
|
441
|
+
changePlayer: "Cambia giocatore",
|
|
442
|
+
back: "Indietro",
|
|
443
|
+
changePicture: "Cambia immagine",
|
|
444
|
+
yourPicture: "La tua immagine: cambiala",
|
|
445
|
+
avatars: { "short-hair": "Capelli corti", bun: "Chignon", glasses: "Occhiali", beanie: "Berretto", beard: "Barba", curls: "Ricci", moustache: "Baffi", "silver-bob": "Caschetto grigio", cat: "Gatto", owl: "Gufo" },
|
|
446
|
+
whilePlaying: "Finisci la partita, o abbandona, prima di cambiare giocatore.",
|
|
447
|
+
badImage: "Questa immagine non si apre: prova con un'altra foto (quelle del telefono di solito vanno bene).",
|
|
448
|
+
},
|
|
449
|
+
start: {
|
|
450
|
+
colour: "Giochi col",
|
|
451
|
+
colours: { white: "Bianco", black: "Nero", random: "A caso" },
|
|
452
|
+
level: "Livello dell'AI",
|
|
453
|
+
levels: {
|
|
454
|
+
beginner: ["Principiante", "Scacchiera e mosse legali", "L'AI vede la scacchiera e le sue mosse legali; Chesspal non le dice pezzi in presa né minacce."],
|
|
455
|
+
club: ["Circolo", "Più pezzi in presa e minacce", "L'AI vede scacchiera e tattica; niente strategia, niente teoria."],
|
|
456
|
+
strong: ["Forte", "Più la struttura: pedoni, colonne, re", "L'AI vede scacchiera, tattica e strategia; niente teoria."],
|
|
457
|
+
master: ["Maestro", "Come Forte, più il libro delle aperture", "L'AI vede scacchiera, tattica, strategia e teoria."],
|
|
458
|
+
},
|
|
459
|
+
clock: "Orologio",
|
|
460
|
+
clockNote: "minuti a testa + secondi a mossa",
|
|
461
|
+
noClock: "Senza",
|
|
462
|
+
abandons: "La partita in corso va nell'archivio, non finita.",
|
|
463
|
+
start: "Inizia",
|
|
464
|
+
},
|
|
465
|
+
study: {
|
|
466
|
+
title: "Analisi",
|
|
467
|
+
paste: "Incolla il PGN della partita",
|
|
468
|
+
file: "oppure scegli un file .pgn",
|
|
469
|
+
note: "La partita resta tra quelle da studiare; l'AI la commenta con te nella chat.",
|
|
470
|
+
start: "Analizza",
|
|
471
|
+
yours: "Le tue analisi",
|
|
472
|
+
bring: "Porta una partita",
|
|
473
|
+
reviewed: "commentata",
|
|
474
|
+
unreviewed: "da commentare",
|
|
475
|
+
moves: (count) => `${count} ${count === 1 ? "mossa" : "mosse"}`,
|
|
476
|
+
download: "Scarica PGN",
|
|
477
|
+
analyseIt: "Analizza la partita",
|
|
478
|
+
analyseLast: "Analizza l'ultima partita",
|
|
479
|
+
},
|
|
480
|
+
helpsCard: {
|
|
481
|
+
title: "Aiuti",
|
|
482
|
+
tactics: "Tattica",
|
|
483
|
+
strategy: "Strategia",
|
|
484
|
+
map: "Mappa",
|
|
485
|
+
mapHint: "Tienilo premuto, o tieni premuto il tasto M, per vedere chi controlla ogni casa; sul telefono un tocco la accende e la spegne",
|
|
486
|
+
hold: "tieni premuto",
|
|
487
|
+
attackers: "attaccanti",
|
|
488
|
+
defenders: "difensori",
|
|
489
|
+
undefended: "nessun difensore",
|
|
490
|
+
cheaper: "un attaccante vale meno",
|
|
491
|
+
outnumbered: "più attaccanti che difensori",
|
|
492
|
+
pinnedTo: (letter) => `davanti ${italianWith("a", letter)}`,
|
|
493
|
+
pinnedBy: (letter) => italianWith("da", letter),
|
|
494
|
+
nothingAtRisk: "Nessun pezzo in pericolo, nessuna inchiodatura.",
|
|
495
|
+
checks: (side, toMove) => `Scacchi del ${side === "white" ? "Bianco" : "Nero"}${toMove ? "" : ", se toccasse a lui"}`,
|
|
496
|
+
loose: "Pezzi né attaccati né difesi",
|
|
497
|
+
white: "Bianco",
|
|
498
|
+
black: "Nero",
|
|
499
|
+
rows: {
|
|
500
|
+
isolated: ["Pedoni isolati", "Un pedone senza pedoni del suo colore sulle colonne accanto: nessun pedone può difenderlo."],
|
|
501
|
+
doubled: ["Pedoni doppiati", "Due pedoni dello stesso colore sulla stessa colonna."],
|
|
502
|
+
backward: ["Pedoni arretrati", "Un pedone rimasto indietro rispetto a quelli accanto, con la casa davanti attaccata da un pedone nemico."],
|
|
503
|
+
passed: ["Pedoni passati", "Nessun pedone nemico davanti a lui, né sulla sua colonna né su quelle accanto."],
|
|
504
|
+
islands: ["Isole di pedoni", "Gruppi di pedoni su colonne vicine, separati fra loro."],
|
|
505
|
+
halfOpen: ["Colonne semiaperte", "Colonne con pedoni nemici e nessuno dei propri."],
|
|
506
|
+
heavyOnFiles: ["Torri e donna su colonne aperte", "Torri e donna su colonne aperte o semiaperte."],
|
|
507
|
+
onSeventh: ["Torri e donna in settima", "Torri e donna sulla seconda traversa del nemico: la settima per il Bianco, la seconda per il Nero."],
|
|
508
|
+
outposts: ["Avamposti", "Case sulle proprie traverse dalla quarta alla sesta, difese da un pedone, che nessun pedone nemico potrà mai attaccare."],
|
|
509
|
+
bishopPair: ["Coppia degli alfieri", "Tutti e due gli alfieri ancora sulla scacchiera."],
|
|
510
|
+
space: ["Spazio (case nella metà avversaria)", "Quante case della metà avversaria attaccano i propri pezzi."],
|
|
511
|
+
undeveloped: ["Pezzi minori non sviluppati", "Cavalli e alfieri ancora sulle case di partenza."],
|
|
512
|
+
castled: ["Arrocco", "Come ha arroccato; non ancora finché può farlo, non più quando il re o le torri si sono già mossi."],
|
|
513
|
+
kingAttacks: ["Attacchi nemici attorno al re", "Quanti attacchi nemici cadono sulle case accanto al re."],
|
|
514
|
+
},
|
|
515
|
+
yes: "sì",
|
|
516
|
+
notYet: "non ancora",
|
|
517
|
+
noMore: "non più",
|
|
518
|
+
phases: { opening: "apertura", middlegame: "mediogioco", endgame: "finale" },
|
|
519
|
+
openFiles: (files) => `Colonne aperte: ${files}`,
|
|
520
|
+
controlled: (white, black, both) => `Case solo del Bianco ${white}, solo del Nero ${black}, di tutti e due ${both}`,
|
|
521
|
+
oppositeBishops: "Alfieri di colore contrario",
|
|
522
|
+
repetitions: (times) => `Questa posizione si è vista ${times} volte`,
|
|
523
|
+
fiftyMoves: (halfMoves) => `Mancano ${halfMoves} semimosse alla patta delle cinquanta mosse`,
|
|
524
|
+
insufficient: "Materiale insufficiente per dare matto",
|
|
525
|
+
pawnSquare: (pawn, caught) => `Il re nemico è ${caught ? "dentro il" : "fuori dal"} quadrato del pedone in ${pawn}`,
|
|
526
|
+
opposition: (side) => `L'opposizione è del ${side === "white" ? "Bianco" : "Nero"}`,
|
|
527
|
+
},
|
|
528
|
+
};
|
|
529
|
+
// How each piece moves, said when it was taken where it cannot go (Anatolij's words).
|
|
530
|
+
const englishMoves = {
|
|
531
|
+
K: "The king moves one square; two only to castle.",
|
|
532
|
+
Q: "The queen moves in a straight line or diagonally.",
|
|
533
|
+
R: "The rook moves only along ranks and files.",
|
|
534
|
+
B: "The bishop moves only diagonally.",
|
|
535
|
+
N: "The knight jumps in an L: two squares one way and one to the side.",
|
|
536
|
+
P: "A pawn moves straight ahead one square, two from its starting square, and captures one square diagonally forward.",
|
|
537
|
+
};
|
|
538
|
+
const englishIllegal = {
|
|
539
|
+
own: ({ to }) => `One of your pieces already stands on ${to}.`,
|
|
540
|
+
blocked: ({ by }) => `${capital(by)} is in the way.`,
|
|
541
|
+
"pawn-straight": () => "A pawn takes only diagonally: straight ahead it needs an empty square.",
|
|
542
|
+
"pawn-double": () => "A pawn goes two squares only from its starting square.",
|
|
543
|
+
"pawn-diagonal": () => "A pawn goes diagonally only to take a piece.",
|
|
544
|
+
"en-passant-late": ({ by }) => `${capital(by)} can be taken en passant only right after its two-square move.`,
|
|
545
|
+
check: ({ by }) => `You are in check from ${by}, and this move does not get you out of it.`,
|
|
546
|
+
pinned: ({ piece, by }) => `The ${englishNames[piece]} is pinned: if you move it, ${by} gives check to your king.`,
|
|
547
|
+
attacked: ({ to, takes, by }) => takes ? `The king cannot take on ${to}: ${by} defends that square.` : `The king cannot go to ${to}: ${by} attacks that square.`,
|
|
548
|
+
"castle-lost": () => "You can no longer castle on that side: the king or that rook has already moved.",
|
|
549
|
+
"castle-rook-gone": ({ at }) => `Your rook on ${at} is gone: you cannot castle on that side.`,
|
|
550
|
+
"castle-blocked": ({ by }) => `To castle, no piece may stand between the king and the rook: ${by} does.`,
|
|
551
|
+
"castle-check": ({ by }) => `You cannot castle out of check: ${by} gives it.`,
|
|
552
|
+
"castle-through": ({ at, by }) => `The king cannot castle through or onto ${at}: ${by} attacks that square.`,
|
|
553
|
+
};
|
|
554
|
+
const italianThe = { K: "il re", Q: "la donna", R: "la torre", B: "l'alfiere", N: "il cavallo", P: "il pedone" };
|
|
555
|
+
const italianMoves = {
|
|
556
|
+
K: "Il re si muove di una casa; di due solo per arroccare.",
|
|
557
|
+
Q: "La donna si muove in linea retta o in diagonale.",
|
|
558
|
+
R: "La torre si muove solo per righe e colonne.",
|
|
559
|
+
B: "L'alfiere si muove solo in diagonale.",
|
|
560
|
+
N: "Il cavallo salta a L: due case in una direzione e una di lato.",
|
|
561
|
+
P: "Il pedone avanza dritto di una casa, di due dalla casa di partenza, e cattura di una casa in diagonale.",
|
|
562
|
+
};
|
|
563
|
+
const italianIllegal = {
|
|
564
|
+
own: ({ to }) => `In ${to} c'è già un tuo pezzo.`,
|
|
565
|
+
blocked: ({ by }) => `${capital(by)} sbarra la strada.`,
|
|
566
|
+
"pawn-straight": () => "Il pedone cattura solo in diagonale: in avanti gli serve una casa libera.",
|
|
567
|
+
"pawn-double": () => "Il pedone avanza di due case solo dalla sua casa di partenza.",
|
|
568
|
+
"pawn-diagonal": () => "Il pedone va in diagonale solo per catturare.",
|
|
569
|
+
"en-passant-late": ({ by }) => `${capital(by)} si prende en passant solo subito dopo il suo passo doppio.`,
|
|
570
|
+
check: ({ by }) => `Sei sotto scacco e questa mossa non lo para: lo dà ${by}.`,
|
|
571
|
+
pinned: ({ by }) => `Questo pezzo è inchiodato: se lo sposti, ${by} dà scacco al tuo re.`,
|
|
572
|
+
attacked: ({ to, takes, by }) => takes ? `Il re non può prendere in ${to}: ${by} difende quella casa.` : `Il re non può andare in ${to}: ${by} controlla quella casa.`,
|
|
573
|
+
"castle-lost": () => "Da quel lato non puoi più arroccare: il re o quella torre si sono già mossi.",
|
|
574
|
+
"castle-rook-gone": ({ at }) => `Non c'è più la tua torre in ${at}: da quel lato non si arrocca.`,
|
|
575
|
+
"castle-blocked": ({ by }) => `Per arroccare non ci devono essere pezzi fra il re e la torre: c'è ${by}.`,
|
|
576
|
+
"castle-check": ({ by }) => `Sotto scacco non si arrocca: lo dà ${by}.`,
|
|
577
|
+
"castle-through": ({ at, by }) => `Arroccando il re passerebbe per ${at}, e ${by} controlla quella casa.`,
|
|
578
|
+
};
|
|
579
|
+
/** The piece that forbids a move, with its article and square; a king with its colour, beside the player's own. */
|
|
580
|
+
function englishCulprit(by) {
|
|
581
|
+
return by === undefined ? "" : `the ${by.letter === "K" ? `${by.side} ` : ""}${englishNames[by.letter]} on ${by.square}`;
|
|
582
|
+
}
|
|
583
|
+
function italianCulprit(by) {
|
|
584
|
+
return by === undefined ? "" : `${italianThe[by.letter]}${by.letter === "K" ? (by.side === "white" ? " bianco" : " nero") : ""} in ${by.square}`;
|
|
585
|
+
}
|
|
586
|
+
/** A piece with its article joined to a preposition: "alla donna", "dall'alfiere". */
|
|
587
|
+
function italianWith(preposition, letter) {
|
|
588
|
+
return italianThe[letter].replace(/^il /, `${preposition}l `).replace(/^la /, `${preposition}lla `).replace(/^l'/, `${preposition}ll'`);
|
|
589
|
+
}
|
|
590
|
+
/** The words with their first letter capital, to open a sentence. */
|
|
591
|
+
function capital(words) {
|
|
592
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
593
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
|
+
// The Torretta (D-45, D-46): the opponent and the logo, a rook that is a robot. Its screen shows the AI's mood (D-14, D-70): only the eyes, the mouth and the light change.
|
|
3
|
+
import { useRef } from "preact/hooks";
|
|
4
|
+
/** The Torretta at a size in pixels, with the face of a mood (neutral by default); with a label it is an image a screen reader names, else a decoration. */
|
|
5
|
+
export function Torretta({ size, label, mood = "neutral" }) {
|
|
6
|
+
// The face pops in when the mood changes, never when the Torretta first shows (the logo, a card, a dialog).
|
|
7
|
+
const changed = useChanged(mood);
|
|
8
|
+
return (_jsxs("svg", { class: `torretta mood-${mood}`, viewBox: "0 0 128 128", width: size, height: size, role: label === undefined ? undefined : "img", "aria-label": label, "aria-hidden": label === undefined ? "true" : undefined, children: [_jsx("path", { class: "antenna", d: "M64 31V19" }), _jsx("circle", { class: "light", cx: "64", cy: "16", r: "5" }), _jsx("rect", { class: "shade", x: "29", y: "64", width: "12", height: "26", rx: "2" }), _jsx("rect", { class: "shade", x: "87", y: "64", width: "12", height: "26", rx: "2" }), _jsx("path", { class: "body", d: "M34 30H47V40H57V30H71V40H81V30H94V54L89 58L92 106H36L39 58L34 54Z" }), _jsx("rect", { class: "shade", x: "30", y: "104", width: "68", height: "12", rx: "4" }), _jsx("rect", { class: "screen", x: "44", y: "63", width: "40", height: "32", rx: "7" }), _jsx("g", { class: changed ? "expression changed" : "expression", children: _jsx(Face, { mood: mood }) }, mood)] }));
|
|
9
|
+
}
|
|
10
|
+
/** Whether the mood has changed since the Torretta first showed: true from its first change on, so a face already shown never starts its entrance again. */
|
|
11
|
+
function useChanged(mood) {
|
|
12
|
+
const first = useRef(mood);
|
|
13
|
+
const changed = useRef(false);
|
|
14
|
+
changed.current ||= mood !== first.current;
|
|
15
|
+
return changed.current;
|
|
16
|
+
}
|
|
17
|
+
/** The eyes and the mouth of a mood, on the screen (x 44–84, y 63–95); strokes of 3.4 at least, to read at 40 px. */
|
|
18
|
+
function Face({ mood }) {
|
|
19
|
+
switch (mood) {
|
|
20
|
+
case "happy":
|
|
21
|
+
// Eyes closed in two arcs, a wide open smile.
|
|
22
|
+
return (_jsxs(_Fragment, { children: [_jsx("path", { class: "eyes line", d: "M50.5 78.5a4.5 4.5 0 0 1 9 0M68.5 78.5a4.5 4.5 0 0 1 9 0" }), _jsx("path", { class: "mouth", d: "M57 84h14a7 7 0 0 1-14 0Z" })] }));
|
|
23
|
+
case "surprised":
|
|
24
|
+
// Wide eyes and a round mouth.
|
|
25
|
+
return (_jsxs(_Fragment, { children: [_jsxs("g", { class: "eyes", children: [_jsx("circle", { cx: "54.5", cy: "75.5", r: "5.8" }), _jsx("circle", { cx: "73.5", cy: "75.5", r: "5.8" })] }), _jsx("ellipse", { class: "mouth", cx: "64", cy: "88.5", rx: "3.4", ry: "4" })] }));
|
|
26
|
+
case "worried":
|
|
27
|
+
// Brows raised in the middle, smaller eyes, a frown; the light turns red.
|
|
28
|
+
return (_jsxs(_Fragment, { children: [_jsx("path", { class: "brows", d: "M50 70L58 67M70 67L78 70" }), _jsxs("g", { class: "eyes", children: [_jsx("circle", { cx: "55", cy: "78.5", r: "3.8" }), _jsx("circle", { cx: "73", cy: "78.5", r: "3.8" })] }), _jsx("path", { class: "mouth line", d: "M56.5 91q7.5-6 15 0" })] }));
|
|
29
|
+
case "thoughtful":
|
|
30
|
+
// A glance to the side under one raised brow, the mouth pushed to the other side; the light breathes.
|
|
31
|
+
return (_jsxs(_Fragment, { children: [_jsx("path", { class: "brows", d: "M71 68L80 66" }), _jsxs("g", { class: "eyes", children: [_jsx("circle", { cx: "58", cy: "76.5", r: "3.9" }), _jsx("circle", { cx: "76", cy: "76.5", r: "3.9" })] }), _jsx("path", { class: "mouth line", d: "M52.5 89L63 87" })] }));
|
|
32
|
+
case "sad":
|
|
33
|
+
// No brows, the face sunk low: eyes half shut under lids that droop outwards, a deep frown; the light goes out.
|
|
34
|
+
return (_jsxs(_Fragment, { children: [_jsx("path", { class: "eyes", d: "M60.3 77.1A5.6 5.6 0 0 1 49.7 80.9ZM78.3 80.9A5.6 5.6 0 0 1 67.7 77.1Z" }), _jsx("path", { class: "mouth line", d: "M57.5 92.5q6.5-6.5 13 0" })] }));
|
|
35
|
+
default:
|
|
36
|
+
return (_jsxs(_Fragment, { children: [_jsxs("g", { class: "eyes", children: [_jsx("circle", { cx: "55", cy: "76", r: "4.6" }), _jsx("circle", { cx: "73", cy: "76", r: "4.6" })] }), _jsx("rect", { class: "mouth", x: "58", y: "85.4", width: "12", height: "3.2", rx: "1.6" })] }));
|
|
37
|
+
}
|
|
38
|
+
}
|