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.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
- - 建议自行添加别名,如 \`cc\` 等更方便的指令。
47
- - 请安装并启用所需服务,\`canvas\` 服务可使用 \`puppeteer\` 提供。
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
- - \`cchess.退出\`: 退出当前游戏。
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
- ## 🐱 QQ 群
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(`默认引擎思考深度,越高 AI 棋力越强。由于 Nodejs 不支持 SIMD,所以不建议设置过高。`),
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
- engines[channelId].send_command("quit");
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 we = 54;
100
- const pe = 33;
101
- const Pe = 33;
102
- const Be = 50;
103
- const Ie = 54;
104
- const Me = 500;
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
241
+ return await sendMessage(session, `**【@${username}】**
260
242
  您加入游戏啦!
261
- 您的队伍为:【${choice}】
262
- 当前玩家人数为:【${playersNum + 1}】
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, `【@${username}】
270
- 您已更换队伍为:【${choice}】
271
- 当前玩家人数为:【${playersNum}】`);
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
274
+ return await sendMessage(session, `**【@${username}】**
298
275
  您已退出游戏!
299
- 剩余玩家人数为:【${playersNum - 1}】`);
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, `【@${username}】
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, `【@${username}】
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 += `【@${randomPlayer.username}】被自动分配到红方。
304
+ message += `**【@${randomPlayer.username}】**被自动分配到红方。
333
305
  `;
334
306
  } else {
335
307
  randomPlayer.side = "黑方";
336
- message += `【@${randomPlayer.username}】被自动分配到黑方。
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) => `【@${player.username}】`).join("\n")}
319
+ ${redPlayers.map((player) => `**【@${player.username}】**`).join("\n")}
348
320
 
349
321
  `;
350
322
  message += `黑方玩家(${blackPlayers.length}):
351
- ${blackPlayers.map((player) => `【@${player.username}】`).join("\n")}`;
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
- 先手方为:【${sideString}】
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, `【@${username}】
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, `【@${username}】
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 += `人类队伍为:【${side}】
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
- 先手方为:【${sideString}】
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, `【@${username}】
425
+ return await sendMessage(session, `**【@${username}】**
478
426
  游戏未开始哦!
479
427
  完全没必要强制结束嘛~`);
480
428
  } else {
481
429
  await endGame(channelId);
482
- return await sendMessage(session, `【@${username}】
430
+ return await sendMessage(session, `**【@${username}】**
483
431
  游戏已被强制结束!`);
484
432
  }
485
433
  });
486
- ctx.command("cchess.移动 <moveOperation:text>", "进行移动操作").action(
487
- async ({ session }, moveOperation) => {
488
- const { username, userId, channelId } = session;
489
- await updateNameInPlayerRecord(userId, username);
490
- if (!isMoveString(moveOperation) && !isValidFigureMoveName(moveOperation)) {
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
- const gameRecord = await getGameRecord(channelId);
495
- if (!gameRecord.isStarted) {
496
- return await sendMessage(session, `【@${username}】
440
+ }
441
+ const gameRecord = await getGameRecord(channelId);
442
+ if (!gameRecord.isStarted) {
443
+ return await sendMessage(session, `**【@${username}】**
497
444
  游戏还未开始哦!`);
498
- }
499
- if (gameRecord.isRegretRequest) {
500
- return await sendMessage(session, `【@${username}】
445
+ }
446
+ if (gameRecord.isRegretRequest) {
447
+ return await sendMessage(session, `**【@${username}】**
501
448
  正在请求悔棋,等待回应中...`);
502
- }
503
- const turn = gameRecord.turn;
504
- const sideString = convertTurnToString(turn);
505
- let playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
506
- if (playerRecord.length === 0) {
507
- if (config.allowFreePieceMovementInHumanMachineMode) {
508
- if (gameRecord.isEnginePlayRed) {
509
- await ctx.database.create("cchess_gaming_player_records", { channelId, userId, username, side: "黑方" });
510
- playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
511
- } else if (gameRecord.isEnginePlayBlack) {
512
- await ctx.database.create("cchess_gaming_player_records", { channelId, userId, username, side: "红方" });
513
- playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
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
- if (playerRecord[0].side !== sideString) {
521
- return await sendMessage(session, `【@${username}】
466
+ }
467
+ if (playerRecord.length === 0 || playerRecord[0].side !== sideString) {
468
+ return await sendMessage(session, `**【@${username}】**
522
469
  还没轮到${sideString}走棋哦!
523
- 当前走棋方为:【${convertTurnToString(gameRecord.turn)}】`);
524
- }
525
- await checkEngine(channelId);
526
- if (engines[channelId] && !gameRecord.isEngineReady) {
527
- await ctx.database.set("cchess_game_records", { channelId }, {
528
- isEngineReady: true
529
- });
530
- }
531
- const board = gameRecord.board;
532
- let selectedPos = void 0;
533
- let newPos = void 0;
534
- if (possibleFigureNames.some((figureName) => moveOperation.includes(figureName))) {
535
- const figureName = getFigureNameFromMoveOperation(moveOperation);
536
- const englishLetter = getEnglishLetterFromFigureName(figureName);
537
- const processedLetter = processEnglishLetter(englishLetter, turn);
538
- const letterPositions = findLetterPositions(board, processedLetter);
539
- const moveInfoList = [];
540
- for (const pos of letterPositions) {
541
- const piece2 = processedLetter;
542
- const side2 = getSide(piece2);
543
- const type2 = getType(piece2);
544
- const moveMap2 = getValidMoveMap(board, type2, side2, [pos[1], pos[0]]);
545
- const legalPositions = findLegalMovePositions(moveMap2);
546
- const fen = getFen(board, side2);
547
- for (const toPos of legalPositions) {
548
- const moveString = moveToMoveString([[pos[1], pos[0]], [toPos[1], toPos[0]]]);
549
- const figureMoveName = getFigureMoveName(fen, moveString);
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
- const duplicateMoveInfo = findMoveInfo(moveInfoList, moveOperation);
558
- if (!duplicateMoveInfo) {
559
- return await sendMessage(session, `【@${username}】
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] = moveStringToPos(moveOperation);
504
+ [selectedPos, newPos] = duplicateMoveInfo.moveCord;
566
505
  }
567
- const [newCol, newRow] = newPos;
568
- const piece = getPiece(board, selectedPos);
569
- const side = getSide(piece);
570
- const type = getType(piece);
571
- if (side !== gameRecord.turn) {
572
- return await sendMessage(session, `【@${username}】
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
- 当前走棋方为:【${convertTurnToString(gameRecord.turn)}】`);
575
- }
576
- const moveMap = getValidMoveMap(board, type, side, selectedPos);
577
- if (moveMap[newRow][newCol] !== "go" && moveMap[newRow][newCol] !== "eat") {
578
- return await sendMessage(session, `【@${username}】
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
- await makeMove(channelId, selectedPos, newPos);
582
- await ctx.database.set("cchess_game_records", { channelId }, {
583
- isAnalyzing: true
584
- });
585
- await engineAction(channelId);
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 gameRecord2 = await getGameRecord(channelId);
588
- if (!gameRecord2.isAnalyzing) {
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 newGameRecord = await getGameRecord(channelId);
594
- if (newGameRecord.winSide !== "") {
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, newGameRecord.winSide, newGameRecord.loseSide);
558
+ await updatePlayerRecords(channelId, engineResultRecord.winSide, engineResultRecord.loseSide);
598
559
  await endGame(channelId);
599
- return await sendMessage(session, `【@${username}】
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
- 获胜方为:【${convertTurnToString(newGameRecord2.winSide)}】
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
595
+ return await sendMessage(session, `**【@${username}】**
672
596
  对局分析中,请稍后再试!`);
673
597
  }
674
598
  if (gameRecord.moveList.length < 1) {
675
- return await sendMessage(session, `【@${username}】
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, `【@${username}】
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, `【@${username}】
612
+ return await sendMessage(session, `**【@${username}】**
689
613
  现在轮到你下棋,不可悔棋!`);
690
614
  } else {
691
- await ctx.database.set("cchess_game_records", { channelId }, {
692
- isRegretRequest: true
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, `【@${username}】
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, `【@${username}】
632
+ return await sendMessage(session, `**【@${username}】**
716
633
  对局分析中,请稍后再试!`);
717
634
  }
718
635
  if (!gameRecord.isRegretRequest) {
719
- return await sendMessage(session, `【@${username}】
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
670
+ return await sendMessage(session, `**【@${username}】**
761
671
  对局分析中,请稍后再试!`);
762
672
  }
763
673
  if (!gameRecord.isRegretRequest) {
764
- return await sendMessage(session, `【@${username}】
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
718
+ return await sendMessage(session, `**【@${username}】**
816
719
  还没轮到${sideString}走棋哦!
817
- 当前走棋方为:【${convertTurnToString(gameRecord.turn)}】`);
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, `【@${username}】
725
+ return await sendMessage(session, `**【@${username}】**
823
726
  认输成功!
824
727
  游戏结束!
825
- 获胜方为:【${anotherSideString}】`);
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, `【@${username}】
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, `【@${username}】
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, `【@${username}】
755
+ return await sendMessage(session, `**【@${username}】**
853
756
  游戏已经开始啦~
854
757
  不可编辑棋盘!`);
855
758
  }
856
759
  await checkEngine(channelId);
857
- if (engines[channelId] && !gameRecord.isEngineReady) {
858
- await ctx.database.set("cchess_game_records", { channelId }, {
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
- board = fenToBoard(t);
884
- turn = "w";
885
- moveList = [];
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, `【@${username}】
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, `【@${username}】
789
+ return await sendMessage(session, `**【@${username}】**
915
790
  游戏还未开始哦!`);
916
791
  }
917
792
  if (gameRecord.isAnalyzing) {
918
- return await sendMessage(session, `【@${username}】
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, `【@${username}】
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, `【@${username}】
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 { channelId, username, userId } = session;
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", "win", "玩家总胜场排行榜", number);
814
+ return await getLeaderboard(session, "win", "玩家总胜场排行榜", number);
945
815
  });
946
816
  ctx.command("cchess.排行榜.总输场 [number:number]", "查看玩家总输场排行榜").action(async ({ session }, number = config.defaultMaxLeaderboardEntries) => {
947
- const { channelId, username, userId } = session;
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", "lose", "查看玩家总输场排行榜", number);
822
+ return await getLeaderboard(session, "lose", "查看玩家总输场排行榜", number);
953
823
  });
954
824
  ctx.command("cchess.查询玩家记录 [targetUser:text]", "查询玩家记录").action(async ({ session }, targetUser) => {
955
- let { channelId, userId, username } = session;
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, `【@${session.username}】
842
+ return sendMessage(session, `**【@${session.username}】**
973
843
  查询对象:${username}
974
844
  无任何游戏记录。`);
975
845
  }
976
846
  const { win, lose } = targetUserRecord[0];
977
- return sendMessage(session, `【@${session.username}】
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, type, sortField, title, number) {
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 = `${title}:
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
- const existingRecord = userRecord[0];
1049
- let isChange = false;
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, t = " ") {
928
+ async function getFenWithFullMove(channelId, separator = " ") {
1078
929
  const gameRecord = await getGameRecord(channelId);
1079
- let {
1080
- // originalState,
1081
- // isHistoryMode,
1082
- startFen
1083
- } = gameRecord;
1084
- let e = [];
1085
- for (let A of gameRecord.moveList)
1086
- e.push(A.move);
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(t) {
1097
- let e = t.split(" "), i = e[0], n = e[1];
1098
- if (!"rwb".includes(n.toLowerCase()))
1099
- return false;
1100
- let A = i.split("/");
1101
- if (10 != A.length)
1102
- return false;
1103
- for (let s = 0; s < A.length; s++) {
1104
- let t2 = A[s], e2 = t2.length, i2 = 0;
1105
- for (let n2 = 0; n2 < e2; n2++) {
1106
- let e3 = t2.charAt(n2);
1107
- e3 >= "0" && e3 <= "9" ? i2 += parseInt(e3) : i2++;
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 (9 != i2)
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, t) {
1116
- const gameRecord = await getGameRecord(channelId);
1117
- let {
1118
- turn,
1119
- board
1120
- } = gameRecord;
1121
- let e = t.split(" ");
1122
- board = fenToBoard(e[0]);
1123
- turn = "b" == e[1] ? "b" : "w";
1124
- await ctx.database.set("cchess_game_records", { channelId }, {
1125
- turn,
1126
- board
1127
- });
1128
- if (e.length > 3 && "moves" == e[2])
1129
- if (4 == e[3].length)
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(t) {
1140
- return JSON.parse(JSON.stringify(t));
987
+ function deepCopy(obj) {
988
+ return JSON.parse(JSON.stringify(obj));
1141
989
  }
1142
990
  __name(deepCopy, "deepCopy");
1143
- async function gotoHistory(channelId, t) {
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
- isHistoryMode || (originalState = {
1158
- fen: getFen(board, turn),
1159
- turn,
1160
- board: deepCopy(board),
1161
- moveList: deepCopy(moveList),
1162
- movesAfterLastEat: deepCopy(movesAfterLastEat),
1163
- boardAfterLastEat: deepCopy(boardAfterLastEat),
1164
- turnAfterLastEat,
1165
- lastMove
1166
- }, isHistoryMode = true);
1167
- let e = t.moveId, i = originalState.moveList.findIndex((t2) => t2.moveId == e);
1168
- moveList = originalState.moveList.slice(0, i + 1), i = originalState.movesAfterLastEat.findIndex((t2) => t2.moveId == e), -1 != i ? movesAfterLastEat = originalState.movesAfterLastEat.slice(0, i + 1) : (boardAfterLastEat = fenToBoard(t.fen), turnAfterLastEat = "w" == t.side ? "b" : "w", movesAfterLastEat = []), lastMove = t.moveCord, turn = "w" == t.side ? "b" : "w", board = fenToBoard(t.fen), await ctx.database.set("cchess_game_records", { channelId }, {
1169
- fen: t.fen,
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
- isHistoryMode || (originalState = {
1198
- fen: getFen(board, turn),
1199
- turn,
1200
- board: deepCopy(board),
1201
- moveList: deepCopy(moveList),
1202
- movesAfterLastEat: deepCopy(movesAfterLastEat),
1203
- boardAfterLastEat: deepCopy(boardAfterLastEat),
1204
- turnAfterLastEat,
1205
- lastMove
1206
- }, isHistoryMode = true), await parseFen(channelId, startFen), moveList = [], movesAfterLastEat = [], boardAfterLastEat = deepCopy(fenToBoard(fen)), turnAfterLastEat = turn, lastMove = null, await ctx.database.set("cchess_game_records", { channelId }, {
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 || (originalState = {
1232
- fen: getFen(board, turn),
1233
- turn,
1234
- board: deepCopy(board),
1235
- moveList: deepCopy(moveList),
1236
- movesAfterLastEat: deepCopy(movesAfterLastEat),
1237
- boardAfterLastEat: deepCopy(boardAfterLastEat),
1238
- turnAfterLastEat,
1239
- lastMove
1240
- }, isHistoryMode = true), await ctx.database.set("cchess_game_records", { channelId }, {
1241
- originalState,
1242
- isHistoryMode
1243
- }), moveList.length > 1) {
1244
- let t = moveList[moveList.length - 2];
1245
- await gotoHistory(channelId, t);
1246
- } else
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, t, e) {
1130
+ async function onEngineBestMove(channelId, move, ponder) {
1256
1131
  const gameRecord = await getGameRecord(channelId);
1257
- let {
1258
- isEnginePlayRed,
1259
- isEnginePlayBlack,
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)" === t) {
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 i = getSideByMoveString(board, t);
1279
- if (i !== turn && isEnginePlayRed || i !== turn && isEnginePlayBlack) {
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" === i && isEnginePlayRed || "b" === i && isEnginePlayBlack) && await makeMoveByString(channelId, t);
1288
- await ctx.database.set("cchess_game_records", { channelId }, {
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
- return i.join(" ");
1157
+ await ctx.database.set("cchess_game_records", { channelId }, { isAnalyzing: false });
1357
1158
  }
1358
- __name(getSerialMoveName, "getSerialMoveName");
1359
- async function go(channelId, t = -1, e = -1, i = -1) {
1360
- {
1361
- let n = "go";
1362
- return t > 0 && (n += " movetime " + t), e > 0 && (n += " depth " + e), i > 0 && (n += " nodes " + i), await sendCommand(channelId, n), true;
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
- isEnginePlayRed,
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(t) {
1382
- let e = {
1383
- a: 0,
1384
- b: 1,
1385
- c: 2,
1386
- d: 3,
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, t) {
1408
- let e = moveStringToPos(t);
1409
- await makeMove(channelId, e[0], e[1]);
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, t) {
1413
- let e = moveStringToPos(t), i = e[0];
1414
- return getSide(board[i[1]][i[0]]);
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 t = [];
1419
- for (let i of movesAfterLastEat)
1420
- t.push(i.move);
1421
- let e = boardToFen(boardAfterLastEat, "w", turnAfterLastEat);
1422
- return t.length > 0 && (e += " moves " + t.join(" ")), e;
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, t, e) {
1426
- await sendCommand(channelId, "setoption name " + t + " value " + e);
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, t) {
1430
- for (let e in t)
1431
- await setOption(channelId, e, t[e]);
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, t) {
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 (null !== engines[channelId] || "uci" == t) {
1443
- engines[channelId].send_command(t);
1217
+ if (engines[channelId] || "uci" == cmd) {
1218
+ engines[channelId].send_command(cmd);
1444
1219
  } else {
1445
- await sendCommand(channelId, t);
1220
+ await sendCommand(channelId, cmd);
1446
1221
  }
1447
1222
  }
1448
1223
  __name(sendCommand, "sendCommand");
1449
- async function receiveOutput(channelId, t) {
1224
+ async function receiveOutput(channelId, output) {
1450
1225
  try {
1451
- if (!t)
1452
- return;
1453
- let e = t.split(" ");
1454
- let i = e[0];
1455
- let keywords = "depth seldepth time nodes pv multipv score currmove currmovenumber hashfull nps tbhits cpuload string refutation currline".split(" ");
1456
- if (i === "info") {
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, e[1], null);
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
- locateFile: (file) => {
1513
- if (file === "pikafish.data") {
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
- setStatus: (status) => {
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, t, e) {
1646
- let i, n, A = getEmptyBoard(), s = e[0], a = e[1];
1647
- a <= 2 ? (i = 0, n = 2) : a >= 7 ? (i = 7, n = 9) : (i = a - 1, n = a + 1);
1648
- let o = 3, r = 5;
1649
- if (s + 1 <= r) {
1650
- let e2 = getValidType(board, t, [s + 1, a]);
1651
- "eat" != e2 && "go" != e2 || setMoveMap(A, [s + 1, a], e2);
1652
- }
1653
- if (s - 1 >= o) {
1654
- let e2 = getValidType(board, t, [s - 1, a]);
1655
- "eat" != e2 && "go" != e2 || setMoveMap(A, [s - 1, a], e2);
1656
- }
1657
- if (a + 1 <= n) {
1658
- let e2 = getValidType(board, t, [s, a + 1]);
1659
- "eat" != e2 && "go" != e2 || setMoveMap(A, [s, a + 1], e2);
1660
- }
1661
- if (a - 1 >= i) {
1662
- let e2 = getValidType(board, t, [s, a - 1]);
1663
- "eat" != e2 && "go" != e2 || setMoveMap(A, [s, a - 1], e2);
1664
- }
1665
- return A;
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, t, e) {
1669
- let i = getEmptyBoard(), n = e[0], A = e[1], s = false;
1670
- for (let a = n; a < 9; a++) {
1671
- if (a == n)
1672
- continue;
1673
- let e2 = getValidType(board, t, [a, A]);
1674
- if (s || "block" != e2 && "eat" != e2) {
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
- s || "go" != e2 || setMoveMap(i, [a, A], "go");
1680
- } else
1681
- s = true;
1682
- }
1683
- s = false;
1684
- for (let a = n; a >= 0; a--) {
1685
- if (a == n)
1686
- continue;
1687
- let e2 = getValidType(board, t, [a, A]);
1688
- if (s || "block" != e2 && "eat" != e2) {
1689
- if (s && "eat" == e2) {
1690
- setMoveMap(i, [a, A], "eat");
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
- s || "go" != e2 || setMoveMap(i, [a, A], "go");
1694
- } else
1695
- s = true;
1696
- }
1697
- s = false;
1698
- for (let a = A; a < 10; a++) {
1699
- if (a == A)
1700
- continue;
1701
- let e2 = getValidType(board, t, [n, a]);
1702
- if (s || "block" != e2 && "eat" != e2) {
1703
- if (s && "eat" == e2) {
1704
- setMoveMap(i, [n, a], "eat");
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
- s || "go" != e2 || setMoveMap(i, [n, a], "go");
1708
- } else
1709
- s = true;
1710
- }
1711
- s = false;
1712
- for (let a = A; a >= 0; a--) {
1713
- if (a == A)
1714
- continue;
1715
- let e2 = getValidType(board, t, [n, a]);
1716
- if (s || "block" != e2 && "eat" != e2) {
1717
- if (s && "eat" == e2) {
1718
- setMoveMap(i, [n, a], "eat");
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
- s || "go" != e2 || setMoveMap(i, [n, a], "go");
1722
- } else
1723
- s = true;
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 i;
1483
+ return map;
1726
1484
  }
1727
1485
  __name(getValidMoveMapCannons, "getValidMoveMapCannons");
1728
- function getSideByKing(board, t) {
1729
- t[0];
1730
- let e = t[1];
1731
- if (e <= 4)
1732
- for (let i = 3; i <= 5; i++)
1733
- for (let t2 = 0; t2 <= 2; t2++) {
1734
- let e2 = getPiece(board, [i, t2]);
1735
- if ("K" == e2)
1736
- return "w";
1737
- if ("k" == e2)
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, t, e) {
1753
- let i = getEmptyBoard(), n = e[0], A = e[1], s = getSideByKing(board, e);
1754
- if (t == s)
1755
- if (A <= 4) {
1756
- let e2 = getValidType(board, t, [n, A + 1]);
1757
- "eat" != e2 && "go" != e2 || setMoveMap(i, [n, A + 1], e2);
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 e2 = getValidType(board, t, [n, A - 1]);
1760
- "eat" != e2 && "go" != e2 || setMoveMap(i, [n, A - 1], e2);
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 (A <= 4) {
1764
- let e3 = getValidType(board, t, [n, A - 1]);
1765
- "eat" != e3 && "go" != e3 || setMoveMap(i, [n, A - 1], e3);
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 e3 = getValidType(board, t, [n, A + 1]);
1768
- "eat" != e3 && "go" != e3 || setMoveMap(i, [n, A + 1], e3);
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 e2 = getValidType(board, t, [n + 1, A]);
1771
- "eat" != e2 && "go" != e2 || setMoveMap(i, [n + 1, A], e2), e2 = getValidType(board, t, [n - 1, A]), "eat" != e2 && "go" != e2 || setMoveMap(i, [n - 1, A], e2);
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 i;
1523
+ return map;
1774
1524
  }
1775
1525
  __name(getValidMoveMapPawns, "getValidMoveMapPawns");
1776
- function getValidMoveMapBishops(board, t, e) {
1777
- let i, n, A = getEmptyBoard(), s = e[0], a = e[1];
1778
- if (a <= 4 ? (i = 0, n = 4) : a >= 5 ? (i = 5, n = 9) : (i = a - 1, n = a + 1), s + 2 <= 9 && a + 2 <= n) {
1779
- let e2 = getPiece(board, [s + 1, a + 1]);
1780
- if ("" == e2) {
1781
- let e3 = getValidType(board, t, [s + 2, a + 2]);
1782
- "eat" != e3 && "go" != e3 || setMoveMap(A, [s + 2, a + 2], e3);
1783
- }
1784
- }
1785
- if (s - 2 >= 0 && a + 2 <= n) {
1786
- let e2 = getPiece(board, [s - 1, a + 1]);
1787
- if ("" == e2) {
1788
- let e3 = getValidType(board, t, [s - 2, a + 2]);
1789
- "eat" != e3 && "go" != e3 || setMoveMap(A, [s - 2, a + 2], e3);
1790
- }
1791
- }
1792
- if (s + 2 <= 9 && a - 2 >= i) {
1793
- let e2 = getPiece(board, [s + 1, a - 1]);
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
- return A;
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, t, e) {
1831
- let i = getEmptyBoard(), n = e[0], A = e[1];
1832
- for (let s = n; s < 9; s++) {
1833
- if (s == n)
1834
- continue;
1835
- let e2 = getValidType(board, t, [s, A]);
1836
- if ("block" == e2)
1837
- break;
1838
- if (i[A][s] = e2, "eat" == e2)
1839
- break;
1840
- }
1841
- for (let s = n; s >= 0; s--) {
1842
- if (s == n)
1843
- continue;
1844
- let e2 = getValidType(board, t, [s, A]);
1845
- if ("block" == e2)
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, t, e) {
1872
- let i = getPiece(board, e);
1873
- return void 0 == i ? "invalid" : "" == i ? "go" : t != getSide(i) ? "eat" : "block";
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, t, e) {
1877
- let i, n, A = getEmptyBoard(), s = e[0], a = e[1];
1878
- a <= 2 ? (i = 0, n = 2) : a >= 7 ? (i = 7, n = 9) : (i = a - 1, n = a + 1);
1879
- let o = 3, r = 5;
1880
- if (s + 1 <= r && a + 1 <= n) {
1881
- let e2 = getValidType(board, t, [s + 1, a + 1]);
1882
- "eat" != e2 && "go" != e2 || setMoveMap(A, [s + 1, a + 1], e2);
1883
- }
1884
- if (s - 1 >= o && a + 1 <= n) {
1885
- let e2 = getValidType(board, t, [s - 1, a + 1]);
1886
- "eat" != e2 && "go" != e2 || setMoveMap(A, [s - 1, a + 1], e2);
1887
- }
1888
- if (s + 1 <= r && a - 1 >= i) {
1889
- let e2 = getValidType(board, t, [s + 1, a - 1]);
1890
- "eat" != e2 && "go" != e2 || setMoveMap(A, [s + 1, a - 1], e2);
1891
- }
1892
- if (s - 1 >= o && a - 1 >= i) {
1893
- let e2 = getValidType(board, t, [s - 1, a - 1]);
1894
- "eat" != e2 && "go" != e2 || setMoveMap(A, [s - 1, a - 1], e2);
1895
- }
1896
- return A;
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(t, e, i) {
1900
- e[0] < 0 || e[0] > 8 || e[1] < 0 || e[1] > 9 || (t[e[1]][e[0]] = i);
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, t, e) {
1904
- let i = getEmptyBoard(), n = e[0], A = e[1];
1905
- return "" == getPiece(board, [n + 1, A]) && (setMoveMap(i, [n + 2, A + 1], getValidType(board, t, [n + 2, A + 1])), setMoveMap(i, [n + 2, A - 1], getValidType(board, t, [n + 2, A - 1]))), "" == getPiece(board, [n - 1, A]) && (setMoveMap(i, [n - 2, A + 1], getValidType(board, t, [n - 2, A + 1])), setMoveMap(i, [n - 2, A - 1], getValidType(board, t, [n - 2, A - 1]))), "" == getPiece(board, [n, A + 1]) && (setMoveMap(i, [n + 1, A + 2], getValidType(board, t, [n + 1, A + 2])), setMoveMap(i, [n - 1, A + 2], getValidType(board, t, [n - 1, A + 2]))), "" == getPiece(board, [n, A - 1]) && (setMoveMap(i, [n + 1, A - 2], getValidType(board, t, [n + 1, A - 2])), setMoveMap(i, [n - 1, A - 2], getValidType(board, t, [n - 1, A - 2]))), i;
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 Et = [];
1909
- Et["w"] = [], Et["b"] = [], Et["w"][0] = "进", Et["w"][1] = "退", Et["b"][0] = "退", Et["b"][1] = "进", Et["p"] = "平";
1910
- var Ht = [];
1911
- Ht["w"] = [], Ht["b"] = [], Ht["w"][0] = "前", Ht["w"][1] = "后", Ht["b"][0] = "后", Ht["b"][1] = "前", Ht["m"] = "中";
1912
- var qt = [];
1913
- qt["k"] = "将", qt["a"] = "士", qt["b"] = "象", qt["r"] = "车", qt["n"] = "马", qt["c"] = "炮", qt["p"] = "卒", qt["K"] = "帅", qt["A"] = "仕", qt["B"] = "相", qt["R"] = "车", qt["N"] = "马", qt["C"] = "炮", qt["P"] = "兵";
1914
- var Qt = [];
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 i2 = 0; i2 < t.length; i2++) {
1936
- let o = t[i2];
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
- if (g != n) {
1954
- for (var f = 0; f < 10; f++)
1955
- 0 != i[g][f] && i[g][f].substring(0, 2) == i[n][A].substring(0, 2) && l++;
1956
- l < 2 && (l = 0);
1957
- }
1958
- for (f = 0; f < 10; f++)
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) ? Et[i[n][A].charAt(0)][0] + Qt[i[n][A].charAt(0)][A - a - 1] : Et[i[n][A].charAt(0)][0] + Qt[i[n][A].charAt(0)][9 - (A - a - 1) - 1] : Et[i[n][A].charAt(0)][0] + Qt[i[n][A].charAt(0)][9 - s - 1] : A == a ? Et["p"] + Qt[i[n][A].charAt(0)][9 - s - 1] : n == s ? "w" == i[n][A].charAt(0) ? Et[i[n][A].charAt(0)][1] + Qt[i[n][A].charAt(0)][a - A - 1] : Et[i[n][A].charAt(0)][1] + Qt[i[n][A].charAt(0)][9 - (a - A - 1) - 1] : Et[i[n][A].charAt(0)][1] + Qt[i[n][A].charAt(0)][9 - s - 1], d + h2;
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
- let e = "RNBAKCP";
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, currentMoveId } = gameRecord;
2111
- const canvas = await ctx.canvas.createCanvas(weight * scale, height * scale);
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, weight * scale, height * scale);
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
- continue;
2127
- const xPos = ((isFlipBoard ? 8 - col : col) * we + Pe - Be / 2) * scale;
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, Be * scale, Be * scale);
1843
+ context.drawImage(pieceImg, xPos, yPos, PIECE_SIZE * scale, PIECE_SIZE * scale);
2131
1844
  }
2132
1845
  }
2133
1846
  if (lastMove !== null) {
2134
- let i = lastMove, n = i[0], A = i[1], s = n[0], a = n[1], o = A[0], r = A[1];
2135
- let l = s * we + pe, d = a * we + Pe, g = o * we + pe, f = r * we + Pe, h2 = Math.sqrt((l - g) * (l - g) + (d - f) * (d - f)), b = l + (g - l) * (h2 - 30) / h2, c = d + (f - d) * (h2 - 30) / h2;
2136
- await drawLineArrow(context, l * scale, d * scale, b * scale, c * scale, "rgba(128, 171, 69, 0.7)", 15 * scale);
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(t, e, i, n, A, s = "black", a = 20) {
2150
- var o = 0.282 * Math.sqrt((e - n) * (e - n) + (i - A) * (i - A));
2151
- o = a;
2152
- var r, l, d = 45, g = 180 * Math.atan2(i - A, e - n) / Math.PI, f = (g + d) * Math.PI / 180, h2 = (g - d) * Math.PI / 180, b = o * Math.cos(f), c = o * Math.sin(f), u = o * Math.cos(h2), v = o * Math.sin(h2), m = e > n, w = i > A;
2153
- r = n + b, l = A + c;
2154
- var I = n + u, p = A + v, P = w ? r + 0.25 * Math.abs(I - r) : r - 0.25 * Math.abs(I - r), B = m ? l - 0.25 * Math.abs(p - l) : l + 0.25 * Math.abs(p - l), M = w ? r + 0.75 * Math.abs(I - r) : r - 0.75 * Math.abs(I - r), y = m ? l - 0.75 * Math.abs(p - l) : l + 0.75 * Math.abs(p - l);
2155
- t.beginPath(), t.moveTo(e, i), t.lineTo(P, B), t.lineTo(r, l), t.lineTo(n, A), t.lineTo(I, p), t.lineTo(M, y), t.lineTo(e, i), t.closePath(), t.strokeStyle = s, t.fillStyle = s, t.fill(), t.stroke();
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 lines = message.split("\n");
2224
- const isOnlyImgTag = lines.length === 1 && lines[0].trim().startsWith("<img");
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
- [messageId] = await session.send(message);
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
- await bot.deleteMessage(channelId, oldestMessageId);
1970
+ try {
1971
+ await bot.deleteMessage(channelId, oldestMessageId);
1972
+ } catch (e) {
1973
+ }
2248
1974
  }, config.retractDelay * 1e3);
2249
1975
  }
2250
1976
  }