slashvibe-mcp 0.3.21 → 0.3.22
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/LICENSE +21 -0
- package/README.md +280 -47
- package/config.js +36 -31
- package/crypto.js +1 -6
- package/discord.js +19 -19
- package/index.js +217 -207
- package/intelligence/index.js +2 -9
- package/intelligence/infer.js +10 -16
- package/intelligence/patterns.js +23 -18
- package/intelligence/proactive.js +16 -15
- package/intelligence/serendipity.js +57 -20
- package/memory.js +13 -8
- package/notify.js +39 -14
- package/package.json +27 -20
- package/presence.js +2 -2
- package/prompts.js +5 -9
- package/protocol/index.js +123 -87
- package/protocol/telegram-commands.js +36 -37
- package/store/api.js +358 -529
- package/store/local.js +9 -10
- package/store/profiles.js +48 -192
- package/store/reservations.js +2 -9
- package/store/skills.js +69 -71
- package/store/sqlite.js +355 -0
- package/tools/_actions.js +48 -387
- package/tools/_connection-queue.js +45 -56
- package/tools/_discovery-enhanced.js +52 -57
- package/tools/_discovery.js +87 -185
- package/tools/{l2-status.js → _experimental/l2-status.js} +68 -70
- package/tools/{shipback.js → _experimental/shipback.js} +4 -3
- package/tools/_proactive-discovery.js +60 -73
- package/tools/_shared/index.js +41 -64
- package/tools/admin-inbox.js +10 -15
- package/tools/agents.js +1 -1
- package/tools/artifact-create.js +13 -23
- package/tools/artifact-view.js +4 -4
- package/tools/{_deprecated/back.js → back.js} +1 -1
- package/tools/bye.js +3 -5
- package/tools/consent.js +2 -2
- package/tools/context.js +9 -10
- package/tools/crossword.js +3 -2
- package/tools/discover.js +94 -356
- package/tools/dm.js +27 -86
- package/tools/doctor.js +12 -41
- package/tools/drawing.js +34 -20
- package/tools/echo.js +11 -11
- package/tools/feed.js +30 -58
- package/tools/follow.js +64 -187
- package/tools/{_deprecated/forget.js → forget.js} +4 -7
- package/tools/game.js +144 -48
- package/tools/handoff.js +6 -8
- package/tools/help.js +3 -3
- package/tools/idea.js +15 -27
- package/tools/inbox.js +121 -293
- package/tools/init.js +54 -151
- package/tools/invite.js +8 -21
- package/tools/migrate.js +27 -24
- package/tools/multiplayer-game.js +50 -40
- package/tools/{_deprecated/mute.js → mute.js} +4 -3
- package/tools/notifications.js +58 -48
- package/tools/observe.js +12 -15
- package/tools/onboarding.js +8 -11
- package/tools/open.js +13 -144
- package/tools/party-game.js +23 -12
- package/tools/patterns.js +2 -1
- package/tools/ping.js +5 -7
- package/tools/react.js +28 -30
- package/tools/{_deprecated/recall.js → recall.js} +5 -10
- package/tools/release.js +4 -2
- package/tools/{_deprecated/remember.js → remember.js} +4 -6
- package/tools/report.js +2 -2
- package/tools/request.js +6 -26
- package/tools/reserve.js +1 -1
- package/tools/session-fork.js +97 -0
- package/tools/session-save.js +109 -0
- package/tools/settings.js +30 -99
- package/tools/ship.js +74 -56
- package/tools/{_deprecated/skills-exchange.js → skills-exchange.js} +38 -39
- package/tools/social-inbox.js +22 -28
- package/tools/social-post.js +24 -27
- package/tools/solo-game.js +54 -46
- package/tools/start.js +14 -148
- package/tools/status.js +21 -68
- package/tools/submit.js +4 -2
- package/tools/suggest-tags.js +36 -33
- package/tools/summarize.js +19 -16
- package/tools/tag-suggestions.js +72 -73
- package/tools/test.js +1 -1
- package/tools/{_deprecated/tictactoe.js → tictactoe.js} +26 -26
- package/tools/token.js +4 -4
- package/tools/update.js +1 -2
- package/tools/watch.js +132 -112
- package/tools/who.js +20 -40
- package/tools/{_deprecated/wordassociation.js → wordassociation.js} +23 -20
- package/tools/workshop-buddy.js +52 -53
- package/tools/x-mentions.js +0 -1
- package/tools/x-reply.js +0 -1
- package/twitter.js +14 -20
- package/version.json +8 -10
- package/analytics.js +0 -107
- package/auth-store.js +0 -148
- package/auto-update.js +0 -130
- package/bridges/bridge-monitor.js +0 -388
- package/bridges/discord-bot.js +0 -431
- package/bridges/farcaster.js +0 -299
- package/bridges/telegram.js +0 -261
- package/bridges/webhook-health.js +0 -420
- package/bridges/webhook-server.js +0 -437
- package/bridges/whatsapp.js +0 -441
- package/bridges/x-webhook.js +0 -423
- package/games/arcade.js +0 -406
- package/games/chess.js +0 -451
- package/games/colorguess.js +0 -343
- package/games/crossword-words.js +0 -171
- package/games/crossword.js +0 -461
- package/games/drawing.js +0 -347
- package/games/gameroulette.js +0 -300
- package/games/gamerouter.js +0 -336
- package/games/gamestatus.js +0 -337
- package/games/guessnumber.js +0 -209
- package/games/hangman.js +0 -279
- package/games/memory.js +0 -338
- package/games/multiplayer-tictactoe.js +0 -389
- package/games/pixelart.js +0 -399
- package/games/quickduel.js +0 -354
- package/games/riddle.js +0 -371
- package/games/rockpaperscissors.js +0 -291
- package/games/snake.js +0 -406
- package/games/storybuilder.js +0 -343
- package/games/tictactoe.js +0 -345
- package/games/twentyquestions.js +0 -286
- package/games/twotruths.js +0 -207
- package/games/werewolf.js +0 -508
- package/games/wordassociation.js +0 -247
- package/games/wordchain.js +0 -135
- package/intelligence/interests.js +0 -369
- package/notification-emitter.js +0 -77
- package/setup.js +0 -480
- package/smart-inbox.js +0 -276
- package/tools/_deprecated/auto-suggest-connections.js +0 -304
- package/tools/_deprecated/bootstrap-skills.js +0 -231
- package/tools/_deprecated/bridge-dashboard.js +0 -342
- package/tools/_deprecated/bridge-health.js +0 -400
- package/tools/_deprecated/bridge-live.js +0 -384
- package/tools/_deprecated/bridges.js +0 -383
- package/tools/_deprecated/colorguess.js +0 -281
- package/tools/_deprecated/discover-insights.js +0 -379
- package/tools/_deprecated/discover-momentum.js +0 -256
- package/tools/_deprecated/discovery-analytics.js +0 -345
- package/tools/_deprecated/discovery-auto-suggest.js +0 -275
- package/tools/_deprecated/discovery-bootstrap.js +0 -267
- package/tools/_deprecated/discovery-daily.js +0 -375
- package/tools/_deprecated/discovery-dashboard.js +0 -385
- package/tools/_deprecated/discovery-digest.js +0 -314
- package/tools/_deprecated/discovery-hub.js +0 -357
- package/tools/_deprecated/discovery-insights.js +0 -384
- package/tools/_deprecated/discovery-momentum.js +0 -281
- package/tools/_deprecated/discovery-monitor.js +0 -319
- package/tools/_deprecated/discovery-proactive.js +0 -300
- package/tools/_deprecated/draw.js +0 -317
- package/tools/_deprecated/farcaster.js +0 -307
- package/tools/_deprecated/games-catalog.js +0 -376
- package/tools/_deprecated/games.js +0 -313
- package/tools/_deprecated/guessnumber.js +0 -194
- package/tools/_deprecated/hangman.js +0 -129
- package/tools/_deprecated/multiplayer-tictactoe.js +0 -303
- package/tools/_deprecated/riddle.js +0 -240
- package/tools/_deprecated/run-bootstrap.js +0 -69
- package/tools/_deprecated/skills-analytics.js +0 -349
- package/tools/_deprecated/skills-bootstrap.js +0 -301
- package/tools/_deprecated/skills-dashboard.js +0 -268
- package/tools/_deprecated/skills.js +0 -380
- package/tools/_deprecated/smart-intro.js +0 -353
- package/tools/_deprecated/storybuilder.js +0 -331
- package/tools/_deprecated/telegram-bot.js +0 -183
- package/tools/_deprecated/telegram-setup.js +0 -214
- package/tools/_deprecated/twentyquestions.js +0 -143
- package/tools/_shared.js +0 -234
- package/tools/_work-context.js +0 -338
- package/tools/_work-context.manual-test.js +0 -199
- package/tools/_work-context.test.js +0 -260
- package/tools/activity.js +0 -220
- package/tools/agent-treasury.js +0 -288
- package/tools/analytics.js +0 -191
- package/tools/approve.js +0 -197
- package/tools/arcade.js +0 -173
- package/tools/artifacts-price.js +0 -107
- package/tools/ask-expert.js +0 -160
- package/tools/available.js +0 -120
- package/tools/become-expert.js +0 -150
- package/tools/broadcast.js +0 -325
- package/tools/chat.js +0 -202
- package/tools/collaborative-drawing.js +0 -286
- package/tools/connection-status.js +0 -178
- package/tools/earnings.js +0 -126
- package/tools/friends.js +0 -207
- package/tools/genesis.js +0 -233
- package/tools/gig-browse.js +0 -206
- package/tools/gig-complete.js +0 -144
- package/tools/health.js +0 -87
- package/tools/leaderboard.js +0 -117
- package/tools/lib/git-apply.js +0 -206
- package/tools/lib/git-bundle.js +0 -407
- package/tools/mint.js +0 -377
- package/tools/plan.js +0 -225
- package/tools/profile.js +0 -219
- package/tools/proof-of-work.js +0 -144
- package/tools/pulse.js +0 -218
- package/tools/reply.js +0 -166
- package/tools/reputation.js +0 -175
- package/tools/schedule.js +0 -367
- package/tools/search-messages.js +0 -123
- package/tools/session.js +0 -467
- package/tools/session_price.js +0 -128
- package/tools/smart-check.js +0 -201
- package/tools/social-processor.js +0 -445
- package/tools/streak.js +0 -147
- package/tools/stuck.js +0 -297
- package/tools/subscribe.js +0 -148
- package/tools/subscriptions.js +0 -134
- package/tools/tip.js +0 -193
- package/tools/wallet.js +0 -269
- package/tools/webhook-test.js +0 -388
- package/tools/withdraw.js +0 -145
- package/tools/work-summary.js +0 -96
- package/tools/workshop.js +0 -327
- /package/tools/{l2-bridge.js → _experimental/l2-bridge.js} +0 -0
- /package/tools/{l2.js → _experimental/l2.js} +0 -0
- /package/tools/{_deprecated/away.js → away.js} +0 -0
package/games/chess.js
DELETED
|
@@ -1,451 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Chess game implementation for /vibe
|
|
3
|
-
* Supports standard chess rules with algebraic notation
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Chess piece values for basic evaluation
|
|
7
|
-
const PIECE_VALUES = {
|
|
8
|
-
'P': 1, 'N': 3, 'B': 3, 'R': 5, 'Q': 9, 'K': 0,
|
|
9
|
-
'p': -1, 'n': -3, 'b': -3, 'r': -5, 'q': -9, 'k': 0
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
// Initial chess board setup
|
|
13
|
-
const INITIAL_BOARD = [
|
|
14
|
-
['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'],
|
|
15
|
-
['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'],
|
|
16
|
-
['', '', '', '', '', '', '', ''],
|
|
17
|
-
['', '', '', '', '', '', '', ''],
|
|
18
|
-
['', '', '', '', '', '', '', ''],
|
|
19
|
-
['', '', '', '', '', '', '', ''],
|
|
20
|
-
['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'],
|
|
21
|
-
['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R']
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
// Convert file letters to indices
|
|
25
|
-
function fileToIndex(file) {
|
|
26
|
-
return file.charCodeAt(0) - 97; // 'a' = 0, 'b' = 1, etc.
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function indexToFile(index) {
|
|
30
|
-
return String.fromCharCode(97 + index);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Convert rank numbers to indices (rank 1 = index 7, rank 8 = index 0)
|
|
34
|
-
function rankToIndex(rank) {
|
|
35
|
-
return 8 - parseInt(rank);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function indexToRank(index) {
|
|
39
|
-
return (8 - index).toString();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Parse algebraic notation to board coordinates
|
|
43
|
-
function parseAlgebraicNotation(notation, board, isWhiteTurn) {
|
|
44
|
-
// Remove check/checkmate indicators
|
|
45
|
-
const move = notation.replace(/[+#]$/, '');
|
|
46
|
-
|
|
47
|
-
// Handle castling
|
|
48
|
-
if (move === 'O-O' || move === '0-0') {
|
|
49
|
-
return isWhiteTurn ?
|
|
50
|
-
{ from: [7, 4], to: [7, 6], type: 'castle-short' } :
|
|
51
|
-
{ from: [0, 4], to: [0, 6], type: 'castle-short' };
|
|
52
|
-
}
|
|
53
|
-
if (move === 'O-O-O' || move === '0-0-0') {
|
|
54
|
-
return isWhiteTurn ?
|
|
55
|
-
{ from: [7, 4], to: [7, 2], type: 'castle-long' } :
|
|
56
|
-
{ from: [0, 4], to: [0, 2], type: 'castle-long' };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Handle pawn moves (no piece letter)
|
|
60
|
-
if (/^[a-h][1-8]$/.test(move)) {
|
|
61
|
-
// Simple pawn move like e4
|
|
62
|
-
const toFile = fileToIndex(move[0]);
|
|
63
|
-
const toRank = rankToIndex(move[1]);
|
|
64
|
-
const fromRank = isWhiteTurn ? toRank + 1 : toRank - 1;
|
|
65
|
-
|
|
66
|
-
// Check if it's a valid pawn move
|
|
67
|
-
if (fromRank >= 0 && fromRank < 8 && board[fromRank][toFile] === (isWhiteTurn ? 'P' : 'p')) {
|
|
68
|
-
return { from: [fromRank, toFile], to: [toRank, toFile], type: 'move' };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Check for double pawn move
|
|
72
|
-
const doubleFromRank = isWhiteTurn ? 6 : 1;
|
|
73
|
-
if (board[doubleFromRank][toFile] === (isWhiteTurn ? 'P' : 'p') && board[toRank][toFile] === '') {
|
|
74
|
-
return { from: [doubleFromRank, toFile], to: [toRank, toFile], type: 'move' };
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Handle pawn captures like exd5
|
|
79
|
-
if (/^[a-h]x[a-h][1-8]$/.test(move)) {
|
|
80
|
-
const fromFile = fileToIndex(move[0]);
|
|
81
|
-
const toFile = fileToIndex(move[2]);
|
|
82
|
-
const toRank = rankToIndex(move[3]);
|
|
83
|
-
const fromRank = isWhiteTurn ? toRank + 1 : toRank - 1;
|
|
84
|
-
|
|
85
|
-
if (fromRank >= 0 && fromRank < 8 && board[fromRank][fromFile] === (isWhiteTurn ? 'P' : 'p')) {
|
|
86
|
-
return { from: [fromRank, fromFile], to: [toRank, toFile], type: 'capture' };
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Handle piece moves like Nf3, Bb5, etc.
|
|
91
|
-
const pieceMatch = move.match(/^([NBRQK])([a-h]?[1-8]?)(x?)([a-h][1-8])$/);
|
|
92
|
-
if (pieceMatch) {
|
|
93
|
-
const piece = isWhiteTurn ? pieceMatch[1] : pieceMatch[1].toLowerCase();
|
|
94
|
-
const disambiguator = pieceMatch[2];
|
|
95
|
-
const isCapture = pieceMatch[3] === 'x';
|
|
96
|
-
const toSquare = pieceMatch[4];
|
|
97
|
-
const toFile = fileToIndex(toSquare[0]);
|
|
98
|
-
const toRank = rankToIndex(toSquare[1]);
|
|
99
|
-
|
|
100
|
-
// Find the piece that can make this move
|
|
101
|
-
const possibleMoves = findPieceLocations(board, piece);
|
|
102
|
-
const validFromSquares = possibleMoves.filter(([fromRank, fromFile]) => {
|
|
103
|
-
return canPieceMove(board, piece, fromRank, fromFile, toRank, toFile);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// Apply disambiguator if provided
|
|
107
|
-
if (disambiguator) {
|
|
108
|
-
if (/[a-h]/.test(disambiguator)) {
|
|
109
|
-
const disambiguatorFile = fileToIndex(disambiguator);
|
|
110
|
-
return validFromSquares.find(([r, f]) => f === disambiguatorFile);
|
|
111
|
-
} else if (/[1-8]/.test(disambiguator)) {
|
|
112
|
-
const disambiguatorRank = rankToIndex(disambiguator);
|
|
113
|
-
return validFromSquares.find(([r, f]) => r === disambiguatorRank);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (validFromSquares.length === 1) {
|
|
118
|
-
return {
|
|
119
|
-
from: validFromSquares[0],
|
|
120
|
-
to: [toRank, toFile],
|
|
121
|
-
type: isCapture ? 'capture' : 'move'
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return null; // Invalid notation
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Find all locations of a specific piece on the board
|
|
130
|
-
function findPieceLocations(board, piece) {
|
|
131
|
-
const locations = [];
|
|
132
|
-
for (let rank = 0; rank < 8; rank++) {
|
|
133
|
-
for (let file = 0; file < 8; file++) {
|
|
134
|
-
if (board[rank][file] === piece) {
|
|
135
|
-
locations.push([rank, file]);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return locations;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Check if a piece can legally move from one square to another
|
|
143
|
-
function canPieceMove(board, piece, fromRank, fromFile, toRank, toFile) {
|
|
144
|
-
const pieceType = piece.toLowerCase();
|
|
145
|
-
const dx = toFile - fromFile;
|
|
146
|
-
const dy = toRank - fromRank;
|
|
147
|
-
|
|
148
|
-
switch (pieceType) {
|
|
149
|
-
case 'p': // Pawn
|
|
150
|
-
const direction = piece === 'P' ? -1 : 1;
|
|
151
|
-
const startRank = piece === 'P' ? 6 : 1;
|
|
152
|
-
|
|
153
|
-
// Forward move
|
|
154
|
-
if (dx === 0) {
|
|
155
|
-
if (dy === direction && board[toRank][toFile] === '') return true;
|
|
156
|
-
if (fromRank === startRank && dy === 2 * direction && board[toRank][toFile] === '') return true;
|
|
157
|
-
}
|
|
158
|
-
// Capture
|
|
159
|
-
if (Math.abs(dx) === 1 && dy === direction) {
|
|
160
|
-
const targetPiece = board[toRank][toFile];
|
|
161
|
-
return targetPiece !== '' && isOpponentPiece(piece, targetPiece);
|
|
162
|
-
}
|
|
163
|
-
return false;
|
|
164
|
-
|
|
165
|
-
case 'r': // Rook
|
|
166
|
-
if (dx === 0 || dy === 0) {
|
|
167
|
-
return isPathClear(board, fromRank, fromFile, toRank, toFile);
|
|
168
|
-
}
|
|
169
|
-
return false;
|
|
170
|
-
|
|
171
|
-
case 'n': // Knight
|
|
172
|
-
return (Math.abs(dx) === 2 && Math.abs(dy) === 1) ||
|
|
173
|
-
(Math.abs(dx) === 1 && Math.abs(dy) === 2);
|
|
174
|
-
|
|
175
|
-
case 'b': // Bishop
|
|
176
|
-
if (Math.abs(dx) === Math.abs(dy)) {
|
|
177
|
-
return isPathClear(board, fromRank, fromFile, toRank, toFile);
|
|
178
|
-
}
|
|
179
|
-
return false;
|
|
180
|
-
|
|
181
|
-
case 'q': // Queen
|
|
182
|
-
if (dx === 0 || dy === 0 || Math.abs(dx) === Math.abs(dy)) {
|
|
183
|
-
return isPathClear(board, fromRank, fromFile, toRank, toFile);
|
|
184
|
-
}
|
|
185
|
-
return false;
|
|
186
|
-
|
|
187
|
-
case 'k': // King
|
|
188
|
-
return Math.abs(dx) <= 1 && Math.abs(dy) <= 1;
|
|
189
|
-
|
|
190
|
-
default:
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Check if path between two squares is clear
|
|
196
|
-
function isPathClear(board, fromRank, fromFile, toRank, toFile) {
|
|
197
|
-
const dx = toFile - fromFile;
|
|
198
|
-
const dy = toRank - fromRank;
|
|
199
|
-
const steps = Math.max(Math.abs(dx), Math.abs(dy));
|
|
200
|
-
|
|
201
|
-
const stepX = dx === 0 ? 0 : dx / Math.abs(dx);
|
|
202
|
-
const stepY = dy === 0 ? 0 : dy / Math.abs(dy);
|
|
203
|
-
|
|
204
|
-
for (let i = 1; i < steps; i++) {
|
|
205
|
-
const checkRank = fromRank + stepY * i;
|
|
206
|
-
const checkFile = fromFile + stepX * i;
|
|
207
|
-
if (board[checkRank][checkFile] !== '') {
|
|
208
|
-
return false;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
return true;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Check if two pieces are opponents
|
|
216
|
-
function isOpponentPiece(piece1, piece2) {
|
|
217
|
-
return (piece1 >= 'A' && piece1 <= 'Z') !== (piece2 >= 'A' && piece2 <= 'Z');
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Check if a piece is white
|
|
221
|
-
function isWhitePiece(piece) {
|
|
222
|
-
return piece >= 'A' && piece <= 'Z';
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Find king position
|
|
226
|
-
function findKing(board, isWhite) {
|
|
227
|
-
const king = isWhite ? 'K' : 'k';
|
|
228
|
-
for (let rank = 0; rank < 8; rank++) {
|
|
229
|
-
for (let file = 0; file < 8; file++) {
|
|
230
|
-
if (board[rank][file] === king) {
|
|
231
|
-
return [rank, file];
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
return null;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Check if a square is attacked by opponent
|
|
239
|
-
function isSquareAttacked(board, rank, file, byWhite) {
|
|
240
|
-
// Check all opponent pieces
|
|
241
|
-
for (let r = 0; r < 8; r++) {
|
|
242
|
-
for (let f = 0; f < 8; f++) {
|
|
243
|
-
const piece = board[r][f];
|
|
244
|
-
if (!piece) continue;
|
|
245
|
-
if (isWhitePiece(piece) !== byWhite) continue;
|
|
246
|
-
|
|
247
|
-
// Check if this piece can attack the target square
|
|
248
|
-
if (canPieceMove(board, piece, r, f, rank, file)) {
|
|
249
|
-
return true;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
return false;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Check if king is in check
|
|
257
|
-
function isKingInCheck(board, isWhiteKing) {
|
|
258
|
-
const kingPos = findKing(board, isWhiteKing);
|
|
259
|
-
if (!kingPos) return false;
|
|
260
|
-
return isSquareAttacked(board, kingPos[0], kingPos[1], !isWhiteKing);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Get all legal moves for a player
|
|
264
|
-
function getAllLegalMoves(board, isWhiteTurn) {
|
|
265
|
-
const moves = [];
|
|
266
|
-
|
|
267
|
-
for (let fromRank = 0; fromRank < 8; fromRank++) {
|
|
268
|
-
for (let fromFile = 0; fromFile < 8; fromFile++) {
|
|
269
|
-
const piece = board[fromRank][fromFile];
|
|
270
|
-
if (!piece) continue;
|
|
271
|
-
if (isWhitePiece(piece) !== isWhiteTurn) continue;
|
|
272
|
-
|
|
273
|
-
// Try all possible destination squares
|
|
274
|
-
for (let toRank = 0; toRank < 8; toRank++) {
|
|
275
|
-
for (let toFile = 0; toFile < 8; toFile++) {
|
|
276
|
-
if (fromRank === toRank && fromFile === toFile) continue;
|
|
277
|
-
|
|
278
|
-
// Check if piece can move there
|
|
279
|
-
if (!canPieceMove(board, piece, fromRank, fromFile, toRank, toFile)) continue;
|
|
280
|
-
|
|
281
|
-
// Check if destination has own piece
|
|
282
|
-
const destPiece = board[toRank][toFile];
|
|
283
|
-
if (destPiece && isWhitePiece(destPiece) === isWhiteTurn) continue;
|
|
284
|
-
|
|
285
|
-
// Simulate move and check if king is still in check
|
|
286
|
-
const testBoard = board.map(row => [...row]);
|
|
287
|
-
testBoard[toRank][toFile] = piece;
|
|
288
|
-
testBoard[fromRank][fromFile] = '';
|
|
289
|
-
|
|
290
|
-
if (!isKingInCheck(testBoard, isWhiteTurn)) {
|
|
291
|
-
moves.push({
|
|
292
|
-
from: [fromRank, fromFile],
|
|
293
|
-
to: [toRank, toFile],
|
|
294
|
-
piece
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return moves;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// Check for checkmate or stalemate
|
|
306
|
-
function getGameEndState(board, isWhiteTurn) {
|
|
307
|
-
const legalMoves = getAllLegalMoves(board, isWhiteTurn);
|
|
308
|
-
const inCheck = isKingInCheck(board, isWhiteTurn);
|
|
309
|
-
|
|
310
|
-
if (legalMoves.length === 0) {
|
|
311
|
-
if (inCheck) {
|
|
312
|
-
return { checkmate: true, winner: isWhiteTurn ? 'black' : 'white' };
|
|
313
|
-
} else {
|
|
314
|
-
return { stalemate: true };
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
return { check: inCheck };
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Convert move to algebraic notation
|
|
322
|
-
function moveToAlgebraicNotation(board, move) {
|
|
323
|
-
const { from, to, piece } = move;
|
|
324
|
-
const [fromRank, fromFile] = from;
|
|
325
|
-
const [toRank, toFile] = to;
|
|
326
|
-
|
|
327
|
-
const toSquare = indexToFile(toFile) + indexToRank(toRank);
|
|
328
|
-
const isCapture = board[toRank][toFile] !== '';
|
|
329
|
-
|
|
330
|
-
if (piece.toLowerCase() === 'p') {
|
|
331
|
-
if (isCapture) {
|
|
332
|
-
return indexToFile(fromFile) + 'x' + toSquare;
|
|
333
|
-
} else {
|
|
334
|
-
return toSquare;
|
|
335
|
-
}
|
|
336
|
-
} else {
|
|
337
|
-
const pieceSymbol = piece.toUpperCase();
|
|
338
|
-
const captureSymbol = isCapture ? 'x' : '';
|
|
339
|
-
return pieceSymbol + captureSymbol + toSquare;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Create initial chess state
|
|
344
|
-
function createInitialChessState() {
|
|
345
|
-
return {
|
|
346
|
-
board: INITIAL_BOARD.map(row => [...row]),
|
|
347
|
-
turn: 'white',
|
|
348
|
-
moves: 0,
|
|
349
|
-
history: [],
|
|
350
|
-
check: false,
|
|
351
|
-
checkmate: false,
|
|
352
|
-
stalemate: false,
|
|
353
|
-
winner: null
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// Format chess board for display
|
|
358
|
-
function formatChessBoard(board, lastMove = null) {
|
|
359
|
-
const files = ' a b c d e f g h';
|
|
360
|
-
let display = '```\n' + files + '\n';
|
|
361
|
-
|
|
362
|
-
for (let rank = 0; rank < 8; rank++) {
|
|
363
|
-
let row = (8 - rank) + ' ';
|
|
364
|
-
for (let file = 0; file < 8; file++) {
|
|
365
|
-
const piece = board[rank][file];
|
|
366
|
-
const symbol = piece || (rank + file) % 2 === 0 ? '·' : ' ';
|
|
367
|
-
row += symbol + ' ';
|
|
368
|
-
}
|
|
369
|
-
row += (8 - rank);
|
|
370
|
-
display += row + '\n';
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
display += files + '\n```';
|
|
374
|
-
return display;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Make a move on the chess board
|
|
378
|
-
function makeMove(gameState, moveNotation) {
|
|
379
|
-
const { board, turn, moves, history } = gameState;
|
|
380
|
-
const isWhiteTurn = turn === 'white';
|
|
381
|
-
|
|
382
|
-
const parsedMove = parseAlgebraicNotation(moveNotation, board, isWhiteTurn);
|
|
383
|
-
if (!parsedMove) {
|
|
384
|
-
return { error: 'Invalid move notation' };
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
const { from, to, type } = parsedMove;
|
|
388
|
-
const [fromRank, fromFile] = from;
|
|
389
|
-
const [toRank, toFile] = to;
|
|
390
|
-
|
|
391
|
-
// Get the piece being moved
|
|
392
|
-
const piece = board[fromRank][fromFile];
|
|
393
|
-
if (!piece) {
|
|
394
|
-
return { error: 'No piece at source square' };
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Check if it's the correct player's piece
|
|
398
|
-
const isPieceWhite = piece >= 'A' && piece <= 'Z';
|
|
399
|
-
if (isPieceWhite !== isWhiteTurn) {
|
|
400
|
-
return { error: 'Not your piece' };
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// Create new board state
|
|
404
|
-
const newBoard = board.map(row => [...row]);
|
|
405
|
-
newBoard[fromRank][fromFile] = '';
|
|
406
|
-
newBoard[toRank][toFile] = piece;
|
|
407
|
-
|
|
408
|
-
// Handle castling
|
|
409
|
-
if (type === 'castle-short') {
|
|
410
|
-
const rookFromFile = 7;
|
|
411
|
-
const rookToFile = 5;
|
|
412
|
-
const rankIndex = isWhiteTurn ? 7 : 0;
|
|
413
|
-
newBoard[rankIndex][rookFromFile] = '';
|
|
414
|
-
newBoard[rankIndex][rookToFile] = isWhiteTurn ? 'R' : 'r';
|
|
415
|
-
} else if (type === 'castle-long') {
|
|
416
|
-
const rookFromFile = 0;
|
|
417
|
-
const rookToFile = 3;
|
|
418
|
-
const rankIndex = isWhiteTurn ? 7 : 0;
|
|
419
|
-
newBoard[rankIndex][rookFromFile] = '';
|
|
420
|
-
newBoard[rankIndex][rookToFile] = isWhiteTurn ? 'R' : 'r';
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// Check game end state for opponent
|
|
424
|
-
const nextPlayerIsWhite = !isWhiteTurn;
|
|
425
|
-
const endState = getGameEndState(newBoard, nextPlayerIsWhite);
|
|
426
|
-
|
|
427
|
-
const newGameState = {
|
|
428
|
-
board: newBoard,
|
|
429
|
-
turn: isWhiteTurn ? 'black' : 'white',
|
|
430
|
-
moves: moves + 1,
|
|
431
|
-
history: [...history, moveNotation],
|
|
432
|
-
check: endState.check || false,
|
|
433
|
-
checkmate: endState.checkmate || false,
|
|
434
|
-
stalemate: endState.stalemate || false,
|
|
435
|
-
winner: endState.winner || null,
|
|
436
|
-
lastMove: { from, to, notation: moveNotation }
|
|
437
|
-
};
|
|
438
|
-
|
|
439
|
-
return { success: true, gameState: newGameState };
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
module.exports = {
|
|
443
|
-
createInitialChessState,
|
|
444
|
-
makeMove,
|
|
445
|
-
formatChessBoard,
|
|
446
|
-
parseAlgebraicNotation,
|
|
447
|
-
moveToAlgebraicNotation,
|
|
448
|
-
isKingInCheck,
|
|
449
|
-
getAllLegalMoves,
|
|
450
|
-
getGameEndState
|
|
451
|
-
};
|