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