koishi-plugin-cchess 1.0.2 → 1.0.4
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/lib/index.d.ts +1 -1
- package/lib/index.js +705 -979
- package/package.json +6 -6
- package/readme.md +22 -45
package/lib/index.js
CHANGED
|
@@ -41,32 +41,22 @@ var import_koishi = require("koishi");
|
|
|
41
41
|
var path = __toESM(require("path"));
|
|
42
42
|
var fs = __toESM(require("fs"));
|
|
43
43
|
var name = "cchess";
|
|
44
|
-
var usage = `##
|
|
44
|
+
var usage = `## 使用
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- 支持使用中国象棋纵线(炮二平五/炮8平5)和字母坐标(a0a1)进行移动。[了解详情 - 中国象棋着法表示](https://www.xqbase.com/protocol/cchess_move.htm)
|
|
46
|
+
1. 安装 \`puppeteer\` 服务。
|
|
47
|
+
2. 设置指令别名。
|
|
49
48
|
|
|
50
|
-
##
|
|
49
|
+
## Q&A
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
- \`cchess.结束\`: 强制结束本局游戏。
|
|
54
|
-
- \`cchess.认输\`: 认输结束本局游戏。
|
|
55
|
-
- \`cchess.排行榜.总胜/输场\`: 请求悔棋操作。
|
|
56
|
-
- \`cchess.开始.人人对战\`: 开始人人对战模式。
|
|
57
|
-
- \`cchess.开始.人机对战\`: 开始人机对战模式。
|
|
58
|
-
- \`cchess.悔棋.请求/同意/拒绝\`: 请求悔棋操作。
|
|
59
|
-
- \`cchess.加入 [红/黑]\`: 加入游戏,可选红/黑方。
|
|
60
|
-
- \`cchess.移动 [纵线/字母坐标]\`: 通过指令移动棋子。
|
|
61
|
-
- \`cchess.查看云库残局.DTM统计/DTC统计\`: 查看云库残局统计。
|
|
62
|
-
- \`cchess.查询玩家记录 [@某人 或 不填则查自己]\`: 查询玩家记录。
|
|
63
|
-
- \`cchess.编辑棋盘.导入/导出/使用方法\`: 导入/导出棋盘状态与fen使用方法。
|
|
51
|
+
1. 如何移动棋子?
|
|
64
52
|
|
|
65
|
-
|
|
53
|
+
- 纵线(炮二平五/炮8平5)或字母坐标(a0a1)。
|
|
54
|
+
- 详见 [中国象棋着法表示](https://www.xqbase.com/protocol/cchess_move.htm)。
|
|
55
|
+
|
|
56
|
+
## QQ 群
|
|
66
57
|
|
|
67
58
|
- 956758505`;
|
|
68
59
|
var inject = {
|
|
69
|
-
// required: ['monetary', 'database', 'puppeteer', 'canvas'],
|
|
70
60
|
required: ["database", "puppeteer", "canvas"],
|
|
71
61
|
optional: ["markdownToImage"]
|
|
72
62
|
};
|
|
@@ -75,8 +65,8 @@ var boardSkins = ["棋弈无限红绿棋盘", "一鸣惊人棋盘", "三星堆
|
|
|
75
65
|
var Config = import_koishi.Schema.object({
|
|
76
66
|
boardSkin: import_koishi.Schema.union(boardSkins).default("象甲2023棋盘").description(`棋盘皮肤。`),
|
|
77
67
|
pieceSkin: import_koishi.Schema.union(pieceSkins).default("象甲棋子").description(`棋子皮肤。`),
|
|
78
|
-
allowFreePieceMovementInHumanMachineMode: import_koishi.Schema.boolean().default(false).description(
|
|
79
|
-
defaultEngineThinkingDepth: import_koishi.Schema.number().min(0).max(100).default(10).description(
|
|
68
|
+
allowFreePieceMovementInHumanMachineMode: import_koishi.Schema.boolean().default(false).description(`是否允许在人机模式下所有用户都可以自由移动棋子,开启后可以不需要加入游戏直接开始玩人机模式。`),
|
|
69
|
+
defaultEngineThinkingDepth: import_koishi.Schema.number().min(0).max(100).default(10).description(`默认引擎思考深度,最小为 0,最大为 100,越高 AI 棋力越强。由于 Nodejs 不支持 SIMD,所以不建议设置过高。`),
|
|
80
70
|
defaultMaxLeaderboardEntries: import_koishi.Schema.number().min(0).default(10).description(`显示排行榜时默认的最大人数。`),
|
|
81
71
|
retractDelay: import_koishi.Schema.number().min(0).default(0).description(`自动撤回等待的时间,单位是秒。值为 0 时不启用自动撤回功能。`),
|
|
82
72
|
imgScale: import_koishi.Schema.number().min(1).default(1).description(`图片分辨率倍率。`),
|
|
@@ -91,29 +81,26 @@ function apply(ctx, config) {
|
|
|
91
81
|
const channelIds = Object.keys(engines);
|
|
92
82
|
channelIds.forEach((channelId) => {
|
|
93
83
|
if (engines[channelId]) {
|
|
94
|
-
|
|
84
|
+
try {
|
|
85
|
+
engines[channelId].send_command("quit");
|
|
86
|
+
} catch (e) {
|
|
87
|
+
}
|
|
95
88
|
engines[channelId] = null;
|
|
96
89
|
}
|
|
97
90
|
});
|
|
98
91
|
});
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
const
|
|
105
|
-
const ye = 550;
|
|
106
|
-
const ze = 500;
|
|
107
|
-
const ke = 120;
|
|
108
|
-
const weight = 500;
|
|
109
|
-
const height = 550;
|
|
92
|
+
const CELL_WIDTH = 54;
|
|
93
|
+
const ARROW_OFFSET = 33;
|
|
94
|
+
const BOARD_PADDING = 33;
|
|
95
|
+
const PIECE_SIZE = 50;
|
|
96
|
+
const BOARD_WIDTH = 500;
|
|
97
|
+
const BOARD_HEIGHT = 550;
|
|
110
98
|
const scale = config.imgScale;
|
|
111
99
|
const isFlipBoard = false;
|
|
112
100
|
const engineSettings = {
|
|
113
101
|
Threads: 1,
|
|
114
102
|
Hash: 128,
|
|
115
103
|
MultiPV: 1
|
|
116
|
-
// "Skill Level": 20,
|
|
117
104
|
};
|
|
118
105
|
const thinkingSettings = {
|
|
119
106
|
moveTime: 1,
|
|
@@ -135,7 +122,6 @@ function apply(ctx, config) {
|
|
|
135
122
|
isDraw: { type: "boolean", initial: false },
|
|
136
123
|
winSide: { type: "string", initial: "" },
|
|
137
124
|
loseSide: { type: "string", initial: "" },
|
|
138
|
-
// lastPV: {type: 'json', initial: null},
|
|
139
125
|
originalState: { type: "json", initial: {} },
|
|
140
126
|
thinkingDetail: { type: "json", initial: [] },
|
|
141
127
|
currentMoveId: { type: "string", initial: "" },
|
|
@@ -144,14 +130,12 @@ function apply(ctx, config) {
|
|
|
144
130
|
isAnalyzing: { type: "boolean", initial: false },
|
|
145
131
|
turnAfterLastEat: { type: "string", initial: "w" },
|
|
146
132
|
isEngineReady: { type: "boolean", initial: false },
|
|
147
|
-
// multiPvInfoBuffer: {type: 'json', initial: {}},
|
|
148
133
|
isEnginePlayRed: { type: "boolean", initial: false },
|
|
149
134
|
isEngineAnalyze: { type: "boolean", initial: false },
|
|
150
135
|
isRegretRequest: { type: "boolean", initial: false },
|
|
151
136
|
lastMove: { type: "json", initial: [[0, 0], [0, 0]] },
|
|
152
137
|
isEnginePlayBlack: { type: "boolean", initial: false },
|
|
153
138
|
ponderHint: { type: "json", initial: [[0, 0], [0, 0]] },
|
|
154
|
-
// bestMoveHint: {type: 'json', initial: [[0, 0], [0, 0]]},
|
|
155
139
|
fen: { type: "string", initial: "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w" },
|
|
156
140
|
startFen: { type: "string", initial: "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w" },
|
|
157
141
|
board: { type: "json", initial: fenToBoard("rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w") },
|
|
@@ -229,20 +213,18 @@ function apply(ctx, config) {
|
|
|
229
213
|
if (gameRecord.isStarted) {
|
|
230
214
|
const buffer = await drawChessBoard(channelId);
|
|
231
215
|
const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
|
|
232
|
-
return await sendMessage(session,
|
|
216
|
+
return await sendMessage(session, `**【@${username}】**
|
|
233
217
|
游戏已经开始啦!
|
|
234
218
|
${hImg}`);
|
|
235
219
|
}
|
|
236
220
|
await checkEngine(channelId);
|
|
237
221
|
if (engines[channelId] && !gameRecord.isEngineReady) {
|
|
238
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
239
|
-
isEngineReady: true
|
|
240
|
-
});
|
|
222
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isEngineReady: true });
|
|
241
223
|
}
|
|
242
224
|
if (!choice) {
|
|
243
225
|
choice = Math.random() < 0.5 ? "红方" : "黑方";
|
|
244
226
|
} else if (choice.includes("红") && choice.includes("黑")) {
|
|
245
|
-
return await sendMessage(session,
|
|
227
|
+
return await sendMessage(session, `**【@${username}】**
|
|
246
228
|
一次只能选择一方哦!`);
|
|
247
229
|
} else if (choice.includes("红")) {
|
|
248
230
|
choice = "红方";
|
|
@@ -256,19 +238,19 @@ ${hImg}`);
|
|
|
256
238
|
const playersNum = getPlayerRecords.length;
|
|
257
239
|
if (getPlayerRecord.length === 0) {
|
|
258
240
|
await ctx.database.create("cchess_gaming_player_records", { channelId, userId, username, side: choice });
|
|
259
|
-
return await sendMessage(session,
|
|
241
|
+
return await sendMessage(session, `**【@${username}】**
|
|
260
242
|
您加入游戏啦!
|
|
261
|
-
|
|
262
|
-
|
|
243
|
+
您的队伍为:**【${choice}】**
|
|
244
|
+
当前玩家人数为:**【${playersNum + 1}】**
|
|
263
245
|
带“黑”或“红”加入游戏可以更换队伍哦~
|
|
264
246
|
例如:
|
|
265
247
|
- 加入指令 红
|
|
266
248
|
- 加入指令 黑`);
|
|
267
249
|
} else {
|
|
268
250
|
await ctx.database.set("cchess_gaming_player_records", { channelId, userId }, { side: choice });
|
|
269
|
-
return await sendMessage(session,
|
|
270
|
-
|
|
271
|
-
|
|
251
|
+
return await sendMessage(session, `**【@${username}】**
|
|
252
|
+
您已更换队伍为:**【${choice}】**
|
|
253
|
+
当前玩家人数为:**【${playersNum}】**`);
|
|
272
254
|
}
|
|
273
255
|
});
|
|
274
256
|
ctx.command("cchess.退出", "退出游戏").action(async ({ session }) => {
|
|
@@ -276,27 +258,22 @@ ${hImg}`);
|
|
|
276
258
|
await updateNameInPlayerRecord(userId, username);
|
|
277
259
|
const gameRecord = await getGameRecord(channelId);
|
|
278
260
|
if (gameRecord.isStarted) {
|
|
279
|
-
return await sendMessage(session,
|
|
261
|
+
return await sendMessage(session, `**【@${username}】**
|
|
280
262
|
游戏已经开始啦~
|
|
281
263
|
不许逃跑哦!`);
|
|
282
264
|
}
|
|
283
265
|
await checkEngine(channelId);
|
|
284
|
-
if (engines[channelId] && !gameRecord.isEngineReady) {
|
|
285
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
286
|
-
isEngineReady: true
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
266
|
const getPlayerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
|
|
290
267
|
const getPlayerRecords = await ctx.database.get("cchess_gaming_player_records", { channelId });
|
|
291
268
|
const playersNum = getPlayerRecords.length;
|
|
292
269
|
if (getPlayerRecord.length === 0) {
|
|
293
|
-
return await sendMessage(session,
|
|
270
|
+
return await sendMessage(session, `**【@${username}】**
|
|
294
271
|
您还未加入游戏呢!`);
|
|
295
272
|
} else {
|
|
296
273
|
await ctx.database.remove("cchess_gaming_player_records", { channelId, userId });
|
|
297
|
-
return await sendMessage(session,
|
|
274
|
+
return await sendMessage(session, `**【@${username}】**
|
|
298
275
|
您已退出游戏!
|
|
299
|
-
|
|
276
|
+
剩余玩家人数为:**【${playersNum - 1}】**`);
|
|
300
277
|
}
|
|
301
278
|
});
|
|
302
279
|
ctx.command("cchess.开始", "开始游戏指令帮助").action(async ({ session }) => {
|
|
@@ -307,33 +284,28 @@ ${hImg}`);
|
|
|
307
284
|
await updateNameInPlayerRecord(userId, username);
|
|
308
285
|
const gameRecord = await getGameRecord(channelId);
|
|
309
286
|
if (gameRecord.isStarted) {
|
|
310
|
-
return await sendMessage(session,
|
|
287
|
+
return await sendMessage(session, `**【@${username}】**
|
|
311
288
|
游戏已经开始啦!`);
|
|
312
289
|
}
|
|
313
290
|
await checkEngine(channelId);
|
|
314
|
-
if (engines[channelId] && !gameRecord.isEngineReady) {
|
|
315
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
316
|
-
isEngineReady: true
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
291
|
const getPlayerRecords = await ctx.database.get("cchess_gaming_player_records", { channelId });
|
|
320
292
|
const playersNum = getPlayerRecords.length;
|
|
321
293
|
let redPlayers = getPlayerRecords.filter((player) => player.side === "红方");
|
|
322
294
|
let blackPlayers = getPlayerRecords.filter((player) => player.side === "黑方");
|
|
323
295
|
let message = "";
|
|
324
296
|
if (playersNum < 2) {
|
|
325
|
-
return await sendMessage(session,
|
|
297
|
+
return await sendMessage(session, `**【@${username}】**
|
|
326
298
|
当前玩家人数不足 2 人,无法开始游戏!`);
|
|
327
299
|
} else {
|
|
328
300
|
if (redPlayers.length !== 1 || blackPlayers.length !== 1) {
|
|
329
301
|
const randomPlayer = getPlayerRecords[Math.floor(Math.random() * getPlayerRecords.length)];
|
|
330
302
|
if (redPlayers.length < 1) {
|
|
331
303
|
randomPlayer.side = "红方";
|
|
332
|
-
message +=
|
|
304
|
+
message += `**【@${randomPlayer.username}】**被自动分配到红方。
|
|
333
305
|
`;
|
|
334
306
|
} else {
|
|
335
307
|
randomPlayer.side = "黑方";
|
|
336
|
-
message +=
|
|
308
|
+
message += `**【@${randomPlayer.username}】**被自动分配到黑方。
|
|
337
309
|
`;
|
|
338
310
|
}
|
|
339
311
|
await ctx.database.set("cchess_gaming_player_records", {
|
|
@@ -344,21 +316,19 @@ ${hImg}`);
|
|
|
344
316
|
blackPlayers = getPlayerRecords.filter((player) => player.side === "黑方");
|
|
345
317
|
}
|
|
346
318
|
message += `红方玩家(${redPlayers.length}):
|
|
347
|
-
${redPlayers.map((player) =>
|
|
319
|
+
${redPlayers.map((player) => `**【@${player.username}】**`).join("\n")}
|
|
348
320
|
|
|
349
321
|
`;
|
|
350
322
|
message += `黑方玩家(${blackPlayers.length}):
|
|
351
|
-
${blackPlayers.map((player) =>
|
|
352
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
353
|
-
isStarted: true
|
|
354
|
-
});
|
|
323
|
+
${blackPlayers.map((player) => `**【@${player.username}】**`).join("\n")}`;
|
|
324
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isStarted: true });
|
|
355
325
|
const turn = gameRecord.turn;
|
|
356
326
|
const sideString = convertTurnToString(turn);
|
|
357
327
|
const buffer = await drawChessBoard(channelId);
|
|
358
328
|
const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
|
|
359
|
-
return await sendMessage(session,
|
|
329
|
+
return await sendMessage(session, `### 游戏开始!
|
|
360
330
|
${message}
|
|
361
|
-
|
|
331
|
+
先手方为:**【${sideString}】**
|
|
362
332
|
${hImg}`);
|
|
363
333
|
}
|
|
364
334
|
});
|
|
@@ -367,15 +337,10 @@ ${hImg}`);
|
|
|
367
337
|
await updateNameInPlayerRecord(userId, username);
|
|
368
338
|
const gameRecord = await getGameRecord(channelId);
|
|
369
339
|
if (gameRecord.isStarted) {
|
|
370
|
-
return await sendMessage(session,
|
|
340
|
+
return await sendMessage(session, `**【@${username}】**
|
|
371
341
|
游戏已经开始啦!`);
|
|
372
342
|
}
|
|
373
343
|
await checkEngine(channelId);
|
|
374
|
-
if (engines[channelId] && !gameRecord.isEngineReady) {
|
|
375
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
376
|
-
isEngineReady: true
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
344
|
const getPlayerRecords = await ctx.database.get("cchess_gaming_player_records", { channelId });
|
|
380
345
|
const playersNum = getPlayerRecords.length;
|
|
381
346
|
let redPlayers = getPlayerRecords.filter((player) => player.side === "红方");
|
|
@@ -383,48 +348,42 @@ ${hImg}`);
|
|
|
383
348
|
let message = "";
|
|
384
349
|
let AISide = "";
|
|
385
350
|
if (playersNum < 1 && !config.allowFreePieceMovementInHumanMachineMode) {
|
|
386
|
-
return await sendMessage(session,
|
|
351
|
+
return await sendMessage(session, `**【@${username}】**
|
|
387
352
|
当前玩家人数不足 1 人,无法开始游戏!`);
|
|
388
353
|
} else {
|
|
389
354
|
if (playersNum === 1) {
|
|
390
355
|
if (getPlayerRecords[0].side === "红方") {
|
|
391
356
|
await ctx.database.set("cchess_game_records", { channelId }, { isEnginePlayBlack: true });
|
|
392
357
|
AISide = "黑方";
|
|
393
|
-
message +=
|
|
358
|
+
message += `人类队伍为:**【红方】**
|
|
394
359
|
`;
|
|
395
360
|
} else {
|
|
396
361
|
await ctx.database.set("cchess_game_records", { channelId }, { isEnginePlayRed: true });
|
|
397
362
|
AISide = "红方";
|
|
398
|
-
message +=
|
|
363
|
+
message += `人类队伍为:**【黑方】**
|
|
399
364
|
`;
|
|
400
365
|
}
|
|
401
366
|
} else {
|
|
402
367
|
if (redPlayers.length > blackPlayers.length) {
|
|
403
368
|
await ctx.database.set("cchess_game_records", { channelId }, { isEnginePlayBlack: true });
|
|
404
369
|
AISide = "黑方";
|
|
405
|
-
message +=
|
|
370
|
+
message += `人类队伍为:**【红方】**
|
|
406
371
|
`;
|
|
407
372
|
for (const player of blackPlayers) {
|
|
408
|
-
await ctx.database.set("cchess_gaming_player_records", {
|
|
409
|
-
channelId,
|
|
410
|
-
userId: player.userId
|
|
411
|
-
}, { side: "红方" });
|
|
373
|
+
await ctx.database.set("cchess_gaming_player_records", { channelId, userId: player.userId }, { side: "红方" });
|
|
412
374
|
}
|
|
413
375
|
} else if (redPlayers.length < blackPlayers.length) {
|
|
414
376
|
await ctx.database.set("cchess_game_records", { channelId }, { isEnginePlayRed: true });
|
|
415
377
|
AISide = "红方";
|
|
416
|
-
message +=
|
|
378
|
+
message += `人类队伍为:**【黑方】**
|
|
417
379
|
`;
|
|
418
380
|
for (const player of redPlayers) {
|
|
419
|
-
await ctx.database.set("cchess_gaming_player_records", {
|
|
420
|
-
channelId,
|
|
421
|
-
userId: player.userId
|
|
422
|
-
}, { side: "黑方" });
|
|
381
|
+
await ctx.database.set("cchess_gaming_player_records", { channelId, userId: player.userId }, { side: "黑方" });
|
|
423
382
|
}
|
|
424
383
|
}
|
|
425
384
|
if (redPlayers.length === blackPlayers.length) {
|
|
426
385
|
const side = Math.random() < 0.5 ? "红方" : "黑方";
|
|
427
|
-
message +=
|
|
386
|
+
message += `人类队伍为:**【${side}】**
|
|
428
387
|
`;
|
|
429
388
|
const computerSide = side === "红方" ? "黑方" : "红方";
|
|
430
389
|
AISide = computerSide;
|
|
@@ -437,29 +396,23 @@ ${hImg}`);
|
|
|
437
396
|
}
|
|
438
397
|
}
|
|
439
398
|
}
|
|
440
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
441
|
-
isStarted: true
|
|
442
|
-
});
|
|
399
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isStarted: true });
|
|
443
400
|
const turn = gameRecord.turn;
|
|
444
401
|
const sideString = convertTurnToString(turn);
|
|
445
402
|
if (AISide === sideString) {
|
|
446
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
447
|
-
isAnalyzing: true
|
|
448
|
-
});
|
|
403
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isAnalyzing: true });
|
|
449
404
|
await engineAction(channelId);
|
|
450
405
|
while (true) {
|
|
451
406
|
const gameRecord2 = await getGameRecord(channelId);
|
|
452
|
-
if (!gameRecord2.isAnalyzing)
|
|
453
|
-
break;
|
|
454
|
-
}
|
|
407
|
+
if (!gameRecord2.isAnalyzing) break;
|
|
455
408
|
await (0, import_koishi.sleep)(500);
|
|
456
409
|
}
|
|
457
410
|
}
|
|
458
411
|
const buffer = await drawChessBoard(channelId);
|
|
459
412
|
const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
|
|
460
|
-
return await sendMessage(session,
|
|
413
|
+
return await sendMessage(session, `### 游戏开始!
|
|
461
414
|
${message}
|
|
462
|
-
|
|
415
|
+
先手方为:**【${sideString}】**
|
|
463
416
|
${hImg}`);
|
|
464
417
|
}
|
|
465
418
|
});
|
|
@@ -468,177 +421,153 @@ ${hImg}`);
|
|
|
468
421
|
await updateNameInPlayerRecord(userId, username);
|
|
469
422
|
const gameRecord = await getGameRecord(channelId);
|
|
470
423
|
await checkEngine(channelId);
|
|
471
|
-
if (engines[channelId] && !gameRecord.isEngineReady) {
|
|
472
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
473
|
-
isEngineReady: true
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
424
|
if (!gameRecord.isStarted) {
|
|
477
|
-
return await sendMessage(session,
|
|
425
|
+
return await sendMessage(session, `**【@${username}】**
|
|
478
426
|
游戏未开始哦!
|
|
479
427
|
完全没必要强制结束嘛~`);
|
|
480
428
|
} else {
|
|
481
429
|
await endGame(channelId);
|
|
482
|
-
return await sendMessage(session,
|
|
430
|
+
return await sendMessage(session, `**【@${username}】**
|
|
483
431
|
游戏已被强制结束!`);
|
|
484
432
|
}
|
|
485
433
|
});
|
|
486
|
-
ctx.command("cchess.移动 <moveOperation:text>", "进行移动操作").action(
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
return await sendMessage(session, `【@${username}】
|
|
434
|
+
ctx.command("cchess.移动 <moveOperation:text>", "进行移动操作").action(async ({ session }, moveOperation) => {
|
|
435
|
+
const { username, userId, channelId } = session;
|
|
436
|
+
await updateNameInPlayerRecord(userId, username);
|
|
437
|
+
if (!isMoveString(moveOperation) && !isValidFigureMoveName(moveOperation)) {
|
|
438
|
+
return await sendMessage(session, `**【@${username}】**
|
|
492
439
|
无效的移动!`);
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
440
|
+
}
|
|
441
|
+
const gameRecord = await getGameRecord(channelId);
|
|
442
|
+
if (!gameRecord.isStarted) {
|
|
443
|
+
return await sendMessage(session, `**【@${username}】**
|
|
497
444
|
游戏还未开始哦!`);
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
445
|
+
}
|
|
446
|
+
if (gameRecord.isRegretRequest) {
|
|
447
|
+
return await sendMessage(session, `**【@${username}】**
|
|
501
448
|
正在请求悔棋,等待回应中...`);
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
}
|
|
515
|
-
} else {
|
|
516
|
-
return await sendMessage(session, `【@${username}】
|
|
517
|
-
您还未加入游戏呢!`);
|
|
449
|
+
}
|
|
450
|
+
const turn = gameRecord.turn;
|
|
451
|
+
const sideString = convertTurnToString(turn);
|
|
452
|
+
let playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
|
|
453
|
+
if (playerRecord.length === 0) {
|
|
454
|
+
if (config.allowFreePieceMovementInHumanMachineMode) {
|
|
455
|
+
const record = { channelId, userId, username, side: "" };
|
|
456
|
+
if (gameRecord.isEnginePlayRed) record.side = "黑方";
|
|
457
|
+
else if (gameRecord.isEnginePlayBlack) record.side = "红方";
|
|
458
|
+
if (record.side) {
|
|
459
|
+
await ctx.database.create("cchess_gaming_player_records", record);
|
|
460
|
+
playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
|
|
518
461
|
}
|
|
462
|
+
} else {
|
|
463
|
+
return await sendMessage(session, `**【@${username}】**
|
|
464
|
+
您还未加入游戏呢!`);
|
|
519
465
|
}
|
|
520
|
-
|
|
521
|
-
|
|
466
|
+
}
|
|
467
|
+
if (playerRecord.length === 0 || playerRecord[0].side !== sideString) {
|
|
468
|
+
return await sendMessage(session, `**【@${username}】**
|
|
522
469
|
还没轮到${sideString}走棋哦!
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
const
|
|
537
|
-
const
|
|
538
|
-
const
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
const
|
|
544
|
-
const
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
moveInfoList.push({
|
|
551
|
-
moveCord: [[pos[1], pos[0]], [toPos[1], toPos[0]]],
|
|
552
|
-
moveString,
|
|
553
|
-
figureMoveName
|
|
554
|
-
});
|
|
555
|
-
}
|
|
470
|
+
当前走棋方为:**【${convertTurnToString(gameRecord.turn)}】**`);
|
|
471
|
+
}
|
|
472
|
+
await checkEngine(channelId);
|
|
473
|
+
const board = gameRecord.board;
|
|
474
|
+
let selectedPos = void 0;
|
|
475
|
+
let newPos = void 0;
|
|
476
|
+
if (possibleFigureNames.some((figureName) => moveOperation.includes(figureName))) {
|
|
477
|
+
const figureName = getFigureNameFromMoveOperation(moveOperation);
|
|
478
|
+
const englishLetter = getEnglishLetterFromFigureName(figureName);
|
|
479
|
+
const processedLetter = processEnglishLetter(englishLetter, turn);
|
|
480
|
+
const letterPositions = findLetterPositions(board, processedLetter);
|
|
481
|
+
const moveInfoList = [];
|
|
482
|
+
for (const pos of letterPositions) {
|
|
483
|
+
const piece2 = processedLetter;
|
|
484
|
+
const side2 = getSide(piece2);
|
|
485
|
+
const type2 = getType(piece2);
|
|
486
|
+
const moveMap2 = getValidMoveMap(board, type2, side2, [pos[1], pos[0]]);
|
|
487
|
+
const legalPositions = findLegalMovePositions(moveMap2);
|
|
488
|
+
const fen = getFen(board, side2);
|
|
489
|
+
for (const toPos of legalPositions) {
|
|
490
|
+
const moveString = moveToMoveString([[pos[1], pos[0]], [toPos[1], toPos[0]]]);
|
|
491
|
+
const figureMoveName = getFigureMoveName(fen, moveString);
|
|
492
|
+
moveInfoList.push({
|
|
493
|
+
moveCord: [[pos[1], pos[0]], [toPos[1], toPos[0]]],
|
|
494
|
+
moveString,
|
|
495
|
+
figureMoveName
|
|
496
|
+
});
|
|
556
497
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
498
|
+
}
|
|
499
|
+
const duplicateMoveInfo = findMoveInfo(moveInfoList, moveOperation);
|
|
500
|
+
if (!duplicateMoveInfo) {
|
|
501
|
+
return await sendMessage(session, `**【@${username}】**
|
|
560
502
|
无效的移动!`);
|
|
561
|
-
} else {
|
|
562
|
-
[selectedPos, newPos] = duplicateMoveInfo.moveCord;
|
|
563
|
-
}
|
|
564
503
|
} else {
|
|
565
|
-
[selectedPos, newPos] =
|
|
504
|
+
[selectedPos, newPos] = duplicateMoveInfo.moveCord;
|
|
566
505
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
506
|
+
} else {
|
|
507
|
+
[selectedPos, newPos] = moveStringToPos(moveOperation);
|
|
508
|
+
}
|
|
509
|
+
const [newCol, newRow] = newPos;
|
|
510
|
+
const piece = getPiece(board, selectedPos);
|
|
511
|
+
const side = getSide(piece);
|
|
512
|
+
const type = getType(piece);
|
|
513
|
+
if (side !== gameRecord.turn) {
|
|
514
|
+
return await sendMessage(session, `**【@${username}】**
|
|
573
515
|
还没轮到${convertTurnToString(side)}走棋哦!
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
516
|
+
当前走棋方为:**【${convertTurnToString(gameRecord.turn)}】**`);
|
|
517
|
+
}
|
|
518
|
+
const moveMap = getValidMoveMap(board, type, side, selectedPos);
|
|
519
|
+
if (moveMap[newRow][newCol] !== "go" && moveMap[newRow][newCol] !== "eat") {
|
|
520
|
+
return await sendMessage(session, `**【@${username}】**
|
|
579
521
|
无效的移动!`);
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
await
|
|
522
|
+
}
|
|
523
|
+
await makeMove(channelId, selectedPos, newPos);
|
|
524
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isAnalyzing: true });
|
|
525
|
+
await engineAction(channelId);
|
|
526
|
+
while (true) {
|
|
527
|
+
const gameRecord2 = await getGameRecord(channelId);
|
|
528
|
+
if (!gameRecord2.isAnalyzing) break;
|
|
529
|
+
await (0, import_koishi.sleep)(500);
|
|
530
|
+
}
|
|
531
|
+
const newGameRecord = await getGameRecord(channelId);
|
|
532
|
+
if (newGameRecord.winSide !== "") {
|
|
533
|
+
const buffer2 = await drawChessBoard(channelId);
|
|
534
|
+
const hImg2 = import_koishi.h.image(buffer2, `image/${config.imageType}`);
|
|
535
|
+
await updatePlayerRecords(channelId, newGameRecord.winSide, newGameRecord.loseSide);
|
|
536
|
+
await endGame(channelId);
|
|
537
|
+
return await sendMessage(session, `**【@${username}】**
|
|
538
|
+
### 绝杀!
|
|
539
|
+
游戏结束!
|
|
540
|
+
获胜方为:**【${convertTurnToString(newGameRecord.winSide)}】**
|
|
541
|
+
${hImg2}`);
|
|
542
|
+
}
|
|
543
|
+
if (gameRecord.isEnginePlayRed || gameRecord.isEnginePlayBlack) {
|
|
544
|
+
const gameRecordAfterMove = await getGameRecord(channelId);
|
|
545
|
+
let { movesAfterLastEat, boardAfterLastEat, turnAfterLastEat } = gameRecordAfterMove;
|
|
546
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isAnalyzing: true });
|
|
547
|
+
await sendCommand(channelId, "fen " + getFenWithMove(movesAfterLastEat, boardAfterLastEat, turnAfterLastEat));
|
|
548
|
+
await go(channelId, 1e3 * thinkingSettings["movetime"], thinkingSettings["depth"], -1);
|
|
586
549
|
while (true) {
|
|
587
|
-
const
|
|
588
|
-
if (!
|
|
589
|
-
break;
|
|
590
|
-
}
|
|
550
|
+
const rec = await getGameRecord(channelId);
|
|
551
|
+
if (!rec.isAnalyzing) break;
|
|
591
552
|
await (0, import_koishi.sleep)(500);
|
|
592
553
|
}
|
|
593
|
-
const
|
|
594
|
-
if (
|
|
554
|
+
const engineResultRecord = await getGameRecord(channelId);
|
|
555
|
+
if (engineResultRecord.winSide !== "") {
|
|
595
556
|
const buffer2 = await drawChessBoard(channelId);
|
|
596
557
|
const hImg2 = import_koishi.h.image(buffer2, `image/${config.imageType}`);
|
|
597
|
-
await updatePlayerRecords(channelId,
|
|
558
|
+
await updatePlayerRecords(channelId, engineResultRecord.winSide, engineResultRecord.loseSide);
|
|
598
559
|
await endGame(channelId);
|
|
599
|
-
return await sendMessage(session,
|
|
600
|
-
绝杀!
|
|
601
|
-
游戏结束!
|
|
602
|
-
获胜方为:【${convertTurnToString(newGameRecord.winSide)}】
|
|
603
|
-
${hImg2}`);
|
|
604
|
-
}
|
|
605
|
-
if (gameRecord.isEnginePlayRed || gameRecord.isEnginePlayBlack) {
|
|
606
|
-
const gameRecord2 = await getGameRecord(channelId);
|
|
607
|
-
let {
|
|
608
|
-
movesAfterLastEat,
|
|
609
|
-
boardAfterLastEat,
|
|
610
|
-
turnAfterLastEat
|
|
611
|
-
// multiPvInfoBuffer
|
|
612
|
-
} = gameRecord2;
|
|
613
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
614
|
-
isAnalyzing: true
|
|
615
|
-
});
|
|
616
|
-
await sendCommand(channelId, "fen " + getFenWithMove(movesAfterLastEat, boardAfterLastEat, turnAfterLastEat)), await go(channelId, 1e3 * thinkingSettings["movetime"], thinkingSettings["depth"], -1);
|
|
617
|
-
while (true) {
|
|
618
|
-
const gameRecord3 = await getGameRecord(channelId);
|
|
619
|
-
if (!gameRecord3.isAnalyzing) {
|
|
620
|
-
break;
|
|
621
|
-
}
|
|
622
|
-
await (0, import_koishi.sleep)(500);
|
|
623
|
-
}
|
|
624
|
-
const newGameRecord2 = await getGameRecord(channelId);
|
|
625
|
-
if (newGameRecord2.winSide !== "") {
|
|
626
|
-
const buffer2 = await drawChessBoard(channelId);
|
|
627
|
-
const hImg2 = import_koishi.h.image(buffer2, `image/${config.imageType}`);
|
|
628
|
-
await updatePlayerRecords(channelId, newGameRecord2.winSide, newGameRecord2.loseSide);
|
|
629
|
-
await endGame(channelId);
|
|
630
|
-
return await sendMessage(session, `【@${username}】
|
|
631
|
-
绝杀!
|
|
560
|
+
return await sendMessage(session, `**【@${username}】**
|
|
561
|
+
### 绝杀!
|
|
632
562
|
游戏结束!
|
|
633
|
-
|
|
563
|
+
获胜方为:**【${convertTurnToString(engineResultRecord.winSide)}】**
|
|
634
564
|
${hImg2}`);
|
|
635
|
-
}
|
|
636
565
|
}
|
|
637
|
-
const buffer = await drawChessBoard(channelId);
|
|
638
|
-
const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
|
|
639
|
-
return await sendMessage(session, `${hImg}`);
|
|
640
566
|
}
|
|
641
|
-
|
|
567
|
+
const buffer = await drawChessBoard(channelId);
|
|
568
|
+
const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
|
|
569
|
+
return await sendMessage(session, `${hImg}`);
|
|
570
|
+
});
|
|
642
571
|
ctx.command("cchess.悔棋", "悔棋指令帮助").action(async ({ session }) => {
|
|
643
572
|
await session.execute(`cchess.悔棋 -h`);
|
|
644
573
|
});
|
|
@@ -647,32 +576,27 @@ ${hImg2}`);
|
|
|
647
576
|
await updateNameInPlayerRecord(userId, username);
|
|
648
577
|
const gameRecord = await getGameRecord(channelId);
|
|
649
578
|
if (!gameRecord.isStarted) {
|
|
650
|
-
return await sendMessage(session,
|
|
579
|
+
return await sendMessage(session, `**【@${username}】**
|
|
651
580
|
游戏还未开始哦!`);
|
|
652
581
|
}
|
|
653
582
|
await checkEngine(channelId);
|
|
654
|
-
if (engines[channelId] && !gameRecord.isEngineReady) {
|
|
655
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
656
|
-
isEngineReady: true
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
583
|
if (gameRecord.isRegretRequest) {
|
|
660
|
-
return await sendMessage(session,
|
|
584
|
+
return await sendMessage(session, `**【@${username}】**
|
|
661
585
|
已经有悔棋请求了!`);
|
|
662
586
|
}
|
|
663
587
|
const playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
|
|
664
588
|
if (playerRecord.length === 0) {
|
|
665
|
-
return await sendMessage(session,
|
|
589
|
+
return await sendMessage(session, `**【@${username}】**
|
|
666
590
|
您还未加入游戏呢!`);
|
|
667
591
|
}
|
|
668
592
|
const turn = gameRecord.turn;
|
|
669
593
|
const sideString = convertTurnToString(turn);
|
|
670
594
|
if (gameRecord.isAnalyzing) {
|
|
671
|
-
return await sendMessage(session,
|
|
595
|
+
return await sendMessage(session, `**【@${username}】**
|
|
672
596
|
对局分析中,请稍后再试!`);
|
|
673
597
|
}
|
|
674
598
|
if (gameRecord.moveList.length < 1) {
|
|
675
|
-
return await sendMessage(session,
|
|
599
|
+
return await sendMessage(session, `**【@${username}】**
|
|
676
600
|
当前无法悔棋!`);
|
|
677
601
|
}
|
|
678
602
|
if (gameRecord.isEnginePlayBlack || gameRecord.isEnginePlayRed) {
|
|
@@ -680,20 +604,18 @@ ${hImg2}`);
|
|
|
680
604
|
await undoMove(channelId);
|
|
681
605
|
const buffer = await drawChessBoard(channelId);
|
|
682
606
|
const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
|
|
683
|
-
return await sendMessage(session,
|
|
607
|
+
return await sendMessage(session, `**【@${username}】**
|
|
684
608
|
悔棋成功!
|
|
685
609
|
${hImg}`);
|
|
686
610
|
} else {
|
|
687
611
|
if (playerRecord[0].side === sideString) {
|
|
688
|
-
return await sendMessage(session,
|
|
612
|
+
return await sendMessage(session, `**【@${username}】**
|
|
689
613
|
现在轮到你下棋,不可悔棋!`);
|
|
690
614
|
} else {
|
|
691
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
692
|
-
|
|
693
|
-
});
|
|
694
|
-
return await sendMessage(session, `【@${username}】
|
|
615
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isRegretRequest: true });
|
|
616
|
+
return await sendMessage(session, `**【@${username}】**
|
|
695
617
|
请求悔棋中...
|
|
696
|
-
|
|
618
|
+
请对方输入相关指令选择同意或拒绝!`);
|
|
697
619
|
}
|
|
698
620
|
}
|
|
699
621
|
});
|
|
@@ -702,41 +624,34 @@ ${hImg}`);
|
|
|
702
624
|
await updateNameInPlayerRecord(userId, username);
|
|
703
625
|
const gameRecord = await getGameRecord(channelId);
|
|
704
626
|
if (!gameRecord.isStarted) {
|
|
705
|
-
return await sendMessage(session,
|
|
627
|
+
return await sendMessage(session, `**【@${username}】**
|
|
706
628
|
游戏还未开始哦!`);
|
|
707
629
|
}
|
|
708
630
|
await checkEngine(channelId);
|
|
709
|
-
if (engines[channelId] && !gameRecord.isEngineReady) {
|
|
710
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
711
|
-
isEngineReady: true
|
|
712
|
-
});
|
|
713
|
-
}
|
|
714
631
|
if (gameRecord.isAnalyzing) {
|
|
715
|
-
return await sendMessage(session,
|
|
632
|
+
return await sendMessage(session, `**【@${username}】**
|
|
716
633
|
对局分析中,请稍后再试!`);
|
|
717
634
|
}
|
|
718
635
|
if (!gameRecord.isRegretRequest) {
|
|
719
|
-
return await sendMessage(session,
|
|
636
|
+
return await sendMessage(session, `**【@${username}】**
|
|
720
637
|
当前无悔棋请求!`);
|
|
721
638
|
}
|
|
722
639
|
const playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
|
|
723
640
|
if (playerRecord.length === 0) {
|
|
724
|
-
return await sendMessage(session,
|
|
641
|
+
return await sendMessage(session, `**【@${username}】**
|
|
725
642
|
您还未加入游戏呢!`);
|
|
726
643
|
}
|
|
727
644
|
const turn = gameRecord.turn;
|
|
728
645
|
const sideString = convertTurnToString(turn);
|
|
729
646
|
if (playerRecord[0].side !== sideString) {
|
|
730
|
-
return await sendMessage(session,
|
|
647
|
+
return await sendMessage(session, `**【@${username}】**
|
|
731
648
|
您所在的队伍不能做出选择!`);
|
|
732
649
|
} else {
|
|
733
650
|
await undoMove(channelId);
|
|
734
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
735
|
-
isRegretRequest: false
|
|
736
|
-
});
|
|
651
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isRegretRequest: false });
|
|
737
652
|
const buffer = await drawChessBoard(channelId);
|
|
738
653
|
const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
|
|
739
|
-
return await sendMessage(session,
|
|
654
|
+
return await sendMessage(session, `**【@${username}】**
|
|
740
655
|
由于您同意了对方的悔棋请求!
|
|
741
656
|
悔棋成功!
|
|
742
657
|
${hImg}`);
|
|
@@ -747,40 +662,33 @@ ${hImg}`);
|
|
|
747
662
|
await updateNameInPlayerRecord(userId, username);
|
|
748
663
|
const gameRecord = await getGameRecord(channelId);
|
|
749
664
|
if (!gameRecord.isStarted) {
|
|
750
|
-
return await sendMessage(session,
|
|
665
|
+
return await sendMessage(session, `**【@${username}】**
|
|
751
666
|
游戏还未开始哦!`);
|
|
752
667
|
}
|
|
753
668
|
await checkEngine(channelId);
|
|
754
|
-
if (engines[channelId] && !gameRecord.isEngineReady) {
|
|
755
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
756
|
-
isEngineReady: true
|
|
757
|
-
});
|
|
758
|
-
}
|
|
759
669
|
if (gameRecord.isAnalyzing) {
|
|
760
|
-
return await sendMessage(session,
|
|
670
|
+
return await sendMessage(session, `**【@${username}】**
|
|
761
671
|
对局分析中,请稍后再试!`);
|
|
762
672
|
}
|
|
763
673
|
if (!gameRecord.isRegretRequest) {
|
|
764
|
-
return await sendMessage(session,
|
|
674
|
+
return await sendMessage(session, `**【@${username}】**
|
|
765
675
|
当前无悔棋请求!`);
|
|
766
676
|
}
|
|
767
677
|
const playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
|
|
768
678
|
if (playerRecord.length === 0) {
|
|
769
|
-
return await sendMessage(session,
|
|
679
|
+
return await sendMessage(session, `**【@${username}】**
|
|
770
680
|
您还未加入游戏呢!`);
|
|
771
681
|
}
|
|
772
682
|
const turn = gameRecord.turn;
|
|
773
683
|
const sideString = convertTurnToString(turn);
|
|
774
684
|
if (playerRecord[0].side !== sideString) {
|
|
775
|
-
return await sendMessage(session,
|
|
685
|
+
return await sendMessage(session, `**【@${username}】**
|
|
776
686
|
您所在的队伍不能做出选择!`);
|
|
777
687
|
} else {
|
|
778
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
779
|
-
isRegretRequest: false
|
|
780
|
-
});
|
|
688
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isRegretRequest: false });
|
|
781
689
|
const buffer = await drawChessBoard(channelId);
|
|
782
690
|
const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
|
|
783
|
-
return await sendMessage(session,
|
|
691
|
+
return await sendMessage(session, `**【@${username}】**
|
|
784
692
|
由于您拒绝了对方的悔棋请求!
|
|
785
693
|
悔棋失败,游戏继续进行!
|
|
786
694
|
${hImg}`);
|
|
@@ -791,38 +699,33 @@ ${hImg}`);
|
|
|
791
699
|
await updateNameInPlayerRecord(userId, username);
|
|
792
700
|
const gameRecord = await getGameRecord(channelId);
|
|
793
701
|
if (!gameRecord.isStarted) {
|
|
794
|
-
return await sendMessage(session,
|
|
702
|
+
return await sendMessage(session, `**【@${username}】**
|
|
795
703
|
游戏还未开始哦!`);
|
|
796
704
|
}
|
|
797
705
|
await checkEngine(channelId);
|
|
798
|
-
if (engines[channelId] && !gameRecord.isEngineReady) {
|
|
799
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
800
|
-
isEngineReady: true
|
|
801
|
-
});
|
|
802
|
-
}
|
|
803
706
|
if (gameRecord.isAnalyzing) {
|
|
804
|
-
return await sendMessage(session,
|
|
707
|
+
return await sendMessage(session, `**【@${username}】**
|
|
805
708
|
对局分析中,请稍后再试!`);
|
|
806
709
|
}
|
|
807
710
|
const playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
|
|
808
711
|
if (playerRecord.length === 0) {
|
|
809
|
-
return await sendMessage(session,
|
|
712
|
+
return await sendMessage(session, `**【@${username}】**
|
|
810
713
|
您还未加入游戏呢!`);
|
|
811
714
|
}
|
|
812
715
|
const turn = gameRecord.turn;
|
|
813
716
|
const sideString = convertTurnToString(turn);
|
|
814
717
|
if (playerRecord[0].side !== sideString) {
|
|
815
|
-
return await sendMessage(session,
|
|
718
|
+
return await sendMessage(session, `**【@${username}】**
|
|
816
719
|
还没轮到${sideString}走棋哦!
|
|
817
|
-
|
|
720
|
+
当前走棋方为:**【${convertTurnToString(gameRecord.turn)}】**`);
|
|
818
721
|
}
|
|
819
722
|
const anotherSideString = convertTurnToString(turn === "w" ? "b" : "w");
|
|
820
723
|
await updatePlayerRecords(channelId, turn === "w" ? "b" : "w", turn);
|
|
821
724
|
await endGame(channelId);
|
|
822
|
-
return await sendMessage(session,
|
|
725
|
+
return await sendMessage(session, `**【@${username}】**
|
|
823
726
|
认输成功!
|
|
824
727
|
游戏结束!
|
|
825
|
-
|
|
728
|
+
获胜方为:**【${anotherSideString}】**`);
|
|
826
729
|
});
|
|
827
730
|
ctx.command("cchess.查看云库残局", "云库残局指令帮助").action(async ({ session }) => {
|
|
828
731
|
await session.execute(`cchess.查看云库残局 -h`);
|
|
@@ -831,14 +734,14 @@ ${hImg}`);
|
|
|
831
734
|
const { username, userId, channelId } = session;
|
|
832
735
|
await updateNameInPlayerRecord(userId, username);
|
|
833
736
|
await checkEngine(channelId);
|
|
834
|
-
return await sendMessage(session,
|
|
737
|
+
return await sendMessage(session, `**【@${username}】**
|
|
835
738
|
https://www.chessdb.cn/egtb_info_dtm.html`);
|
|
836
739
|
});
|
|
837
740
|
ctx.command("cchess.查看云库残局.DTC统计", "云库残局DTM统计").action(async ({ session }) => {
|
|
838
741
|
const { username, userId, channelId } = session;
|
|
839
742
|
await updateNameInPlayerRecord(userId, username);
|
|
840
743
|
await checkEngine(channelId);
|
|
841
|
-
return await sendMessage(session,
|
|
744
|
+
return await sendMessage(session, `**【@${username}】**
|
|
842
745
|
https://www.chessdb.cn/egtb_info.html`);
|
|
843
746
|
});
|
|
844
747
|
ctx.command("cchess.编辑棋盘", "编辑棋盘指令帮助").action(async ({ session }) => {
|
|
@@ -849,61 +752,33 @@ https://www.chessdb.cn/egtb_info.html`);
|
|
|
849
752
|
await updateNameInPlayerRecord(userId, username);
|
|
850
753
|
const gameRecord = await getGameRecord(channelId);
|
|
851
754
|
if (gameRecord.isStarted) {
|
|
852
|
-
return await sendMessage(session,
|
|
755
|
+
return await sendMessage(session, `**【@${username}】**
|
|
853
756
|
游戏已经开始啦~
|
|
854
757
|
不可编辑棋盘!`);
|
|
855
758
|
}
|
|
856
759
|
await checkEngine(channelId);
|
|
857
|
-
if (
|
|
858
|
-
await
|
|
859
|
-
isEngineReady: true
|
|
860
|
-
});
|
|
861
|
-
}
|
|
862
|
-
if (!fen) {
|
|
863
|
-
return await sendMessage(session, `【@${username}】
|
|
864
|
-
无效的FEN串!`);
|
|
865
|
-
}
|
|
866
|
-
if (!isValidateFen(fen)) {
|
|
867
|
-
return await sendMessage(session, `【@${username}】
|
|
760
|
+
if (!fen || !isValidateFen(fen)) {
|
|
761
|
+
return await sendMessage(session, `**【@${username}】**
|
|
868
762
|
无效的FEN串!`);
|
|
869
763
|
}
|
|
870
|
-
let {
|
|
871
|
-
turn,
|
|
872
|
-
board,
|
|
873
|
-
moveList,
|
|
874
|
-
movesAfterLastEat,
|
|
875
|
-
boardAfterLastEat,
|
|
876
|
-
turnAfterLastEat,
|
|
877
|
-
lastMove,
|
|
878
|
-
isHistoryMode,
|
|
879
|
-
originalState,
|
|
880
|
-
startFen
|
|
881
|
-
} = gameRecord;
|
|
882
764
|
const t = fen;
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
movesAfterLastEat = [];
|
|
887
|
-
boardAfterLastEat = fenToBoard(t);
|
|
888
|
-
turnAfterLastEat = fenToTurn(t);
|
|
889
|
-
t.includes("moves") ? startFen = t.split("moves")[0] : startFen = t;
|
|
890
|
-
isHistoryMode = false;
|
|
891
|
-
originalState = {};
|
|
892
|
-
lastMove = null;
|
|
765
|
+
const newBoard = fenToBoard(t);
|
|
766
|
+
const newTurn = "w";
|
|
767
|
+
const newStartFen = t.includes("moves") ? t.split("moves")[0] : t;
|
|
893
768
|
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
894
|
-
turn,
|
|
895
|
-
board,
|
|
896
|
-
moveList,
|
|
897
|
-
movesAfterLastEat,
|
|
898
|
-
boardAfterLastEat,
|
|
899
|
-
turnAfterLastEat,
|
|
900
|
-
lastMove,
|
|
901
|
-
isHistoryMode,
|
|
902
|
-
originalState,
|
|
903
|
-
startFen
|
|
769
|
+
turn: newTurn,
|
|
770
|
+
board: newBoard,
|
|
771
|
+
moveList: [],
|
|
772
|
+
movesAfterLastEat: [],
|
|
773
|
+
boardAfterLastEat: fenToBoard(t),
|
|
774
|
+
turnAfterLastEat: fenToTurn(t),
|
|
775
|
+
lastMove: null,
|
|
776
|
+
isHistoryMode: false,
|
|
777
|
+
originalState: {},
|
|
778
|
+
startFen: newStartFen
|
|
904
779
|
});
|
|
905
780
|
await parseFen(channelId, t);
|
|
906
|
-
return await sendMessage(session,
|
|
781
|
+
return await sendMessage(session, `**【@${username}】**
|
|
907
782
|
棋盘编辑成功!`);
|
|
908
783
|
});
|
|
909
784
|
ctx.command("cchess.编辑棋盘.导出", "导出FEN串").action(async ({ session }) => {
|
|
@@ -911,48 +786,43 @@ https://www.chessdb.cn/egtb_info.html`);
|
|
|
911
786
|
await updateNameInPlayerRecord(userId, username);
|
|
912
787
|
const gameRecord = await getGameRecord(channelId);
|
|
913
788
|
if (!gameRecord.isStarted) {
|
|
914
|
-
return await sendMessage(session,
|
|
789
|
+
return await sendMessage(session, `**【@${username}】**
|
|
915
790
|
游戏还未开始哦!`);
|
|
916
791
|
}
|
|
917
792
|
if (gameRecord.isAnalyzing) {
|
|
918
|
-
return await sendMessage(session,
|
|
793
|
+
return await sendMessage(session, `**【@${username}】**
|
|
919
794
|
对局分析中,请稍后再试!`);
|
|
920
795
|
}
|
|
921
796
|
await checkEngine(channelId);
|
|
922
|
-
if (engines[channelId] && !gameRecord.isEngineReady) {
|
|
923
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
924
|
-
isEngineReady: true
|
|
925
|
-
});
|
|
926
|
-
}
|
|
927
797
|
const fenWithFullMove = await getFenWithFullMove(channelId);
|
|
928
|
-
return await sendMessage(session,
|
|
798
|
+
return await sendMessage(session, `**【@${username}】**
|
|
929
799
|
${fenWithFullMove}`);
|
|
930
800
|
});
|
|
931
801
|
ctx.command("cchess.编辑棋盘.使用方法", "查看编辑棋盘的fen使用方法").action(async ({ session }) => {
|
|
932
802
|
const { username, userId, channelId } = session;
|
|
933
803
|
await updateNameInPlayerRecord(userId, username);
|
|
934
804
|
await checkEngine(channelId);
|
|
935
|
-
return await sendMessage(session,
|
|
805
|
+
return await sendMessage(session, `**【@${username}】**
|
|
936
806
|
https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
937
807
|
});
|
|
938
808
|
ctx.command("cchess.排行榜.总胜场 [number:number]", "查看玩家总胜场排行榜").action(async ({ session }, number = config.defaultMaxLeaderboardEntries) => {
|
|
939
|
-
const {
|
|
809
|
+
const { userId, username } = session;
|
|
940
810
|
await updateNameInPlayerRecord(userId, username);
|
|
941
811
|
if (typeof number !== "number" || isNaN(number) || number < 0) {
|
|
942
812
|
return "请输入大于等于 0 的数字作为排行榜的参数。";
|
|
943
813
|
}
|
|
944
|
-
return await getLeaderboard(session, "win", "
|
|
814
|
+
return await getLeaderboard(session, "win", "玩家总胜场排行榜", number);
|
|
945
815
|
});
|
|
946
816
|
ctx.command("cchess.排行榜.总输场 [number:number]", "查看玩家总输场排行榜").action(async ({ session }, number = config.defaultMaxLeaderboardEntries) => {
|
|
947
|
-
const {
|
|
817
|
+
const { userId, username } = session;
|
|
948
818
|
await updateNameInPlayerRecord(userId, username);
|
|
949
819
|
if (typeof number !== "number" || isNaN(number) || number < 0) {
|
|
950
820
|
return "请输入大于等于 0 的数字作为排行榜的参数。";
|
|
951
821
|
}
|
|
952
|
-
return await getLeaderboard(session, "lose", "
|
|
822
|
+
return await getLeaderboard(session, "lose", "查看玩家总输场排行榜", number);
|
|
953
823
|
});
|
|
954
824
|
ctx.command("cchess.查询玩家记录 [targetUser:text]", "查询玩家记录").action(async ({ session }, targetUser) => {
|
|
955
|
-
let {
|
|
825
|
+
let { userId, username } = session;
|
|
956
826
|
await updateNameInPlayerRecord(userId, username);
|
|
957
827
|
if (targetUser) {
|
|
958
828
|
targetUser = await replaceAtTags(session, targetUser);
|
|
@@ -969,12 +839,12 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
969
839
|
lose: 0,
|
|
970
840
|
win: 0
|
|
971
841
|
});
|
|
972
|
-
return sendMessage(session,
|
|
842
|
+
return sendMessage(session, `**【@${session.username}】**
|
|
973
843
|
查询对象:${username}
|
|
974
844
|
无任何游戏记录。`);
|
|
975
845
|
}
|
|
976
846
|
const { win, lose } = targetUserRecord[0];
|
|
977
|
-
return sendMessage(session,
|
|
847
|
+
return sendMessage(session, `**【@${session.username}】**
|
|
978
848
|
查询对象:${username}
|
|
979
849
|
总胜场次数为:${win} 次
|
|
980
850
|
总输场次数为:${lose} 次
|
|
@@ -991,11 +861,7 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
991
861
|
try {
|
|
992
862
|
guildMember = await session.bot.getGuildMember(session.guildId, userId);
|
|
993
863
|
} catch (error) {
|
|
994
|
-
guildMember = {
|
|
995
|
-
user: {
|
|
996
|
-
name: "未知用户"
|
|
997
|
-
}
|
|
998
|
-
};
|
|
864
|
+
guildMember = { user: { name: "未知用户" } };
|
|
999
865
|
}
|
|
1000
866
|
const newAtTag = `<at id="${userId}" name="${guildMember.user.name}"/>`;
|
|
1001
867
|
content = content.replace(match[0], newAtTag);
|
|
@@ -1023,11 +889,11 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1023
889
|
}
|
|
1024
890
|
}
|
|
1025
891
|
__name(updatePlayerRecords, "updatePlayerRecords");
|
|
1026
|
-
async function getLeaderboard(session,
|
|
892
|
+
async function getLeaderboard(session, sortField, title, number) {
|
|
1027
893
|
const getPlayers = await ctx.database.get("cchess_player_records", {});
|
|
1028
894
|
const sortedPlayers = getPlayers.sort((a, b) => b[sortField] - a[sortField]);
|
|
1029
895
|
const topPlayers = sortedPlayers.slice(0, number);
|
|
1030
|
-
let result =
|
|
896
|
+
let result = `### ${title}:
|
|
1031
897
|
`;
|
|
1032
898
|
topPlayers.forEach((player, index) => {
|
|
1033
899
|
result += `${index + 1}. ${player.username}:${player[sortField]} 次
|
|
@@ -1039,53 +905,36 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1039
905
|
async function updateNameInPlayerRecord(userId, username) {
|
|
1040
906
|
const userRecord = await ctx.database.get("cchess_player_records", { userId });
|
|
1041
907
|
if (userRecord.length === 0) {
|
|
1042
|
-
await ctx.database.create("cchess_player_records", {
|
|
1043
|
-
userId,
|
|
1044
|
-
username
|
|
1045
|
-
});
|
|
908
|
+
await ctx.database.create("cchess_player_records", { userId, username });
|
|
1046
909
|
return;
|
|
1047
910
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
if (username !== existingRecord.username) {
|
|
1051
|
-
existingRecord.username = username;
|
|
1052
|
-
isChange = true;
|
|
1053
|
-
}
|
|
1054
|
-
if (isChange) {
|
|
1055
|
-
await ctx.database.set("cchess_player_records", { userId }, {
|
|
1056
|
-
username: existingRecord.username
|
|
1057
|
-
});
|
|
911
|
+
if (username !== userRecord[0].username) {
|
|
912
|
+
await ctx.database.set("cchess_player_records", { userId }, { username });
|
|
1058
913
|
}
|
|
1059
914
|
}
|
|
1060
915
|
__name(updateNameInPlayerRecord, "updateNameInPlayerRecord");
|
|
1061
916
|
async function checkEngine(channelId) {
|
|
1062
917
|
if (!engines[channelId]) {
|
|
1063
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
1064
|
-
isEngineReady: false
|
|
1065
|
-
});
|
|
918
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isEngineReady: false });
|
|
1066
919
|
await initEngine(channelId);
|
|
1067
920
|
while (true) {
|
|
1068
921
|
const gameRecord = await getGameRecord(channelId);
|
|
1069
|
-
if (gameRecord.isEngineReady)
|
|
1070
|
-
break;
|
|
1071
|
-
}
|
|
922
|
+
if (gameRecord.isEngineReady) break;
|
|
1072
923
|
await (0, import_koishi.sleep)(500);
|
|
1073
924
|
}
|
|
1074
925
|
}
|
|
1075
926
|
}
|
|
1076
927
|
__name(checkEngine, "checkEngine");
|
|
1077
|
-
async function getFenWithFullMove(channelId,
|
|
928
|
+
async function getFenWithFullMove(channelId, separator = " ") {
|
|
1078
929
|
const gameRecord = await getGameRecord(channelId);
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
let n = startFen;
|
|
1088
|
-
return e.length > 0 && (n += " moves " + e.join(t)), n;
|
|
930
|
+
const { startFen, moveList } = gameRecord;
|
|
931
|
+
let moves = [];
|
|
932
|
+
for (let move of moveList) moves.push(move.move);
|
|
933
|
+
let fullFen = startFen;
|
|
934
|
+
if (moves.length > 0) {
|
|
935
|
+
fullFen += " moves " + moves.join(separator);
|
|
936
|
+
}
|
|
937
|
+
return fullFen;
|
|
1089
938
|
}
|
|
1090
939
|
__name(getFenWithFullMove, "getFenWithFullMove");
|
|
1091
940
|
function fenToTurn(t) {
|
|
@@ -1093,57 +942,55 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1093
942
|
return "b" == e[1] ? "b" : "w";
|
|
1094
943
|
}
|
|
1095
944
|
__name(fenToTurn, "fenToTurn");
|
|
1096
|
-
function isValidateFen(
|
|
1097
|
-
let
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
for (let
|
|
1104
|
-
let
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
945
|
+
function isValidateFen(fen) {
|
|
946
|
+
let parts = fen.split(" ");
|
|
947
|
+
let boardPart = parts[0];
|
|
948
|
+
let turnPart = parts[1];
|
|
949
|
+
if (!"rwb".includes(turnPart.toLowerCase())) return false;
|
|
950
|
+
let rows = boardPart.split("/");
|
|
951
|
+
if (rows.length != 10) return false;
|
|
952
|
+
for (let i = 0; i < rows.length; i++) {
|
|
953
|
+
let row = rows[i];
|
|
954
|
+
let count = 0;
|
|
955
|
+
for (let j = 0; j < row.length; j++) {
|
|
956
|
+
let char = row.charAt(j);
|
|
957
|
+
if (char >= "0" && char <= "9") {
|
|
958
|
+
count += parseInt(char);
|
|
959
|
+
} else {
|
|
960
|
+
count++;
|
|
961
|
+
}
|
|
1108
962
|
}
|
|
1109
|
-
if (
|
|
1110
|
-
return false;
|
|
963
|
+
if (count != 9) return false;
|
|
1111
964
|
}
|
|
1112
965
|
return true;
|
|
1113
966
|
}
|
|
1114
967
|
__name(isValidateFen, "isValidateFen");
|
|
1115
|
-
async function parseFen(channelId,
|
|
1116
|
-
const
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
for (let i = 3; i < e.length; i++)
|
|
1131
|
-
await makeMoveByString(channelId, e[i]);
|
|
1132
|
-
else {
|
|
1133
|
-
let t2 = e[3];
|
|
1134
|
-
for (let e2 = 0; e2 < t2.length; e2 += 4)
|
|
1135
|
-
await makeMoveByString(channelId, t2.substring(e2, e2 + 4));
|
|
968
|
+
async function parseFen(channelId, fenString) {
|
|
969
|
+
const parts = fenString.split(" ");
|
|
970
|
+
const board = fenToBoard(parts[0]);
|
|
971
|
+
const turn = "b" == parts[1] ? "b" : "w";
|
|
972
|
+
await ctx.database.set("cchess_game_records", { channelId }, { turn, board });
|
|
973
|
+
if (parts.length > 3 && "moves" == parts[2]) {
|
|
974
|
+
if (parts[3].length == 4) {
|
|
975
|
+
for (let i = 3; i < parts.length; i++) {
|
|
976
|
+
await makeMoveByString(channelId, parts[i]);
|
|
977
|
+
}
|
|
978
|
+
} else {
|
|
979
|
+
let movesStr = parts[3];
|
|
980
|
+
for (let i = 0; i < movesStr.length; i += 4) {
|
|
981
|
+
await makeMoveByString(channelId, movesStr.substring(i, i + 4));
|
|
982
|
+
}
|
|
1136
983
|
}
|
|
984
|
+
}
|
|
1137
985
|
}
|
|
1138
986
|
__name(parseFen, "parseFen");
|
|
1139
|
-
function deepCopy(
|
|
1140
|
-
return JSON.parse(JSON.stringify(
|
|
987
|
+
function deepCopy(obj) {
|
|
988
|
+
return JSON.parse(JSON.stringify(obj));
|
|
1141
989
|
}
|
|
1142
990
|
__name(deepCopy, "deepCopy");
|
|
1143
|
-
async function gotoHistory(channelId,
|
|
991
|
+
async function gotoHistory(channelId, targetMove) {
|
|
1144
992
|
const gameRecord = await getGameRecord(channelId);
|
|
1145
993
|
let {
|
|
1146
|
-
fen,
|
|
1147
994
|
turn,
|
|
1148
995
|
board,
|
|
1149
996
|
moveList,
|
|
@@ -1154,19 +1001,35 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1154
1001
|
isHistoryMode,
|
|
1155
1002
|
originalState
|
|
1156
1003
|
} = gameRecord;
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1004
|
+
if (!isHistoryMode) {
|
|
1005
|
+
originalState = {
|
|
1006
|
+
fen: getFen(board, turn),
|
|
1007
|
+
turn,
|
|
1008
|
+
board: deepCopy(board),
|
|
1009
|
+
moveList: deepCopy(moveList),
|
|
1010
|
+
movesAfterLastEat: deepCopy(movesAfterLastEat),
|
|
1011
|
+
boardAfterLastEat: deepCopy(boardAfterLastEat),
|
|
1012
|
+
turnAfterLastEat,
|
|
1013
|
+
lastMove
|
|
1014
|
+
};
|
|
1015
|
+
isHistoryMode = true;
|
|
1016
|
+
}
|
|
1017
|
+
let moveId = targetMove.moveId;
|
|
1018
|
+
let idx = originalState.moveList.findIndex((m) => m.moveId == moveId);
|
|
1019
|
+
moveList = originalState.moveList.slice(0, idx + 1);
|
|
1020
|
+
idx = originalState.movesAfterLastEat.findIndex((m) => m.moveId == moveId);
|
|
1021
|
+
if (idx != -1) {
|
|
1022
|
+
movesAfterLastEat = originalState.movesAfterLastEat.slice(0, idx + 1);
|
|
1023
|
+
} else {
|
|
1024
|
+
boardAfterLastEat = fenToBoard(targetMove.fen);
|
|
1025
|
+
turnAfterLastEat = "w" == targetMove.side ? "b" : "w";
|
|
1026
|
+
movesAfterLastEat = [];
|
|
1027
|
+
}
|
|
1028
|
+
lastMove = targetMove.moveCord;
|
|
1029
|
+
turn = "w" == targetMove.side ? "b" : "w";
|
|
1030
|
+
board = fenToBoard(targetMove.fen);
|
|
1031
|
+
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
1032
|
+
fen: targetMove.fen,
|
|
1170
1033
|
turn,
|
|
1171
1034
|
board,
|
|
1172
1035
|
moveList,
|
|
@@ -1194,16 +1057,26 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1194
1057
|
originalState,
|
|
1195
1058
|
startFen
|
|
1196
1059
|
} = gameRecord;
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1060
|
+
if (!isHistoryMode) {
|
|
1061
|
+
originalState = {
|
|
1062
|
+
fen: getFen(board, turn),
|
|
1063
|
+
turn,
|
|
1064
|
+
board: deepCopy(board),
|
|
1065
|
+
moveList: deepCopy(moveList),
|
|
1066
|
+
movesAfterLastEat: deepCopy(movesAfterLastEat),
|
|
1067
|
+
boardAfterLastEat: deepCopy(boardAfterLastEat),
|
|
1068
|
+
turnAfterLastEat,
|
|
1069
|
+
lastMove
|
|
1070
|
+
};
|
|
1071
|
+
isHistoryMode = true;
|
|
1072
|
+
}
|
|
1073
|
+
await parseFen(channelId, startFen);
|
|
1074
|
+
moveList = [];
|
|
1075
|
+
movesAfterLastEat = [];
|
|
1076
|
+
boardAfterLastEat = deepCopy(fenToBoard(fen));
|
|
1077
|
+
turnAfterLastEat = turn;
|
|
1078
|
+
lastMove = null;
|
|
1079
|
+
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
1207
1080
|
moveList,
|
|
1208
1081
|
movesAfterLastEat,
|
|
1209
1082
|
boardAfterLastEat,
|
|
@@ -1217,7 +1090,6 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1217
1090
|
async function undoMove(channelId) {
|
|
1218
1091
|
const gameRecord = await getGameRecord(channelId);
|
|
1219
1092
|
let {
|
|
1220
|
-
fen,
|
|
1221
1093
|
turn,
|
|
1222
1094
|
board,
|
|
1223
1095
|
moveList,
|
|
@@ -1228,23 +1100,26 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1228
1100
|
isHistoryMode,
|
|
1229
1101
|
originalState
|
|
1230
1102
|
} = gameRecord;
|
|
1231
|
-
if (isHistoryMode
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
isHistoryMode
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1103
|
+
if (!isHistoryMode) {
|
|
1104
|
+
originalState = {
|
|
1105
|
+
fen: getFen(board, turn),
|
|
1106
|
+
turn,
|
|
1107
|
+
board: deepCopy(board),
|
|
1108
|
+
moveList: deepCopy(moveList),
|
|
1109
|
+
movesAfterLastEat: deepCopy(movesAfterLastEat),
|
|
1110
|
+
boardAfterLastEat: deepCopy(boardAfterLastEat),
|
|
1111
|
+
turnAfterLastEat,
|
|
1112
|
+
lastMove
|
|
1113
|
+
};
|
|
1114
|
+
isHistoryMode = true;
|
|
1115
|
+
}
|
|
1116
|
+
await ctx.database.set("cchess_game_records", { channelId }, { originalState, isHistoryMode });
|
|
1117
|
+
if (moveList.length > 1) {
|
|
1118
|
+
let target = moveList[moveList.length - 2];
|
|
1119
|
+
await gotoHistory(channelId, target);
|
|
1120
|
+
} else {
|
|
1247
1121
|
await gotoStart(channelId);
|
|
1122
|
+
}
|
|
1248
1123
|
}
|
|
1249
1124
|
__name(undoMove, "undoMove");
|
|
1250
1125
|
async function endGame(channelId) {
|
|
@@ -1252,22 +1127,14 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1252
1127
|
await ctx.database.remove("cchess_gaming_player_records", { channelId });
|
|
1253
1128
|
}
|
|
1254
1129
|
__name(endGame, "endGame");
|
|
1255
|
-
async function onEngineBestMove(channelId,
|
|
1130
|
+
async function onEngineBestMove(channelId, move, ponder) {
|
|
1256
1131
|
const gameRecord = await getGameRecord(channelId);
|
|
1257
|
-
let {
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
// bestMoveHint,
|
|
1261
|
-
board,
|
|
1262
|
-
turn
|
|
1263
|
-
} = gameRecord;
|
|
1264
|
-
if (!t) {
|
|
1265
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
1266
|
-
isAnalyzing: false
|
|
1267
|
-
});
|
|
1132
|
+
let { isEnginePlayRed, isEnginePlayBlack, board, turn } = gameRecord;
|
|
1133
|
+
if (!move) {
|
|
1134
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isAnalyzing: false });
|
|
1268
1135
|
return;
|
|
1269
1136
|
}
|
|
1270
|
-
if ("(none)" ===
|
|
1137
|
+
if ("(none)" === move) {
|
|
1271
1138
|
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
1272
1139
|
winSide: turn === "w" ? "b" : "w",
|
|
1273
1140
|
loseSide: turn,
|
|
@@ -1275,8 +1142,8 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1275
1142
|
});
|
|
1276
1143
|
return;
|
|
1277
1144
|
}
|
|
1278
|
-
let
|
|
1279
|
-
if (
|
|
1145
|
+
let side = getSideByMoveString(board, move);
|
|
1146
|
+
if (side !== turn && isEnginePlayRed || side !== turn && isEnginePlayBlack) {
|
|
1280
1147
|
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
1281
1148
|
winSide: turn,
|
|
1282
1149
|
loseSide: turn === "w" ? "b" : "w",
|
|
@@ -1284,213 +1151,87 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1284
1151
|
});
|
|
1285
1152
|
return;
|
|
1286
1153
|
}
|
|
1287
|
-
("w" ===
|
|
1288
|
-
|
|
1289
|
-
// bestMoveHint,
|
|
1290
|
-
isAnalyzing: false
|
|
1291
|
-
});
|
|
1292
|
-
}
|
|
1293
|
-
__name(onEngineBestMove, "onEngineBestMove");
|
|
1294
|
-
function getLocalMoveName(t, e) {
|
|
1295
|
-
let i = {};
|
|
1296
|
-
if ("zh-CN" === e)
|
|
1297
|
-
return t;
|
|
1298
|
-
if ("en-US" === e)
|
|
1299
|
-
i = {
|
|
1300
|
-
"进": "+",
|
|
1301
|
-
"退": "-",
|
|
1302
|
-
"平": "=",
|
|
1303
|
-
"前": "+",
|
|
1304
|
-
"后": "-",
|
|
1305
|
-
"中": "=",
|
|
1306
|
-
"将": "k",
|
|
1307
|
-
"帅": "K",
|
|
1308
|
-
"士": "a",
|
|
1309
|
-
"仕": "A",
|
|
1310
|
-
"象": "b",
|
|
1311
|
-
"相": "B",
|
|
1312
|
-
"车": "r",
|
|
1313
|
-
"马": "n",
|
|
1314
|
-
"炮": "c",
|
|
1315
|
-
"卒": "p",
|
|
1316
|
-
"兵": "P"
|
|
1317
|
-
};
|
|
1318
|
-
else {
|
|
1319
|
-
if ("vi-VN" !== e)
|
|
1320
|
-
return t;
|
|
1321
|
-
i = {
|
|
1322
|
-
"进": ".",
|
|
1323
|
-
"退": "/",
|
|
1324
|
-
"平": "-",
|
|
1325
|
-
"前": ".",
|
|
1326
|
-
"后": "/",
|
|
1327
|
-
"中": "-",
|
|
1328
|
-
"将": "Tg",
|
|
1329
|
-
"帅": "Tg",
|
|
1330
|
-
"士": "S",
|
|
1331
|
-
"仕": "S",
|
|
1332
|
-
"象": "T",
|
|
1333
|
-
"相": "T",
|
|
1334
|
-
"车": "X",
|
|
1335
|
-
"马": "M",
|
|
1336
|
-
"炮": "P",
|
|
1337
|
-
"卒": "B",
|
|
1338
|
-
"兵": "B"
|
|
1339
|
-
};
|
|
1340
|
-
}
|
|
1341
|
-
let n = "一二三四五六七八九", A = "123456789", s = "123456789", a = "", o = -1 !== A.indexOf(t[3]) ? "b" : "w";
|
|
1342
|
-
for (let r of t) {
|
|
1343
|
-
let t2 = n.indexOf(r), e2 = A.indexOf(r);
|
|
1344
|
-
a += r in i ? i[r] : -1 !== t2 ? s[t2] : -1 !== e2 ? s[e2] : r;
|
|
1345
|
-
}
|
|
1346
|
-
return a = "w" === o ? a.toUpperCase() : a.toLowerCase(), a;
|
|
1347
|
-
}
|
|
1348
|
-
__name(getLocalMoveName, "getLocalMoveName");
|
|
1349
|
-
async function getSerialMoveName(channelId, t, e) {
|
|
1350
|
-
const gameRecord = await getGameRecord(channelId);
|
|
1351
|
-
let i = [];
|
|
1352
|
-
for (let A = 0; A < e.length; A++) {
|
|
1353
|
-
let t2 = e[A], s = getFigureMoveName(getFen(gameRecord.board, gameRecord.turn), t2);
|
|
1354
|
-
i.push(getLocalMoveName(s, "zh-CN")), await makeMoveByString(channelId, t2);
|
|
1154
|
+
if ("w" === side && isEnginePlayRed || "b" === side && isEnginePlayBlack) {
|
|
1155
|
+
await makeMoveByString(channelId, move);
|
|
1355
1156
|
}
|
|
1356
|
-
|
|
1157
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isAnalyzing: false });
|
|
1357
1158
|
}
|
|
1358
|
-
__name(
|
|
1359
|
-
async function go(channelId,
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1159
|
+
__name(onEngineBestMove, "onEngineBestMove");
|
|
1160
|
+
async function go(channelId, movetime = -1, depth = -1, nodes = -1) {
|
|
1161
|
+
let cmd = "go";
|
|
1162
|
+
if (movetime > 0) cmd += " movetime " + movetime;
|
|
1163
|
+
if (depth > 0) cmd += " depth " + depth;
|
|
1164
|
+
if (nodes > 0) cmd += " nodes " + nodes;
|
|
1165
|
+
await sendCommand(channelId, cmd);
|
|
1166
|
+
return true;
|
|
1364
1167
|
}
|
|
1365
1168
|
__name(go, "go");
|
|
1366
1169
|
async function engineAction(channelId) {
|
|
1367
1170
|
const gameRecord = await getGameRecord(channelId);
|
|
1368
|
-
let {
|
|
1369
|
-
|
|
1370
|
-
isEnginePlayBlack,
|
|
1371
|
-
turn,
|
|
1372
|
-
movesAfterLastEat,
|
|
1373
|
-
boardAfterLastEat,
|
|
1374
|
-
turnAfterLastEat
|
|
1375
|
-
// multiPvInfoBuffer
|
|
1376
|
-
} = gameRecord;
|
|
1377
|
-
await sendCommand(channelId, "fen " + getFenWithMove(movesAfterLastEat, boardAfterLastEat, turnAfterLastEat)), // multiPvInfoBuffer = {},
|
|
1171
|
+
let { movesAfterLastEat, boardAfterLastEat, turnAfterLastEat } = gameRecord;
|
|
1172
|
+
await sendCommand(channelId, "fen " + getFenWithMove(movesAfterLastEat, boardAfterLastEat, turnAfterLastEat));
|
|
1378
1173
|
await go(channelId, 1e3 * thinkingSettings["movetime"], thinkingSettings["depth"], -1);
|
|
1379
1174
|
}
|
|
1380
1175
|
__name(engineAction, "engineAction");
|
|
1381
|
-
function moveStringToPos(
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
e: 4,
|
|
1388
|
-
f: 5,
|
|
1389
|
-
g: 6,
|
|
1390
|
-
h: 7,
|
|
1391
|
-
i: 8
|
|
1392
|
-
}, i = {
|
|
1393
|
-
0: 9,
|
|
1394
|
-
1: 8,
|
|
1395
|
-
2: 7,
|
|
1396
|
-
3: 6,
|
|
1397
|
-
4: 5,
|
|
1398
|
-
5: 4,
|
|
1399
|
-
6: 3,
|
|
1400
|
-
7: 2,
|
|
1401
|
-
8: 1,
|
|
1402
|
-
9: 0
|
|
1403
|
-
}, n = [e[t[0]], i[t[1]]], A = [e[t[2]], i[t[3]]];
|
|
1404
|
-
return [n, A];
|
|
1176
|
+
function moveStringToPos(moveStr) {
|
|
1177
|
+
const xMap = { a: 0, b: 1, c: 2, d: 3, e: 4, f: 5, g: 6, h: 7, i: 8 };
|
|
1178
|
+
const yMap = { 0: 9, 1: 8, 2: 7, 3: 6, 4: 5, 5: 4, 6: 3, 7: 2, 8: 1, 9: 0 };
|
|
1179
|
+
const from = [xMap[moveStr[0]], yMap[moveStr[1]]];
|
|
1180
|
+
const to = [xMap[moveStr[2]], yMap[moveStr[3]]];
|
|
1181
|
+
return [from, to];
|
|
1405
1182
|
}
|
|
1406
1183
|
__name(moveStringToPos, "moveStringToPos");
|
|
1407
|
-
async function makeMoveByString(channelId,
|
|
1408
|
-
let
|
|
1409
|
-
await makeMove(channelId,
|
|
1184
|
+
async function makeMoveByString(channelId, moveStr) {
|
|
1185
|
+
let [from, to] = moveStringToPos(moveStr);
|
|
1186
|
+
await makeMove(channelId, from, to);
|
|
1410
1187
|
}
|
|
1411
1188
|
__name(makeMoveByString, "makeMoveByString");
|
|
1412
|
-
function getSideByMoveString(board,
|
|
1413
|
-
let
|
|
1414
|
-
return getSide(board[
|
|
1189
|
+
function getSideByMoveString(board, moveStr) {
|
|
1190
|
+
let [from, to] = moveStringToPos(moveStr);
|
|
1191
|
+
return getSide(board[from[1]][from[0]]);
|
|
1415
1192
|
}
|
|
1416
1193
|
__name(getSideByMoveString, "getSideByMoveString");
|
|
1417
1194
|
function getFenWithMove(movesAfterLastEat, boardAfterLastEat, turnAfterLastEat) {
|
|
1418
|
-
let
|
|
1419
|
-
for (let
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
return
|
|
1195
|
+
let moves = [];
|
|
1196
|
+
for (let m of movesAfterLastEat) moves.push(m.move);
|
|
1197
|
+
let fen = boardToFen(boardAfterLastEat, "w", turnAfterLastEat);
|
|
1198
|
+
if (moves.length > 0) fen += " moves " + moves.join(" ");
|
|
1199
|
+
return fen;
|
|
1423
1200
|
}
|
|
1424
1201
|
__name(getFenWithMove, "getFenWithMove");
|
|
1425
|
-
async function setOption(channelId,
|
|
1426
|
-
await sendCommand(channelId, "setoption name " +
|
|
1202
|
+
async function setOption(channelId, name2, value) {
|
|
1203
|
+
await sendCommand(channelId, "setoption name " + name2 + " value " + value);
|
|
1427
1204
|
}
|
|
1428
1205
|
__name(setOption, "setOption");
|
|
1429
|
-
async function setOptionList(channelId,
|
|
1430
|
-
for (let
|
|
1431
|
-
await setOption(channelId,
|
|
1206
|
+
async function setOptionList(channelId, options) {
|
|
1207
|
+
for (let key in options)
|
|
1208
|
+
await setOption(channelId, key, options[key]);
|
|
1432
1209
|
}
|
|
1433
1210
|
__name(setOptionList, "setOptionList");
|
|
1434
|
-
async function sendCommand(channelId,
|
|
1211
|
+
async function sendCommand(channelId, cmd) {
|
|
1435
1212
|
const gameRecord = await getGameRecord(channelId);
|
|
1436
1213
|
await checkEngine(channelId);
|
|
1437
1214
|
if (engines[channelId] && !gameRecord.isEngineReady) {
|
|
1438
|
-
await ctx.database.set("cchess_game_records", { channelId }, {
|
|
1439
|
-
isEngineReady: true
|
|
1440
|
-
});
|
|
1215
|
+
await ctx.database.set("cchess_game_records", { channelId }, { isEngineReady: true });
|
|
1441
1216
|
}
|
|
1442
|
-
if (
|
|
1443
|
-
engines[channelId].send_command(
|
|
1217
|
+
if (engines[channelId] || "uci" == cmd) {
|
|
1218
|
+
engines[channelId].send_command(cmd);
|
|
1444
1219
|
} else {
|
|
1445
|
-
await sendCommand(channelId,
|
|
1220
|
+
await sendCommand(channelId, cmd);
|
|
1446
1221
|
}
|
|
1447
1222
|
}
|
|
1448
1223
|
__name(sendCommand, "sendCommand");
|
|
1449
|
-
async function receiveOutput(channelId,
|
|
1224
|
+
async function receiveOutput(channelId, output) {
|
|
1450
1225
|
try {
|
|
1451
|
-
if (!
|
|
1452
|
-
|
|
1453
|
-
let
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
let infoObj = {};
|
|
1458
|
-
for (let j = 1; j < e.length; j++) {
|
|
1459
|
-
switch (e[j]) {
|
|
1460
|
-
case "pv":
|
|
1461
|
-
case "string":
|
|
1462
|
-
infoObj[e[j]] = e.slice(j + 1).join(" ");
|
|
1463
|
-
break;
|
|
1464
|
-
case "score":
|
|
1465
|
-
if (e[j + 1] === "cp") {
|
|
1466
|
-
infoObj[e[j]] = { cp: parseInt(e[j + 2]) };
|
|
1467
|
-
j += 2;
|
|
1468
|
-
} else if (e[j + 1] === "mate") {
|
|
1469
|
-
infoObj[e[j]] = { mate: parseInt(e[j + 2]) };
|
|
1470
|
-
j += 2;
|
|
1471
|
-
} else {
|
|
1472
|
-
infoObj[e[j]] = { cp: parseInt(e[j + 1]) };
|
|
1473
|
-
j++;
|
|
1474
|
-
}
|
|
1475
|
-
break;
|
|
1476
|
-
default:
|
|
1477
|
-
if (e.length > j + 1 && keywords.includes(e[j])) {
|
|
1478
|
-
infoObj[e[j]] = parseInt(e[j + 1]);
|
|
1479
|
-
j++;
|
|
1480
|
-
} else {
|
|
1481
|
-
infoObj[e[j]] = "";
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
if ("pv" in infoObj) {
|
|
1486
|
-
}
|
|
1487
|
-
} else if (i === "bestmove") {
|
|
1488
|
-
if (e.length === 4 && e[2] === "ponder") {
|
|
1489
|
-
await onEngineBestMove(channelId, e[1], e[3]);
|
|
1226
|
+
if (!output) return;
|
|
1227
|
+
let parts = output.split(" ");
|
|
1228
|
+
let command = parts[0];
|
|
1229
|
+
if (command === "bestmove") {
|
|
1230
|
+
if (parts.length === 4 && parts[2] === "ponder") {
|
|
1231
|
+
await onEngineBestMove(channelId, parts[1], parts[3]);
|
|
1490
1232
|
} else {
|
|
1491
|
-
await onEngineBestMove(channelId,
|
|
1233
|
+
await onEngineBestMove(channelId, parts[1], null);
|
|
1492
1234
|
}
|
|
1493
|
-
} else if (i === "option" || i === "uciok") {
|
|
1494
1235
|
}
|
|
1495
1236
|
} catch (error) {
|
|
1496
1237
|
logger.error(error);
|
|
@@ -1507,17 +1248,36 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1507
1248
|
} else if (wasmType !== void 0) {
|
|
1508
1249
|
const wasmOrigin = origin;
|
|
1509
1250
|
const wasmScriptPath = path.join(wasmOrigin, "assets", "wasm", "pikafish.js");
|
|
1251
|
+
const wasmBinaryPath = path.join(wasmOrigin, "assets", "wasm", "pikafish.wasm");
|
|
1510
1252
|
const Pikafish = require(wasmScriptPath);
|
|
1253
|
+
let wasmBinary;
|
|
1254
|
+
try {
|
|
1255
|
+
wasmBinary = fs.readFileSync(wasmBinaryPath);
|
|
1256
|
+
} catch (e) {
|
|
1257
|
+
console.error(`无法读取 WASM 文件,请检查路径: ${wasmBinaryPath}`, e);
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1511
1260
|
const instance = await Pikafish({
|
|
1512
|
-
|
|
1513
|
-
|
|
1261
|
+
// 显式传入二进制数据
|
|
1262
|
+
wasmBinary,
|
|
1263
|
+
locateFile: /* @__PURE__ */ __name((file) => {
|
|
1264
|
+
if (file.endsWith(".data")) {
|
|
1514
1265
|
return path.join(wasmOrigin, "assets", "wasm", "data", file);
|
|
1266
|
+
} else if (file.endsWith(".wasm")) {
|
|
1267
|
+
return path.join(wasmOrigin, "assets", "wasm", file);
|
|
1515
1268
|
} else {
|
|
1516
1269
|
return path.join(wasmOrigin, "assets", "wasm", file);
|
|
1517
1270
|
}
|
|
1518
|
-
},
|
|
1519
|
-
|
|
1520
|
-
|
|
1271
|
+
}, "locateFile"),
|
|
1272
|
+
// 打印错误日志以便调试
|
|
1273
|
+
print: /* @__PURE__ */ __name((text) => {
|
|
1274
|
+
console.log("[Pikafish stdout]:", text);
|
|
1275
|
+
}, "print"),
|
|
1276
|
+
printErr: /* @__PURE__ */ __name((text) => {
|
|
1277
|
+
console.error("[Pikafish stderr]:", text);
|
|
1278
|
+
}, "printErr"),
|
|
1279
|
+
setStatus: /* @__PURE__ */ __name((status) => {
|
|
1280
|
+
}, "setStatus")
|
|
1521
1281
|
});
|
|
1522
1282
|
engines[channelId] = instance;
|
|
1523
1283
|
engines[channelId].read_stdout = async (stdout) => {
|
|
@@ -1603,13 +1363,11 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1603
1363
|
const figureNamesRegex = new RegExp(possibleFigureNames.join("|"));
|
|
1604
1364
|
const actionRegex = new RegExp(possibleActions.join("|"));
|
|
1605
1365
|
const positionRegex = new RegExp(possiblePositions.join("|"), "g");
|
|
1606
|
-
if (move.length !== 4)
|
|
1607
|
-
return false;
|
|
1608
|
-
}
|
|
1366
|
+
if (move.length !== 4) return false;
|
|
1609
1367
|
const figureNameMatches = move.match(figureNamesRegex);
|
|
1610
1368
|
const actionMatches = move.match(actionRegex);
|
|
1611
1369
|
const positionMatches = move.match(positionRegex);
|
|
1612
|
-
return figureNameMatches && figureNameMatches.length === 1 && actionMatches && actionMatches.length === 1 && positionMatches && positionMatches.length >= 1 && positionMatches.length <= 2;
|
|
1370
|
+
return !!(figureNameMatches && figureNameMatches.length === 1 && actionMatches && actionMatches.length === 1 && positionMatches && positionMatches.length >= 1 && positionMatches.length <= 2);
|
|
1613
1371
|
}
|
|
1614
1372
|
__name(isValidFigureMoveName, "isValidFigureMoveName");
|
|
1615
1373
|
function convertTurnToString(turn) {
|
|
@@ -1618,6 +1376,7 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1618
1376
|
} else if (turn === "b") {
|
|
1619
1377
|
return "黑方";
|
|
1620
1378
|
}
|
|
1379
|
+
return "";
|
|
1621
1380
|
}
|
|
1622
1381
|
__name(convertTurnToString, "convertTurnToString");
|
|
1623
1382
|
async function createImage(buffer) {
|
|
@@ -1632,9 +1391,7 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1632
1391
|
__name(createImage, "createImage");
|
|
1633
1392
|
function isMoveString(str) {
|
|
1634
1393
|
const boardLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"];
|
|
1635
|
-
if (str.length !== 4)
|
|
1636
|
-
return false;
|
|
1637
|
-
}
|
|
1394
|
+
if (str.length !== 4) return false;
|
|
1638
1395
|
return boardLetters.includes(str[0]) && boardLetters.includes(str[2]) && parseInt(str[1]) >= 0 && parseInt(str[1]) <= 9 && parseInt(str[3]) >= 0 && parseInt(str[3]) <= 9;
|
|
1639
1396
|
}
|
|
1640
1397
|
__name(isMoveString, "isMoveString");
|
|
@@ -1642,168 +1399,155 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1642
1399
|
return t.toLowerCase();
|
|
1643
1400
|
}
|
|
1644
1401
|
__name(getType, "getType");
|
|
1645
|
-
function getValidMoveMapKings(board,
|
|
1646
|
-
let
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1402
|
+
function getValidMoveMapKings(board, side, pos) {
|
|
1403
|
+
let minRow, maxRow, map = getEmptyBoard(), col = pos[0], row = pos[1];
|
|
1404
|
+
if (row <= 2) {
|
|
1405
|
+
minRow = 0;
|
|
1406
|
+
maxRow = 2;
|
|
1407
|
+
} else if (row >= 7) {
|
|
1408
|
+
minRow = 7;
|
|
1409
|
+
maxRow = 9;
|
|
1410
|
+
} else {
|
|
1411
|
+
minRow = row - 1;
|
|
1412
|
+
maxRow = row + 1;
|
|
1413
|
+
}
|
|
1414
|
+
const minCol = 3, maxCol = 5;
|
|
1415
|
+
const checkAndSet = /* @__PURE__ */ __name((c, r) => {
|
|
1416
|
+
let type = getValidType(board, side, [c, r]);
|
|
1417
|
+
if (type === "eat" || type === "go") setMoveMap(map, [c, r], type);
|
|
1418
|
+
}, "checkAndSet");
|
|
1419
|
+
if (col + 1 <= maxCol) checkAndSet(col + 1, row);
|
|
1420
|
+
if (col - 1 >= minCol) checkAndSet(col - 1, row);
|
|
1421
|
+
if (row + 1 <= maxRow) checkAndSet(col, row + 1);
|
|
1422
|
+
if (row - 1 >= minRow) checkAndSet(col, row - 1);
|
|
1423
|
+
return map;
|
|
1666
1424
|
}
|
|
1667
1425
|
__name(getValidMoveMapKings, "getValidMoveMapKings");
|
|
1668
|
-
function getValidMoveMapCannons(board,
|
|
1669
|
-
let
|
|
1670
|
-
for (let
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
if (s && "eat" == e2) {
|
|
1676
|
-
setMoveMap(i, [a, A], "eat");
|
|
1426
|
+
function getValidMoveMapCannons(board, side, pos) {
|
|
1427
|
+
let map = getEmptyBoard(), col = pos[0], row = pos[1], flag = false;
|
|
1428
|
+
for (let c = col + 1; c < 9; c++) {
|
|
1429
|
+
let type = getValidType(board, side, [c, row]);
|
|
1430
|
+
if (flag) {
|
|
1431
|
+
if (type === "eat") {
|
|
1432
|
+
setMoveMap(map, [c, row], "eat");
|
|
1677
1433
|
break;
|
|
1678
1434
|
}
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
let
|
|
1688
|
-
if (
|
|
1689
|
-
if (
|
|
1690
|
-
setMoveMap(
|
|
1435
|
+
} else {
|
|
1436
|
+
if (type === "block" || type === "eat") {
|
|
1437
|
+
flag = true;
|
|
1438
|
+
} else if (type === "go") setMoveMap(map, [c, row], "go");
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
flag = false;
|
|
1442
|
+
for (let c = col - 1; c >= 0; c--) {
|
|
1443
|
+
let type = getValidType(board, side, [c, row]);
|
|
1444
|
+
if (flag) {
|
|
1445
|
+
if (type === "eat") {
|
|
1446
|
+
setMoveMap(map, [c, row], "eat");
|
|
1691
1447
|
break;
|
|
1692
1448
|
}
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
let
|
|
1702
|
-
if (
|
|
1703
|
-
if (
|
|
1704
|
-
setMoveMap(
|
|
1449
|
+
} else {
|
|
1450
|
+
if (type === "block" || type === "eat") {
|
|
1451
|
+
flag = true;
|
|
1452
|
+
} else if (type === "go") setMoveMap(map, [c, row], "go");
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
flag = false;
|
|
1456
|
+
for (let r = row + 1; r < 10; r++) {
|
|
1457
|
+
let type = getValidType(board, side, [col, r]);
|
|
1458
|
+
if (flag) {
|
|
1459
|
+
if (type === "eat") {
|
|
1460
|
+
setMoveMap(map, [col, r], "eat");
|
|
1705
1461
|
break;
|
|
1706
1462
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
let
|
|
1716
|
-
if (
|
|
1717
|
-
if (
|
|
1718
|
-
setMoveMap(
|
|
1463
|
+
} else {
|
|
1464
|
+
if (type === "block" || type === "eat") {
|
|
1465
|
+
flag = true;
|
|
1466
|
+
} else if (type === "go") setMoveMap(map, [col, r], "go");
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
flag = false;
|
|
1470
|
+
for (let r = row - 1; r >= 0; r--) {
|
|
1471
|
+
let type = getValidType(board, side, [col, r]);
|
|
1472
|
+
if (flag) {
|
|
1473
|
+
if (type === "eat") {
|
|
1474
|
+
setMoveMap(map, [col, r], "eat");
|
|
1719
1475
|
break;
|
|
1720
1476
|
}
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1477
|
+
} else {
|
|
1478
|
+
if (type === "block" || type === "eat") {
|
|
1479
|
+
flag = true;
|
|
1480
|
+
} else if (type === "go") setMoveMap(map, [col, r], "go");
|
|
1481
|
+
}
|
|
1724
1482
|
}
|
|
1725
|
-
return
|
|
1483
|
+
return map;
|
|
1726
1484
|
}
|
|
1727
1485
|
__name(getValidMoveMapCannons, "getValidMoveMapCannons");
|
|
1728
|
-
function getSideByKing(board,
|
|
1729
|
-
|
|
1730
|
-
let
|
|
1731
|
-
|
|
1732
|
-
for (let
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
return "b";
|
|
1739
|
-
}
|
|
1740
|
-
else
|
|
1741
|
-
for (let i = 3; i <= 5; i++)
|
|
1742
|
-
for (let t2 = 7; t2 <= 9; t2++) {
|
|
1743
|
-
let e2 = getPiece(board, [i, t2]);
|
|
1744
|
-
if ("K" == e2)
|
|
1745
|
-
return "w";
|
|
1746
|
-
if ("k" == e2)
|
|
1747
|
-
return "b";
|
|
1748
|
-
}
|
|
1486
|
+
function getSideByKing(board, pos) {
|
|
1487
|
+
let row = pos[1];
|
|
1488
|
+
let searchRange = row <= 4 ? { min: 0, max: 2 } : { min: 7, max: 9 };
|
|
1489
|
+
for (let r = searchRange.min; r <= searchRange.max; r++) {
|
|
1490
|
+
for (let c = 3; c <= 5; c++) {
|
|
1491
|
+
let p = getPiece(board, [c, r]);
|
|
1492
|
+
if (p === "K") return "w";
|
|
1493
|
+
if (p === "k") return "b";
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1749
1496
|
return "";
|
|
1750
1497
|
}
|
|
1751
1498
|
__name(getSideByKing, "getSideByKing");
|
|
1752
|
-
function getValidMoveMapPawns(board,
|
|
1753
|
-
let
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1499
|
+
function getValidMoveMapPawns(board, side, pos) {
|
|
1500
|
+
let map = getEmptyBoard(), col = pos[0], row = pos[1];
|
|
1501
|
+
let kingSide = getSideByKing(board, pos);
|
|
1502
|
+
if (side === kingSide) {
|
|
1503
|
+
if (row <= 4) {
|
|
1504
|
+
let type = getValidType(board, side, [col, row + 1]);
|
|
1505
|
+
if (type === "eat" || type === "go") setMoveMap(map, [col, row + 1], type);
|
|
1758
1506
|
} else {
|
|
1759
|
-
let
|
|
1760
|
-
"eat"
|
|
1507
|
+
let type = getValidType(board, side, [col, row - 1]);
|
|
1508
|
+
if (type === "eat" || type === "go") setMoveMap(map, [col, row - 1], type);
|
|
1761
1509
|
}
|
|
1762
|
-
else {
|
|
1763
|
-
if (
|
|
1764
|
-
let
|
|
1765
|
-
"eat"
|
|
1510
|
+
} else {
|
|
1511
|
+
if (row <= 4) {
|
|
1512
|
+
let type = getValidType(board, side, [col, row - 1]);
|
|
1513
|
+
if (type === "eat" || type === "go") setMoveMap(map, [col, row - 1], type);
|
|
1766
1514
|
} else {
|
|
1767
|
-
let
|
|
1768
|
-
"eat"
|
|
1515
|
+
let type = getValidType(board, side, [col, row + 1]);
|
|
1516
|
+
if (type === "eat" || type === "go") setMoveMap(map, [col, row + 1], type);
|
|
1769
1517
|
}
|
|
1770
|
-
let
|
|
1771
|
-
|
|
1518
|
+
let typeL = getValidType(board, side, [col - 1, row]);
|
|
1519
|
+
if (typeL === "eat" || typeL === "go") setMoveMap(map, [col - 1, row], typeL);
|
|
1520
|
+
let typeR = getValidType(board, side, [col + 1, row]);
|
|
1521
|
+
if (typeR === "eat" || typeR === "go") setMoveMap(map, [col + 1, row], typeR);
|
|
1772
1522
|
}
|
|
1773
|
-
return
|
|
1523
|
+
return map;
|
|
1774
1524
|
}
|
|
1775
1525
|
__name(getValidMoveMapPawns, "getValidMoveMapPawns");
|
|
1776
|
-
function getValidMoveMapBishops(board,
|
|
1777
|
-
let
|
|
1778
|
-
if (
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
if ("" == e2) {
|
|
1795
|
-
let e3 = getValidType(board, t, [s + 2, a - 2]);
|
|
1796
|
-
"eat" != e3 && "go" != e3 || setMoveMap(A, [s + 2, a - 2], e3);
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1799
|
-
if (s - 2 >= 0 && a - 2 >= i) {
|
|
1800
|
-
let e2 = getPiece(board, [s - 1, a - 1]);
|
|
1801
|
-
if ("" == e2) {
|
|
1802
|
-
let e3 = getValidType(board, t, [s - 2, a - 2]);
|
|
1803
|
-
"eat" != e3 && "go" != e3 || setMoveMap(A, [s - 2, a - 2], e3);
|
|
1526
|
+
function getValidMoveMapBishops(board, side, pos) {
|
|
1527
|
+
let minRow, maxRow, map = getEmptyBoard(), col = pos[0], row = pos[1];
|
|
1528
|
+
if (row <= 4) {
|
|
1529
|
+
minRow = 0;
|
|
1530
|
+
maxRow = 4;
|
|
1531
|
+
} else if (row >= 5) {
|
|
1532
|
+
minRow = 5;
|
|
1533
|
+
maxRow = 9;
|
|
1534
|
+
} else {
|
|
1535
|
+
minRow = row - 1;
|
|
1536
|
+
maxRow = row + 1;
|
|
1537
|
+
}
|
|
1538
|
+
const check = /* @__PURE__ */ __name((cOffset, rOffset) => {
|
|
1539
|
+
if (col + cOffset * 2 >= 0 && col + cOffset * 2 <= 8 && row + rOffset * 2 >= minRow && row + rOffset * 2 <= maxRow) {
|
|
1540
|
+
if (getPiece(board, [col + cOffset, row + rOffset]) === "") {
|
|
1541
|
+
let type = getValidType(board, side, [col + cOffset * 2, row + rOffset * 2]);
|
|
1542
|
+
if (type === "eat" || type === "go") setMoveMap(map, [col + cOffset * 2, row + rOffset * 2], type);
|
|
1543
|
+
}
|
|
1804
1544
|
}
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1545
|
+
}, "check");
|
|
1546
|
+
check(1, 1);
|
|
1547
|
+
check(-1, 1);
|
|
1548
|
+
check(1, -1);
|
|
1549
|
+
check(-1, -1);
|
|
1550
|
+
return map;
|
|
1807
1551
|
}
|
|
1808
1552
|
__name(getValidMoveMapBishops, "getValidMoveMapBishops");
|
|
1809
1553
|
function getValidMoveMap(board, type, side, position) {
|
|
@@ -1827,115 +1571,100 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1827
1571
|
}
|
|
1828
1572
|
}
|
|
1829
1573
|
__name(getValidMoveMap, "getValidMoveMap");
|
|
1830
|
-
function getValidMoveMapRooks(board,
|
|
1831
|
-
let
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
continue;
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
}
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
break;
|
|
1847
|
-
if (i[A][s] = e2, "eat" == e2)
|
|
1848
|
-
break;
|
|
1849
|
-
}
|
|
1850
|
-
for (let s = A; s < 10; s++) {
|
|
1851
|
-
if (s == A)
|
|
1852
|
-
continue;
|
|
1853
|
-
let e2 = getValidType(board, t, [n, s]);
|
|
1854
|
-
if ("block" == e2)
|
|
1855
|
-
break;
|
|
1856
|
-
if (i[s][n] = e2, "eat" == e2)
|
|
1857
|
-
break;
|
|
1858
|
-
}
|
|
1859
|
-
for (let s = A; s >= 0; s--) {
|
|
1860
|
-
if (s == A)
|
|
1861
|
-
continue;
|
|
1862
|
-
let e2 = getValidType(board, t, [n, s]);
|
|
1863
|
-
if ("block" == e2)
|
|
1864
|
-
break;
|
|
1865
|
-
if (i[s][n] = e2, "eat" == e2)
|
|
1866
|
-
break;
|
|
1867
|
-
}
|
|
1868
|
-
return i;
|
|
1574
|
+
function getValidMoveMapRooks(board, side, pos) {
|
|
1575
|
+
let map = getEmptyBoard(), col = pos[0], row = pos[1];
|
|
1576
|
+
const scan = /* @__PURE__ */ __name((cStart, cEnd, rStart, rEnd, cStep, rStep) => {
|
|
1577
|
+
for (let c = cStart, r = rStart; c !== cEnd && r !== rEnd; c += cStep, r += rStep) {
|
|
1578
|
+
if (c === col && r === row) continue;
|
|
1579
|
+
let type = getValidType(board, side, [c, r]);
|
|
1580
|
+
if (type === "block") break;
|
|
1581
|
+
map[r][c] = type;
|
|
1582
|
+
if (type === "eat") break;
|
|
1583
|
+
}
|
|
1584
|
+
}, "scan");
|
|
1585
|
+
scan(col, 9, row, row + 1, 1, 0);
|
|
1586
|
+
scan(col, -1, row, row + 1, -1, 0);
|
|
1587
|
+
scan(col, col + 1, row, 10, 0, 1);
|
|
1588
|
+
scan(col, col + 1, row, -1, 0, -1);
|
|
1589
|
+
return map;
|
|
1869
1590
|
}
|
|
1870
1591
|
__name(getValidMoveMapRooks, "getValidMoveMapRooks");
|
|
1871
|
-
function getValidType(board,
|
|
1872
|
-
let
|
|
1873
|
-
return void 0
|
|
1592
|
+
function getValidType(board, side, pos) {
|
|
1593
|
+
let p = getPiece(board, pos);
|
|
1594
|
+
return p === void 0 ? "invalid" : p === "" ? "go" : side !== getSide(p) ? "eat" : "block";
|
|
1874
1595
|
}
|
|
1875
1596
|
__name(getValidType, "getValidType");
|
|
1876
|
-
function getValidMoveMapAdvisors(board,
|
|
1877
|
-
let
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
}
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
}
|
|
1896
|
-
|
|
1597
|
+
function getValidMoveMapAdvisors(board, side, pos) {
|
|
1598
|
+
let minRow, maxRow, map = getEmptyBoard(), col = pos[0], row = pos[1];
|
|
1599
|
+
if (row <= 2) {
|
|
1600
|
+
minRow = 0;
|
|
1601
|
+
maxRow = 2;
|
|
1602
|
+
} else if (row >= 7) {
|
|
1603
|
+
minRow = 7;
|
|
1604
|
+
maxRow = 9;
|
|
1605
|
+
} else {
|
|
1606
|
+
minRow = row - 1;
|
|
1607
|
+
maxRow = row + 1;
|
|
1608
|
+
}
|
|
1609
|
+
const minCol = 3, maxCol = 5;
|
|
1610
|
+
const check = /* @__PURE__ */ __name((cOffset, rOffset) => {
|
|
1611
|
+
let c = col + cOffset, r = row + rOffset;
|
|
1612
|
+
if (c >= minCol && c <= maxCol && r >= minRow && r <= maxRow) {
|
|
1613
|
+
let type = getValidType(board, side, [c, r]);
|
|
1614
|
+
if (type === "eat" || type === "go") setMoveMap(map, [c, r], type);
|
|
1615
|
+
}
|
|
1616
|
+
}, "check");
|
|
1617
|
+
check(1, 1);
|
|
1618
|
+
check(-1, 1);
|
|
1619
|
+
check(1, -1);
|
|
1620
|
+
check(-1, -1);
|
|
1621
|
+
return map;
|
|
1897
1622
|
}
|
|
1898
1623
|
__name(getValidMoveMapAdvisors, "getValidMoveMapAdvisors");
|
|
1899
|
-
function setMoveMap(
|
|
1900
|
-
|
|
1624
|
+
function setMoveMap(map, pos, type) {
|
|
1625
|
+
if (pos[0] >= 0 && pos[0] <= 8 && pos[1] >= 0 && pos[1] <= 9) {
|
|
1626
|
+
map[pos[1]][pos[0]] = type;
|
|
1627
|
+
}
|
|
1901
1628
|
}
|
|
1902
1629
|
__name(setMoveMap, "setMoveMap");
|
|
1903
|
-
function getValidMoveMapKnights(board,
|
|
1904
|
-
let
|
|
1905
|
-
|
|
1630
|
+
function getValidMoveMapKnights(board, side, pos) {
|
|
1631
|
+
let map = getEmptyBoard(), col = pos[0], row = pos[1];
|
|
1632
|
+
const check = /* @__PURE__ */ __name((legC, legR, targetC, targetR) => {
|
|
1633
|
+
if (getPiece(board, [col + legC, row + legR]) === "") {
|
|
1634
|
+
let type = getValidType(board, side, [col + targetC, row + targetR]);
|
|
1635
|
+
setMoveMap(map, [col + targetC, row + targetR], type);
|
|
1636
|
+
}
|
|
1637
|
+
}, "check");
|
|
1638
|
+
check(1, 0, 2, 1);
|
|
1639
|
+
check(1, 0, 2, -1);
|
|
1640
|
+
check(-1, 0, -2, 1);
|
|
1641
|
+
check(-1, 0, -2, -1);
|
|
1642
|
+
check(0, 1, 1, 2);
|
|
1643
|
+
check(0, 1, -1, 2);
|
|
1644
|
+
check(0, -1, 1, -2);
|
|
1645
|
+
check(0, -1, -1, -2);
|
|
1646
|
+
return map;
|
|
1906
1647
|
}
|
|
1907
1648
|
__name(getValidMoveMapKnights, "getValidMoveMapKnights");
|
|
1908
|
-
var
|
|
1909
|
-
|
|
1910
|
-
var
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
Qt["w"] = [], Qt["b"] = [], Qt["w"][0] = "一", Qt["w"][1] = "二", Qt["w"][2] = "三", Qt["w"][3] = "四", Qt["w"][4] = "五", Qt["w"][5] = "六", Qt["w"][6] = "七", Qt["w"][7] = "八", Qt["w"][8] = "九", // Qt["b"][0] = "9",
|
|
1916
|
-
// Qt["b"][1] = "8",
|
|
1917
|
-
// Qt["b"][2] = "7",
|
|
1918
|
-
// Qt["b"][3] = "6",
|
|
1919
|
-
// Qt["b"][4] = "5",
|
|
1920
|
-
// Qt["b"][5] = "4",
|
|
1921
|
-
// Qt["b"][6] = "3",
|
|
1922
|
-
// Qt["b"][7] = "2",
|
|
1923
|
-
// Qt["b"][8] = "1";
|
|
1924
|
-
Qt["b"][0] = "9", Qt["b"][1] = "8", Qt["b"][2] = "7", Qt["b"][3] = "6", Qt["b"][4] = "5", Qt["b"][5] = "4", Qt["b"][6] = "3", Qt["b"][7] = "2", Qt["b"][8] = "1";
|
|
1649
|
+
var ActionMap = { w: ["进", "退"], b: ["退", "进"], p: "平" };
|
|
1650
|
+
var PositionMap = { w: ["前", "后"], b: ["后", "前"], m: "中" };
|
|
1651
|
+
var PieceNameMap = { k: "将", a: "士", b: "象", r: "车", n: "马", c: "炮", p: "卒", K: "帅", A: "仕", B: "相", R: "车", N: "马", C: "炮", P: "兵" };
|
|
1652
|
+
var NumberMap = {
|
|
1653
|
+
w: ["一", "二", "三", "四", "五", "六", "七", "八", "九"],
|
|
1654
|
+
b: ["9", "8", "7", "6", "5", "4", "3", "2", "1"]
|
|
1655
|
+
};
|
|
1925
1656
|
function parseChessNotation(fen) {
|
|
1926
1657
|
let e = [];
|
|
1927
1658
|
for (let s = 0; s < 9; s++) {
|
|
1928
1659
|
e[s] = [];
|
|
1929
|
-
for (let t = 0; t < 10; t++)
|
|
1930
|
-
e[s][t] = 0;
|
|
1660
|
+
for (let t = 0; t < 10; t++) e[s][t] = 0;
|
|
1931
1661
|
}
|
|
1932
1662
|
let i = fen.split(" ")[0].split("/"), n = ["k", "a", "b", "r", "n", "c", "p", "K", "A", "B", "R", "N", "C", "P"], A = 0;
|
|
1933
1663
|
for (let s = 0; s < 10; s++) {
|
|
1934
1664
|
let t = i[s], a = 0;
|
|
1935
|
-
for (let
|
|
1936
|
-
let o = t[
|
|
1937
|
-
if (o >= "0" && o <= "9")
|
|
1938
|
-
a += parseInt(o);
|
|
1665
|
+
for (let k = 0; k < t.length; k++) {
|
|
1666
|
+
let o = t[k];
|
|
1667
|
+
if (o >= "0" && o <= "9") a += parseInt(o);
|
|
1939
1668
|
else if (-1 != n.indexOf(o)) {
|
|
1940
1669
|
let t2 = o >= "a" && o <= "z" ? "b" : "w";
|
|
1941
1670
|
e[a][s] = t2 + o + A, a++, A++;
|
|
@@ -1949,19 +1678,15 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1949
1678
|
let i = parseChessNotation(fen);
|
|
1950
1679
|
var n = moveString.charCodeAt(0) - 97, A = 9 - (moveString.charCodeAt(1) - 48), s = moveString.charCodeAt(2) - 97, a = 9 - (moveString.charCodeAt(3) - 48), o = 0, r = 0, l = 0, d = "";
|
|
1951
1680
|
if ("A" != i[n][A].charAt(1) && "B" != i[n][A].charAt(1) && "a" != i[n][A].charAt(1) && "b" != i[n][A].charAt(1)) {
|
|
1952
|
-
for (var g = 0; g < 9; g++)
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
0 != i[n][f] && i[n][f].substring(0, 2) == i[n][A].substring(0, 2) && (f < A ? 0 == l ? (d = Ht[i[n][A].charAt(0)][1] + qt[i[n][A].charAt(1)], o++) : (d = Ht[i[n][A].charAt(0)][1] + Qt[i[n][A].charAt(0)][9 - n - 1], o++) : f == A ? 0 == o ? d = qt[i[n][A].charAt(1)] + Qt[i[n][A].charAt(0)][9 - n - 1] : r = o : 0 == l ? 0 == o ? d = Ht[i[n][A].charAt(0)][0] + qt[i[n][A].charAt(1)] : (d = Ht["m"] + qt[i[n][A].charAt(1)], o++) : 0 == o ? d = Ht[i[n][A].charAt(0)][0] + Qt[i[n][A].charAt(0)][9 - n - 1] : (d = Ht["m"] + Qt[i[n][A].charAt(0)][9 - n - 1], o++));
|
|
1960
|
-
o > 2 && o != r && (d = "w" == i[n][A].charAt(0) ? Qt["w"][r] + qt[i[n][A].charAt(1)] : Qt["w"][o - r] + qt[i[n][A].charAt(1)]);
|
|
1961
|
-
} else
|
|
1962
|
-
d = qt[i[n][A].charAt(1)] + Qt[i[n][A].charAt(0)][9 - n - 1];
|
|
1681
|
+
for (var g = 0; g < 9; g++) if (g != n) {
|
|
1682
|
+
for (var f = 0; f < 10; f++) 0 != i[g][f] && i[g][f].substring(0, 2) == i[n][A].substring(0, 2) && l++;
|
|
1683
|
+
l < 2 && (l = 0);
|
|
1684
|
+
}
|
|
1685
|
+
for (f = 0; f < 10; f++) 0 != i[n][f] && i[n][f].substring(0, 2) == i[n][A].substring(0, 2) && (f < A ? 0 == l ? (d = PositionMap[i[n][A].charAt(0)][1] + PieceNameMap[i[n][A].charAt(1)], o++) : (d = PositionMap[i[n][A].charAt(0)][1] + NumberMap[i[n][A].charAt(0)][9 - n - 1], o++) : f == A ? 0 == o ? d = PieceNameMap[i[n][A].charAt(1)] + NumberMap[i[n][A].charAt(0)][9 - n - 1] : r = o : 0 == l ? 0 == o ? d = PositionMap[i[n][A].charAt(0)][0] + PieceNameMap[i[n][A].charAt(1)] : (d = PositionMap["m"] + PieceNameMap[i[n][A].charAt(1)], o++) : 0 == o ? d = PositionMap[i[n][A].charAt(0)][0] + NumberMap[i[n][A].charAt(0)][9 - n - 1] : (d = PositionMap["m"] + NumberMap[i[n][A].charAt(0)][9 - n - 1], o++));
|
|
1686
|
+
o > 2 && o != r && (d = "w" == i[n][A].charAt(0) ? NumberMap["w"][r] + PieceNameMap[i[n][A].charAt(1)] : NumberMap["w"][o - r] + PieceNameMap[i[n][A].charAt(1)]);
|
|
1687
|
+
} else d = PieceNameMap[i[n][A].charAt(1)] + NumberMap[i[n][A].charAt(0)][9 - n - 1];
|
|
1963
1688
|
var h2 = "";
|
|
1964
|
-
return h2 = A > a ? n == s ? "w" == i[n][A].charAt(0) ?
|
|
1689
|
+
return h2 = A > a ? n == s ? "w" == i[n][A].charAt(0) ? ActionMap[i[n][A].charAt(0)][0] + NumberMap[i[n][A].charAt(0)][A - a - 1] : ActionMap[i[n][A].charAt(0)][0] + NumberMap[i[n][A].charAt(0)][9 - (A - a - 1) - 1] : ActionMap[i[n][A].charAt(0)][0] + NumberMap[i[n][A].charAt(0)][9 - s - 1] : A == a ? ActionMap["p"] + NumberMap[i[n][A].charAt(0)][9 - s - 1] : n == s ? "w" == i[n][A].charAt(0) ? ActionMap[i[n][A].charAt(0)][1] + NumberMap[i[n][A].charAt(0)][a - A - 1] : ActionMap[i[n][A].charAt(0)][1] + NumberMap[i[n][A].charAt(0)][9 - (a - A - 1) - 1] : ActionMap[i[n][A].charAt(0)][1] + NumberMap[i[n][A].charAt(0)][9 - s - 1], d + h2;
|
|
1965
1690
|
}
|
|
1966
1691
|
__name(getFigureMoveName, "getFigureMoveName");
|
|
1967
1692
|
function moveToMoveString(move) {
|
|
@@ -1985,9 +1710,7 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
1985
1710
|
function genRandomId(length) {
|
|
1986
1711
|
let id = "";
|
|
1987
1712
|
const characters = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
1988
|
-
for (let i = 0; i < length; i++)
|
|
1989
|
-
id += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
1990
|
-
}
|
|
1713
|
+
for (let i = 0; i < length; i++) id += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
1991
1714
|
return id;
|
|
1992
1715
|
}
|
|
1993
1716
|
__name(genRandomId, "genRandomId");
|
|
@@ -2003,9 +1726,7 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
2003
1726
|
turnAfterLastEat,
|
|
2004
1727
|
movesAfterLastEat
|
|
2005
1728
|
} = gameRecord;
|
|
2006
|
-
if (isHistoryMode)
|
|
2007
|
-
gameRecord.isHistoryMode = false;
|
|
2008
|
-
}
|
|
1729
|
+
if (isHistoryMode) gameRecord.isHistoryMode = false;
|
|
2009
1730
|
const lastMove = [fromPos, toPos];
|
|
2010
1731
|
const moveId = genRandomId(8);
|
|
2011
1732
|
const pieceAtDestination = board[toPos[1]][toPos[0]] !== "";
|
|
@@ -2061,9 +1782,7 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
2061
1782
|
}
|
|
2062
1783
|
__name(getFen, "getFen");
|
|
2063
1784
|
function boardToFen(board, side, turn = "w") {
|
|
2064
|
-
if (board === null)
|
|
2065
|
-
return "";
|
|
2066
|
-
}
|
|
1785
|
+
if (board === null) return "";
|
|
2067
1786
|
const ranks = side === "w" ? [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] : [9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
|
|
2068
1787
|
let fenString = "";
|
|
2069
1788
|
for (const row of ranks) {
|
|
@@ -2080,9 +1799,7 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
2080
1799
|
fenString += piece;
|
|
2081
1800
|
}
|
|
2082
1801
|
}
|
|
2083
|
-
if (emptyCount > 0)
|
|
2084
|
-
fenString += emptyCount;
|
|
2085
|
-
}
|
|
1802
|
+
if (emptyCount > 0) fenString += emptyCount;
|
|
2086
1803
|
fenString += "/";
|
|
2087
1804
|
}
|
|
2088
1805
|
fenString = fenString.substring(0, fenString.length - 1) + " " + turn;
|
|
@@ -2090,16 +1807,13 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
2090
1807
|
}
|
|
2091
1808
|
__name(boardToFen, "boardToFen");
|
|
2092
1809
|
function getSide(piece) {
|
|
2093
|
-
|
|
2094
|
-
return e.includes(piece) ? "w" : "b";
|
|
1810
|
+
return "RNBAKCP".includes(piece) ? "w" : "b";
|
|
2095
1811
|
}
|
|
2096
1812
|
__name(getSide, "getSide");
|
|
2097
1813
|
async function getGameRecord(channelId) {
|
|
2098
1814
|
let gameRecord = await ctx.database.get("cchess_game_records", { channelId });
|
|
2099
1815
|
if (gameRecord.length === 0) {
|
|
2100
|
-
await ctx.database.create("cchess_game_records", {
|
|
2101
|
-
channelId
|
|
2102
|
-
});
|
|
1816
|
+
await ctx.database.create("cchess_game_records", { channelId });
|
|
2103
1817
|
gameRecord = await ctx.database.get("cchess_game_records", { channelId });
|
|
2104
1818
|
}
|
|
2105
1819
|
return gameRecord[0];
|
|
@@ -2107,11 +1821,11 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
2107
1821
|
__name(getGameRecord, "getGameRecord");
|
|
2108
1822
|
async function drawChessBoard(channelId) {
|
|
2109
1823
|
const gameRecord = await getGameRecord(channelId);
|
|
2110
|
-
let { board, lastMove, moveList
|
|
2111
|
-
const canvas = await ctx.canvas.createCanvas(
|
|
1824
|
+
let { board, lastMove, moveList } = gameRecord;
|
|
1825
|
+
const canvas = await ctx.canvas.createCanvas(BOARD_WIDTH * scale, BOARD_HEIGHT * scale);
|
|
2112
1826
|
const context = canvas.getContext("2d");
|
|
2113
1827
|
const boardImg = await ctx.canvas.loadImage(boardSkinImg);
|
|
2114
|
-
context.drawImage(boardImg, 0, 0,
|
|
1828
|
+
context.drawImage(boardImg, 0, 0, BOARD_WIDTH * scale, BOARD_HEIGHT * scale);
|
|
2115
1829
|
const pieceImages = {};
|
|
2116
1830
|
const pieceImagePromises = Object.keys(piecesImgResources).map((piece) => {
|
|
2117
1831
|
return ctx.canvas.loadImage(piecesImgResources[piece]).then((img) => {
|
|
@@ -2122,21 +1836,27 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
2122
1836
|
for (let row = 0; row < 10; row++) {
|
|
2123
1837
|
for (let col = 0; col < 9; col++) {
|
|
2124
1838
|
const piece = getPiece(board, [col, row]);
|
|
2125
|
-
if (piece === "")
|
|
2126
|
-
|
|
2127
|
-
const
|
|
2128
|
-
const yPos = ((isFlipBoard ? 9 - row : row) * we + Pe - Be / 2) * scale;
|
|
1839
|
+
if (piece === "") continue;
|
|
1840
|
+
const xPos = ((isFlipBoard ? 8 - col : col) * CELL_WIDTH + BOARD_PADDING - PIECE_SIZE / 2) * scale;
|
|
1841
|
+
const yPos = ((isFlipBoard ? 9 - row : row) * CELL_WIDTH + BOARD_PADDING - PIECE_SIZE / 2) * scale;
|
|
2129
1842
|
const pieceImg = pieceImages[piece];
|
|
2130
|
-
context.drawImage(pieceImg, xPos, yPos,
|
|
1843
|
+
context.drawImage(pieceImg, xPos, yPos, PIECE_SIZE * scale, PIECE_SIZE * scale);
|
|
2131
1844
|
}
|
|
2132
1845
|
}
|
|
2133
1846
|
if (lastMove !== null) {
|
|
2134
|
-
let
|
|
2135
|
-
let
|
|
2136
|
-
|
|
1847
|
+
let [start, end] = lastMove;
|
|
1848
|
+
let sx = start[0], sy = start[1], ex = end[0], ey = end[1];
|
|
1849
|
+
let startX = sx * CELL_WIDTH + ARROW_OFFSET;
|
|
1850
|
+
let startY = sy * CELL_WIDTH + BOARD_PADDING;
|
|
1851
|
+
let endX = ex * CELL_WIDTH + ARROW_OFFSET;
|
|
1852
|
+
let endY = ey * CELL_WIDTH + BOARD_PADDING;
|
|
1853
|
+
let dist = Math.sqrt((startX - endX) ** 2 + (startY - endY) ** 2);
|
|
1854
|
+
let adjustedEndX = startX + (endX - startX) * (dist - 30) / dist;
|
|
1855
|
+
let adjustedEndY = startY + (endY - startY) * (dist - 30) / dist;
|
|
1856
|
+
await drawLineArrow(context, startX * scale, startY * scale, adjustedEndX * scale, adjustedEndY * scale, "rgba(128, 171, 69, 0.7)", 15 * scale);
|
|
2137
1857
|
}
|
|
2138
1858
|
if (moveList.length > 0) {
|
|
2139
|
-
currentMoveId = moveList[moveList.length - 1].moveId;
|
|
1859
|
+
const currentMoveId = moveList[moveList.length - 1].moveId;
|
|
2140
1860
|
await ctx.database.set("cchess_game_records", { channelId }, { currentMoveId });
|
|
2141
1861
|
}
|
|
2142
1862
|
if (config.isChessImageWithOutlineEnabled) {
|
|
@@ -2146,13 +1866,29 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
2146
1866
|
}
|
|
2147
1867
|
}
|
|
2148
1868
|
__name(drawChessBoard, "drawChessBoard");
|
|
2149
|
-
async function drawLineArrow(
|
|
2150
|
-
var
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
var
|
|
2155
|
-
|
|
1869
|
+
async function drawLineArrow(ctx2, fromX, fromY, toX, toY, color = "black", headSize = 20) {
|
|
1870
|
+
var angle = Math.atan2(toY - fromY, toX - fromX);
|
|
1871
|
+
var headAngle = 45 * Math.PI / 180;
|
|
1872
|
+
ctx2.beginPath();
|
|
1873
|
+
ctx2.moveTo(fromX, fromY);
|
|
1874
|
+
var angle1 = angle + headAngle;
|
|
1875
|
+
var angle2 = angle - headAngle;
|
|
1876
|
+
var topX = toX - headSize * Math.cos(angle1);
|
|
1877
|
+
var topY = toY - headSize * Math.sin(angle1);
|
|
1878
|
+
var botX = toX - headSize * Math.cos(angle2);
|
|
1879
|
+
var botY = toY - headSize * Math.sin(angle2);
|
|
1880
|
+
ctx2.lineTo(toX, toY);
|
|
1881
|
+
ctx2.stroke();
|
|
1882
|
+
ctx2.beginPath();
|
|
1883
|
+
ctx2.moveTo(toX, toY);
|
|
1884
|
+
ctx2.lineTo(topX, topY);
|
|
1885
|
+
ctx2.lineTo(botX, botY);
|
|
1886
|
+
ctx2.lineTo(toX, toY);
|
|
1887
|
+
ctx2.closePath();
|
|
1888
|
+
ctx2.fillStyle = color;
|
|
1889
|
+
ctx2.strokeStyle = color;
|
|
1890
|
+
ctx2.fill();
|
|
1891
|
+
ctx2.stroke();
|
|
2156
1892
|
}
|
|
2157
1893
|
__name(drawLineArrow, "drawLineArrow");
|
|
2158
1894
|
function loadPiecesImageResources(folder, format = "webp") {
|
|
@@ -2220,31 +1956,21 @@ https://www.xqbase.com/protocol/cchess_fen.htm`);
|
|
|
2220
1956
|
const { bot, channelId } = session;
|
|
2221
1957
|
let messageId;
|
|
2222
1958
|
if (config.isTextToImageConversionEnabled) {
|
|
2223
|
-
const
|
|
2224
|
-
|
|
2225
|
-
if (isOnlyImgTag) {
|
|
2226
|
-
await session.send(message);
|
|
2227
|
-
} else {
|
|
2228
|
-
const modifiedMessage = lines.map((line) => {
|
|
2229
|
-
if (line.trim() !== "" && !line.includes("<img")) {
|
|
2230
|
-
return `# ${line}`;
|
|
2231
|
-
} else {
|
|
2232
|
-
return line + "\n";
|
|
2233
|
-
}
|
|
2234
|
-
}).join("\n");
|
|
2235
|
-
const imageBuffer = await ctx.markdownToImage.convertToImage(modifiedMessage);
|
|
2236
|
-
[messageId] = await session.send(import_koishi.h.image(imageBuffer, `image/${config.imageType}`));
|
|
2237
|
-
}
|
|
1959
|
+
const imageBuffer = await ctx.markdownToImage.convertToImage(message);
|
|
1960
|
+
[messageId] = await session.send(import_koishi.h.image(imageBuffer, `image/${config.imageType}`));
|
|
2238
1961
|
} else {
|
|
2239
|
-
|
|
1962
|
+
let plainText = message.replace(/\*\*(.*?)\*\*/g, "$1").replace(/^#+\s*/gm, "").replace(/\[([^\]]+)\]\([^\)]+\)/g, "$1");
|
|
1963
|
+
[messageId] = await session.send(plainText);
|
|
2240
1964
|
}
|
|
2241
|
-
if (config.retractDelay === 0)
|
|
2242
|
-
return;
|
|
1965
|
+
if (config.retractDelay === 0) return;
|
|
2243
1966
|
sentMessages.push(messageId);
|
|
2244
1967
|
if (sentMessages.length > 1) {
|
|
2245
1968
|
const oldestMessageId = sentMessages.shift();
|
|
2246
1969
|
setTimeout(async () => {
|
|
2247
|
-
|
|
1970
|
+
try {
|
|
1971
|
+
await bot.deleteMessage(channelId, oldestMessageId);
|
|
1972
|
+
} catch (e) {
|
|
1973
|
+
}
|
|
2248
1974
|
}, config.retractDelay * 1e3);
|
|
2249
1975
|
}
|
|
2250
1976
|
}
|