koishi-plugin-cchess 1.0.1 → 1.0.2

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 (2) hide show
  1. package/lib/index.js +2210 -2246
  2. package/package.json +2 -2
package/lib/index.js CHANGED
@@ -1,35 +1,47 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
+ var __export = (target, all) => {
9
+ for (var name2 in all)
10
+ __defProp(target, name2, { get: all[name2], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
24
19
  };
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.Config = exports.inject = exports.usage = exports.name = void 0;
27
- exports.apply = apply;
28
- const koishi_1 = require("koishi");
29
- const path = __importStar(require("path"));
30
- const fs = __importStar(require("fs"));
31
- exports.name = 'cchess';
32
- exports.usage = `## 🌈 使用
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ Config: () => Config,
34
+ apply: () => apply,
35
+ inject: () => inject,
36
+ name: () => name,
37
+ usage: () => usage
38
+ });
39
+ module.exports = __toCommonJS(src_exports);
40
+ var import_koishi = require("koishi");
41
+ var path = __toESM(require("path"));
42
+ var fs = __toESM(require("fs"));
43
+ var name = "cchess";
44
+ var usage = `## 🌈 使用
33
45
 
34
46
  - 建议自行添加别名,如 \`cc\` 等更方便的指令。
35
47
  - 请安装并启用所需服务,\`canvas\` 服务可使用 \`puppeteer\` 提供。
@@ -53,2245 +65,2197 @@ exports.usage = `## 🌈 使用
53
65
  ## 🐱 QQ 群
54
66
 
55
67
  - 956758505`;
56
- exports.inject = {
57
- // required: ['monetary', 'database', 'puppeteer', 'canvas'],
58
- required: ['database', 'puppeteer', 'canvas'],
59
- optional: ['markdownToImage'],
68
+ var inject = {
69
+ // required: ['monetary', 'database', 'puppeteer', 'canvas'],
70
+ required: ["database", "puppeteer", "canvas"],
71
+ optional: ["markdownToImage"]
60
72
  };
61
- const pieceSkins = ["棋弈无限图形棋子", "云库木制棋子", "刘炳森红黑牛角隶书棋子", "木制棋子", "本纹隶书棋子", "银灰将军体棋子", "棋弈无限红绿正棋子", "棋弈无限红绿棋子", "棋天大圣棋子", "棋者象棋棋子", "楷书玉石棋子", "水墨青瓷棋子", "牛皮纸华康金文棋子", "皮卡鱼棋子", "红蓝祥隶棋子", "红黑精典无阴影棋子", "红黑精典棋子", "行书玉石棋子", "象甲棋子", "金属棋子篆体棋子", "镌刻华彩棋子", "鹏飞红黑棋子", "鹏飞经典棋子", "鹏飞绿龙棋子", "龙腾四海棋子"];
62
- const boardSkins = ["棋弈无限红绿棋盘", "一鸣惊人棋盘", "三星堆棋盘", "云库木制棋盘", "云心鹤眼棋盘", "兰亭集序无字棋盘", "兰亭集序棋盘", "凤舞九天棋盘", "卯兔添福棋盘", "叱咤风云棋盘", "君临天下棋盘", "壁画古梦棋盘", "大闹天宫棋盘", "天山共色棋盘", "女神之约棋盘", "小吕飞刀棋盘", "山海绘卷棋盘", "护眼绿棋盘", "星河璀璨棋盘", "木制棋盘", "本纹隶书白棋盘", "本纹隶书黑棋盘", "桃花源记棋盘", "棋天大圣棋盘", "棋天无大圣棋盘", "武侠江湖棋盘", "水墨青瓷棋盘", "清悠茶道棋盘", "游园惊梦棋盘", "牛转乾坤棋盘", "玉石太极棋盘", "皓月无痕棋盘", "皮卡鱼棋盘", "盲棋神迹棋盘", "空城计棋盘", "竹波烟雨棋盘", "经典木棋盘棋盘", "绿色棋盘", "象甲2023棋盘", "象甲征程棋盘", "象甲重燃棋盘", "金牛降世棋盘", "金虎贺岁棋盘", "金虎贺岁(王天一签名版)棋盘", "鎏金岁月棋盘", "霸王别姬棋盘", "鸿门宴棋盘", "鹏飞红黑棋盘", "鹏飞经典棋盘", "鹏飞绿龙棋盘", "龙腾天坛棋盘"];
63
- exports.Config = koishi_1.Schema.object({
64
- boardSkin: koishi_1.Schema.union(boardSkins).default('象甲2023棋盘').description(`棋盘皮肤。`),
65
- pieceSkin: koishi_1.Schema.union(pieceSkins).default('象甲棋子').description(`棋子皮肤。`),
66
- allowFreePieceMovementInHumanMachineMode: koishi_1.Schema.boolean().default(false).description(` 是否允许在人机模式下自由移动棋子,开启后可以不需要加入游戏直接开始玩人机模式。`),
67
- defaultEngineThinkingDepth: koishi_1.Schema.number().min(0).max(100).default(10).description(`默认引擎思考深度,越高 AI 棋力越强。由于 Nodejs 不支持 SIMD,所以不建议设置过高。`),
68
- defaultMaxLeaderboardEntries: koishi_1.Schema.number().min(0).default(10).description(`显示排行榜时默认的最大人数。`),
69
- retractDelay: koishi_1.Schema.number().min(0).default(0).description(`自动撤回等待的时间,单位是秒。值为 0 时不启用自动撤回功能。`),
70
- imgScale: koishi_1.Schema.number().min(1).default(1).description(`图片分辨率倍率。`),
71
- imageType: koishi_1.Schema.union(['png', 'jpeg', 'webp']).default('png').description(`发送的图片类型。`),
72
- isTextToImageConversionEnabled: koishi_1.Schema.boolean().default(false).description(`是否开启将文本转为图片的功能(可选),如需启用,需要启用 \`markdownToImage\` 服务。`),
73
- isChessImageWithOutlineEnabled: koishi_1.Schema.boolean().default(true).description(`是否为象棋图片添加辅助外框,关闭后可以显著提升图片速度,但无辅助外框,玩起来可能会比较累。`),
73
+ var pieceSkins = ["棋弈无限图形棋子", "云库木制棋子", "刘炳森红黑牛角隶书棋子", "木制棋子", "本纹隶书棋子", "银灰将军体棋子", "棋弈无限红绿正棋子", "棋弈无限红绿棋子", "棋天大圣棋子", "棋者象棋棋子", "楷书玉石棋子", "水墨青瓷棋子", "牛皮纸华康金文棋子", "皮卡鱼棋子", "红蓝祥隶棋子", "红黑精典无阴影棋子", "红黑精典棋子", "行书玉石棋子", "象甲棋子", "金属棋子篆体棋子", "镌刻华彩棋子", "鹏飞红黑棋子", "鹏飞经典棋子", "鹏飞绿龙棋子", "龙腾四海棋子"];
74
+ var boardSkins = ["棋弈无限红绿棋盘", "一鸣惊人棋盘", "三星堆棋盘", "云库木制棋盘", "云心鹤眼棋盘", "兰亭集序无字棋盘", "兰亭集序棋盘", "凤舞九天棋盘", "卯兔添福棋盘", "叱咤风云棋盘", "君临天下棋盘", "壁画古梦棋盘", "大闹天宫棋盘", "天山共色棋盘", "女神之约棋盘", "小吕飞刀棋盘", "山海绘卷棋盘", "护眼绿棋盘", "星河璀璨棋盘", "木制棋盘", "本纹隶书白棋盘", "本纹隶书黑棋盘", "桃花源记棋盘", "棋天大圣棋盘", "棋天无大圣棋盘", "武侠江湖棋盘", "水墨青瓷棋盘", "清悠茶道棋盘", "游园惊梦棋盘", "牛转乾坤棋盘", "玉石太极棋盘", "皓月无痕棋盘", "皮卡鱼棋盘", "盲棋神迹棋盘", "空城计棋盘", "竹波烟雨棋盘", "经典木棋盘棋盘", "绿色棋盘", "象甲2023棋盘", "象甲征程棋盘", "象甲重燃棋盘", "金牛降世棋盘", "金虎贺岁棋盘", "金虎贺岁(王天一签名版)棋盘", "鎏金岁月棋盘", "霸王别姬棋盘", "鸿门宴棋盘", "鹏飞红黑棋盘", "鹏飞经典棋盘", "鹏飞绿龙棋盘", "龙腾天坛棋盘"];
75
+ var Config = import_koishi.Schema.object({
76
+ boardSkin: import_koishi.Schema.union(boardSkins).default("象甲2023棋盘").description(`棋盘皮肤。`),
77
+ pieceSkin: import_koishi.Schema.union(pieceSkins).default("象甲棋子").description(`棋子皮肤。`),
78
+ allowFreePieceMovementInHumanMachineMode: import_koishi.Schema.boolean().default(false).description(` 是否允许在人机模式下自由移动棋子,开启后可以不需要加入游戏直接开始玩人机模式。`),
79
+ defaultEngineThinkingDepth: import_koishi.Schema.number().min(0).max(100).default(10).description(`默认引擎思考深度,越高 AI 棋力越强。由于 Nodejs 不支持 SIMD,所以不建议设置过高。`),
80
+ defaultMaxLeaderboardEntries: import_koishi.Schema.number().min(0).default(10).description(`显示排行榜时默认的最大人数。`),
81
+ retractDelay: import_koishi.Schema.number().min(0).default(0).description(`自动撤回等待的时间,单位是秒。值为 0 时不启用自动撤回功能。`),
82
+ imgScale: import_koishi.Schema.number().min(1).default(1).description(`图片分辨率倍率。`),
83
+ imageType: import_koishi.Schema.union(["png", "jpeg", "webp"]).default("png").description(`发送的图片类型。`),
84
+ isTextToImageConversionEnabled: import_koishi.Schema.boolean().default(false).description(`是否开启将文本转为图片的功能(可选),如需启用,需要启用 \`markdownToImage\` 服务。`),
85
+ isChessImageWithOutlineEnabled: import_koishi.Schema.boolean().default(true).description(`是否为象棋图片添加辅助外框,关闭后可以显著提升图片速度,但无辅助外框,玩起来可能会比较累。`)
74
86
  });
75
87
  function apply(ctx, config) {
76
- const logger = ctx.logger('cchess');
77
- // cl*
78
- const engines = {};
79
- // fzy*
80
- ctx.on('dispose', () => {
81
- const channelIds = Object.keys(engines);
82
- channelIds.forEach((channelId) => {
83
- if (engines[channelId]) {
84
- engines[channelId].send_command('quit');
85
- engines[channelId] = null;
86
- }
87
- });
88
- });
89
- const we = 54; // 棋子宽度
90
- const pe = 33;
91
- const Pe = 33; // 棋盘边距
92
- const Be = 50; // 棋子显示大小
93
- const Ie = 54;
94
- const Me = 500;
95
- const ye = 550;
96
- const ze = 500;
97
- const ke = 120;
98
- const weight = 500;
99
- const height = 550;
100
- const scale = config.imgScale;
101
- const isFlipBoard = false;
102
- const engineSettings = {
103
- Threads: 1,
104
- Hash: 128,
105
- MultiPV: 1,
106
- // "Skill Level": 20,
107
- };
108
- const thinkingSettings = {
109
- moveTime: 1,
110
- depth: config.defaultEngineThinkingDepth,
111
- enableHint: true,
112
- };
113
- const piecesImgResources = loadPiecesImageResources(config.pieceSkin);
114
- // wj*
115
- const outerFrameImg = fs.readFileSync(path.join(__dirname, 'assets', '棋盘皮肤', `外框.png`));
116
- const boardSkinImg = fs.readFileSync(path.join(__dirname, 'assets', '棋盘皮肤', `${config.boardSkin}.webp`));
117
- const possibleFigureNames = ["将", "士", "象", "车", "马", "炮", "卒", "帅", "仕", "相", "兵"];
118
- // tzb*
119
- ctx.model.extend('cchess_game_records', {
120
- id: 'unsigned',
121
- channelId: 'string',
122
- isStarted: 'boolean',
123
- isFlipBoard: 'boolean',
124
- isHistoryMode: 'boolean',
125
- turn: { type: 'string', initial: 'w' },
126
- moveList: { type: 'json', initial: [] },
127
- isDraw: { type: 'boolean', initial: false },
128
- winSide: { type: 'string', initial: '' },
129
- loseSide: { type: 'string', initial: '' },
130
- // lastPV: {type: 'json', initial: null},
131
- originalState: { type: 'json', initial: {} },
132
- thinkingDetail: { type: 'json', initial: [] },
133
- currentMoveId: { type: 'string', initial: '' },
134
- thinkingSide: { type: 'string', initial: 'w' },
135
- movesAfterLastEat: { type: 'json', initial: [] },
136
- isAnalyzing: { type: 'boolean', initial: false },
137
- turnAfterLastEat: { type: 'string', initial: 'w' },
138
- isEngineReady: { type: 'boolean', initial: false },
139
- // multiPvInfoBuffer: {type: 'json', initial: {}},
140
- isEnginePlayRed: { type: 'boolean', initial: false },
141
- isEngineAnalyze: { type: 'boolean', initial: false },
142
- isRegretRequest: { type: 'boolean', initial: false },
143
- lastMove: { type: 'json', initial: [[0, 0], [0, 0]] },
144
- isEnginePlayBlack: { type: 'boolean', initial: false },
145
- ponderHint: { type: 'json', initial: [[0, 0], [0, 0]] },
146
- // bestMoveHint: {type: 'json', initial: [[0, 0], [0, 0]]},
147
- fen: { type: 'string', initial: 'rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w' },
148
- startFen: { type: 'string', initial: 'rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w' },
149
- board: { type: 'json', initial: fenToBoard('rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w') },
150
- boardAfterLastEat: {
151
- type: 'json',
152
- initial: fenToBoard('rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w')
153
- },
154
- moveTreePtr: {
155
- type: 'json',
156
- initial: { moveId: '', fen: '', side: '', moveCord: [[0, 0], [0, 0]], move: '', chnMoveName: '', next: null }
157
- },
158
- }, {
159
- primary: 'id',
160
- autoInc: true,
161
- });
162
- ctx.model.extend('cchess_gaming_player_records', {
163
- id: 'unsigned',
164
- channelId: 'string',
165
- userId: 'string',
166
- username: 'string',
167
- side: 'string',
168
- }, {
169
- primary: 'id',
170
- autoInc: true,
171
- });
172
- ctx.model.extend('cchess_player_records', {
173
- id: 'unsigned',
174
- userId: 'string',
175
- username: 'string',
176
- win: 'unsigned',
177
- lose: 'unsigned',
178
- }, {
179
- primary: 'id',
180
- autoInc: true,
181
- });
182
- // zjj*
183
- ctx.middleware(async (session, next) => {
184
- let { channelId, content, userId, username } = session;
185
- const gameRecord = await getGameRecord(channelId);
186
- if (!gameRecord.isStarted) {
187
- return await next();
188
- }
189
- let playerRecord = await ctx.database.get('cchess_gaming_player_records', { channelId, userId });
190
- if (playerRecord.length === 0 && !config.allowFreePieceMovementInHumanMachineMode) {
191
- if (!(gameRecord.isEnginePlayRed || gameRecord.isEnginePlayBlack)) {
192
- return await next();
193
- }
194
- else {
195
- if (gameRecord.isEnginePlayRed) {
196
- await ctx.database.create('cchess_gaming_player_records', { channelId, userId, username, side: '黑方' });
197
- playerRecord = await ctx.database.get('cchess_gaming_player_records', { channelId, userId });
198
- }
199
- else if (gameRecord.isEnginePlayBlack) {
200
- await ctx.database.create('cchess_gaming_player_records', { channelId, userId, username, side: '红方' });
201
- playerRecord = await ctx.database.get('cchess_gaming_player_records', { channelId, userId });
202
- }
203
- }
204
- }
205
- if (playerRecord.length !== 0) {
206
- const turn = gameRecord.turn;
207
- const sideString = turn === 'w' ? '红方' : '黑方';
208
- if (playerRecord[0].side !== sideString) {
209
- return await next();
210
- }
211
- }
212
- if (!isMoveString(content) && !isValidFigureMoveName(content)) {
213
- return await next();
214
- }
215
- await session.execute(`cchess.移动 ${content}`);
216
- });
217
- // bz*
218
- ctx.command('cchess', '中国象棋游戏指令帮助')
219
- .action(async ({ session }) => {
220
- await session.execute(`cchess -h`);
221
- });
222
- // jr* j*
223
- ctx.command('cchess.加入 [choice:string]', '加入游戏并选择红黑方')
224
- .action(async ({ session }, choice) => {
225
- const { username, userId, channelId } = session;
226
- await updateNameInPlayerRecord(userId, username);
227
- const gameRecord = await getGameRecord(channelId);
228
- if (gameRecord.isStarted) {
229
- const buffer = await drawChessBoard(channelId);
230
- const hImg = koishi_1.h.image(buffer, `image/${config.imageType}`);
231
- return await sendMessage(session, `【@${username}】\n游戏已经开始啦!\n${hImg}`);
232
- }
233
- await checkEngine(channelId);
234
- if (engines[channelId] && !gameRecord.isEngineReady) {
235
- await ctx.database.set('cchess_game_records', { channelId }, {
236
- isEngineReady: true
237
- });
238
- }
239
- if (!choice) {
240
- choice = Math.random() < 0.5 ? '红方' : '黑方';
241
- }
242
- else if (choice.includes('红') && choice.includes('黑')) {
243
- return await sendMessage(session, `【@${username}】\n一次只能选择一方哦!`);
244
- }
245
- else if (choice.includes('红')) {
246
- choice = '红方';
247
- }
248
- else if (choice.includes('黑')) {
249
- choice = '黑方';
250
- }
251
- else {
252
- choice = Math.random() < 0.5 ? '红方' : '黑方';
253
- }
254
- const getPlayerRecord = await ctx.database.get('cchess_gaming_player_records', { channelId, userId });
255
- const getPlayerRecords = await ctx.database.get('cchess_gaming_player_records', { channelId });
256
- const playersNum = getPlayerRecords.length;
257
- if (getPlayerRecord.length === 0) {
258
- await ctx.database.create('cchess_gaming_player_records', { channelId, userId, username, side: choice });
259
- return await sendMessage(session, `【@${username}】\n您加入游戏啦!\n您的队伍为:【${choice}】\n当前玩家人数为:【${playersNum + 1}】\n带“黑”或“红”加入游戏可以更换队伍哦~\n例如:\n- 加入指令 红\n- 加入指令 黑`);
260
- }
261
- else {
262
- await ctx.database.set('cchess_gaming_player_records', { channelId, userId }, { side: choice });
263
- return await sendMessage(session, `【@${username}】\n您已更换队伍为:【${choice}】\n当前玩家人数为:【${playersNum}】`);
264
- }
265
- });
266
- // tc* q*
267
- ctx.command('cchess.退出', '退出游戏')
268
- .action(async ({ session }) => {
269
- const { username, userId, channelId } = session;
270
- await updateNameInPlayerRecord(userId, username);
271
- const gameRecord = await getGameRecord(channelId);
272
- if (gameRecord.isStarted) {
273
- return await sendMessage(session, `【@${username}】\n游戏已经开始啦~\n不许逃跑哦!`);
274
- }
275
- await checkEngine(channelId);
276
- if (engines[channelId] && !gameRecord.isEngineReady) {
277
- await ctx.database.set('cchess_game_records', { channelId }, {
278
- isEngineReady: true
279
- });
280
- }
281
- const getPlayerRecord = await ctx.database.get('cchess_gaming_player_records', { channelId, userId });
282
- const getPlayerRecords = await ctx.database.get('cchess_gaming_player_records', { channelId });
283
- const playersNum = getPlayerRecords.length;
284
- if (getPlayerRecord.length === 0) {
285
- return await sendMessage(session, `【@${username}】\n您还未加入游戏呢!`);
286
- }
287
- else {
288
- await ctx.database.remove('cchess_gaming_player_records', { channelId, userId });
289
- return await sendMessage(session, `【@${username}】\n您已退出游戏!\n剩余玩家人数为:【${playersNum - 1}】`);
290
- }
291
- });
292
- // ksbz* ks*
293
- ctx.command('cchess.开始', '开始游戏指令帮助')
294
- .action(async ({ session }) => {
295
- await session.execute(`cchess.开始 -h`);
296
- });
297
- // rrdz*
298
- ctx.command('cchess.开始.人人对战', '开始人人对战')
299
- .action(async ({ session }) => {
300
- const { username, userId, channelId } = session;
301
- await updateNameInPlayerRecord(userId, username);
302
- const gameRecord = await getGameRecord(channelId);
303
- if (gameRecord.isStarted) {
304
- return await sendMessage(session, `【@${username}】\n游戏已经开始啦!`);
305
- }
306
- await checkEngine(channelId);
307
- if (engines[channelId] && !gameRecord.isEngineReady) {
308
- await ctx.database.set('cchess_game_records', { channelId }, {
309
- isEngineReady: true
310
- });
311
- }
312
- const getPlayerRecords = await ctx.database.get('cchess_gaming_player_records', { channelId });
313
- const playersNum = getPlayerRecords.length;
314
- let redPlayers = getPlayerRecords.filter((player) => player.side === '红方');
315
- let blackPlayers = getPlayerRecords.filter((player) => player.side === '黑方');
316
- let message = '';
317
- if (playersNum < 2) {
318
- return await sendMessage(session, `【@${username}】\n当前玩家人数不足 2 人,无法开始游戏!`);
319
- }
320
- else {
321
- if (redPlayers.length !== 1 || blackPlayers.length !== 1) {
322
- const randomPlayer = getPlayerRecords[Math.floor(Math.random() * getPlayerRecords.length)];
323
- if (redPlayers.length < 1) {
324
- randomPlayer.side = '红方';
325
- message += `【@${randomPlayer.username}】被自动分配到红方。\n`;
326
- }
327
- else {
328
- randomPlayer.side = '黑方';
329
- message += `【@${randomPlayer.username}】被自动分配到黑方。\n`;
330
- }
331
- await ctx.database.set('cchess_gaming_player_records', {
332
- channelId,
333
- userId: randomPlayer.userId
334
- }, { side: randomPlayer.side });
335
- redPlayers = getPlayerRecords.filter((player) => player.side === '红方');
336
- blackPlayers = getPlayerRecords.filter((player) => player.side === '黑方');
337
- }
338
- message += `红方玩家(${redPlayers.length}):\n${redPlayers.map(player => `【@${player.username}】`).join('\n')}\n\n`;
339
- message += `黑方玩家(${blackPlayers.length}):\n${blackPlayers.map(player => `【@${player.username}】`).join('\n')}`;
340
- await ctx.database.set('cchess_game_records', { channelId }, {
341
- isStarted: true,
342
- });
343
- const turn = gameRecord.turn;
344
- const sideString = convertTurnToString(turn);
345
- const buffer = await drawChessBoard(channelId);
346
- const hImg = koishi_1.h.image(buffer, `image/${config.imageType}`);
347
- return await sendMessage(session, `游戏开始!\n${message}\n先手方为:【${sideString}】\n${hImg}`);
348
- }
349
- });
350
- // rjdz*
351
- ctx.command('cchess.开始.人机对战', '开始人机对战')
352
- .action(async ({ session }) => {
353
- const { username, userId, channelId } = session;
354
- await updateNameInPlayerRecord(userId, username);
355
- const gameRecord = await getGameRecord(channelId);
356
- if (gameRecord.isStarted) {
357
- return await sendMessage(session, `【@${username}】\n游戏已经开始啦!`);
358
- }
359
- await checkEngine(channelId);
360
- if (engines[channelId] && !gameRecord.isEngineReady) {
361
- await ctx.database.set('cchess_game_records', { channelId }, {
362
- isEngineReady: true
363
- });
364
- }
365
- const getPlayerRecords = await ctx.database.get('cchess_gaming_player_records', { channelId });
366
- const playersNum = getPlayerRecords.length;
367
- let redPlayers = getPlayerRecords.filter((player) => player.side === '红方');
368
- let blackPlayers = getPlayerRecords.filter((player) => player.side === '黑方');
369
- let message = '';
370
- let AISide = '';
371
- if (playersNum < 1 && !config.allowFreePieceMovementInHumanMachineMode) {
372
- return await sendMessage(session, `【@${username}】\n当前玩家人数不足 1 人,无法开始游戏!`);
373
- }
374
- else {
375
- if (playersNum === 1) {
376
- if (getPlayerRecords[0].side === '红方') {
377
- await ctx.database.set('cchess_game_records', { channelId }, { isEnginePlayBlack: true });
378
- AISide = '黑方';
379
- message += `人类队伍为:【红方】\n`;
380
- }
381
- else {
382
- await ctx.database.set('cchess_game_records', { channelId }, { isEnginePlayRed: true });
383
- AISide = '红方';
384
- message += `人类队伍为:【黑方】\n`;
385
- }
386
- }
387
- else {
388
- if (redPlayers.length > blackPlayers.length) {
389
- await ctx.database.set('cchess_game_records', { channelId }, { isEnginePlayBlack: true });
390
- AISide = '黑方';
391
- message += `人类队伍为:【红方】\n`;
392
- for (const player of blackPlayers) {
393
- await ctx.database.set('cchess_gaming_player_records', {
394
- channelId,
395
- userId: player.userId
396
- }, { side: '红方' });
397
- }
398
- }
399
- else if (redPlayers.length < blackPlayers.length) {
400
- await ctx.database.set('cchess_game_records', { channelId }, { isEnginePlayRed: true });
401
- AISide = '红方';
402
- message += `人类队伍为:【黑方】\n`;
403
- for (const player of redPlayers) {
404
- await ctx.database.set('cchess_gaming_player_records', {
405
- channelId,
406
- userId: player.userId
407
- }, { side: '黑方' });
408
- }
409
- }
410
- if (redPlayers.length === blackPlayers.length) {
411
- const side = Math.random() < 0.5 ? '红方' : '黑方';
412
- message += `人类队伍为:【${side}】\n`;
413
- const computerSide = side === '红方' ? '黑方' : '红方';
414
- AISide = computerSide;
415
- await ctx.database.set('cchess_game_records', { channelId }, {
416
- isEnginePlayRed: computerSide === '红方',
417
- isEnginePlayBlack: computerSide === '黑方'
418
- });
419
- for (const player of getPlayerRecords) {
420
- await ctx.database.set('cchess_gaming_player_records', { channelId, userId: player.userId }, { side: side });
421
- }
422
- }
423
- }
424
- await ctx.database.set('cchess_game_records', { channelId }, {
425
- isStarted: true,
426
- });
427
- const turn = gameRecord.turn;
428
- const sideString = convertTurnToString(turn);
429
- if (AISide === sideString) {
430
- await ctx.database.set('cchess_game_records', { channelId }, {
431
- isAnalyzing: true,
432
- });
433
- await engineAction(channelId);
434
- while (true) {
435
- const gameRecord = await getGameRecord(channelId);
436
- if (!gameRecord.isAnalyzing) {
437
- break;
438
- }
439
- await (0, koishi_1.sleep)(500);
440
- }
441
- }
442
- const buffer = await drawChessBoard(channelId);
443
- const hImg = koishi_1.h.image(buffer, `image/${config.imageType}`);
444
- return await sendMessage(session, `游戏开始!\n${message}\n先手方为:【${sideString}】\n${hImg}`);
445
- }
446
- });
447
- // js*
448
- ctx.command('cchess.结束', '强制结束游戏')
449
- .action(async ({ session }) => {
450
- const { username, userId, channelId } = session;
451
- await updateNameInPlayerRecord(userId, username);
452
- const gameRecord = await getGameRecord(channelId);
453
- await checkEngine(channelId);
454
- if (engines[channelId] && !gameRecord.isEngineReady) {
455
- await ctx.database.set('cchess_game_records', { channelId }, {
456
- isEngineReady: true
457
- });
458
- }
459
- if (!gameRecord.isStarted) {
460
- return await sendMessage(session, `【@${username}】\n游戏未开始哦!\n完全没必要强制结束嘛~`);
461
- }
462
- else {
463
- await endGame(channelId);
464
- return await sendMessage(session, `【@${username}】\n游戏已被强制结束!`);
465
- }
88
+ const logger = ctx.logger("cchess");
89
+ const engines = {};
90
+ ctx.on("dispose", () => {
91
+ const channelIds = Object.keys(engines);
92
+ channelIds.forEach((channelId) => {
93
+ if (engines[channelId]) {
94
+ engines[channelId].send_command("quit");
95
+ engines[channelId] = null;
96
+ }
466
97
  });
467
- // yd*
468
- ctx.command('cchess.移动 <moveOperation:text>', '进行移动操作')
469
- .action(async ({ session }, moveOperation) => {
470
- const { username, userId, channelId } = session;
471
- await updateNameInPlayerRecord(userId, username);
472
- if (!isMoveString(moveOperation) && !isValidFigureMoveName(moveOperation)) {
473
- return await sendMessage(session, `【@${username}】\n无效的移动!`);
474
- }
475
- const gameRecord = await getGameRecord(channelId);
476
- if (!gameRecord.isStarted) {
477
- return await sendMessage(session, `【@${username}】\n游戏还未开始哦!`);
478
- }
479
- if (gameRecord.isRegretRequest) {
480
- return await sendMessage(session, `【@${username}】\n正在请求悔棋,等待回应中...`);
481
- }
482
- const turn = gameRecord.turn;
483
- const sideString = convertTurnToString(turn);
484
- let playerRecord = await ctx.database.get('cchess_gaming_player_records', { channelId, userId });
485
- if (playerRecord.length === 0) {
486
- if (config.allowFreePieceMovementInHumanMachineMode) {
487
- if (gameRecord.isEnginePlayRed) {
488
- await ctx.database.create('cchess_gaming_player_records', { channelId, userId, username, side: '黑方' });
489
- playerRecord = await ctx.database.get('cchess_gaming_player_records', { channelId, userId });
490
- }
491
- else if (gameRecord.isEnginePlayBlack) {
492
- await ctx.database.create('cchess_gaming_player_records', { channelId, userId, username, side: '红方' });
493
- playerRecord = await ctx.database.get('cchess_gaming_player_records', { channelId, userId });
494
- }
495
- }
496
- else {
497
- return await sendMessage(session, `【@${username}】\n您还未加入游戏呢!`);
498
- }
499
- }
500
- if (playerRecord[0].side !== sideString) {
501
- return await sendMessage(session, `【@${username}】\n还没轮到${sideString}走棋哦!\n当前走棋方为:【${convertTurnToString(gameRecord.turn)}】`);
502
- }
503
- await checkEngine(channelId);
504
- if (engines[channelId] && !gameRecord.isEngineReady) {
505
- await ctx.database.set('cchess_game_records', { channelId }, {
506
- isEngineReady: true
507
- });
508
- }
509
- const board = gameRecord.board;
510
- let selectedPos = undefined;
511
- let newPos = undefined;
512
- // 中文纵线
513
- if (possibleFigureNames.some(figureName => moveOperation.includes(figureName))) {
514
- const figureName = getFigureNameFromMoveOperation(moveOperation);
515
- const englishLetter = getEnglishLetterFromFigureName(figureName);
516
- const processedLetter = processEnglishLetter(englishLetter, turn);
517
- const letterPositions = findLetterPositions(board, processedLetter);
518
- const moveInfoList = [];
519
- for (const pos of letterPositions) {
520
- const piece = processedLetter;
521
- const side = getSide(piece);
522
- const type = getType(piece);
523
- const moveMap = getValidMoveMap(board, type, side, [pos[1], pos[0]]);
524
- const legalPositions = findLegalMovePositions(moveMap);
525
- const fen = getFen(board, side);
526
- for (const toPos of legalPositions) {
527
- const moveString = moveToMoveString([[pos[1], pos[0]], [toPos[1], toPos[0]]]);
528
- const figureMoveName = getFigureMoveName(fen, moveString);
529
- moveInfoList.push({
530
- moveCord: [[pos[1], pos[0]], [toPos[1], toPos[0]]],
531
- moveString: moveString,
532
- figureMoveName: figureMoveName
533
- });
534
- }
535
- }
536
- const duplicateMoveInfo = findMoveInfo(moveInfoList, moveOperation);
537
- if (!duplicateMoveInfo) {
538
- return await sendMessage(session, `【@${username}】\n无效的移动!`);
539
- }
540
- else {
541
- [selectedPos, newPos] = duplicateMoveInfo.moveCord;
542
- }
543
- }
544
- else {
545
- // 字母坐标
546
- // [selectedPos, newPos] = moveStringToMove(moveOperation);
547
- [selectedPos, newPos] = moveStringToPos(moveOperation);
548
- }
549
- const [newCol, newRow] = newPos;
550
- const piece = getPiece(board, selectedPos);
551
- const side = getSide(piece);
552
- const type = getType(piece);
553
- if (side !== gameRecord.turn) {
554
- return await sendMessage(session, `【@${username}】\n还没轮到${convertTurnToString(side)}走棋哦!\n当前走棋方为:【${convertTurnToString(gameRecord.turn)}】`);
555
- }
556
- const moveMap = getValidMoveMap(board, type, side, selectedPos);
557
- if (moveMap[newRow][newCol] !== 'go' && moveMap[newRow][newCol] !== 'eat') {
558
- return await sendMessage(session, `【@${username}】\n无效的移动!`);
559
- }
560
- await makeMove(channelId, selectedPos, newPos);
561
- await ctx.database.set('cchess_game_records', { channelId }, {
562
- isAnalyzing: true
98
+ });
99
+ const we = 54;
100
+ const pe = 33;
101
+ const Pe = 33;
102
+ const Be = 50;
103
+ const Ie = 54;
104
+ const Me = 500;
105
+ const ye = 550;
106
+ const ze = 500;
107
+ const ke = 120;
108
+ const weight = 500;
109
+ const height = 550;
110
+ const scale = config.imgScale;
111
+ const isFlipBoard = false;
112
+ const engineSettings = {
113
+ Threads: 1,
114
+ Hash: 128,
115
+ MultiPV: 1
116
+ // "Skill Level": 20,
117
+ };
118
+ const thinkingSettings = {
119
+ moveTime: 1,
120
+ depth: config.defaultEngineThinkingDepth,
121
+ enableHint: true
122
+ };
123
+ const piecesImgResources = loadPiecesImageResources(config.pieceSkin);
124
+ const outerFrameImg = fs.readFileSync(path.join(__dirname, "assets", "棋盘皮肤", `外框.png`));
125
+ const boardSkinImg = fs.readFileSync(path.join(__dirname, "assets", "棋盘皮肤", `${config.boardSkin}.webp`));
126
+ const possibleFigureNames = ["将", "士", "象", "车", "马", "炮", "卒", "帅", "仕", "相", "兵"];
127
+ ctx.model.extend("cchess_game_records", {
128
+ id: "unsigned",
129
+ channelId: "string",
130
+ isStarted: "boolean",
131
+ isFlipBoard: "boolean",
132
+ isHistoryMode: "boolean",
133
+ turn: { type: "string", initial: "w" },
134
+ moveList: { type: "json", initial: [] },
135
+ isDraw: { type: "boolean", initial: false },
136
+ winSide: { type: "string", initial: "" },
137
+ loseSide: { type: "string", initial: "" },
138
+ // lastPV: {type: 'json', initial: null},
139
+ originalState: { type: "json", initial: {} },
140
+ thinkingDetail: { type: "json", initial: [] },
141
+ currentMoveId: { type: "string", initial: "" },
142
+ thinkingSide: { type: "string", initial: "w" },
143
+ movesAfterLastEat: { type: "json", initial: [] },
144
+ isAnalyzing: { type: "boolean", initial: false },
145
+ turnAfterLastEat: { type: "string", initial: "w" },
146
+ isEngineReady: { type: "boolean", initial: false },
147
+ // multiPvInfoBuffer: {type: 'json', initial: {}},
148
+ isEnginePlayRed: { type: "boolean", initial: false },
149
+ isEngineAnalyze: { type: "boolean", initial: false },
150
+ isRegretRequest: { type: "boolean", initial: false },
151
+ lastMove: { type: "json", initial: [[0, 0], [0, 0]] },
152
+ isEnginePlayBlack: { type: "boolean", initial: false },
153
+ ponderHint: { type: "json", initial: [[0, 0], [0, 0]] },
154
+ // bestMoveHint: {type: 'json', initial: [[0, 0], [0, 0]]},
155
+ fen: { type: "string", initial: "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w" },
156
+ startFen: { type: "string", initial: "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w" },
157
+ board: { type: "json", initial: fenToBoard("rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w") },
158
+ boardAfterLastEat: {
159
+ type: "json",
160
+ initial: fenToBoard("rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w")
161
+ },
162
+ moveTreePtr: {
163
+ type: "json",
164
+ initial: { moveId: "", fen: "", side: "", moveCord: [[0, 0], [0, 0]], move: "", chnMoveName: "", next: null }
165
+ }
166
+ }, {
167
+ primary: "id",
168
+ autoInc: true
169
+ });
170
+ ctx.model.extend("cchess_gaming_player_records", {
171
+ id: "unsigned",
172
+ channelId: "string",
173
+ userId: "string",
174
+ username: "string",
175
+ side: "string"
176
+ }, {
177
+ primary: "id",
178
+ autoInc: true
179
+ });
180
+ ctx.model.extend("cchess_player_records", {
181
+ id: "unsigned",
182
+ userId: "string",
183
+ username: "string",
184
+ win: "unsigned",
185
+ lose: "unsigned"
186
+ }, {
187
+ primary: "id",
188
+ autoInc: true
189
+ });
190
+ ctx.middleware(async (session, next) => {
191
+ let { channelId, content, userId, username } = session;
192
+ const gameRecord = await getGameRecord(channelId);
193
+ if (!gameRecord.isStarted) {
194
+ return await next();
195
+ }
196
+ let playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
197
+ if (playerRecord.length === 0 && !config.allowFreePieceMovementInHumanMachineMode) {
198
+ if (!(gameRecord.isEnginePlayRed || gameRecord.isEnginePlayBlack)) {
199
+ return await next();
200
+ } else {
201
+ if (gameRecord.isEnginePlayRed) {
202
+ await ctx.database.create("cchess_gaming_player_records", { channelId, userId, username, side: "黑方" });
203
+ playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
204
+ } else if (gameRecord.isEnginePlayBlack) {
205
+ await ctx.database.create("cchess_gaming_player_records", { channelId, userId, username, side: "红方" });
206
+ playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
207
+ }
208
+ }
209
+ }
210
+ if (playerRecord.length !== 0) {
211
+ const turn = gameRecord.turn;
212
+ const sideString = turn === "w" ? "红方" : "黑方";
213
+ if (playerRecord[0].side !== sideString) {
214
+ return await next();
215
+ }
216
+ }
217
+ if (!isMoveString(content) && !isValidFigureMoveName(content)) {
218
+ return await next();
219
+ }
220
+ await session.execute(`cchess.移动 ${content}`);
221
+ });
222
+ ctx.command("cchess", "中国象棋游戏指令帮助").action(async ({ session }) => {
223
+ await session.execute(`cchess -h`);
224
+ });
225
+ ctx.command("cchess.加入 [choice:string]", "加入游戏并选择红黑方").action(async ({ session }, choice) => {
226
+ const { username, userId, channelId } = session;
227
+ await updateNameInPlayerRecord(userId, username);
228
+ const gameRecord = await getGameRecord(channelId);
229
+ if (gameRecord.isStarted) {
230
+ const buffer = await drawChessBoard(channelId);
231
+ const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
232
+ return await sendMessage(session, `【@${username}】
233
+ 游戏已经开始啦!
234
+ ${hImg}`);
235
+ }
236
+ await checkEngine(channelId);
237
+ if (engines[channelId] && !gameRecord.isEngineReady) {
238
+ await ctx.database.set("cchess_game_records", { channelId }, {
239
+ isEngineReady: true
240
+ });
241
+ }
242
+ if (!choice) {
243
+ choice = Math.random() < 0.5 ? "红方" : "黑方";
244
+ } else if (choice.includes("红") && choice.includes("黑")) {
245
+ return await sendMessage(session, `【@${username}】
246
+ 一次只能选择一方哦!`);
247
+ } else if (choice.includes("红")) {
248
+ choice = "红方";
249
+ } else if (choice.includes("黑")) {
250
+ choice = "黑方";
251
+ } else {
252
+ choice = Math.random() < 0.5 ? "红方" : "黑方";
253
+ }
254
+ const getPlayerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
255
+ const getPlayerRecords = await ctx.database.get("cchess_gaming_player_records", { channelId });
256
+ const playersNum = getPlayerRecords.length;
257
+ if (getPlayerRecord.length === 0) {
258
+ await ctx.database.create("cchess_gaming_player_records", { channelId, userId, username, side: choice });
259
+ return await sendMessage(session, `【@${username}】
260
+ 您加入游戏啦!
261
+ 您的队伍为:【${choice}】
262
+ 当前玩家人数为:【${playersNum + 1}】
263
+ 带“黑”或“红”加入游戏可以更换队伍哦~
264
+ 例如:
265
+ - 加入指令 红
266
+ - 加入指令 黑`);
267
+ } else {
268
+ await ctx.database.set("cchess_gaming_player_records", { channelId, userId }, { side: choice });
269
+ return await sendMessage(session, `【@${username}】
270
+ 您已更换队伍为:【${choice}】
271
+ 当前玩家人数为:【${playersNum}】`);
272
+ }
273
+ });
274
+ ctx.command("cchess.退出", "退出游戏").action(async ({ session }) => {
275
+ const { username, userId, channelId } = session;
276
+ await updateNameInPlayerRecord(userId, username);
277
+ const gameRecord = await getGameRecord(channelId);
278
+ if (gameRecord.isStarted) {
279
+ return await sendMessage(session, `【@${username}】
280
+ 游戏已经开始啦~
281
+ 不许逃跑哦!`);
282
+ }
283
+ await checkEngine(channelId);
284
+ if (engines[channelId] && !gameRecord.isEngineReady) {
285
+ await ctx.database.set("cchess_game_records", { channelId }, {
286
+ isEngineReady: true
287
+ });
288
+ }
289
+ const getPlayerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
290
+ const getPlayerRecords = await ctx.database.get("cchess_gaming_player_records", { channelId });
291
+ const playersNum = getPlayerRecords.length;
292
+ if (getPlayerRecord.length === 0) {
293
+ return await sendMessage(session, `【@${username}】
294
+ 您还未加入游戏呢!`);
295
+ } else {
296
+ await ctx.database.remove("cchess_gaming_player_records", { channelId, userId });
297
+ return await sendMessage(session, `【@${username}】
298
+ 您已退出游戏!
299
+ 剩余玩家人数为:【${playersNum - 1}】`);
300
+ }
301
+ });
302
+ ctx.command("cchess.开始", "开始游戏指令帮助").action(async ({ session }) => {
303
+ await session.execute(`cchess.开始 -h`);
304
+ });
305
+ ctx.command("cchess.开始.人人对战", "开始人人对战").action(async ({ session }) => {
306
+ const { username, userId, channelId } = session;
307
+ await updateNameInPlayerRecord(userId, username);
308
+ const gameRecord = await getGameRecord(channelId);
309
+ if (gameRecord.isStarted) {
310
+ return await sendMessage(session, `【@${username}】
311
+ 游戏已经开始啦!`);
312
+ }
313
+ await checkEngine(channelId);
314
+ if (engines[channelId] && !gameRecord.isEngineReady) {
315
+ await ctx.database.set("cchess_game_records", { channelId }, {
316
+ isEngineReady: true
317
+ });
318
+ }
319
+ const getPlayerRecords = await ctx.database.get("cchess_gaming_player_records", { channelId });
320
+ const playersNum = getPlayerRecords.length;
321
+ let redPlayers = getPlayerRecords.filter((player) => player.side === "红方");
322
+ let blackPlayers = getPlayerRecords.filter((player) => player.side === "黑方");
323
+ let message = "";
324
+ if (playersNum < 2) {
325
+ return await sendMessage(session, `【@${username}】
326
+ 当前玩家人数不足 2 人,无法开始游戏!`);
327
+ } else {
328
+ if (redPlayers.length !== 1 || blackPlayers.length !== 1) {
329
+ const randomPlayer = getPlayerRecords[Math.floor(Math.random() * getPlayerRecords.length)];
330
+ if (redPlayers.length < 1) {
331
+ randomPlayer.side = "红方";
332
+ message += `【@${randomPlayer.username}】被自动分配到红方。
333
+ `;
334
+ } else {
335
+ randomPlayer.side = "黑方";
336
+ message += `【@${randomPlayer.username}】被自动分配到黑方。
337
+ `;
338
+ }
339
+ await ctx.database.set("cchess_gaming_player_records", {
340
+ channelId,
341
+ userId: randomPlayer.userId
342
+ }, { side: randomPlayer.side });
343
+ redPlayers = getPlayerRecords.filter((player) => player.side === "红方");
344
+ blackPlayers = getPlayerRecords.filter((player) => player.side === "黑方");
345
+ }
346
+ message += `红方玩家(${redPlayers.length}):
347
+ ${redPlayers.map((player) => `【@${player.username}】`).join("\n")}
348
+
349
+ `;
350
+ message += `黑方玩家(${blackPlayers.length}):
351
+ ${blackPlayers.map((player) => `【@${player.username}】`).join("\n")}`;
352
+ await ctx.database.set("cchess_game_records", { channelId }, {
353
+ isStarted: true
354
+ });
355
+ const turn = gameRecord.turn;
356
+ const sideString = convertTurnToString(turn);
357
+ const buffer = await drawChessBoard(channelId);
358
+ const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
359
+ return await sendMessage(session, `游戏开始!
360
+ ${message}
361
+ 先手方为:【${sideString}】
362
+ ${hImg}`);
363
+ }
364
+ });
365
+ ctx.command("cchess.开始.人机对战", "开始人机对战").action(async ({ session }) => {
366
+ const { username, userId, channelId } = session;
367
+ await updateNameInPlayerRecord(userId, username);
368
+ const gameRecord = await getGameRecord(channelId);
369
+ if (gameRecord.isStarted) {
370
+ return await sendMessage(session, `【@${username}】
371
+ 游戏已经开始啦!`);
372
+ }
373
+ await checkEngine(channelId);
374
+ if (engines[channelId] && !gameRecord.isEngineReady) {
375
+ await ctx.database.set("cchess_game_records", { channelId }, {
376
+ isEngineReady: true
377
+ });
378
+ }
379
+ const getPlayerRecords = await ctx.database.get("cchess_gaming_player_records", { channelId });
380
+ const playersNum = getPlayerRecords.length;
381
+ let redPlayers = getPlayerRecords.filter((player) => player.side === "红方");
382
+ let blackPlayers = getPlayerRecords.filter((player) => player.side === "黑方");
383
+ let message = "";
384
+ let AISide = "";
385
+ if (playersNum < 1 && !config.allowFreePieceMovementInHumanMachineMode) {
386
+ return await sendMessage(session, `【@${username}】
387
+ 当前玩家人数不足 1 人,无法开始游戏!`);
388
+ } else {
389
+ if (playersNum === 1) {
390
+ if (getPlayerRecords[0].side === "红方") {
391
+ await ctx.database.set("cchess_game_records", { channelId }, { isEnginePlayBlack: true });
392
+ AISide = "黑方";
393
+ message += `人类队伍为:【红方】
394
+ `;
395
+ } else {
396
+ await ctx.database.set("cchess_game_records", { channelId }, { isEnginePlayRed: true });
397
+ AISide = "红方";
398
+ message += `人类队伍为:【黑方】
399
+ `;
400
+ }
401
+ } else {
402
+ if (redPlayers.length > blackPlayers.length) {
403
+ await ctx.database.set("cchess_game_records", { channelId }, { isEnginePlayBlack: true });
404
+ AISide = "黑方";
405
+ message += `人类队伍为:【红方】
406
+ `;
407
+ for (const player of blackPlayers) {
408
+ await ctx.database.set("cchess_gaming_player_records", {
409
+ channelId,
410
+ userId: player.userId
411
+ }, { side: "红方" });
412
+ }
413
+ } else if (redPlayers.length < blackPlayers.length) {
414
+ await ctx.database.set("cchess_game_records", { channelId }, { isEnginePlayRed: true });
415
+ AISide = "红方";
416
+ message += `人类队伍为:【黑方】
417
+ `;
418
+ for (const player of redPlayers) {
419
+ await ctx.database.set("cchess_gaming_player_records", {
420
+ channelId,
421
+ userId: player.userId
422
+ }, { side: "黑方" });
423
+ }
424
+ }
425
+ if (redPlayers.length === blackPlayers.length) {
426
+ const side = Math.random() < 0.5 ? "红方" : "黑方";
427
+ message += `人类队伍为:【${side}】
428
+ `;
429
+ const computerSide = side === "红方" ? "黑方" : "红方";
430
+ AISide = computerSide;
431
+ await ctx.database.set("cchess_game_records", { channelId }, {
432
+ isEnginePlayRed: computerSide === "红方",
433
+ isEnginePlayBlack: computerSide === "黑方"
434
+ });
435
+ for (const player of getPlayerRecords) {
436
+ await ctx.database.set("cchess_gaming_player_records", { channelId, userId: player.userId }, { side });
437
+ }
438
+ }
439
+ }
440
+ await ctx.database.set("cchess_game_records", { channelId }, {
441
+ isStarted: true
442
+ });
443
+ const turn = gameRecord.turn;
444
+ const sideString = convertTurnToString(turn);
445
+ if (AISide === sideString) {
446
+ await ctx.database.set("cchess_game_records", { channelId }, {
447
+ isAnalyzing: true
563
448
  });
564
449
  await engineAction(channelId);
565
450
  while (true) {
566
- const gameRecord = await getGameRecord(channelId);
567
- if (!gameRecord.isAnalyzing) {
568
- break;
569
- }
570
- await (0, koishi_1.sleep)(500);
571
- }
572
- const newGameRecord = await getGameRecord(channelId);
573
- if (newGameRecord.winSide !== '') {
574
- const buffer = await drawChessBoard(channelId);
575
- const hImg = koishi_1.h.image(buffer, `image/${config.imageType}`);
576
- await updatePlayerRecords(channelId, newGameRecord.winSide, newGameRecord.loseSide);
577
- await endGame(channelId);
578
- return await sendMessage(session, `【@${username}】\n绝杀!\n游戏结束!\n获胜方为:【${convertTurnToString(newGameRecord.winSide)}】\n${hImg}`);
579
- }
580
- if (gameRecord.isEnginePlayRed || gameRecord.isEnginePlayBlack) {
581
- // 分析人类的局势
582
- const gameRecord = await getGameRecord(channelId);
583
- let { movesAfterLastEat, boardAfterLastEat, turnAfterLastEat,
584
- // multiPvInfoBuffer
585
- } = gameRecord;
586
- await ctx.database.set('cchess_game_records', { channelId }, {
587
- isAnalyzing: true
588
- });
589
- await sendCommand(channelId, "fen " + getFenWithMove(movesAfterLastEat, boardAfterLastEat, turnAfterLastEat)),
590
- await go(channelId, 1e3 * thinkingSettings["movetime"], thinkingSettings["depth"], -1);
591
- while (true) {
592
- const gameRecord = await getGameRecord(channelId);
593
- if (!gameRecord.isAnalyzing) {
594
- break;
595
- }
596
- await (0, koishi_1.sleep)(500);
597
- }
598
- const newGameRecord = await getGameRecord(channelId);
599
- if (newGameRecord.winSide !== '') {
600
- const buffer = await drawChessBoard(channelId);
601
- const hImg = koishi_1.h.image(buffer, `image/${config.imageType}`);
602
- await updatePlayerRecords(channelId, newGameRecord.winSide, newGameRecord.loseSide);
603
- await endGame(channelId);
604
- return await sendMessage(session, `【@${username}】\n绝杀!\n游戏结束!\n获胜方为:【${convertTurnToString(newGameRecord.winSide)}】\n${hImg}`);
605
- }
606
- }
607
- const buffer = await drawChessBoard(channelId);
608
- const hImg = koishi_1.h.image(buffer, `image/${config.imageType}`);
609
- return await sendMessage(session, `${hImg}`);
610
- });
611
- // hq*
612
- ctx.command('cchess.悔棋', '悔棋指令帮助')
613
- .action(async ({ session }) => {
614
- await session.execute(`cchess.悔棋 -h`);
615
- });
616
- // qqhq*
617
- ctx.command('cchess.悔棋.请求', '请求悔棋')
618
- .action(async ({ session }) => {
619
- const { username, userId, channelId } = session;
620
- await updateNameInPlayerRecord(userId, username);
621
- const gameRecord = await getGameRecord(channelId);
622
- if (!gameRecord.isStarted) {
623
- return await sendMessage(session, `【@${username}】\n游戏还未开始哦!`);
624
- }
625
- await checkEngine(channelId);
626
- if (engines[channelId] && !gameRecord.isEngineReady) {
627
- await ctx.database.set('cchess_game_records', { channelId }, {
628
- isEngineReady: true
629
- });
630
- }
631
- if (gameRecord.isRegretRequest) {
632
- return await sendMessage(session, `【@${username}】\n已经有悔棋请求了!`);
633
- }
634
- const playerRecord = await ctx.database.get('cchess_gaming_player_records', { channelId, userId });
635
- if (playerRecord.length === 0) {
636
- return await sendMessage(session, `【@${username}】\n您还未加入游戏呢!`);
637
- }
638
- const turn = gameRecord.turn;
639
- const sideString = convertTurnToString(turn);
640
- if (gameRecord.isAnalyzing) {
641
- return await sendMessage(session, `【@${username}】\n对局分析中,请稍后再试!`);
642
- }
643
- if (gameRecord.moveList.length < 1) {
644
- return await sendMessage(session, `【@${username}】\n当前无法悔棋!`);
645
- }
646
- if (gameRecord.isEnginePlayBlack || gameRecord.isEnginePlayRed) {
647
- await undoMove(channelId);
648
- await undoMove(channelId);
649
- const buffer = await drawChessBoard(channelId);
650
- const hImg = koishi_1.h.image(buffer, `image/${config.imageType}`);
651
- return await sendMessage(session, `【@${username}】\n悔棋成功!\n${hImg}`);
652
- }
653
- else {
654
- if (playerRecord[0].side === sideString) {
655
- return await sendMessage(session, `【@${username}】\n现在轮到你下棋,不可悔棋!`);
656
- }
657
- else {
658
- await ctx.database.set('cchess_game_records', { channelId }, {
659
- isRegretRequest: true
660
- });
661
- return await sendMessage(session, `【@${username}】\n请求悔棋中...\n清对方输入相关指令选择同意或拒绝!`);
662
- }
663
- }
664
- });
665
- // tyhq*
666
- ctx.command('cchess.悔棋.同意', '同意悔棋')
667
- .action(async ({ session }) => {
668
- const { username, userId, channelId } = session;
669
- await updateNameInPlayerRecord(userId, username);
670
- const gameRecord = await getGameRecord(channelId);
671
- if (!gameRecord.isStarted) {
672
- return await sendMessage(session, `【@${username}】\n游戏还未开始哦!`);
673
- }
674
- await checkEngine(channelId);
675
- if (engines[channelId] && !gameRecord.isEngineReady) {
676
- await ctx.database.set('cchess_game_records', { channelId }, {
677
- isEngineReady: true
678
- });
679
- }
680
- if (gameRecord.isAnalyzing) {
681
- return await sendMessage(session, `【@${username}】\n对局分析中,请稍后再试!`);
682
- }
683
- if (!gameRecord.isRegretRequest) {
684
- return await sendMessage(session, `【@${username}】\n当前无悔棋请求!`);
685
- }
686
- const playerRecord = await ctx.database.get('cchess_gaming_player_records', { channelId, userId });
687
- if (playerRecord.length === 0) {
688
- return await sendMessage(session, `【@${username}】\n您还未加入游戏呢!`);
689
- }
690
- const turn = gameRecord.turn;
691
- const sideString = convertTurnToString(turn);
692
- if (playerRecord[0].side !== sideString) {
693
- return await sendMessage(session, `【@${username}】\n您所在的队伍不能做出选择!`);
694
- }
695
- else {
696
- await undoMove(channelId);
697
- await ctx.database.set('cchess_game_records', { channelId }, {
698
- isRegretRequest: false
699
- });
700
- const buffer = await drawChessBoard(channelId);
701
- const hImg = koishi_1.h.image(buffer, `image/${config.imageType}`);
702
- return await sendMessage(session, `【@${username}】\n由于您同意了对方的悔棋请求!\n悔棋成功!\n${hImg}`);
703
- }
704
- });
705
- // jjhq*
706
- ctx.command('cchess.悔棋.拒绝', '拒绝悔棋')
707
- .action(async ({ session }) => {
708
- const { username, userId, channelId } = session;
709
- await updateNameInPlayerRecord(userId, username);
710
- const gameRecord = await getGameRecord(channelId);
711
- if (!gameRecord.isStarted) {
712
- return await sendMessage(session, `【@${username}】\n游戏还未开始哦!`);
713
- }
714
- await checkEngine(channelId);
715
- if (engines[channelId] && !gameRecord.isEngineReady) {
716
- await ctx.database.set('cchess_game_records', { channelId }, {
717
- isEngineReady: true
718
- });
719
- }
720
- if (gameRecord.isAnalyzing) {
721
- return await sendMessage(session, `【@${username}】\n对局分析中,请稍后再试!`);
722
- }
723
- if (!gameRecord.isRegretRequest) {
724
- return await sendMessage(session, `【@${username}】\n当前无悔棋请求!`);
725
- }
726
- const playerRecord = await ctx.database.get('cchess_gaming_player_records', { channelId, userId });
727
- if (playerRecord.length === 0) {
728
- return await sendMessage(session, `【@${username}】\n您还未加入游戏呢!`);
729
- }
730
- const turn = gameRecord.turn;
731
- const sideString = convertTurnToString(turn);
732
- if (playerRecord[0].side !== sideString) {
733
- return await sendMessage(session, `【@${username}】\n您所在的队伍不能做出选择!`);
734
- }
735
- else {
736
- await ctx.database.set('cchess_game_records', { channelId }, {
737
- isRegretRequest: false
738
- });
739
- const buffer = await drawChessBoard(channelId);
740
- const hImg = koishi_1.h.image(buffer, `image/${config.imageType}`);
741
- return await sendMessage(session, `【@${username}】\n由于您拒绝了对方的悔棋请求!\n悔棋失败,游戏继续进行!\n${hImg}`);
742
- }
743
- });
744
- // rs*
745
- ctx.command('cchess.认输', '认输')
746
- .action(async ({ session }) => {
747
- const { username, userId, channelId } = session;
748
- await updateNameInPlayerRecord(userId, username);
749
- const gameRecord = await getGameRecord(channelId);
750
- if (!gameRecord.isStarted) {
751
- return await sendMessage(session, `【@${username}】\n游戏还未开始哦!`);
752
- }
753
- await checkEngine(channelId);
754
- if (engines[channelId] && !gameRecord.isEngineReady) {
755
- await ctx.database.set('cchess_game_records', { channelId }, {
756
- isEngineReady: true
451
+ const gameRecord2 = await getGameRecord(channelId);
452
+ if (!gameRecord2.isAnalyzing) {
453
+ break;
454
+ }
455
+ await (0, import_koishi.sleep)(500);
456
+ }
457
+ }
458
+ const buffer = await drawChessBoard(channelId);
459
+ const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
460
+ return await sendMessage(session, `游戏开始!
461
+ ${message}
462
+ 先手方为:【${sideString}】
463
+ ${hImg}`);
464
+ }
465
+ });
466
+ ctx.command("cchess.结束", "强制结束游戏").action(async ({ session }) => {
467
+ const { username, userId, channelId } = session;
468
+ await updateNameInPlayerRecord(userId, username);
469
+ const gameRecord = await getGameRecord(channelId);
470
+ await checkEngine(channelId);
471
+ if (engines[channelId] && !gameRecord.isEngineReady) {
472
+ await ctx.database.set("cchess_game_records", { channelId }, {
473
+ isEngineReady: true
474
+ });
475
+ }
476
+ if (!gameRecord.isStarted) {
477
+ return await sendMessage(session, `【@${username}】
478
+ 游戏未开始哦!
479
+ 完全没必要强制结束嘛~`);
480
+ } else {
481
+ await endGame(channelId);
482
+ return await sendMessage(session, `【@${username}
483
+ 游戏已被强制结束!`);
484
+ }
485
+ });
486
+ ctx.command("cchess.移动 <moveOperation:text>", "进行移动操作").action(
487
+ async ({ session }, moveOperation) => {
488
+ const { username, userId, channelId } = session;
489
+ await updateNameInPlayerRecord(userId, username);
490
+ if (!isMoveString(moveOperation) && !isValidFigureMoveName(moveOperation)) {
491
+ return await sendMessage(session, `【@${username}
492
+ 无效的移动!`);
493
+ }
494
+ const gameRecord = await getGameRecord(channelId);
495
+ if (!gameRecord.isStarted) {
496
+ return await sendMessage(session, `【@${username}】
497
+ 游戏还未开始哦!`);
498
+ }
499
+ if (gameRecord.isRegretRequest) {
500
+ return await sendMessage(session, `【@${username}
501
+ 正在请求悔棋,等待回应中...`);
502
+ }
503
+ const turn = gameRecord.turn;
504
+ const sideString = convertTurnToString(turn);
505
+ let playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
506
+ if (playerRecord.length === 0) {
507
+ if (config.allowFreePieceMovementInHumanMachineMode) {
508
+ if (gameRecord.isEnginePlayRed) {
509
+ await ctx.database.create("cchess_gaming_player_records", { channelId, userId, username, side: "黑方" });
510
+ playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
511
+ } else if (gameRecord.isEnginePlayBlack) {
512
+ await ctx.database.create("cchess_gaming_player_records", { channelId, userId, username, side: "红方" });
513
+ playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
514
+ }
515
+ } else {
516
+ return await sendMessage(session, `【@${username}】
517
+ 您还未加入游戏呢!`);
518
+ }
519
+ }
520
+ if (playerRecord[0].side !== sideString) {
521
+ return await sendMessage(session, `【@${username}
522
+ 还没轮到${sideString}走棋哦!
523
+ 当前走棋方为:【${convertTurnToString(gameRecord.turn)}】`);
524
+ }
525
+ await checkEngine(channelId);
526
+ if (engines[channelId] && !gameRecord.isEngineReady) {
527
+ await ctx.database.set("cchess_game_records", { channelId }, {
528
+ isEngineReady: true
529
+ });
530
+ }
531
+ const board = gameRecord.board;
532
+ let selectedPos = void 0;
533
+ let newPos = void 0;
534
+ if (possibleFigureNames.some((figureName) => moveOperation.includes(figureName))) {
535
+ const figureName = getFigureNameFromMoveOperation(moveOperation);
536
+ const englishLetter = getEnglishLetterFromFigureName(figureName);
537
+ const processedLetter = processEnglishLetter(englishLetter, turn);
538
+ const letterPositions = findLetterPositions(board, processedLetter);
539
+ const moveInfoList = [];
540
+ for (const pos of letterPositions) {
541
+ const piece2 = processedLetter;
542
+ const side2 = getSide(piece2);
543
+ const type2 = getType(piece2);
544
+ const moveMap2 = getValidMoveMap(board, type2, side2, [pos[1], pos[0]]);
545
+ const legalPositions = findLegalMovePositions(moveMap2);
546
+ const fen = getFen(board, side2);
547
+ for (const toPos of legalPositions) {
548
+ const moveString = moveToMoveString([[pos[1], pos[0]], [toPos[1], toPos[0]]]);
549
+ const figureMoveName = getFigureMoveName(fen, moveString);
550
+ moveInfoList.push({
551
+ moveCord: [[pos[1], pos[0]], [toPos[1], toPos[0]]],
552
+ moveString,
553
+ figureMoveName
757
554
  });
758
- }
759
- if (gameRecord.isAnalyzing) {
760
- return await sendMessage(session, `【@${username}】\n对局分析中,请稍后再试!`);
761
- }
762
- const playerRecord = await ctx.database.get('cchess_gaming_player_records', { channelId, userId });
763
- if (playerRecord.length === 0) {
764
- return await sendMessage(session, `【@${username}】\n您还未加入游戏呢!`);
765
- }
766
- const turn = gameRecord.turn;
767
- const sideString = convertTurnToString(turn);
768
- if (playerRecord[0].side !== sideString) {
769
- return await sendMessage(session, `【@${username}】\n还没轮到${sideString}走棋哦!\n当前走棋方为:【${convertTurnToString(gameRecord.turn)}】`);
770
- }
771
- const anotherSideString = convertTurnToString(turn === 'w' ? 'b' : 'w');
772
- await updatePlayerRecords(channelId, turn === 'w' ? 'b' : 'w', turn);
555
+ }
556
+ }
557
+ const duplicateMoveInfo = findMoveInfo(moveInfoList, moveOperation);
558
+ if (!duplicateMoveInfo) {
559
+ return await sendMessage(session, `【@${username}
560
+ 无效的移动!`);
561
+ } else {
562
+ [selectedPos, newPos] = duplicateMoveInfo.moveCord;
563
+ }
564
+ } else {
565
+ [selectedPos, newPos] = moveStringToPos(moveOperation);
566
+ }
567
+ const [newCol, newRow] = newPos;
568
+ const piece = getPiece(board, selectedPos);
569
+ const side = getSide(piece);
570
+ const type = getType(piece);
571
+ if (side !== gameRecord.turn) {
572
+ return await sendMessage(session, `【@${username}】
573
+ 还没轮到${convertTurnToString(side)}走棋哦!
574
+ 当前走棋方为:【${convertTurnToString(gameRecord.turn)}】`);
575
+ }
576
+ const moveMap = getValidMoveMap(board, type, side, selectedPos);
577
+ if (moveMap[newRow][newCol] !== "go" && moveMap[newRow][newCol] !== "eat") {
578
+ return await sendMessage(session, `【@${username}】
579
+ 无效的移动!`);
580
+ }
581
+ await makeMove(channelId, selectedPos, newPos);
582
+ await ctx.database.set("cchess_game_records", { channelId }, {
583
+ isAnalyzing: true
584
+ });
585
+ await engineAction(channelId);
586
+ while (true) {
587
+ const gameRecord2 = await getGameRecord(channelId);
588
+ if (!gameRecord2.isAnalyzing) {
589
+ break;
590
+ }
591
+ await (0, import_koishi.sleep)(500);
592
+ }
593
+ const newGameRecord = await getGameRecord(channelId);
594
+ if (newGameRecord.winSide !== "") {
595
+ const buffer2 = await drawChessBoard(channelId);
596
+ const hImg2 = import_koishi.h.image(buffer2, `image/${config.imageType}`);
597
+ await updatePlayerRecords(channelId, newGameRecord.winSide, newGameRecord.loseSide);
773
598
  await endGame(channelId);
774
- return await sendMessage(session, `【@${username}】\n认输成功!\n游戏结束!\n获胜方为:【${anotherSideString}】`);
775
- });
776
- // ykcj*
777
- ctx.command('cchess.查看云库残局', '云库残局指令帮助')
778
- .action(async ({ session }) => {
779
- await session.execute(`cchess.查看云库残局 -h`);
599
+ return await sendMessage(session, `【@${username}
600
+ 绝杀!
601
+ 游戏结束!
602
+ 获胜方为:【${convertTurnToString(newGameRecord.winSide)}】
603
+ ${hImg2}`);
604
+ }
605
+ if (gameRecord.isEnginePlayRed || gameRecord.isEnginePlayBlack) {
606
+ const gameRecord2 = await getGameRecord(channelId);
607
+ let {
608
+ movesAfterLastEat,
609
+ boardAfterLastEat,
610
+ turnAfterLastEat
611
+ // multiPvInfoBuffer
612
+ } = gameRecord2;
613
+ await ctx.database.set("cchess_game_records", { channelId }, {
614
+ isAnalyzing: true
615
+ });
616
+ await sendCommand(channelId, "fen " + getFenWithMove(movesAfterLastEat, boardAfterLastEat, turnAfterLastEat)), await go(channelId, 1e3 * thinkingSettings["movetime"], thinkingSettings["depth"], -1);
617
+ while (true) {
618
+ const gameRecord3 = await getGameRecord(channelId);
619
+ if (!gameRecord3.isAnalyzing) {
620
+ break;
621
+ }
622
+ await (0, import_koishi.sleep)(500);
623
+ }
624
+ const newGameRecord2 = await getGameRecord(channelId);
625
+ if (newGameRecord2.winSide !== "") {
626
+ const buffer2 = await drawChessBoard(channelId);
627
+ const hImg2 = import_koishi.h.image(buffer2, `image/${config.imageType}`);
628
+ await updatePlayerRecords(channelId, newGameRecord2.winSide, newGameRecord2.loseSide);
629
+ await endGame(channelId);
630
+ return await sendMessage(session, `【@${username}】
631
+ 绝杀!
632
+ 游戏结束!
633
+ 获胜方为:【${convertTurnToString(newGameRecord2.winSide)}】
634
+ ${hImg2}`);
635
+ }
636
+ }
637
+ const buffer = await drawChessBoard(channelId);
638
+ const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
639
+ return await sendMessage(session, `${hImg}`);
640
+ }
641
+ );
642
+ ctx.command("cchess.悔棋", "悔棋指令帮助").action(async ({ session }) => {
643
+ await session.execute(`cchess.悔棋 -h`);
644
+ });
645
+ ctx.command("cchess.悔棋.请求", "请求悔棋").action(async ({ session }) => {
646
+ const { username, userId, channelId } = session;
647
+ await updateNameInPlayerRecord(userId, username);
648
+ const gameRecord = await getGameRecord(channelId);
649
+ if (!gameRecord.isStarted) {
650
+ return await sendMessage(session, `【@${username}】
651
+ 游戏还未开始哦!`);
652
+ }
653
+ await checkEngine(channelId);
654
+ if (engines[channelId] && !gameRecord.isEngineReady) {
655
+ await ctx.database.set("cchess_game_records", { channelId }, {
656
+ isEngineReady: true
657
+ });
658
+ }
659
+ if (gameRecord.isRegretRequest) {
660
+ return await sendMessage(session, `【@${username}】
661
+ 已经有悔棋请求了!`);
662
+ }
663
+ const playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
664
+ if (playerRecord.length === 0) {
665
+ return await sendMessage(session, `【@${username}】
666
+ 您还未加入游戏呢!`);
667
+ }
668
+ const turn = gameRecord.turn;
669
+ const sideString = convertTurnToString(turn);
670
+ if (gameRecord.isAnalyzing) {
671
+ return await sendMessage(session, `【@${username}】
672
+ 对局分析中,请稍后再试!`);
673
+ }
674
+ if (gameRecord.moveList.length < 1) {
675
+ return await sendMessage(session, `【@${username}】
676
+ 当前无法悔棋!`);
677
+ }
678
+ if (gameRecord.isEnginePlayBlack || gameRecord.isEnginePlayRed) {
679
+ await undoMove(channelId);
680
+ await undoMove(channelId);
681
+ const buffer = await drawChessBoard(channelId);
682
+ const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
683
+ return await sendMessage(session, `【@${username}】
684
+ 悔棋成功!
685
+ ${hImg}`);
686
+ } else {
687
+ if (playerRecord[0].side === sideString) {
688
+ return await sendMessage(session, `【@${username}】
689
+ 现在轮到你下棋,不可悔棋!`);
690
+ } else {
691
+ await ctx.database.set("cchess_game_records", { channelId }, {
692
+ isRegretRequest: true
693
+ });
694
+ return await sendMessage(session, `【@${username}】
695
+ 请求悔棋中...
696
+ 清对方输入相关指令选择同意或拒绝!`);
697
+ }
698
+ }
699
+ });
700
+ ctx.command("cchess.悔棋.同意", "同意悔棋").action(async ({ session }) => {
701
+ const { username, userId, channelId } = session;
702
+ await updateNameInPlayerRecord(userId, username);
703
+ const gameRecord = await getGameRecord(channelId);
704
+ if (!gameRecord.isStarted) {
705
+ return await sendMessage(session, `【@${username}】
706
+ 游戏还未开始哦!`);
707
+ }
708
+ await checkEngine(channelId);
709
+ if (engines[channelId] && !gameRecord.isEngineReady) {
710
+ await ctx.database.set("cchess_game_records", { channelId }, {
711
+ isEngineReady: true
712
+ });
713
+ }
714
+ if (gameRecord.isAnalyzing) {
715
+ return await sendMessage(session, `【@${username}】
716
+ 对局分析中,请稍后再试!`);
717
+ }
718
+ if (!gameRecord.isRegretRequest) {
719
+ return await sendMessage(session, `【@${username}】
720
+ 当前无悔棋请求!`);
721
+ }
722
+ const playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
723
+ if (playerRecord.length === 0) {
724
+ return await sendMessage(session, `【@${username}】
725
+ 您还未加入游戏呢!`);
726
+ }
727
+ const turn = gameRecord.turn;
728
+ const sideString = convertTurnToString(turn);
729
+ if (playerRecord[0].side !== sideString) {
730
+ return await sendMessage(session, `【@${username}】
731
+ 您所在的队伍不能做出选择!`);
732
+ } else {
733
+ await undoMove(channelId);
734
+ await ctx.database.set("cchess_game_records", { channelId }, {
735
+ isRegretRequest: false
736
+ });
737
+ const buffer = await drawChessBoard(channelId);
738
+ const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
739
+ return await sendMessage(session, `【@${username}】
740
+ 由于您同意了对方的悔棋请求!
741
+ 悔棋成功!
742
+ ${hImg}`);
743
+ }
744
+ });
745
+ ctx.command("cchess.悔棋.拒绝", "拒绝悔棋").action(async ({ session }) => {
746
+ const { username, userId, channelId } = session;
747
+ await updateNameInPlayerRecord(userId, username);
748
+ const gameRecord = await getGameRecord(channelId);
749
+ if (!gameRecord.isStarted) {
750
+ return await sendMessage(session, `【@${username}】
751
+ 游戏还未开始哦!`);
752
+ }
753
+ await checkEngine(channelId);
754
+ if (engines[channelId] && !gameRecord.isEngineReady) {
755
+ await ctx.database.set("cchess_game_records", { channelId }, {
756
+ isEngineReady: true
757
+ });
758
+ }
759
+ if (gameRecord.isAnalyzing) {
760
+ return await sendMessage(session, `【@${username}】
761
+ 对局分析中,请稍后再试!`);
762
+ }
763
+ if (!gameRecord.isRegretRequest) {
764
+ return await sendMessage(session, `【@${username}】
765
+ 当前无悔棋请求!`);
766
+ }
767
+ const playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
768
+ if (playerRecord.length === 0) {
769
+ return await sendMessage(session, `【@${username}】
770
+ 您还未加入游戏呢!`);
771
+ }
772
+ const turn = gameRecord.turn;
773
+ const sideString = convertTurnToString(turn);
774
+ if (playerRecord[0].side !== sideString) {
775
+ return await sendMessage(session, `【@${username}】
776
+ 您所在的队伍不能做出选择!`);
777
+ } else {
778
+ await ctx.database.set("cchess_game_records", { channelId }, {
779
+ isRegretRequest: false
780
+ });
781
+ const buffer = await drawChessBoard(channelId);
782
+ const hImg = import_koishi.h.image(buffer, `image/${config.imageType}`);
783
+ return await sendMessage(session, `【@${username}】
784
+ 由于您拒绝了对方的悔棋请求!
785
+ 悔棋失败,游戏继续进行!
786
+ ${hImg}`);
787
+ }
788
+ });
789
+ ctx.command("cchess.认输", "认输").action(async ({ session }) => {
790
+ const { username, userId, channelId } = session;
791
+ await updateNameInPlayerRecord(userId, username);
792
+ const gameRecord = await getGameRecord(channelId);
793
+ if (!gameRecord.isStarted) {
794
+ return await sendMessage(session, `【@${username}】
795
+ 游戏还未开始哦!`);
796
+ }
797
+ await checkEngine(channelId);
798
+ if (engines[channelId] && !gameRecord.isEngineReady) {
799
+ await ctx.database.set("cchess_game_records", { channelId }, {
800
+ isEngineReady: true
801
+ });
802
+ }
803
+ if (gameRecord.isAnalyzing) {
804
+ return await sendMessage(session, `【@${username}】
805
+ 对局分析中,请稍后再试!`);
806
+ }
807
+ const playerRecord = await ctx.database.get("cchess_gaming_player_records", { channelId, userId });
808
+ if (playerRecord.length === 0) {
809
+ return await sendMessage(session, `【@${username}】
810
+ 您还未加入游戏呢!`);
811
+ }
812
+ const turn = gameRecord.turn;
813
+ const sideString = convertTurnToString(turn);
814
+ if (playerRecord[0].side !== sideString) {
815
+ return await sendMessage(session, `【@${username}】
816
+ 还没轮到${sideString}走棋哦!
817
+ 当前走棋方为:【${convertTurnToString(gameRecord.turn)}】`);
818
+ }
819
+ const anotherSideString = convertTurnToString(turn === "w" ? "b" : "w");
820
+ await updatePlayerRecords(channelId, turn === "w" ? "b" : "w", turn);
821
+ await endGame(channelId);
822
+ return await sendMessage(session, `【@${username}】
823
+ 认输成功!
824
+ 游戏结束!
825
+ 获胜方为:【${anotherSideString}】`);
826
+ });
827
+ ctx.command("cchess.查看云库残局", "云库残局指令帮助").action(async ({ session }) => {
828
+ await session.execute(`cchess.查看云库残局 -h`);
829
+ });
830
+ ctx.command("cchess.查看云库残局.DTM统计", "云库残局DTM统计").action(async ({ session }) => {
831
+ const { username, userId, channelId } = session;
832
+ await updateNameInPlayerRecord(userId, username);
833
+ await checkEngine(channelId);
834
+ return await sendMessage(session, `【@${username}】
835
+ https://www.chessdb.cn/egtb_info_dtm.html`);
836
+ });
837
+ ctx.command("cchess.查看云库残局.DTC统计", "云库残局DTM统计").action(async ({ session }) => {
838
+ const { username, userId, channelId } = session;
839
+ await updateNameInPlayerRecord(userId, username);
840
+ await checkEngine(channelId);
841
+ return await sendMessage(session, `【@${username}】
842
+ https://www.chessdb.cn/egtb_info.html`);
843
+ });
844
+ ctx.command("cchess.编辑棋盘", "编辑棋盘指令帮助").action(async ({ session }) => {
845
+ await session.execute(`cchess.编辑棋盘 -h`);
846
+ });
847
+ ctx.command("cchess.编辑棋盘.导入 <fen:text>", "导入FEN串").action(async ({ session }, fen) => {
848
+ const { username, userId, channelId } = session;
849
+ await updateNameInPlayerRecord(userId, username);
850
+ const gameRecord = await getGameRecord(channelId);
851
+ if (gameRecord.isStarted) {
852
+ return await sendMessage(session, `【@${username}】
853
+ 游戏已经开始啦~
854
+ 不可编辑棋盘!`);
855
+ }
856
+ await checkEngine(channelId);
857
+ if (engines[channelId] && !gameRecord.isEngineReady) {
858
+ await ctx.database.set("cchess_game_records", { channelId }, {
859
+ isEngineReady: true
860
+ });
861
+ }
862
+ if (!fen) {
863
+ return await sendMessage(session, `【@${username}】
864
+ 无效的FEN串!`);
865
+ }
866
+ if (!isValidateFen(fen)) {
867
+ return await sendMessage(session, `【@${username}】
868
+ 无效的FEN串!`);
869
+ }
870
+ let {
871
+ turn,
872
+ board,
873
+ moveList,
874
+ movesAfterLastEat,
875
+ boardAfterLastEat,
876
+ turnAfterLastEat,
877
+ lastMove,
878
+ isHistoryMode,
879
+ originalState,
880
+ startFen
881
+ } = gameRecord;
882
+ const t = fen;
883
+ board = fenToBoard(t);
884
+ turn = "w";
885
+ moveList = [];
886
+ movesAfterLastEat = [];
887
+ boardAfterLastEat = fenToBoard(t);
888
+ turnAfterLastEat = fenToTurn(t);
889
+ t.includes("moves") ? startFen = t.split("moves")[0] : startFen = t;
890
+ isHistoryMode = false;
891
+ originalState = {};
892
+ lastMove = null;
893
+ await ctx.database.set("cchess_game_records", { channelId }, {
894
+ turn,
895
+ board,
896
+ moveList,
897
+ movesAfterLastEat,
898
+ boardAfterLastEat,
899
+ turnAfterLastEat,
900
+ lastMove,
901
+ isHistoryMode,
902
+ originalState,
903
+ startFen
780
904
  });
781
- // DTM*
782
- ctx.command('cchess.查看云库残局.DTM统计', '云库残局DTM统计')
783
- .action(async ({ session }) => {
784
- const { username, userId, channelId } = session;
785
- await updateNameInPlayerRecord(userId, username);
786
- await checkEngine(channelId);
787
- return await sendMessage(session, `【@${username}】\nhttps://www.chessdb.cn/egtb_info_dtm.html`);
905
+ await parseFen(channelId, t);
906
+ return await sendMessage(session, `【@${username}】
907
+ 棋盘编辑成功!`);
908
+ });
909
+ ctx.command("cchess.编辑棋盘.导出", "导出FEN串").action(async ({ session }) => {
910
+ const { username, userId, channelId } = session;
911
+ await updateNameInPlayerRecord(userId, username);
912
+ const gameRecord = await getGameRecord(channelId);
913
+ if (!gameRecord.isStarted) {
914
+ return await sendMessage(session, `【@${username}】
915
+ 游戏还未开始哦!`);
916
+ }
917
+ if (gameRecord.isAnalyzing) {
918
+ return await sendMessage(session, `【@${username}】
919
+ 对局分析中,请稍后再试!`);
920
+ }
921
+ await checkEngine(channelId);
922
+ if (engines[channelId] && !gameRecord.isEngineReady) {
923
+ await ctx.database.set("cchess_game_records", { channelId }, {
924
+ isEngineReady: true
925
+ });
926
+ }
927
+ const fenWithFullMove = await getFenWithFullMove(channelId);
928
+ return await sendMessage(session, `【@${username}】
929
+ ${fenWithFullMove}`);
930
+ });
931
+ ctx.command("cchess.编辑棋盘.使用方法", "查看编辑棋盘的fen使用方法").action(async ({ session }) => {
932
+ const { username, userId, channelId } = session;
933
+ await updateNameInPlayerRecord(userId, username);
934
+ await checkEngine(channelId);
935
+ return await sendMessage(session, `【@${username}】
936
+ https://www.xqbase.com/protocol/cchess_fen.htm`);
937
+ });
938
+ ctx.command("cchess.排行榜.总胜场 [number:number]", "查看玩家总胜场排行榜").action(async ({ session }, number = config.defaultMaxLeaderboardEntries) => {
939
+ const { channelId, username, userId } = session;
940
+ await updateNameInPlayerRecord(userId, username);
941
+ if (typeof number !== "number" || isNaN(number) || number < 0) {
942
+ return "请输入大于等于 0 的数字作为排行榜的参数。";
943
+ }
944
+ return await getLeaderboard(session, "win", "win", "玩家总胜场排行榜", number);
945
+ });
946
+ ctx.command("cchess.排行榜.总输场 [number:number]", "查看玩家总输场排行榜").action(async ({ session }, number = config.defaultMaxLeaderboardEntries) => {
947
+ const { channelId, username, userId } = session;
948
+ await updateNameInPlayerRecord(userId, username);
949
+ if (typeof number !== "number" || isNaN(number) || number < 0) {
950
+ return "请输入大于等于 0 的数字作为排行榜的参数。";
951
+ }
952
+ return await getLeaderboard(session, "lose", "lose", "查看玩家总输场排行榜", number);
953
+ });
954
+ ctx.command("cchess.查询玩家记录 [targetUser:text]", "查询玩家记录").action(async ({ session }, targetUser) => {
955
+ let { channelId, userId, username } = session;
956
+ await updateNameInPlayerRecord(userId, username);
957
+ if (targetUser) {
958
+ targetUser = await replaceAtTags(session, targetUser);
959
+ const userIdRegex = /<at id="([^"]+)"(?: name="([^"]+)")?\/>/;
960
+ const match = targetUser.match(userIdRegex);
961
+ userId = match?.[1] ?? userId;
962
+ username = match?.[2] ?? username;
963
+ }
964
+ const targetUserRecord = await ctx.database.get("cchess_player_records", { userId });
965
+ if (targetUserRecord.length === 0) {
966
+ await ctx.database.create("cchess_player_records", {
967
+ userId,
968
+ username,
969
+ lose: 0,
970
+ win: 0
971
+ });
972
+ return sendMessage(session, `【@${session.username}】
973
+ 查询对象:${username}
974
+ 无任何游戏记录。`);
975
+ }
976
+ const { win, lose } = targetUserRecord[0];
977
+ return sendMessage(session, `【@${session.username}】
978
+ 查询对象:${username}
979
+ 总胜场次数为:${win} 次
980
+ 总输场次数为:${lose} 次
981
+ `);
982
+ });
983
+ async function replaceAtTags(session, content) {
984
+ const atRegex = /<at id="(\d+)"(?: name="([^"]*)")?\/>/g;
985
+ let match;
986
+ while ((match = atRegex.exec(content)) !== null) {
987
+ const userId = match[1];
988
+ const name2 = match[2];
989
+ if (!name2) {
990
+ let guildMember;
991
+ try {
992
+ guildMember = await session.bot.getGuildMember(session.guildId, userId);
993
+ } catch (error) {
994
+ guildMember = {
995
+ user: {
996
+ name: "未知用户"
997
+ }
998
+ };
999
+ }
1000
+ const newAtTag = `<at id="${userId}" name="${guildMember.user.name}"/>`;
1001
+ content = content.replace(match[0], newAtTag);
1002
+ }
1003
+ }
1004
+ return content;
1005
+ }
1006
+ __name(replaceAtTags, "replaceAtTags");
1007
+ async function updatePlayerRecords(channelId, winSide, loseSide) {
1008
+ const winnerPlayerRecords = await ctx.database.get("cchess_gaming_player_records", {
1009
+ channelId,
1010
+ side: convertTurnToString(winSide)
788
1011
  });
789
- // DTC*
790
- ctx.command('cchess.查看云库残局.DTC统计', '云库残局DTM统计')
791
- .action(async ({ session }) => {
792
- const { username, userId, channelId } = session;
793
- await updateNameInPlayerRecord(userId, username);
794
- await checkEngine(channelId);
795
- return await sendMessage(session, `【@${username}】\nhttps://www.chessdb.cn/egtb_info.html`);
1012
+ const loserPlayerRecords = await ctx.database.get("cchess_gaming_player_records", {
1013
+ channelId,
1014
+ side: convertTurnToString(loseSide)
796
1015
  });
797
- // bjqp*
798
- ctx.command('cchess.编辑棋盘', '编辑棋盘指令帮助')
799
- .action(async ({ session }) => {
800
- await session.execute(`cchess.编辑棋盘 -h`);
1016
+ for (const winnerPlayerRecord of winnerPlayerRecords) {
1017
+ const playerRecord = await ctx.database.get("cchess_player_records", { userId: winnerPlayerRecord.userId });
1018
+ await ctx.database.set("cchess_player_records", { userId: winnerPlayerRecord.userId }, { win: playerRecord[0].win + 1 });
1019
+ }
1020
+ for (const loserPlayerRecord of loserPlayerRecords) {
1021
+ const playerRecord = await ctx.database.get("cchess_player_records", { userId: loserPlayerRecord.userId });
1022
+ await ctx.database.set("cchess_player_records", { userId: loserPlayerRecord.userId }, { lose: playerRecord[0].lose + 1 });
1023
+ }
1024
+ }
1025
+ __name(updatePlayerRecords, "updatePlayerRecords");
1026
+ async function getLeaderboard(session, type, sortField, title, number) {
1027
+ const getPlayers = await ctx.database.get("cchess_player_records", {});
1028
+ const sortedPlayers = getPlayers.sort((a, b) => b[sortField] - a[sortField]);
1029
+ const topPlayers = sortedPlayers.slice(0, number);
1030
+ let result = `${title}:
1031
+ `;
1032
+ topPlayers.forEach((player, index) => {
1033
+ result += `${index + 1}. ${player.username}:${player[sortField]} 次
1034
+ `;
801
1035
  });
802
- // dr*
803
- ctx.command('cchess.编辑棋盘.导入 <fen:text>', '导入FEN串')
804
- .action(async ({ session }, fen) => {
805
- const { username, userId, channelId } = session;
806
- await updateNameInPlayerRecord(userId, username);
1036
+ return await sendMessage(session, result);
1037
+ }
1038
+ __name(getLeaderboard, "getLeaderboard");
1039
+ async function updateNameInPlayerRecord(userId, username) {
1040
+ const userRecord = await ctx.database.get("cchess_player_records", { userId });
1041
+ if (userRecord.length === 0) {
1042
+ await ctx.database.create("cchess_player_records", {
1043
+ userId,
1044
+ username
1045
+ });
1046
+ return;
1047
+ }
1048
+ const existingRecord = userRecord[0];
1049
+ let isChange = false;
1050
+ if (username !== existingRecord.username) {
1051
+ existingRecord.username = username;
1052
+ isChange = true;
1053
+ }
1054
+ if (isChange) {
1055
+ await ctx.database.set("cchess_player_records", { userId }, {
1056
+ username: existingRecord.username
1057
+ });
1058
+ }
1059
+ }
1060
+ __name(updateNameInPlayerRecord, "updateNameInPlayerRecord");
1061
+ async function checkEngine(channelId) {
1062
+ if (!engines[channelId]) {
1063
+ await ctx.database.set("cchess_game_records", { channelId }, {
1064
+ isEngineReady: false
1065
+ });
1066
+ await initEngine(channelId);
1067
+ while (true) {
807
1068
  const gameRecord = await getGameRecord(channelId);
808
- if (gameRecord.isStarted) {
809
- return await sendMessage(session, `【@${username}】\n游戏已经开始啦~\n不可编辑棋盘!`);
810
- }
811
- await checkEngine(channelId);
812
- if (engines[channelId] && !gameRecord.isEngineReady) {
813
- await ctx.database.set('cchess_game_records', { channelId }, {
814
- isEngineReady: true
815
- });
816
- }
817
- if (!fen) {
818
- return await sendMessage(session, `【@${username}】\n无效的FEN串!`);
819
- }
820
- if (!isValidateFen(fen)) {
821
- return await sendMessage(session, `【@${username}】\n无效的FEN串!`);
822
- }
823
- let { turn, board, moveList, movesAfterLastEat, boardAfterLastEat, turnAfterLastEat, lastMove, isHistoryMode, originalState, startFen } = gameRecord;
824
- const t = fen;
825
- board = fenToBoard(t);
826
- turn = "w";
827
- moveList = [];
828
- movesAfterLastEat = [];
829
- boardAfterLastEat = fenToBoard(t);
830
- turnAfterLastEat = fenToTurn(t);
831
- t.includes("moves") ? startFen = t.split("moves")[0] : startFen = t;
832
- isHistoryMode = !1;
833
- originalState = {};
834
- lastMove = null;
835
- await ctx.database.set('cchess_game_records', { channelId }, {
836
- turn,
837
- board,
838
- moveList,
839
- movesAfterLastEat,
840
- boardAfterLastEat,
841
- turnAfterLastEat,
842
- lastMove,
843
- isHistoryMode,
844
- originalState,
845
- startFen
846
- });
847
- await parseFen(channelId, t);
848
- return await sendMessage(session, `【@${username}】\n棋盘编辑成功!`);
1069
+ if (gameRecord.isEngineReady) {
1070
+ break;
1071
+ }
1072
+ await (0, import_koishi.sleep)(500);
1073
+ }
1074
+ }
1075
+ }
1076
+ __name(checkEngine, "checkEngine");
1077
+ async function getFenWithFullMove(channelId, t = " ") {
1078
+ const gameRecord = await getGameRecord(channelId);
1079
+ let {
1080
+ // originalState,
1081
+ // isHistoryMode,
1082
+ startFen
1083
+ } = gameRecord;
1084
+ let e = [];
1085
+ for (let A of gameRecord.moveList)
1086
+ e.push(A.move);
1087
+ let n = startFen;
1088
+ return e.length > 0 && (n += " moves " + e.join(t)), n;
1089
+ }
1090
+ __name(getFenWithFullMove, "getFenWithFullMove");
1091
+ function fenToTurn(t) {
1092
+ let e = t.split(" ");
1093
+ return "b" == e[1] ? "b" : "w";
1094
+ }
1095
+ __name(fenToTurn, "fenToTurn");
1096
+ function isValidateFen(t) {
1097
+ let e = t.split(" "), i = e[0], n = e[1];
1098
+ if (!"rwb".includes(n.toLowerCase()))
1099
+ return false;
1100
+ let A = i.split("/");
1101
+ if (10 != A.length)
1102
+ return false;
1103
+ for (let s = 0; s < A.length; s++) {
1104
+ let t2 = A[s], e2 = t2.length, i2 = 0;
1105
+ for (let n2 = 0; n2 < e2; n2++) {
1106
+ let e3 = t2.charAt(n2);
1107
+ e3 >= "0" && e3 <= "9" ? i2 += parseInt(e3) : i2++;
1108
+ }
1109
+ if (9 != i2)
1110
+ return false;
1111
+ }
1112
+ return true;
1113
+ }
1114
+ __name(isValidateFen, "isValidateFen");
1115
+ async function parseFen(channelId, t) {
1116
+ const gameRecord = await getGameRecord(channelId);
1117
+ let {
1118
+ turn,
1119
+ board
1120
+ } = gameRecord;
1121
+ let e = t.split(" ");
1122
+ board = fenToBoard(e[0]);
1123
+ turn = "b" == e[1] ? "b" : "w";
1124
+ await ctx.database.set("cchess_game_records", { channelId }, {
1125
+ turn,
1126
+ board
849
1127
  });
850
- // dc*
851
- ctx.command('cchess.编辑棋盘.导出', '导出FEN串')
852
- .action(async ({ session }) => {
853
- const { username, userId, channelId } = session;
854
- await updateNameInPlayerRecord(userId, username);
855
- const gameRecord = await getGameRecord(channelId);
856
- if (!gameRecord.isStarted) {
857
- return await sendMessage(session, `【@${username}】\n游戏还未开始哦!`);
858
- }
859
- if (gameRecord.isAnalyzing) {
860
- return await sendMessage(session, `【@${username}】\n对局分析中,请稍后再试!`);
861
- }
862
- await checkEngine(channelId);
863
- if (engines[channelId] && !gameRecord.isEngineReady) {
864
- await ctx.database.set('cchess_game_records', { channelId }, {
865
- isEngineReady: true
866
- });
867
- }
868
- const fenWithFullMove = await getFenWithFullMove(channelId);
869
- return await sendMessage(session, `【@${username}】\n${fenWithFullMove}`);
1128
+ if (e.length > 3 && "moves" == e[2])
1129
+ if (4 == e[3].length)
1130
+ for (let i = 3; i < e.length; i++)
1131
+ await makeMoveByString(channelId, e[i]);
1132
+ else {
1133
+ let t2 = e[3];
1134
+ for (let e2 = 0; e2 < t2.length; e2 += 4)
1135
+ await makeMoveByString(channelId, t2.substring(e2, e2 + 4));
1136
+ }
1137
+ }
1138
+ __name(parseFen, "parseFen");
1139
+ function deepCopy(t) {
1140
+ return JSON.parse(JSON.stringify(t));
1141
+ }
1142
+ __name(deepCopy, "deepCopy");
1143
+ async function gotoHistory(channelId, t) {
1144
+ const gameRecord = await getGameRecord(channelId);
1145
+ let {
1146
+ fen,
1147
+ turn,
1148
+ board,
1149
+ moveList,
1150
+ movesAfterLastEat,
1151
+ boardAfterLastEat,
1152
+ turnAfterLastEat,
1153
+ lastMove,
1154
+ isHistoryMode,
1155
+ originalState
1156
+ } = gameRecord;
1157
+ isHistoryMode || (originalState = {
1158
+ fen: getFen(board, turn),
1159
+ turn,
1160
+ board: deepCopy(board),
1161
+ moveList: deepCopy(moveList),
1162
+ movesAfterLastEat: deepCopy(movesAfterLastEat),
1163
+ boardAfterLastEat: deepCopy(boardAfterLastEat),
1164
+ turnAfterLastEat,
1165
+ lastMove
1166
+ }, isHistoryMode = true);
1167
+ let e = t.moveId, i = originalState.moveList.findIndex((t2) => t2.moveId == e);
1168
+ moveList = originalState.moveList.slice(0, i + 1), i = originalState.movesAfterLastEat.findIndex((t2) => t2.moveId == e), -1 != i ? movesAfterLastEat = originalState.movesAfterLastEat.slice(0, i + 1) : (boardAfterLastEat = fenToBoard(t.fen), turnAfterLastEat = "w" == t.side ? "b" : "w", movesAfterLastEat = []), lastMove = t.moveCord, turn = "w" == t.side ? "b" : "w", board = fenToBoard(t.fen), await ctx.database.set("cchess_game_records", { channelId }, {
1169
+ fen: t.fen,
1170
+ turn,
1171
+ board,
1172
+ moveList,
1173
+ movesAfterLastEat,
1174
+ boardAfterLastEat,
1175
+ turnAfterLastEat,
1176
+ lastMove,
1177
+ originalState,
1178
+ isHistoryMode
870
1179
  });
871
- // syff*
872
- ctx.command('cchess.编辑棋盘.使用方法', '查看编辑棋盘的fen使用方法')
873
- .action(async ({ session }) => {
874
- const { username, userId, channelId } = session;
875
- await updateNameInPlayerRecord(userId, username);
876
- await checkEngine(channelId);
877
- return await sendMessage(session, `【@${username}】\nhttps://www.xqbase.com/protocol/cchess_fen.htm`);
1180
+ }
1181
+ __name(gotoHistory, "gotoHistory");
1182
+ async function gotoStart(channelId) {
1183
+ const gameRecord = await getGameRecord(channelId);
1184
+ let {
1185
+ fen,
1186
+ turn,
1187
+ board,
1188
+ moveList,
1189
+ movesAfterLastEat,
1190
+ boardAfterLastEat,
1191
+ turnAfterLastEat,
1192
+ lastMove,
1193
+ isHistoryMode,
1194
+ originalState,
1195
+ startFen
1196
+ } = gameRecord;
1197
+ isHistoryMode || (originalState = {
1198
+ fen: getFen(board, turn),
1199
+ turn,
1200
+ board: deepCopy(board),
1201
+ moveList: deepCopy(moveList),
1202
+ movesAfterLastEat: deepCopy(movesAfterLastEat),
1203
+ boardAfterLastEat: deepCopy(boardAfterLastEat),
1204
+ turnAfterLastEat,
1205
+ lastMove
1206
+ }, isHistoryMode = true), await parseFen(channelId, startFen), moveList = [], movesAfterLastEat = [], boardAfterLastEat = deepCopy(fenToBoard(fen)), turnAfterLastEat = turn, lastMove = null, await ctx.database.set("cchess_game_records", { channelId }, {
1207
+ moveList,
1208
+ movesAfterLastEat,
1209
+ boardAfterLastEat,
1210
+ turnAfterLastEat,
1211
+ lastMove,
1212
+ originalState,
1213
+ isHistoryMode
878
1214
  });
879
- // zsc*
880
- ctx.command('cchess.排行榜.总胜场 [number:number]', '查看玩家总胜场排行榜')
881
- .action(async ({ session }, number = config.defaultMaxLeaderboardEntries) => {
882
- const { channelId, username, userId } = session;
883
- // 更新玩家记录表中的用户名
884
- await updateNameInPlayerRecord(userId, username);
885
- if (typeof number !== 'number' || isNaN(number) || number < 0) {
886
- return '请输入大于等于 0 的数字作为排行榜的参数。';
887
- }
888
- return await getLeaderboard(session, 'win', 'win', '玩家总胜场排行榜', number);
889
- });
890
- // zsc*
891
- ctx.command('cchess.排行榜.总输场 [number:number]', '查看玩家总输场排行榜')
892
- .action(async ({ session }, number = config.defaultMaxLeaderboardEntries) => {
893
- const { channelId, username, userId } = session;
894
- // 更新玩家记录表中的用户名
895
- await updateNameInPlayerRecord(userId, username);
896
- if (typeof number !== 'number' || isNaN(number) || number < 0) {
897
- return '请输入大于等于 0 的数字作为排行榜的参数。';
898
- }
899
- return await getLeaderboard(session, 'lose', 'lose', '查看玩家总输场排行榜', number);
1215
+ }
1216
+ __name(gotoStart, "gotoStart");
1217
+ async function undoMove(channelId) {
1218
+ const gameRecord = await getGameRecord(channelId);
1219
+ let {
1220
+ fen,
1221
+ turn,
1222
+ board,
1223
+ moveList,
1224
+ movesAfterLastEat,
1225
+ boardAfterLastEat,
1226
+ turnAfterLastEat,
1227
+ lastMove,
1228
+ isHistoryMode,
1229
+ originalState
1230
+ } = gameRecord;
1231
+ if (isHistoryMode || (originalState = {
1232
+ fen: getFen(board, turn),
1233
+ turn,
1234
+ board: deepCopy(board),
1235
+ moveList: deepCopy(moveList),
1236
+ movesAfterLastEat: deepCopy(movesAfterLastEat),
1237
+ boardAfterLastEat: deepCopy(boardAfterLastEat),
1238
+ turnAfterLastEat,
1239
+ lastMove
1240
+ }, isHistoryMode = true), await ctx.database.set("cchess_game_records", { channelId }, {
1241
+ originalState,
1242
+ isHistoryMode
1243
+ }), moveList.length > 1) {
1244
+ let t = moveList[moveList.length - 2];
1245
+ await gotoHistory(channelId, t);
1246
+ } else
1247
+ await gotoStart(channelId);
1248
+ }
1249
+ __name(undoMove, "undoMove");
1250
+ async function endGame(channelId) {
1251
+ await ctx.database.remove("cchess_game_records", { channelId });
1252
+ await ctx.database.remove("cchess_gaming_player_records", { channelId });
1253
+ }
1254
+ __name(endGame, "endGame");
1255
+ async function onEngineBestMove(channelId, t, e) {
1256
+ const gameRecord = await getGameRecord(channelId);
1257
+ let {
1258
+ isEnginePlayRed,
1259
+ isEnginePlayBlack,
1260
+ // bestMoveHint,
1261
+ board,
1262
+ turn
1263
+ } = gameRecord;
1264
+ if (!t) {
1265
+ await ctx.database.set("cchess_game_records", { channelId }, {
1266
+ isAnalyzing: false
1267
+ });
1268
+ return;
1269
+ }
1270
+ if ("(none)" === t) {
1271
+ await ctx.database.set("cchess_game_records", { channelId }, {
1272
+ winSide: turn === "w" ? "b" : "w",
1273
+ loseSide: turn,
1274
+ isAnalyzing: false
1275
+ });
1276
+ return;
1277
+ }
1278
+ let i = getSideByMoveString(board, t);
1279
+ if (i !== turn && isEnginePlayRed || i !== turn && isEnginePlayBlack) {
1280
+ await ctx.database.set("cchess_game_records", { channelId }, {
1281
+ winSide: turn,
1282
+ loseSide: turn === "w" ? "b" : "w",
1283
+ isAnalyzing: false
1284
+ });
1285
+ return;
1286
+ }
1287
+ ("w" === i && isEnginePlayRed || "b" === i && isEnginePlayBlack) && await makeMoveByString(channelId, t);
1288
+ await ctx.database.set("cchess_game_records", { channelId }, {
1289
+ // bestMoveHint,
1290
+ isAnalyzing: false
900
1291
  });
901
- // cx*
902
- ctx.command('cchess.查询玩家记录 [targetUser:text]', '查询玩家记录')
903
- .action(async ({ session }, targetUser) => {
904
- let { channelId, userId, username } = session;
905
- await updateNameInPlayerRecord(userId, username);
906
- if (targetUser) {
907
- targetUser = await replaceAtTags(session, targetUser);
908
- const userIdRegex = /<at id="([^"]+)"(?: name="([^"]+)")?\/>/;
909
- const match = targetUser.match(userIdRegex);
910
- userId = match?.[1] ?? userId;
911
- username = match?.[2] ?? username;
912
- }
913
- const targetUserRecord = await ctx.database.get('cchess_player_records', { userId });
914
- if (targetUserRecord.length === 0) {
915
- await ctx.database.create('cchess_player_records', {
916
- userId,
917
- username,
918
- lose: 0,
919
- win: 0,
920
- });
921
- return sendMessage(session, `【@${session.username}】\n查询对象:${username}
922
- 无任何游戏记录。`);
923
- }
924
- const { win, lose } = targetUserRecord[0];
925
- return sendMessage(session, `【@${session.username}】\n查询对象:${username}
926
- 总胜场次数为:${win} 次
927
- 总输场次数为:${lose} 次
928
- `);
929
- });
930
- // hs*
931
- async function replaceAtTags(session, content) {
932
- // 正则表达式用于匹配 at 标签
933
- const atRegex = /<at id="(\d+)"(?: name="([^"]*)")?\/>/g;
934
- // 匹配所有 at 标签
935
- let match;
936
- while ((match = atRegex.exec(content)) !== null) {
937
- const userId = match[1];
938
- const name = match[2];
939
- // 如果 name 不存在,根据 userId 获取相应的 name
940
- if (!name) {
941
- const guildMember = await session.bot.getGuildMember(session.guildId, userId);
942
- // 替换原始的 at 标签
943
- const newAtTag = `<at id="${userId}" name="${guildMember.user.name}"/>`;
944
- content = content.replace(match[0], newAtTag);
945
- }
946
- }
947
- return content;
948
- }
949
- async function updatePlayerRecords(channelId, winSide, loseSide) {
950
- const winnerPlayerRecords = await ctx.database.get('cchess_gaming_player_records', {
951
- channelId,
952
- side: convertTurnToString(winSide)
953
- });
954
- const loserPlayerRecords = await ctx.database.get('cchess_gaming_player_records', {
955
- channelId,
956
- side: convertTurnToString(loseSide)
957
- });
958
- for (const winnerPlayerRecord of winnerPlayerRecords) {
959
- const playerRecord = await ctx.database.get('cchess_player_records', { userId: winnerPlayerRecord.userId });
960
- await ctx.database.set('cchess_player_records', { userId: winnerPlayerRecord.userId }, { win: playerRecord[0].win + 1 });
961
- }
962
- for (const loserPlayerRecord of loserPlayerRecords) {
963
- const playerRecord = await ctx.database.get('cchess_player_records', { userId: loserPlayerRecord.userId });
964
- await ctx.database.set('cchess_player_records', { userId: loserPlayerRecord.userId }, { lose: playerRecord[0].lose + 1 });
965
- }
966
- }
967
- async function getLeaderboard(session, type, sortField, title, number) {
968
- const getPlayers = await ctx.database.get('cchess_player_records', {});
969
- const sortedPlayers = getPlayers.sort((a, b) => b[sortField] - a[sortField]);
970
- const topPlayers = sortedPlayers.slice(0, number);
971
- let result = `${title}:\n`;
972
- topPlayers.forEach((player, index) => {
973
- result += `${index + 1}. ${player.username}:${player[sortField]} 次\n`;
974
- });
975
- return await sendMessage(session, result);
976
- }
977
- async function updateNameInPlayerRecord(userId, username) {
978
- const userRecord = await ctx.database.get('cchess_player_records', { userId });
979
- if (userRecord.length === 0) {
980
- await ctx.database.create('cchess_player_records', {
981
- userId,
982
- username,
983
- });
984
- return;
985
- }
986
- const existingRecord = userRecord[0];
987
- let isChange = false;
988
- if (username !== existingRecord.username) {
989
- existingRecord.username = username;
990
- isChange = true;
991
- }
992
- if (isChange) {
993
- await ctx.database.set('cchess_player_records', { userId }, {
994
- username: existingRecord.username,
995
- });
996
- }
997
- }
998
- async function checkEngine(channelId) {
999
- if (!engines[channelId]) {
1000
- await ctx.database.set('cchess_game_records', { channelId }, {
1001
- isEngineReady: false
1002
- });
1003
- await initEngine(channelId);
1004
- while (true) {
1005
- const gameRecord = await getGameRecord(channelId);
1006
- if (gameRecord.isEngineReady) {
1007
- break;
1008
- }
1009
- await (0, koishi_1.sleep)(500);
1010
- }
1011
- }
1012
- }
1013
- async function getFenWithFullMove(channelId, t = " ") {
1014
- const gameRecord = await getGameRecord(channelId);
1015
- let {
1016
- // originalState,
1017
- // isHistoryMode,
1018
- startFen } = gameRecord;
1019
- let e = [];
1020
- // , i = this;
1021
- // isHistoryMode && (i = originalState);
1022
- for (let A of gameRecord.moveList)
1023
- e.push(A.move);
1024
- let n = startFen;
1025
- return e.length > 0 && (n += " moves " + e.join(t)),
1026
- n;
1027
- }
1028
- function fenToTurn(t) {
1029
- let e = t.split(" ");
1030
- return "b" == e[1] ? "b" : "w";
1031
- }
1032
- function isValidateFen(t) {
1033
- let e = t.split(" "), i = e[0], n = e[1];
1034
- if (!"rwb".includes(n.toLowerCase()))
1035
- return !1;
1036
- let A = i.split("/");
1037
- if (10 != A.length)
1038
- return !1;
1039
- for (let s = 0; s < A.length; s++) {
1040
- let t = A[s], e = t.length, i = 0;
1041
- for (let n = 0; n < e; n++) {
1042
- let e = t.charAt(n);
1043
- e >= "0" && e <= "9" ? i += parseInt(e) : i++;
1044
- }
1045
- if (9 != i)
1046
- return !1;
1047
- }
1048
- return !0;
1049
- }
1050
- async function parseFen(channelId, t) {
1051
- const gameRecord = await getGameRecord(channelId);
1052
- let { turn, board, } = gameRecord;
1053
- let e = t.split(" ");
1054
- board = fenToBoard(e[0]);
1055
- turn = "b" == e[1] ? "b" : "w";
1056
- await ctx.database.set('cchess_game_records', { channelId }, {
1057
- turn,
1058
- board,
1059
- });
1060
- if (e.length > 3 && "moves" == e[2])
1061
- if (4 == e[3].length)
1062
- for (let i = 3; i < e.length; i++)
1063
- await makeMoveByString(channelId, e[i]);
1064
- else {
1065
- let t = e[3];
1066
- for (let e = 0; e < t.length; e += 4)
1067
- await makeMoveByString(channelId, t.substring(e, e + 4));
1068
- }
1069
- }
1070
- function deepCopy(t) {
1071
- return JSON.parse(JSON.stringify(t));
1072
- }
1073
- async function gotoHistory(channelId, t) {
1074
- const gameRecord = await getGameRecord(channelId);
1075
- let { fen, turn, board, moveList, movesAfterLastEat, boardAfterLastEat, turnAfterLastEat, lastMove, isHistoryMode, originalState } = gameRecord;
1076
- isHistoryMode || (originalState = {
1077
- fen: getFen(board, turn),
1078
- turn: turn,
1079
- board: deepCopy(board),
1080
- moveList: deepCopy(moveList),
1081
- movesAfterLastEat: deepCopy(movesAfterLastEat),
1082
- boardAfterLastEat: deepCopy(boardAfterLastEat),
1083
- turnAfterLastEat: turnAfterLastEat,
1084
- lastMove: lastMove
1085
- },
1086
- isHistoryMode = !0);
1087
- let e = t.moveId, i = originalState.moveList.findIndex((t => t.moveId == e));
1088
- moveList = originalState.moveList.slice(0, i + 1),
1089
- i = originalState.movesAfterLastEat.findIndex((t => t.moveId == e)),
1090
- -1 != i ? movesAfterLastEat = originalState.movesAfterLastEat.slice(0, i + 1) : (boardAfterLastEat = fenToBoard(t.fen),
1091
- turnAfterLastEat = "w" == t.side ? "b" : "w",
1092
- movesAfterLastEat = []),
1093
- lastMove = t.moveCord,
1094
- turn = "w" == t.side ? "b" : "w",
1095
- board = fenToBoard(t.fen),
1096
- await ctx.database.set('cchess_game_records', { channelId }, {
1097
- fen: t.fen,
1098
- turn,
1099
- board,
1100
- moveList,
1101
- movesAfterLastEat,
1102
- boardAfterLastEat,
1103
- turnAfterLastEat,
1104
- lastMove,
1105
- originalState,
1106
- isHistoryMode
1107
- });
1108
- }
1109
- async function gotoStart(channelId) {
1110
- const gameRecord = await getGameRecord(channelId);
1111
- let { fen, turn, board, moveList, movesAfterLastEat, boardAfterLastEat, turnAfterLastEat, lastMove, isHistoryMode, originalState, startFen } = gameRecord;
1112
- isHistoryMode || (originalState = {
1113
- fen: getFen(board, turn),
1114
- turn: turn,
1115
- board: deepCopy(board),
1116
- moveList: deepCopy(moveList),
1117
- movesAfterLastEat: deepCopy(movesAfterLastEat),
1118
- boardAfterLastEat: deepCopy(boardAfterLastEat),
1119
- turnAfterLastEat: turnAfterLastEat,
1120
- lastMove: lastMove
1121
- },
1122
- isHistoryMode = !0),
1123
- await parseFen(channelId, startFen),
1124
- moveList = [],
1125
- movesAfterLastEat = [],
1126
- boardAfterLastEat = deepCopy(fenToBoard(fen)),
1127
- turnAfterLastEat = turn,
1128
- lastMove = null,
1129
- await ctx.database.set('cchess_game_records', { channelId }, {
1130
- moveList,
1131
- movesAfterLastEat,
1132
- boardAfterLastEat,
1133
- turnAfterLastEat,
1134
- lastMove,
1135
- originalState,
1136
- isHistoryMode
1137
- });
1138
- }
1139
- async function undoMove(channelId) {
1140
- const gameRecord = await getGameRecord(channelId);
1141
- let { fen, turn, board, moveList, movesAfterLastEat, boardAfterLastEat, turnAfterLastEat, lastMove, isHistoryMode, originalState } = gameRecord;
1142
- if (isHistoryMode || (originalState = {
1143
- fen: getFen(board, turn),
1144
- turn: turn,
1145
- board: deepCopy(board),
1146
- moveList: deepCopy(moveList),
1147
- movesAfterLastEat: deepCopy(movesAfterLastEat),
1148
- boardAfterLastEat: deepCopy(boardAfterLastEat),
1149
- turnAfterLastEat: turnAfterLastEat,
1150
- lastMove: lastMove
1151
- },
1152
- isHistoryMode = !0),
1153
- await ctx.database.set('cchess_game_records', { channelId }, {
1154
- originalState,
1155
- isHistoryMode
1156
- }), moveList.length > 1) {
1157
- let t = moveList[moveList.length - 2];
1158
- await gotoHistory(channelId, t);
1159
- }
1160
- else
1161
- await gotoStart(channelId);
1162
- }
1163
- async function endGame(channelId) {
1164
- await ctx.database.remove('cchess_game_records', { channelId });
1165
- await ctx.database.remove('cchess_gaming_player_records', { channelId });
1166
- }
1167
- async function onEngineBestMove(channelId, t, e) {
1168
- const gameRecord = await getGameRecord(channelId);
1169
- let { isEnginePlayRed, isEnginePlayBlack,
1170
- // bestMoveHint,
1171
- board, turn } = gameRecord;
1172
- if (!t) {
1173
- await ctx.database.set('cchess_game_records', { channelId }, {
1174
- isAnalyzing: false
1175
- });
1176
- return;
1177
- }
1178
- if ("(none)" === t) {
1179
- await ctx.database.set('cchess_game_records', { channelId }, {
1180
- winSide: turn === 'w' ? 'b' : 'w',
1181
- loseSide: turn,
1182
- isAnalyzing: false
1183
- });
1184
- return;
1185
- }
1186
- let i = getSideByMoveString(board, t);
1187
- if (i !== turn && isEnginePlayRed || i !== turn && isEnginePlayBlack) {
1188
- await ctx.database.set('cchess_game_records', { channelId }, {
1189
- winSide: turn,
1190
- loseSide: turn === 'w' ? 'b' : 'w',
1191
- isAnalyzing: false
1192
- });
1193
- return;
1194
- }
1195
- ("w" === i && isEnginePlayRed || "b" === i && isEnginePlayBlack) && (await makeMoveByString(channelId, t));
1196
- await ctx.database.set('cchess_game_records', { channelId }, {
1197
- // bestMoveHint,
1198
- isAnalyzing: false
1199
- });
1200
- }
1201
- function getLocalMoveName(t, e) {
1202
- let i = {};
1203
- if ("zh-CN" === e)
1204
- return t;
1205
- if ("en-US" === e)
1206
- i = {
1207
- "进": "+",
1208
- "退": "-",
1209
- "平": "=",
1210
- "前": "+",
1211
- "后": "-",
1212
- "中": "=",
1213
- "将": "k",
1214
- "帅": "K",
1215
- "士": "a",
1216
- "仕": "A",
1217
- "象": "b",
1218
- "相": "B",
1219
- "车": "r",
1220
- "马": "n",
1221
- "炮": "c",
1222
- "卒": "p",
1223
- "兵": "P"
1224
- };
1225
- else {
1226
- if ("vi-VN" !== e)
1227
- return t;
1228
- i = {
1229
- "进": ".",
1230
- "退": "/",
1231
- "平": "-",
1232
- "前": ".",
1233
- "后": "/",
1234
- "中": "-",
1235
- "将": "Tg",
1236
- "帅": "Tg",
1237
- "士": "S",
1238
- "仕": "S",
1239
- "象": "T",
1240
- "相": "T",
1241
- "车": "X",
1242
- "马": "M",
1243
- "炮": "P",
1244
- "卒": "B",
1245
- "兵": "B"
1246
- };
1247
- }
1248
- let n = "一二三四五六七八九", A = "123456789", s = "123456789", a = "", o = -1 !== A.indexOf(t[3]) ? "b" : "w";
1249
- for (let r of t) {
1250
- let t = n.indexOf(r), e = A.indexOf(r);
1251
- a += r in i ? i[r] : -1 !== t ? s[t] : -1 !== e ? s[e] : r;
1252
- }
1253
- return a = "w" === o ? a.toUpperCase() : a.toLowerCase(),
1254
- a;
1255
- }
1256
- async function getSerialMoveName(channelId, t, e) {
1257
- const gameRecord = await getGameRecord(channelId);
1258
- let i = [];
1259
- for (let A = 0; A < e.length; A++) {
1260
- let t = e[A], s = getFigureMoveName(getFen(gameRecord.board, gameRecord.turn), t);
1261
- i.push(getLocalMoveName(s, 'zh-CN')),
1262
- await makeMoveByString(channelId, t);
1263
- }
1264
- return i.join(" ");
1265
- }
1266
- // async function onEngineInfo(channelId, t, e) {
1267
- // const gameRecord = await getGameRecord(channelId);
1268
- // let {
1269
- // isFlipBoard,
1270
- // bestMoveHint,
1271
- // ponderHint,
1272
- // thinkingDetail,
1273
- // // multiPvInfoBuffer,
1274
- // thinkingSide
1275
- // } = gameRecord;
1276
- // if ("pv" in e) {
1277
- // let t = e["multipv"]
1278
- // , n = e["pv"].split(" ");
1279
- // bestMoveHint[t] = moveStringToPos(n[0]),
1280
- // n.length > 1 && (ponderHint[t] = moveStringToPos(n[1])),
1281
- // // drawBoard(),
1282
- // thinkingSide = gameRecord.turn,
1283
- // "score" in e && "cp" in e["score"] ? e["score"]["cp"] = e["score"]["cp"] * ("w" == thinkingSide ? 1 : -1) * (isFlipBoard ? -1 : 1) : "score" in e && "mate" in e["score"] && (e["score"]["mate"] = e["score"]["mate"] * ("w" == thinkingSide ? 1 : -1) * (isFlipBoard ? -1 : 1)),
1284
- // e["board_side"] = isFlipBoard ? "b" : "w",
1285
- // e["type"] = "engine";
1286
- // try {
1287
- // engineSettings.MultiPV > 1 ? e["pv"] = getSerialMoveName(channelId, getFen(gameRecord.board, gameRecord.turn), e["pv"].split(" ").slice(0, 4)) : e["pv"] = getSerialMoveName(channelId, getFen(gameRecord.board, gameRecord.turn), e["pv"].split(" "))
1288
- // } catch (i) {
1289
- // }
1290
- // if (engineSettings.MultiPV > 1) {
1291
- // if (multiPvInfoBuffer[t] = e,
1292
- // Object.keys(multiPvInfoBuffer).length === engineSettings.MultiPV) {
1293
- // for (let t = engineSettings.MultiPV; t >= 1; t--)
1294
- // thinkingDetail.unshift(multiPvInfoBuffer[t]),
1295
- // thinkingDetail.length > 50 && thinkingDetail.pop();
1296
- // multiPvInfoBuffer = {}
1297
- // }
1298
- // } else
1299
- // thinkingDetail.unshift(e),
1300
- // thinkingDetail.length > 50 && thinkingDetail.pop()
1301
- // }
1302
- // await ctx.database.set('cchess_game_records', {channelId}, {
1303
- // bestMoveHint,
1304
- // ponderHint,
1305
- // thinkingDetail,
1306
- // multiPvInfoBuffer,
1307
- // thinkingSide
1308
- // })
1309
- // }
1310
- // async function stop(channelId) {
1311
- // // const gameRecord = await getGameRecord(channelId);
1312
- // // const lastPV = gameRecord.lastPV;
1313
- // engines[channelId].terminate()
1314
- // // engines[channelId].terminate(),
1315
- // // engines[channelId] = null,
1316
- // // gameRecord.isAnalyzing = false,
1317
- // // // null != lastPV && (2 == lastPV.length ? await onEngineInfo(channelId, lastPV[0], lastPV[1]) : await onEngineInfo(channelId, lastPV[0], null)),
1318
- // // await initEngine(channelId)
1319
- // }
1320
- async function go(channelId, t = -1, e = -1, i = -1) {
1321
- // const gameRecord = await getGameRecord(channelId);
1322
- // if (gameRecord.isAnalyzing)
1323
- // return false;
1324
- {
1325
- let n = "go";
1326
- return t > 0 && (n += " movetime " + t),
1327
- e > 0 && (n += " depth " + e),
1328
- i > 0 && (n += " nodes " + i),
1329
- await sendCommand(channelId, n),
1330
- true;
1331
- }
1332
- }
1333
- async function engineAction(channelId) {
1334
- const gameRecord = await getGameRecord(channelId);
1335
- let { isEnginePlayRed, isEnginePlayBlack, turn, movesAfterLastEat, boardAfterLastEat, turnAfterLastEat,
1336
- // multiPvInfoBuffer
1337
- } = gameRecord;
1338
- // if (isEnginePlayRed && "w" === turn || isEnginePlayBlack && "b" === turn) {
1339
- await sendCommand(channelId, "fen " + getFenWithMove(movesAfterLastEat, boardAfterLastEat, turnAfterLastEat)),
1340
- // multiPvInfoBuffer = {},
1341
- await go(channelId, 1e3 * thinkingSettings["movetime"], thinkingSettings["depth"], -1);
1342
- // }
1343
- // await ctx.database.set('cchess_game_records', {channelId}, {
1344
- // multiPvInfoBuffer
1345
- // })
1346
- }
1347
- function moveStringToPos(t) {
1348
- let e = {
1349
- a: 0,
1350
- b: 1,
1351
- c: 2,
1352
- d: 3,
1353
- e: 4,
1354
- f: 5,
1355
- g: 6,
1356
- h: 7,
1357
- i: 8
1358
- }, i = {
1359
- 0: 9,
1360
- 1: 8,
1361
- 2: 7,
1362
- 3: 6,
1363
- 4: 5,
1364
- 5: 4,
1365
- 6: 3,
1366
- 7: 2,
1367
- 8: 1,
1368
- 9: 0
1369
- }, n = [e[t[0]], i[t[1]]], A = [e[t[2]], i[t[3]]];
1370
- return [n, A];
1371
- }
1372
- async function makeMoveByString(channelId, t) {
1373
- let e = moveStringToPos(t);
1374
- await makeMove(channelId, e[0], e[1]);
1375
- }
1376
- function getSideByMoveString(board, t) {
1377
- let e = moveStringToPos(t), i = e[0];
1378
- return getSide(board[i[1]][i[0]]);
1379
- }
1380
- function getFenWithMove(movesAfterLastEat, boardAfterLastEat, turnAfterLastEat) {
1381
- let t = [];
1382
- for (let i of movesAfterLastEat)
1383
- t.push(i.move);
1384
- let e = boardToFen(boardAfterLastEat, "w", turnAfterLastEat);
1385
- return t.length > 0 && (e += " moves " + t.join(" ")),
1386
- e;
1387
- }
1388
- async function setOption(channelId, t, e) {
1389
- await sendCommand(channelId, "setoption name " + t + " value " + e);
1390
- }
1391
- async function setOptionList(channelId, t) {
1392
- for (let e in t)
1393
- await setOption(channelId, e, t[e]);
1394
- }
1395
- // zl*
1396
- async function sendCommand(channelId, t) {
1397
- const gameRecord = await getGameRecord(channelId);
1398
- await checkEngine(channelId);
1399
- if (engines[channelId] && !gameRecord.isEngineReady) {
1400
- await ctx.database.set('cchess_game_records', { channelId }, {
1401
- isEngineReady: true
1402
- });
1403
- }
1404
- if (null !== engines[channelId] || "uci" == t) {
1405
- engines[channelId].send_command(t);
1406
- }
1407
- else {
1408
- await sendCommand(channelId, t);
1409
- }
1410
- }
1411
- // sc*
1412
- async function receiveOutput(channelId, t) {
1413
- try {
1414
- if (!t)
1415
- return;
1416
- let e = t.split(" ");
1417
- let i = e[0];
1418
- let keywords = "depth seldepth time nodes pv multipv score currmove currmovenumber hashfull nps tbhits cpuload string refutation currline".split(" ");
1419
- if (i === "info") {
1420
- let infoObj = {};
1421
- for (let j = 1; j < e.length; j++) {
1422
- switch (e[j]) {
1423
- case "pv":
1424
- case "string":
1425
- infoObj[e[j]] = e.slice(j + 1).join(" ");
1426
- break;
1427
- case "score":
1428
- if (e[j + 1] === "cp") {
1429
- infoObj[e[j]] = { cp: parseInt(e[j + 2]) };
1430
- j += 2;
1431
- }
1432
- else if (e[j + 1] === "mate") {
1433
- infoObj[e[j]] = { mate: parseInt(e[j + 2]) };
1434
- j += 2;
1435
- }
1436
- else {
1437
- infoObj[e[j]] = { cp: parseInt(e[j + 1]) };
1438
- j++;
1439
- }
1440
- break;
1441
- default:
1442
- if (e.length > j + 1 && keywords.includes(e[j])) {
1443
- infoObj[e[j]] = parseInt(e[j + 1]);
1444
- j++;
1445
- }
1446
- else {
1447
- infoObj[e[j]] = "";
1448
- }
1449
- }
1450
- }
1451
- if ("pv" in infoObj) {
1452
- // lastPV = (infoObj["pv"] as string).split(" ");
1453
- }
1454
- // await onEngineInfo(channelId, i, infoObj);
1455
- }
1456
- else if (i === "bestmove") {
1457
- // isAnalyzing = false;
1458
- if (e.length === 4 && e[2] === "ponder") {
1459
- await onEngineBestMove(channelId, e[1], e[3]);
1460
- }
1461
- else {
1462
- await onEngineBestMove(channelId, e[1], null);
1463
- }
1464
- }
1465
- else if (i === "option" || i === "uciok") {
1466
- // await ctx.database.set('cchess_game_records', {channelId}, {isEngineReady: true})
1467
- }
1468
- }
1469
- catch (error) {
1470
- logger.error(error);
1471
- }
1472
- }
1473
- async function engineMessageHandler(channelId, message) {
1474
- const { command, wasmType, origin } = message;
1475
- if (!engines[channelId]) {
1476
- engines[channelId] = null;
1477
- }
1478
- if (command !== undefined) {
1479
- engines[channelId].send_command(command);
1480
- }
1481
- else if (wasmType !== undefined) {
1482
- const wasmOrigin = origin;
1483
- const wasmScriptPath = path.join(wasmOrigin, 'assets', 'wasm', 'pikafish.js');
1484
- const Pikafish = require(wasmScriptPath);
1485
- const instance = await Pikafish({
1486
- locateFile: (file) => {
1487
- if (file === "pikafish.data") {
1488
- return path.join(wasmOrigin, 'assets', 'wasm', 'data', file);
1489
- }
1490
- else {
1491
- return path.join(wasmOrigin, 'assets', 'wasm', file);
1492
- }
1493
- },
1494
- setStatus: (status) => {
1495
- }
1496
- });
1497
- engines[channelId] = instance;
1498
- engines[channelId].read_stdout = async (stdout) => {
1499
- // 处理接收到的输出
1500
- await receiveOutput(channelId, stdout);
1501
- };
1502
- // isReady
1503
- await ctx.database.set('cchess_game_records', { channelId }, { isEngineReady: true });
1504
- await (0, koishi_1.sleep)(100);
1505
- // 发送命令 "uci"
1506
- await sendCommand(channelId, "uci");
1507
- await (0, koishi_1.sleep)(100);
1508
- // 设置选项
1509
- await setOptionList(channelId, engineSettings);
1510
- }
1511
- }
1512
- async function initEngine(channelId) {
1513
- await engineMessageHandler(channelId, { command: undefined, wasmType: 'single', origin: __dirname });
1514
- }
1515
- function findMoveInfo(moveInfoList, moveOperation) {
1516
- return moveInfoList.find(moveInfo => moveInfo.figureMoveName === moveOperation);
1517
- }
1518
- function findLegalMovePositions(moveMap) {
1519
- const legalPositions = [];
1520
- for (let i = 0; i < 10; i++) {
1521
- for (let j = 0; j < 9; j++) {
1522
- if ((moveMap[i][j] === 'go' || moveMap[i][j] === 'eat')) {
1523
- legalPositions.push([i, j]);
1524
- }
1525
- }
1526
- }
1527
- return legalPositions;
1528
- }
1529
- function findLetterPositions(board, processedLetter) {
1530
- const positions = [];
1531
- for (let i = 0; i < board.length; i++) {
1532
- for (let j = 0; j < board[i].length; j++) {
1533
- if (board[i][j] === processedLetter) {
1534
- positions.push([i, j]);
1535
- }
1536
- }
1537
- }
1538
- return positions;
1539
- }
1540
- function processEnglishLetter(englishLetter, turn) {
1541
- if (turn === 'w') {
1542
- return englishLetter.toUpperCase();
1543
- }
1544
- else {
1545
- return englishLetter.toLowerCase();
1546
- }
1547
- }
1548
- const chineseToEnglishMap = {
1292
+ }
1293
+ __name(onEngineBestMove, "onEngineBestMove");
1294
+ function getLocalMoveName(t, e) {
1295
+ let i = {};
1296
+ if ("zh-CN" === e)
1297
+ return t;
1298
+ if ("en-US" === e)
1299
+ i = {
1300
+ "进": "+",
1301
+ "退": "-",
1302
+ "平": "=",
1303
+ "前": "+",
1304
+ "后": "-",
1305
+ "中": "=",
1549
1306
  "将": "k",
1307
+ "帅": "K",
1550
1308
  "士": "a",
1309
+ "仕": "A",
1551
1310
  "象": "b",
1311
+ "相": "B",
1552
1312
  "车": "r",
1553
1313
  "马": "n",
1554
1314
  "炮": "c",
1555
1315
  "卒": "p",
1556
- "": "k",
1557
- "仕": "a",
1558
- "相": "b",
1559
- "": "p"
1560
- };
1561
- function getEnglishLetterFromFigureName(figureName) {
1562
- return chineseToEnglishMap[figureName] || null;
1563
- }
1564
- function getFigureNameFromMoveOperation(moveOperation) {
1565
- const figureNamesRegex = new RegExp(possibleFigureNames.join("|"));
1566
- const figureNameMatches = moveOperation.match(figureNamesRegex);
1567
- if (figureNameMatches && figureNameMatches.length > 0) {
1568
- return figureNameMatches[0];
1569
- }
1570
- return null;
1571
- }
1572
- function isValidFigureMoveName(move) {
1573
- const possibleActions = ["", "退", "平"];
1574
- const possiblePositions = ["", "", "三", "四", "五", "六", "七", "八", "九", "9", "8", "7", "6", "5", "4", "3", "2", "1"];
1575
- const figureNamesRegex = new RegExp(possibleFigureNames.join("|"));
1576
- const actionRegex = new RegExp(possibleActions.join("|"));
1577
- const positionRegex = new RegExp(possiblePositions.join("|"), "g");
1578
- if (move.length !== 4) {
1579
- return false;
1580
- }
1581
- const figureNameMatches = move.match(figureNamesRegex);
1582
- const actionMatches = move.match(actionRegex);
1583
- const positionMatches = move.match(positionRegex);
1584
- return figureNameMatches && figureNameMatches.length === 1 &&
1585
- actionMatches && actionMatches.length === 1 &&
1586
- positionMatches && positionMatches.length >= 1 && positionMatches.length <= 2;
1587
- }
1588
- function convertTurnToString(turn) {
1589
- if (turn === 'w') {
1590
- return '红方';
1591
- }
1592
- else if (turn === 'b') {
1593
- return '黑方';
1594
- }
1595
- }
1596
- async function createImage(buffer) {
1597
- const canvas = await ctx.canvas.createCanvas(620 * scale, 780 * scale);
1598
- const context = canvas.getContext('2d');
1599
- const outerFrame = await ctx.canvas.loadImage(outerFrameImg);
1600
- context.drawImage(outerFrame, 0, 0, 620 * scale, 780 * scale);
1601
- const boardImg = await ctx.canvas.loadImage(buffer);
1602
- context.drawImage(boardImg, 36.5 * scale, 90 * scale, 550 * scale, 605 * scale);
1603
- return canvas.toBuffer('image/png');
1604
- }
1605
- function isMoveString(str) {
1606
- const boardLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"];
1607
- if (str.length !== 4) {
1608
- return false;
1609
- }
1610
- return boardLetters.includes(str[0]) &&
1611
- boardLetters.includes(str[2]) &&
1612
- parseInt(str[1]) >= 0 && parseInt(str[1]) <= 9 &&
1613
- parseInt(str[3]) >= 0 && parseInt(str[3]) <= 9;
1614
- }
1615
- function getType(t) {
1616
- return t.toLowerCase();
1617
- }
1618
- function getValidMoveMapKings(board, t, e) {
1619
- let i, n, A = getEmptyBoard(), s = e[0], a = e[1];
1620
- a <= 2 ? (i = 0,
1621
- n = 2) : a >= 7 ? (i = 7,
1622
- n = 9) : (i = a - 1,
1623
- n = a + 1);
1624
- let o = 3, r = 5;
1625
- if (s + 1 <= r) {
1626
- let e = getValidType(board, t, [s + 1, a]);
1627
- "eat" != e && "go" != e || setMoveMap(A, [s + 1, a], e);
1628
- }
1629
- if (s - 1 >= o) {
1630
- let e = getValidType(board, t, [s - 1, a]);
1631
- "eat" != e && "go" != e || setMoveMap(A, [s - 1, a], e);
1632
- }
1633
- if (a + 1 <= n) {
1634
- let e = getValidType(board, t, [s, a + 1]);
1635
- "eat" != e && "go" != e || setMoveMap(A, [s, a + 1], e);
1636
- }
1637
- if (a - 1 >= i) {
1638
- let e = getValidType(board, t, [s, a - 1]);
1639
- "eat" != e && "go" != e || setMoveMap(A, [s, a - 1], e);
1640
- }
1641
- return A;
1642
- }
1643
- function getValidMoveMapCannons(board, t, e) {
1644
- let i = getEmptyBoard(), n = e[0], A = e[1], s = !1;
1645
- for (let a = n; a < 9; a++) {
1646
- if (a == n)
1647
- continue;
1648
- let e = getValidType(board, t, [a, A]);
1649
- if (s || "block" != e && "eat" != e) {
1650
- if (s && "eat" == e) {
1651
- setMoveMap(i, [a, A], "eat");
1652
- break;
1653
- }
1654
- s || "go" != e || setMoveMap(i, [a, A], "go");
1655
- }
1656
- else
1657
- s = !0;
1658
- }
1659
- s = !1;
1660
- for (let a = n; a >= 0; a--) {
1661
- if (a == n)
1662
- continue;
1663
- let e = getValidType(board, t, [a, A]);
1664
- if (s || "block" != e && "eat" != e) {
1665
- if (s && "eat" == e) {
1666
- setMoveMap(i, [a, A], "eat");
1667
- break;
1668
- }
1669
- s || "go" != e || setMoveMap(i, [a, A], "go");
1670
- }
1671
- else
1672
- s = !0;
1673
- }
1674
- s = !1;
1675
- for (let a = A; a < 10; a++) {
1676
- if (a == A)
1677
- continue;
1678
- let e = getValidType(board, t, [n, a]);
1679
- if (s || "block" != e && "eat" != e) {
1680
- if (s && "eat" == e) {
1681
- setMoveMap(i, [n, a], "eat");
1682
- break;
1683
- }
1684
- s || "go" != e || setMoveMap(i, [n, a], "go");
1685
- }
1686
- else
1687
- s = !0;
1688
- }
1689
- s = !1;
1690
- for (let a = A; a >= 0; a--) {
1691
- if (a == A)
1692
- continue;
1693
- let e = getValidType(board, t, [n, a]);
1694
- if (s || "block" != e && "eat" != e) {
1695
- if (s && "eat" == e) {
1696
- setMoveMap(i, [n, a], "eat");
1697
- break;
1698
- }
1699
- s || "go" != e || setMoveMap(i, [n, a], "go");
1700
- }
1701
- else
1702
- s = !0;
1703
- }
1704
- return i;
1705
- }
1706
- function getSideByKing(board, t) {
1707
- t[0];
1708
- let e = t[1];
1709
- if (e <= 4)
1710
- for (let i = 3; i <= 5; i++)
1711
- for (let t = 0; t <= 2; t++) {
1712
- let e = getPiece(board, [i, t]);
1713
- if ("K" == e)
1714
- return "w";
1715
- if ("k" == e)
1716
- return "b";
1717
- }
1718
- else
1719
- for (let i = 3; i <= 5; i++)
1720
- for (let t = 7; t <= 9; t++) {
1721
- let e = getPiece(board, [i, t]);
1722
- if ("K" == e)
1723
- return "w";
1724
- if ("k" == e)
1725
- return "b";
1726
- }
1727
- return "";
1728
- }
1729
- function getValidMoveMapPawns(board, t, e) {
1730
- let i = getEmptyBoard(), n = e[0], A = e[1], s = getSideByKing(board, e);
1731
- if (t == s)
1732
- if (A <= 4) {
1733
- let e = getValidType(board, t, [n, A + 1]);
1734
- "eat" != e && "go" != e || setMoveMap(i, [n, A + 1], e);
1735
- }
1736
- else {
1737
- let e = getValidType(board, t, [n, A - 1]);
1738
- "eat" != e && "go" != e || setMoveMap(i, [n, A - 1], e);
1739
- }
1740
- else {
1741
- if (A <= 4) {
1742
- let e = getValidType(board, t, [n, A - 1]);
1743
- "eat" != e && "go" != e || setMoveMap(i, [n, A - 1], e);
1744
- }
1745
- else {
1746
- let e = getValidType(board, t, [n, A + 1]);
1747
- "eat" != e && "go" != e || setMoveMap(i, [n, A + 1], e);
1748
- }
1749
- let e = getValidType(board, t, [n + 1, A]);
1750
- "eat" != e && "go" != e || setMoveMap(i, [n + 1, A], e),
1751
- e = getValidType(board, t, [n - 1, A]),
1752
- "eat" != e && "go" != e || setMoveMap(i, [n - 1, A], e);
1753
- }
1754
- return i;
1755
- }
1756
- function getValidMoveMapBishops(board, t, e) {
1757
- let i, n, A = getEmptyBoard(), s = e[0], a = e[1];
1758
- if (a <= 4 ? (i = 0,
1759
- n = 4) : a >= 5 ? (i = 5,
1760
- n = 9) : (i = a - 1,
1761
- n = a + 1),
1762
- s + 2 <= 9 && a + 2 <= n) {
1763
- let e = getPiece(board, [s + 1, a + 1]);
1764
- if ("" == e) {
1765
- let e = getValidType(board, t, [s + 2, a + 2]);
1766
- "eat" != e && "go" != e || setMoveMap(A, [s + 2, a + 2], e);
1767
- }
1768
- }
1769
- if (s - 2 >= 0 && a + 2 <= n) {
1770
- let e = getPiece(board, [s - 1, a + 1]);
1771
- if ("" == e) {
1772
- let e = getValidType(board, t, [s - 2, a + 2]);
1773
- "eat" != e && "go" != e || setMoveMap(A, [s - 2, a + 2], e);
1774
- }
1775
- }
1776
- if (s + 2 <= 9 && a - 2 >= i) {
1777
- let e = getPiece(board, [s + 1, a - 1]);
1778
- if ("" == e) {
1779
- let e = getValidType(board, t, [s + 2, a - 2]);
1780
- "eat" != e && "go" != e || setMoveMap(A, [s + 2, a - 2], e);
1781
- }
1782
- }
1783
- if (s - 2 >= 0 && a - 2 >= i) {
1784
- let e = getPiece(board, [s - 1, a - 1]);
1785
- if ("" == e) {
1786
- let e = getValidType(board, t, [s - 2, a - 2]);
1787
- "eat" != e && "go" != e || setMoveMap(A, [s - 2, a - 2], e);
1788
- }
1789
- }
1790
- return A;
1791
- }
1792
- function getValidMoveMap(board, type, side, position) {
1793
- switch (type) {
1794
- case "r":
1795
- return getValidMoveMapRooks(board, side, position);
1796
- case "n":
1797
- return getValidMoveMapKnights(board, side, position);
1798
- case "a":
1799
- return getValidMoveMapAdvisors(board, side, position);
1800
- case "b":
1801
- return getValidMoveMapBishops(board, side, position);
1802
- case "k":
1803
- return getValidMoveMapKings(board, side, position);
1804
- case "c":
1805
- return getValidMoveMapCannons(board, side, position);
1806
- case "p":
1807
- return getValidMoveMapPawns(board, side, position);
1316
+ "": "P"
1317
+ };
1318
+ else {
1319
+ if ("vi-VN" !== e)
1320
+ return t;
1321
+ i = {
1322
+ "进": ".",
1323
+ "退": "/",
1324
+ "平": "-",
1325
+ "前": ".",
1326
+ "后": "/",
1327
+ "中": "-",
1328
+ "将": "Tg",
1329
+ "帅": "Tg",
1330
+ "士": "S",
1331
+ "仕": "S",
1332
+ "象": "T",
1333
+ "": "T",
1334
+ "": "X",
1335
+ "马": "M",
1336
+ "炮": "P",
1337
+ "": "B",
1338
+ "兵": "B"
1339
+ };
1340
+ }
1341
+ let n = "一二三四五六七八九", A = "123456789", s = "123456789", a = "", o = -1 !== A.indexOf(t[3]) ? "b" : "w";
1342
+ for (let r of t) {
1343
+ let t2 = n.indexOf(r), e2 = A.indexOf(r);
1344
+ a += r in i ? i[r] : -1 !== t2 ? s[t2] : -1 !== e2 ? s[e2] : r;
1345
+ }
1346
+ return a = "w" === o ? a.toUpperCase() : a.toLowerCase(), a;
1347
+ }
1348
+ __name(getLocalMoveName, "getLocalMoveName");
1349
+ async function getSerialMoveName(channelId, t, e) {
1350
+ const gameRecord = await getGameRecord(channelId);
1351
+ let i = [];
1352
+ for (let A = 0; A < e.length; A++) {
1353
+ let t2 = e[A], s = getFigureMoveName(getFen(gameRecord.board, gameRecord.turn), t2);
1354
+ i.push(getLocalMoveName(s, "zh-CN")), await makeMoveByString(channelId, t2);
1355
+ }
1356
+ return i.join(" ");
1357
+ }
1358
+ __name(getSerialMoveName, "getSerialMoveName");
1359
+ async function go(channelId, t = -1, e = -1, i = -1) {
1360
+ {
1361
+ let n = "go";
1362
+ return t > 0 && (n += " movetime " + t), e > 0 && (n += " depth " + e), i > 0 && (n += " nodes " + i), await sendCommand(channelId, n), true;
1363
+ }
1364
+ }
1365
+ __name(go, "go");
1366
+ async function engineAction(channelId) {
1367
+ const gameRecord = await getGameRecord(channelId);
1368
+ let {
1369
+ isEnginePlayRed,
1370
+ isEnginePlayBlack,
1371
+ turn,
1372
+ movesAfterLastEat,
1373
+ boardAfterLastEat,
1374
+ turnAfterLastEat
1375
+ // multiPvInfoBuffer
1376
+ } = gameRecord;
1377
+ await sendCommand(channelId, "fen " + getFenWithMove(movesAfterLastEat, boardAfterLastEat, turnAfterLastEat)), // multiPvInfoBuffer = {},
1378
+ await go(channelId, 1e3 * thinkingSettings["movetime"], thinkingSettings["depth"], -1);
1379
+ }
1380
+ __name(engineAction, "engineAction");
1381
+ function moveStringToPos(t) {
1382
+ let e = {
1383
+ a: 0,
1384
+ b: 1,
1385
+ c: 2,
1386
+ d: 3,
1387
+ e: 4,
1388
+ f: 5,
1389
+ g: 6,
1390
+ h: 7,
1391
+ i: 8
1392
+ }, i = {
1393
+ 0: 9,
1394
+ 1: 8,
1395
+ 2: 7,
1396
+ 3: 6,
1397
+ 4: 5,
1398
+ 5: 4,
1399
+ 6: 3,
1400
+ 7: 2,
1401
+ 8: 1,
1402
+ 9: 0
1403
+ }, n = [e[t[0]], i[t[1]]], A = [e[t[2]], i[t[3]]];
1404
+ return [n, A];
1405
+ }
1406
+ __name(moveStringToPos, "moveStringToPos");
1407
+ async function makeMoveByString(channelId, t) {
1408
+ let e = moveStringToPos(t);
1409
+ await makeMove(channelId, e[0], e[1]);
1410
+ }
1411
+ __name(makeMoveByString, "makeMoveByString");
1412
+ function getSideByMoveString(board, t) {
1413
+ let e = moveStringToPos(t), i = e[0];
1414
+ return getSide(board[i[1]][i[0]]);
1415
+ }
1416
+ __name(getSideByMoveString, "getSideByMoveString");
1417
+ function getFenWithMove(movesAfterLastEat, boardAfterLastEat, turnAfterLastEat) {
1418
+ let t = [];
1419
+ for (let i of movesAfterLastEat)
1420
+ t.push(i.move);
1421
+ let e = boardToFen(boardAfterLastEat, "w", turnAfterLastEat);
1422
+ return t.length > 0 && (e += " moves " + t.join(" ")), e;
1423
+ }
1424
+ __name(getFenWithMove, "getFenWithMove");
1425
+ async function setOption(channelId, t, e) {
1426
+ await sendCommand(channelId, "setoption name " + t + " value " + e);
1427
+ }
1428
+ __name(setOption, "setOption");
1429
+ async function setOptionList(channelId, t) {
1430
+ for (let e in t)
1431
+ await setOption(channelId, e, t[e]);
1432
+ }
1433
+ __name(setOptionList, "setOptionList");
1434
+ async function sendCommand(channelId, t) {
1435
+ const gameRecord = await getGameRecord(channelId);
1436
+ await checkEngine(channelId);
1437
+ if (engines[channelId] && !gameRecord.isEngineReady) {
1438
+ await ctx.database.set("cchess_game_records", { channelId }, {
1439
+ isEngineReady: true
1440
+ });
1441
+ }
1442
+ if (null !== engines[channelId] || "uci" == t) {
1443
+ engines[channelId].send_command(t);
1444
+ } else {
1445
+ await sendCommand(channelId, t);
1446
+ }
1447
+ }
1448
+ __name(sendCommand, "sendCommand");
1449
+ async function receiveOutput(channelId, t) {
1450
+ try {
1451
+ if (!t)
1452
+ return;
1453
+ let e = t.split(" ");
1454
+ let i = e[0];
1455
+ let keywords = "depth seldepth time nodes pv multipv score currmove currmovenumber hashfull nps tbhits cpuload string refutation currline".split(" ");
1456
+ if (i === "info") {
1457
+ let infoObj = {};
1458
+ for (let j = 1; j < e.length; j++) {
1459
+ switch (e[j]) {
1460
+ case "pv":
1461
+ case "string":
1462
+ infoObj[e[j]] = e.slice(j + 1).join(" ");
1463
+ break;
1464
+ case "score":
1465
+ if (e[j + 1] === "cp") {
1466
+ infoObj[e[j]] = { cp: parseInt(e[j + 2]) };
1467
+ j += 2;
1468
+ } else if (e[j + 1] === "mate") {
1469
+ infoObj[e[j]] = { mate: parseInt(e[j + 2]) };
1470
+ j += 2;
1471
+ } else {
1472
+ infoObj[e[j]] = { cp: parseInt(e[j + 1]) };
1473
+ j++;
1474
+ }
1475
+ break;
1808
1476
  default:
1809
- return getEmptyBoard();
1810
- }
1811
- }
1812
- function getValidMoveMapRooks(board, t, e) {
1813
- let i = getEmptyBoard(), n = e[0], A = e[1];
1814
- for (let s = n; s < 9; s++) {
1815
- if (s == n)
1816
- continue;
1817
- let e = getValidType(board, t, [s, A]);
1818
- if ("block" == e)
1819
- break;
1820
- if (i[A][s] = e,
1821
- "eat" == e)
1822
- break;
1823
- }
1824
- for (let s = n; s >= 0; s--) {
1825
- if (s == n)
1826
- continue;
1827
- let e = getValidType(board, t, [s, A]);
1828
- if ("block" == e)
1829
- break;
1830
- if (i[A][s] = e,
1831
- "eat" == e)
1832
- break;
1833
- }
1834
- for (let s = A; s < 10; s++) {
1835
- if (s == A)
1836
- continue;
1837
- let e = getValidType(board, t, [n, s]);
1838
- if ("block" == e)
1839
- break;
1840
- if (i[s][n] = e,
1841
- "eat" == e)
1842
- break;
1843
- }
1844
- for (let s = A; s >= 0; s--) {
1845
- if (s == A)
1846
- continue;
1847
- let e = getValidType(board, t, [n, s]);
1848
- if ("block" == e)
1849
- break;
1850
- if (i[s][n] = e,
1851
- "eat" == e)
1852
- break;
1853
- }
1854
- return i;
1855
- }
1856
- function getValidType(board, t, e) {
1857
- let i = getPiece(board, e);
1858
- return void 0 == i ? "invalid" : "" == i ? "go" : t != getSide(i) ? "eat" : "block";
1859
- }
1860
- function getValidMoveMapAdvisors(board, t, e) {
1861
- let i, n, A = getEmptyBoard(), s = e[0], a = e[1];
1862
- a <= 2 ? (i = 0,
1863
- n = 2) : a >= 7 ? (i = 7,
1864
- n = 9) : (i = a - 1,
1865
- n = a + 1);
1866
- let o = 3, r = 5;
1867
- if (s + 1 <= r && a + 1 <= n) {
1868
- let e = getValidType(board, t, [s + 1, a + 1]);
1869
- "eat" != e && "go" != e || setMoveMap(A, [s + 1, a + 1], e);
1870
- }
1871
- if (s - 1 >= o && a + 1 <= n) {
1872
- let e = getValidType(board, t, [s - 1, a + 1]);
1873
- "eat" != e && "go" != e || setMoveMap(A, [s - 1, a + 1], e);
1874
- }
1875
- if (s + 1 <= r && a - 1 >= i) {
1876
- let e = getValidType(board, t, [s + 1, a - 1]);
1877
- "eat" != e && "go" != e || setMoveMap(A, [s + 1, a - 1], e);
1878
- }
1879
- if (s - 1 >= o && a - 1 >= i) {
1880
- let e = getValidType(board, t, [s - 1, a - 1]);
1881
- "eat" != e && "go" != e || setMoveMap(A, [s - 1, a - 1], e);
1882
- }
1883
- return A;
1884
- }
1885
- function setMoveMap(t, e, i) {
1886
- e[0] < 0 || e[0] > 8 || e[1] < 0 || e[1] > 9 || (t[e[1]][e[0]] = i);
1887
- }
1888
- function getValidMoveMapKnights(board, t, e) {
1889
- let i = getEmptyBoard(), n = e[0], A = e[1];
1890
- return "" == getPiece(board, [n + 1, A]) && (setMoveMap(i, [n + 2, A + 1], getValidType(board, t, [n + 2, A + 1])),
1891
- setMoveMap(i, [n + 2, A - 1], getValidType(board, t, [n + 2, A - 1]))),
1892
- "" == getPiece(board, [n - 1, A]) && (setMoveMap(i, [n - 2, A + 1], getValidType(board, t, [n - 2, A + 1])),
1893
- setMoveMap(i, [n - 2, A - 1], getValidType(board, t, [n - 2, A - 1]))),
1894
- "" == getPiece(board, [n, A + 1]) && (setMoveMap(i, [n + 1, A + 2], getValidType(board, t, [n + 1, A + 2])),
1895
- setMoveMap(i, [n - 1, A + 2], getValidType(board, t, [n - 1, A + 2]))),
1896
- "" == getPiece(board, [n, A - 1]) && (setMoveMap(i, [n + 1, A - 2], getValidType(board, t, [n + 1, A - 2])),
1897
- setMoveMap(i, [n - 1, A - 2], getValidType(board, t, [n - 1, A - 2]))),
1898
- i;
1899
- }
1900
- var Et = [];
1901
- Et["w"] = [],
1902
- Et["b"] = [],
1903
- Et["w"][0] = "进",
1904
- Et["w"][1] = "退",
1905
- Et["b"][0] = "退",
1906
- Et["b"][1] = "进",
1907
- Et["p"] = "";
1908
- var Ht = [];
1909
- Ht["w"] = [],
1910
- Ht["b"] = [],
1911
- Ht["w"][0] = "",
1912
- Ht["w"][1] = "",
1913
- Ht["b"][0] = "",
1914
- Ht["b"][1] = "",
1915
- Ht["m"] = "";
1916
- var qt = [];
1917
- qt["k"] = "",
1918
- qt["a"] = "士",
1919
- qt["b"] = "象",
1920
- qt["r"] = "车",
1921
- qt["n"] = "马",
1922
- qt["c"] = "",
1923
- qt["p"] = "卒",
1924
- qt["K"] = "",
1925
- qt["A"] = "仕",
1926
- qt["B"] = "相",
1927
- qt["R"] = "车",
1928
- qt["N"] = "马",
1929
- qt["C"] = "炮",
1930
- qt["P"] = "兵";
1931
- var Qt = [];
1932
- Qt["w"] = [],
1933
- Qt["b"] = [],
1934
- Qt["w"][0] = "",
1935
- Qt["w"][1] = "",
1936
- Qt["w"][2] = "",
1937
- Qt["w"][3] = "",
1938
- Qt["w"][4] = "五",
1939
- Qt["w"][5] = "六",
1940
- Qt["w"][6] = "七",
1941
- Qt["w"][7] = "八",
1942
- Qt["w"][8] = "九",
1943
- // Qt["b"][0] = "9",
1944
- // Qt["b"][1] = "8",
1945
- // Qt["b"][2] = "7",
1946
- // Qt["b"][3] = "6",
1947
- // Qt["b"][4] = "5",
1948
- // Qt["b"][5] = "",
1949
- // Qt["b"][6] = "3",
1950
- // Qt["b"][7] = "2",
1951
- // Qt["b"][8] = "1";
1952
- Qt["b"][0] = "9",
1953
- Qt["b"][1] = "8",
1954
- Qt["b"][2] = "7",
1955
- Qt["b"][3] = "6",
1956
- Qt["b"][4] = "5",
1957
- Qt["b"][5] = "4",
1958
- Qt["b"][6] = "3",
1959
- Qt["b"][7] = "2",
1960
- Qt["b"][8] = "1";
1961
- function parseChessNotation(fen) {
1962
- let e = [];
1963
- for (let s = 0; s < 9; s++) {
1964
- e[s] = [];
1965
- for (let t = 0; t < 10; t++)
1966
- e[s][t] = 0;
1967
- }
1968
- let i = fen.split(" ")[0].split("/"), n = ["k", "a", "b", "r", "n", "c", "p", "K", "A", "B", "R", "N", "C", "P"], A = 0;
1969
- for (let s = 0; s < 10; s++) {
1970
- let t = i[s], a = 0;
1971
- for (let i = 0; i < t.length; i++) {
1972
- let o = t[i];
1973
- if (o >= "0" && o <= "9")
1974
- a += parseInt(o);
1975
- else if (-1 != n.indexOf(o)) {
1976
- let t = o >= "a" && o <= "z" ? "b" : "w";
1977
- e[a][s] = t + o + A,
1978
- a++,
1979
- A++;
1980
- }
1981
- }
1982
- }
1983
- return e;
1984
- }
1985
- function getFigureMoveName(fen, moveString) {
1986
- let i = parseChessNotation(fen);
1987
- 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 = '';
1988
- 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)) {
1989
- for (var g = 0; g < 9; g++)
1990
- if (g != n) {
1991
- for (var f = 0; f < 10; f++)
1992
- 0 != i[g][f] && i[g][f].substring(0, 2) == i[n][A].substring(0, 2) && l++;
1993
- l < 2 && (l = 0);
1994
- }
1995
- for (f = 0; f < 10; f++)
1996
- 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)],
1997
- o++) : (d = Ht[i[n][A].charAt(0)][1] + Qt[i[n][A].charAt(0)][9 - n - 1],
1998
- 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)],
1999
- 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],
2000
- o++));
2001
- 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)]);
2002
- }
2003
- else
2004
- d = qt[i[n][A].charAt(1)] + Qt[i[n][A].charAt(0)][9 - n - 1];
2005
- var h = '';
2006
- return h = 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],
2007
- d + h;
2008
- }
2009
- function moveToMoveString(move) {
2010
- const boardLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"];
2011
- let startSquare = move[0];
2012
- let endSquare = move[1];
2013
- let startSquareAlgebraic = boardLetters[startSquare[0]] + (9 - startSquare[1]).toString();
2014
- let endSquareAlgebraic = boardLetters[endSquare[0]] + (9 - endSquare[1]).toString();
2015
- return startSquareAlgebraic + endSquareAlgebraic;
2016
- }
2017
- function moveStringToMove(moveString) {
2018
- const boardLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"];
2019
- let startSquareAlgebraic = moveString.substring(0, 2);
2020
- let endSquareAlgebraic = moveString.substring(2);
2021
- let startSquare = [boardLetters.indexOf(startSquareAlgebraic[0]), 9 - parseInt(startSquareAlgebraic[1])];
2022
- let endSquare = [boardLetters.indexOf(endSquareAlgebraic[0]), 9 - parseInt(endSquareAlgebraic[1])];
2023
- return [startSquare, endSquare];
2024
- }
2025
- function genRandomId(length) {
2026
- let id = "";
2027
- const characters = "abcdefghijklmnopqrstuvwxyz0123456789";
2028
- for (let i = 0; i < length; i++) {
2029
- id += characters.charAt(Math.floor(Math.random() * characters.length));
2030
- }
2031
- return id;
2032
- }
2033
- async function makeMove(channelId, fromPos, toPos) {
2034
- const gameRecord = await getGameRecord(channelId);
2035
- let { turn, board, moveTreePtr, moveList, isHistoryMode, boardAfterLastEat, turnAfterLastEat, movesAfterLastEat } = gameRecord;
2036
- if (isHistoryMode) {
2037
- gameRecord.isHistoryMode = false;
2038
- }
2039
- const lastMove = [fromPos, toPos];
2040
- const moveId = genRandomId(8);
2041
- const pieceAtDestination = board[toPos[1]][toPos[0]] !== "";
2042
- const side = getSide(getPiece(board, fromPos));
2043
- const fen = getFen(board, side);
2044
- if (board[toPos[1]][toPos[0]] === 'K' || board[toPos[1]][toPos[0]] === 'k') {
2045
- await ctx.database.set('cchess_game_records', { channelId }, {
2046
- winSide: board[toPos[1]][toPos[0]] === 'K' ? 'b' : 'w',
2047
- loseSide: board[toPos[1]][toPos[0]] === 'K' ? 'w' : 'b',
2048
- });
2049
- }
2050
- board[toPos[1]][toPos[0]] = board[fromPos[1]][fromPos[0]];
2051
- board[fromPos[1]][fromPos[0]] = "";
2052
- turn = turn === getSide(board[toPos[1]][toPos[0]]) ? (turn === "w" ? "b" : "w") : turn;
2053
- const moveString = moveToMoveString([fromPos, toPos]);
2054
- const figureMoveName = getFigureMoveName(fen, moveString);
2055
- const moveData = {
2056
- moveId,
2057
- fen: getFen(board, turn),
2058
- side,
2059
- moveCord: [fromPos, toPos],
2060
- move: moveString,
2061
- chnMoveName: figureMoveName,
2062
- next: null
2063
- };
2064
- moveList.push(moveData);
2065
- moveTreePtr.next = moveData;
2066
- moveTreePtr = moveData;
2067
- if (pieceAtDestination) {
2068
- boardAfterLastEat = fenToBoard(getFen(board, turn));
2069
- turnAfterLastEat = turn;
2070
- movesAfterLastEat = [];
2071
- }
2072
- else {
2073
- movesAfterLastEat.push(moveData);
2074
- }
2075
- const updatedGameRecord = {
2076
- turn,
2077
- board,
2078
- lastMove,
2079
- moveTreePtr,
2080
- moveList,
2081
- isHistoryMode,
2082
- boardAfterLastEat,
2083
- turnAfterLastEat,
2084
- movesAfterLastEat
2085
- };
2086
- Object.assign(gameRecord, updatedGameRecord);
2087
- await ctx.database.set('cchess_game_records', { channelId }, updatedGameRecord);
2088
- }
2089
- function getFen(board, turn) {
2090
- return boardToFen(board, 'w', turn);
2091
- }
2092
- function boardToFen(board, side, turn = "w") {
2093
- if (board === null) {
2094
- return "";
2095
- }
2096
- const ranks = side === "w" ? [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] : [9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
2097
- let fenString = "";
2098
- for (const row of ranks) {
2099
- let emptyCount = 0;
2100
- for (let col = 0; col < 9; col++) {
2101
- const piece = board[row][col];
2102
- if (piece === "") {
2103
- emptyCount++;
2104
- }
2105
- else {
2106
- if (emptyCount > 0) {
2107
- fenString += emptyCount;
2108
- emptyCount = 0;
2109
- }
2110
- fenString += piece;
2111
- }
2112
- }
2113
- if (emptyCount > 0) {
2114
- fenString += emptyCount;
2115
- }
2116
- fenString += "/";
2117
- }
2118
- fenString = fenString.substring(0, fenString.length - 1) + " " + turn;
2119
- return fenString;
2120
- }
2121
- function getSide(piece) {
2122
- let e = "RNBAKCP";
2123
- return e.includes(piece) ? "w" : "b";
2124
- }
2125
- async function getGameRecord(channelId) {
2126
- let gameRecord = await ctx.database.get('cchess_game_records', { channelId });
2127
- if (gameRecord.length === 0) {
2128
- await ctx.database.create('cchess_game_records', {
2129
- channelId,
2130
- });
2131
- gameRecord = await ctx.database.get('cchess_game_records', { channelId });
2132
- }
2133
- return gameRecord[0];
2134
- }
2135
- async function drawChessBoard(channelId) {
2136
- const gameRecord = await getGameRecord(channelId);
2137
- let { board, lastMove, moveList, currentMoveId } = gameRecord;
2138
- const canvas = await ctx.canvas.createCanvas(weight * scale, height * scale);
2139
- const context = canvas.getContext('2d');
2140
- const boardImg = await ctx.canvas.loadImage(boardSkinImg);
2141
- context.drawImage(boardImg, 0, 0, weight * scale, height * scale);
2142
- const pieceImages = {};
2143
- const pieceImagePromises = Object.keys(piecesImgResources).map(piece => {
2144
- return ctx.canvas.loadImage(piecesImgResources[piece]).then(img => {
2145
- pieceImages[piece] = img;
2146
- });
2147
- });
2148
- await Promise.all(pieceImagePromises);
2149
- for (let row = 0; row < 10; row++) {
2150
- for (let col = 0; col < 9; col++) {
2151
- const piece = getPiece(board, [col, row]);
2152
- if (piece === "")
2153
- continue;
2154
- const xPos = ((isFlipBoard ? 8 - col : col) * we + Pe - Be / 2) * scale;
2155
- const yPos = ((isFlipBoard ? 9 - row : row) * we + Pe - Be / 2) * scale;
2156
- const pieceImg = pieceImages[piece];
2157
- context.drawImage(pieceImg, xPos, yPos, Be * scale, Be * scale);
2158
- }
2159
- }
2160
- if (lastMove !== null) {
2161
- let i = lastMove, n = i[0], A = i[1], s = n[0], a = n[1], o = A[0], r = A[1];
2162
- // isFlipBoard && (s = 8 - s,
2163
- // a = 9 - a,
2164
- // o = 8 - o,
2165
- // r = 9 - r);
2166
- let l = s * we + pe, d = a * we + Pe, g = o * we + pe, f = r * we + Pe, h = Math.sqrt((l - g) * (l - g) + (d - f) * (d - f)), b = l + (g - l) * (h - 30) / h, c = d + (f - d) * (h - 30) / h;
2167
- await drawLineArrow(context, l * scale, d * scale, b * scale, c * scale, "rgba(128, 171, 69, 0.7)", 15 * scale);
2168
- }
2169
- if (moveList.length > 0) {
2170
- currentMoveId = moveList[moveList.length - 1].moveId;
2171
- await ctx.database.set('cchess_game_records', { channelId }, { currentMoveId });
2172
- }
2173
- if (config.isChessImageWithOutlineEnabled) {
2174
- return await createImage(await canvas.toBuffer('image/png'));
2175
- }
2176
- else {
2177
- return await canvas.toBuffer('image/png');
2178
- }
2179
- }
2180
- async function drawLineArrow(t, e, i, n, A, s = "black", a = 20) {
2181
- var o = .282 * Math.sqrt((e - n) * (e - n) + (i - A) * (i - A));
2182
- o = a;
2183
- var r, l, d = 45, g = 180 * Math.atan2(i - A, e - n) / Math.PI, f = (g + d) * Math.PI / 180, h = (g - d) * Math.PI / 180, b = o * Math.cos(f), c = o * Math.sin(f), u = o * Math.cos(h), v = o * Math.sin(h), m = e > n, w = i > A;
2184
- r = n + b,
2185
- l = A + c;
2186
- var I = n + u, p = A + v, P = w ? r + .25 * Math.abs(I - r) : r - .25 * Math.abs(I - r), B = m ? l - .25 * Math.abs(p - l) : l + .25 * Math.abs(p - l), M = w ? r + .75 * Math.abs(I - r) : r - .75 * Math.abs(I - r), y = m ? l - .75 * Math.abs(p - l) : l + .75 * Math.abs(p - l);
2187
- t.beginPath(),
2188
- t.moveTo(e, i),
2189
- t.lineTo(P, B),
2190
- t.lineTo(r, l),
2191
- t.lineTo(n, A),
2192
- t.lineTo(I, p),
2193
- t.lineTo(M, y),
2194
- t.lineTo(e, i),
2195
- t.closePath(),
2196
- t.strokeStyle = s,
2197
- t.fillStyle = s,
2198
- t.fill(),
2199
- t.stroke();
2200
- }
2201
- function loadPiecesImageResources(folder, format = "webp") {
2202
- const imgResources = {};
2203
- const resources = [
2204
- { prefix: 'w', type: 'rnbakcp' },
2205
- { prefix: 'b', type: 'rnbakcp' },
2206
- ];
2207
- for (const { prefix, type } of resources) {
2208
- const items = Array.from(type);
2209
- for (const item of items) {
2210
- const filename = `${prefix}${item}`;
2211
- const imgFilePath = path.join(__dirname, 'assets', '棋子皮肤', folder, `${filename}.${format}`);
2212
- const key = prefix === 'w' ? item.toUpperCase() : item;
2213
- imgResources[key] = fs.readFileSync(imgFilePath);
2214
- }
2215
- }
2216
- return imgResources;
2217
- }
2218
- function fenToBoard(fenString) {
2219
- let fenParts = fenString.split(" ");
2220
- let rows = fenParts[0].split("/");
2221
- let emptyBoard = getEmptyBoard();
2222
- let pieceTypes = "rnbakRNBAKCPcp".split("");
2223
- let numbers = "123456789".split("");
2224
- for (let rowIdx in rows) {
2225
- let colIdx = 0;
2226
- let currentRow = rows[rowIdx].split("");
2227
- for (let i = 0; i < currentRow.length; i++) {
2228
- if (pieceTypes.includes(currentRow[i])) {
2229
- emptyBoard[rowIdx][colIdx] = currentRow[i];
2230
- colIdx++;
2231
- }
2232
- else if (numbers.includes(currentRow[i])) {
2233
- colIdx += Number(currentRow[i]);
2234
- }
2235
- }
2236
- }
2237
- return emptyBoard;
2238
- }
2239
- function getEmptyBoard() {
2240
- let emptyBoard = [];
2241
- for (let row = 0; row < 10; row++) {
2242
- let currentRow = [];
2243
- for (let col = 0; col < 9; col++) {
2244
- currentRow.push("");
2245
- }
2246
- emptyBoard.push(currentRow);
2247
- }
2248
- return emptyBoard;
2249
- }
2250
- function getPiece(board, position) {
2251
- if (position[0] < 0 || position[0] > 8 || position[1] < 0 || position[1] > 9) {
2252
- return "invalid";
2253
- }
2254
- else {
2255
- const piece = board[position[1]][position[0]];
2256
- return piece ? piece : "";
2257
- }
2258
- }
2259
- let sentMessages = [];
2260
- async function sendMessage(session, message) {
2261
- const { bot, channelId } = session;
2262
- let messageId;
2263
- if (config.isTextToImageConversionEnabled) {
2264
- const lines = message.split('\n');
2265
- const isOnlyImgTag = lines.length === 1 && lines[0].trim().startsWith('<img');
2266
- if (isOnlyImgTag) {
2267
- await session.send(message);
2268
- }
2269
- else {
2270
- const modifiedMessage = lines
2271
- .map((line) => {
2272
- if (line.trim() !== '' && !line.includes('<img')) {
2273
- return `# ${line}`;
2274
- }
2275
- else {
2276
- return line + '\n';
2277
- }
2278
- })
2279
- .join('\n');
2280
- const imageBuffer = await ctx.markdownToImage.convertToImage(modifiedMessage);
2281
- [messageId] = await session.send(koishi_1.h.image(imageBuffer, `image/${config.imageType}`));
2282
- }
2283
- }
2284
- else {
2285
- [messageId] = await session.send(message);
2286
- }
2287
- if (config.retractDelay === 0)
2288
- return;
2289
- sentMessages.push(messageId);
2290
- if (sentMessages.length > 1) {
2291
- const oldestMessageId = sentMessages.shift();
2292
- setTimeout(async () => {
2293
- await bot.deleteMessage(channelId, oldestMessageId);
2294
- }, config.retractDelay * 1000);
2295
- }
2296
- }
1477
+ if (e.length > j + 1 && keywords.includes(e[j])) {
1478
+ infoObj[e[j]] = parseInt(e[j + 1]);
1479
+ j++;
1480
+ } else {
1481
+ infoObj[e[j]] = "";
1482
+ }
1483
+ }
1484
+ }
1485
+ if ("pv" in infoObj) {
1486
+ }
1487
+ } else if (i === "bestmove") {
1488
+ if (e.length === 4 && e[2] === "ponder") {
1489
+ await onEngineBestMove(channelId, e[1], e[3]);
1490
+ } else {
1491
+ await onEngineBestMove(channelId, e[1], null);
1492
+ }
1493
+ } else if (i === "option" || i === "uciok") {
1494
+ }
1495
+ } catch (error) {
1496
+ logger.error(error);
1497
+ }
1498
+ }
1499
+ __name(receiveOutput, "receiveOutput");
1500
+ async function engineMessageHandler(channelId, message) {
1501
+ const { command, wasmType, origin } = message;
1502
+ if (!engines[channelId]) {
1503
+ engines[channelId] = null;
1504
+ }
1505
+ if (command !== void 0) {
1506
+ engines[channelId].send_command(command);
1507
+ } else if (wasmType !== void 0) {
1508
+ const wasmOrigin = origin;
1509
+ const wasmScriptPath = path.join(wasmOrigin, "assets", "wasm", "pikafish.js");
1510
+ const Pikafish = require(wasmScriptPath);
1511
+ const instance = await Pikafish({
1512
+ locateFile: (file) => {
1513
+ if (file === "pikafish.data") {
1514
+ return path.join(wasmOrigin, "assets", "wasm", "data", file);
1515
+ } else {
1516
+ return path.join(wasmOrigin, "assets", "wasm", file);
1517
+ }
1518
+ },
1519
+ setStatus: (status) => {
1520
+ }
1521
+ });
1522
+ engines[channelId] = instance;
1523
+ engines[channelId].read_stdout = async (stdout) => {
1524
+ await receiveOutput(channelId, stdout);
1525
+ };
1526
+ await ctx.database.set("cchess_game_records", { channelId }, { isEngineReady: true });
1527
+ await (0, import_koishi.sleep)(100);
1528
+ await sendCommand(channelId, "uci");
1529
+ await (0, import_koishi.sleep)(100);
1530
+ await setOptionList(channelId, engineSettings);
1531
+ }
1532
+ }
1533
+ __name(engineMessageHandler, "engineMessageHandler");
1534
+ async function initEngine(channelId) {
1535
+ await engineMessageHandler(channelId, { command: void 0, wasmType: "single", origin: __dirname });
1536
+ }
1537
+ __name(initEngine, "initEngine");
1538
+ function findMoveInfo(moveInfoList, moveOperation) {
1539
+ return moveInfoList.find((moveInfo) => moveInfo.figureMoveName === moveOperation);
1540
+ }
1541
+ __name(findMoveInfo, "findMoveInfo");
1542
+ function findLegalMovePositions(moveMap) {
1543
+ const legalPositions = [];
1544
+ for (let i = 0; i < 10; i++) {
1545
+ for (let j = 0; j < 9; j++) {
1546
+ if (moveMap[i][j] === "go" || moveMap[i][j] === "eat") {
1547
+ legalPositions.push([i, j]);
1548
+ }
1549
+ }
1550
+ }
1551
+ return legalPositions;
1552
+ }
1553
+ __name(findLegalMovePositions, "findLegalMovePositions");
1554
+ function findLetterPositions(board, processedLetter) {
1555
+ const positions = [];
1556
+ for (let i = 0; i < board.length; i++) {
1557
+ for (let j = 0; j < board[i].length; j++) {
1558
+ if (board[i][j] === processedLetter) {
1559
+ positions.push([i, j]);
1560
+ }
1561
+ }
1562
+ }
1563
+ return positions;
1564
+ }
1565
+ __name(findLetterPositions, "findLetterPositions");
1566
+ function processEnglishLetter(englishLetter, turn) {
1567
+ if (turn === "w") {
1568
+ return englishLetter.toUpperCase();
1569
+ } else {
1570
+ return englishLetter.toLowerCase();
1571
+ }
1572
+ }
1573
+ __name(processEnglishLetter, "processEnglishLetter");
1574
+ const chineseToEnglishMap = {
1575
+ "": "k",
1576
+ "士": "a",
1577
+ "": "b",
1578
+ "": "r",
1579
+ "": "n",
1580
+ "": "c",
1581
+ "": "p",
1582
+ "": "k",
1583
+ "": "a",
1584
+ "相": "b",
1585
+ "": "p"
1586
+ };
1587
+ function getEnglishLetterFromFigureName(figureName) {
1588
+ return chineseToEnglishMap[figureName] || null;
1589
+ }
1590
+ __name(getEnglishLetterFromFigureName, "getEnglishLetterFromFigureName");
1591
+ function getFigureNameFromMoveOperation(moveOperation) {
1592
+ const figureNamesRegex = new RegExp(possibleFigureNames.join("|"));
1593
+ const figureNameMatches = moveOperation.match(figureNamesRegex);
1594
+ if (figureNameMatches && figureNameMatches.length > 0) {
1595
+ return figureNameMatches[0];
1596
+ }
1597
+ return null;
1598
+ }
1599
+ __name(getFigureNameFromMoveOperation, "getFigureNameFromMoveOperation");
1600
+ function isValidFigureMoveName(move) {
1601
+ const possibleActions = ["", "退", "平"];
1602
+ const possiblePositions = ["", "二", "", "四", "五", "六", "七", "八", "九", "9", "8", "7", "6", "5", "4", "3", "2", "1"];
1603
+ const figureNamesRegex = new RegExp(possibleFigureNames.join("|"));
1604
+ const actionRegex = new RegExp(possibleActions.join("|"));
1605
+ const positionRegex = new RegExp(possiblePositions.join("|"), "g");
1606
+ if (move.length !== 4) {
1607
+ return false;
1608
+ }
1609
+ const figureNameMatches = move.match(figureNamesRegex);
1610
+ const actionMatches = move.match(actionRegex);
1611
+ const positionMatches = move.match(positionRegex);
1612
+ return figureNameMatches && figureNameMatches.length === 1 && actionMatches && actionMatches.length === 1 && positionMatches && positionMatches.length >= 1 && positionMatches.length <= 2;
1613
+ }
1614
+ __name(isValidFigureMoveName, "isValidFigureMoveName");
1615
+ function convertTurnToString(turn) {
1616
+ if (turn === "w") {
1617
+ return "红方";
1618
+ } else if (turn === "b") {
1619
+ return "黑方";
1620
+ }
1621
+ }
1622
+ __name(convertTurnToString, "convertTurnToString");
1623
+ async function createImage(buffer) {
1624
+ const canvas = await ctx.canvas.createCanvas(620 * scale, 780 * scale);
1625
+ const context = canvas.getContext("2d");
1626
+ const outerFrame = await ctx.canvas.loadImage(outerFrameImg);
1627
+ context.drawImage(outerFrame, 0, 0, 620 * scale, 780 * scale);
1628
+ const boardImg = await ctx.canvas.loadImage(buffer);
1629
+ context.drawImage(boardImg, 36.5 * scale, 90 * scale, 550 * scale, 605 * scale);
1630
+ return canvas.toBuffer("image/png");
1631
+ }
1632
+ __name(createImage, "createImage");
1633
+ function isMoveString(str) {
1634
+ const boardLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"];
1635
+ if (str.length !== 4) {
1636
+ return false;
1637
+ }
1638
+ return boardLetters.includes(str[0]) && boardLetters.includes(str[2]) && parseInt(str[1]) >= 0 && parseInt(str[1]) <= 9 && parseInt(str[3]) >= 0 && parseInt(str[3]) <= 9;
1639
+ }
1640
+ __name(isMoveString, "isMoveString");
1641
+ function getType(t) {
1642
+ return t.toLowerCase();
1643
+ }
1644
+ __name(getType, "getType");
1645
+ function getValidMoveMapKings(board, t, e) {
1646
+ let i, n, A = getEmptyBoard(), s = e[0], a = e[1];
1647
+ a <= 2 ? (i = 0, n = 2) : a >= 7 ? (i = 7, n = 9) : (i = a - 1, n = a + 1);
1648
+ let o = 3, r = 5;
1649
+ if (s + 1 <= r) {
1650
+ let e2 = getValidType(board, t, [s + 1, a]);
1651
+ "eat" != e2 && "go" != e2 || setMoveMap(A, [s + 1, a], e2);
1652
+ }
1653
+ if (s - 1 >= o) {
1654
+ let e2 = getValidType(board, t, [s - 1, a]);
1655
+ "eat" != e2 && "go" != e2 || setMoveMap(A, [s - 1, a], e2);
1656
+ }
1657
+ if (a + 1 <= n) {
1658
+ let e2 = getValidType(board, t, [s, a + 1]);
1659
+ "eat" != e2 && "go" != e2 || setMoveMap(A, [s, a + 1], e2);
1660
+ }
1661
+ if (a - 1 >= i) {
1662
+ let e2 = getValidType(board, t, [s, a - 1]);
1663
+ "eat" != e2 && "go" != e2 || setMoveMap(A, [s, a - 1], e2);
1664
+ }
1665
+ return A;
1666
+ }
1667
+ __name(getValidMoveMapKings, "getValidMoveMapKings");
1668
+ function getValidMoveMapCannons(board, t, e) {
1669
+ let i = getEmptyBoard(), n = e[0], A = e[1], s = false;
1670
+ for (let a = n; a < 9; a++) {
1671
+ if (a == n)
1672
+ continue;
1673
+ let e2 = getValidType(board, t, [a, A]);
1674
+ if (s || "block" != e2 && "eat" != e2) {
1675
+ if (s && "eat" == e2) {
1676
+ setMoveMap(i, [a, A], "eat");
1677
+ break;
1678
+ }
1679
+ s || "go" != e2 || setMoveMap(i, [a, A], "go");
1680
+ } else
1681
+ s = true;
1682
+ }
1683
+ s = false;
1684
+ for (let a = n; a >= 0; a--) {
1685
+ if (a == n)
1686
+ continue;
1687
+ let e2 = getValidType(board, t, [a, A]);
1688
+ if (s || "block" != e2 && "eat" != e2) {
1689
+ if (s && "eat" == e2) {
1690
+ setMoveMap(i, [a, A], "eat");
1691
+ break;
1692
+ }
1693
+ s || "go" != e2 || setMoveMap(i, [a, A], "go");
1694
+ } else
1695
+ s = true;
1696
+ }
1697
+ s = false;
1698
+ for (let a = A; a < 10; a++) {
1699
+ if (a == A)
1700
+ continue;
1701
+ let e2 = getValidType(board, t, [n, a]);
1702
+ if (s || "block" != e2 && "eat" != e2) {
1703
+ if (s && "eat" == e2) {
1704
+ setMoveMap(i, [n, a], "eat");
1705
+ break;
1706
+ }
1707
+ s || "go" != e2 || setMoveMap(i, [n, a], "go");
1708
+ } else
1709
+ s = true;
1710
+ }
1711
+ s = false;
1712
+ for (let a = A; a >= 0; a--) {
1713
+ if (a == A)
1714
+ continue;
1715
+ let e2 = getValidType(board, t, [n, a]);
1716
+ if (s || "block" != e2 && "eat" != e2) {
1717
+ if (s && "eat" == e2) {
1718
+ setMoveMap(i, [n, a], "eat");
1719
+ break;
1720
+ }
1721
+ s || "go" != e2 || setMoveMap(i, [n, a], "go");
1722
+ } else
1723
+ s = true;
1724
+ }
1725
+ return i;
1726
+ }
1727
+ __name(getValidMoveMapCannons, "getValidMoveMapCannons");
1728
+ function getSideByKing(board, t) {
1729
+ t[0];
1730
+ let e = t[1];
1731
+ if (e <= 4)
1732
+ for (let i = 3; i <= 5; i++)
1733
+ for (let t2 = 0; t2 <= 2; t2++) {
1734
+ let e2 = getPiece(board, [i, t2]);
1735
+ if ("K" == e2)
1736
+ return "w";
1737
+ if ("k" == e2)
1738
+ return "b";
1739
+ }
1740
+ else
1741
+ for (let i = 3; i <= 5; i++)
1742
+ for (let t2 = 7; t2 <= 9; t2++) {
1743
+ let e2 = getPiece(board, [i, t2]);
1744
+ if ("K" == e2)
1745
+ return "w";
1746
+ if ("k" == e2)
1747
+ return "b";
1748
+ }
1749
+ return "";
1750
+ }
1751
+ __name(getSideByKing, "getSideByKing");
1752
+ function getValidMoveMapPawns(board, t, e) {
1753
+ let i = getEmptyBoard(), n = e[0], A = e[1], s = getSideByKing(board, e);
1754
+ if (t == s)
1755
+ if (A <= 4) {
1756
+ let e2 = getValidType(board, t, [n, A + 1]);
1757
+ "eat" != e2 && "go" != e2 || setMoveMap(i, [n, A + 1], e2);
1758
+ } else {
1759
+ let e2 = getValidType(board, t, [n, A - 1]);
1760
+ "eat" != e2 && "go" != e2 || setMoveMap(i, [n, A - 1], e2);
1761
+ }
1762
+ else {
1763
+ if (A <= 4) {
1764
+ let e3 = getValidType(board, t, [n, A - 1]);
1765
+ "eat" != e3 && "go" != e3 || setMoveMap(i, [n, A - 1], e3);
1766
+ } else {
1767
+ let e3 = getValidType(board, t, [n, A + 1]);
1768
+ "eat" != e3 && "go" != e3 || setMoveMap(i, [n, A + 1], e3);
1769
+ }
1770
+ let e2 = getValidType(board, t, [n + 1, A]);
1771
+ "eat" != e2 && "go" != e2 || setMoveMap(i, [n + 1, A], e2), e2 = getValidType(board, t, [n - 1, A]), "eat" != e2 && "go" != e2 || setMoveMap(i, [n - 1, A], e2);
1772
+ }
1773
+ return i;
1774
+ }
1775
+ __name(getValidMoveMapPawns, "getValidMoveMapPawns");
1776
+ function getValidMoveMapBishops(board, t, e) {
1777
+ let i, n, A = getEmptyBoard(), s = e[0], a = e[1];
1778
+ if (a <= 4 ? (i = 0, n = 4) : a >= 5 ? (i = 5, n = 9) : (i = a - 1, n = a + 1), s + 2 <= 9 && a + 2 <= n) {
1779
+ let e2 = getPiece(board, [s + 1, a + 1]);
1780
+ if ("" == e2) {
1781
+ let e3 = getValidType(board, t, [s + 2, a + 2]);
1782
+ "eat" != e3 && "go" != e3 || setMoveMap(A, [s + 2, a + 2], e3);
1783
+ }
1784
+ }
1785
+ if (s - 2 >= 0 && a + 2 <= n) {
1786
+ let e2 = getPiece(board, [s - 1, a + 1]);
1787
+ if ("" == e2) {
1788
+ let e3 = getValidType(board, t, [s - 2, a + 2]);
1789
+ "eat" != e3 && "go" != e3 || setMoveMap(A, [s - 2, a + 2], e3);
1790
+ }
1791
+ }
1792
+ if (s + 2 <= 9 && a - 2 >= i) {
1793
+ let e2 = getPiece(board, [s + 1, a - 1]);
1794
+ if ("" == e2) {
1795
+ let e3 = getValidType(board, t, [s + 2, a - 2]);
1796
+ "eat" != e3 && "go" != e3 || setMoveMap(A, [s + 2, a - 2], e3);
1797
+ }
1798
+ }
1799
+ if (s - 2 >= 0 && a - 2 >= i) {
1800
+ let e2 = getPiece(board, [s - 1, a - 1]);
1801
+ if ("" == e2) {
1802
+ let e3 = getValidType(board, t, [s - 2, a - 2]);
1803
+ "eat" != e3 && "go" != e3 || setMoveMap(A, [s - 2, a - 2], e3);
1804
+ }
1805
+ }
1806
+ return A;
1807
+ }
1808
+ __name(getValidMoveMapBishops, "getValidMoveMapBishops");
1809
+ function getValidMoveMap(board, type, side, position) {
1810
+ switch (type) {
1811
+ case "r":
1812
+ return getValidMoveMapRooks(board, side, position);
1813
+ case "n":
1814
+ return getValidMoveMapKnights(board, side, position);
1815
+ case "a":
1816
+ return getValidMoveMapAdvisors(board, side, position);
1817
+ case "b":
1818
+ return getValidMoveMapBishops(board, side, position);
1819
+ case "k":
1820
+ return getValidMoveMapKings(board, side, position);
1821
+ case "c":
1822
+ return getValidMoveMapCannons(board, side, position);
1823
+ case "p":
1824
+ return getValidMoveMapPawns(board, side, position);
1825
+ default:
1826
+ return getEmptyBoard();
1827
+ }
1828
+ }
1829
+ __name(getValidMoveMap, "getValidMoveMap");
1830
+ function getValidMoveMapRooks(board, t, e) {
1831
+ let i = getEmptyBoard(), n = e[0], A = e[1];
1832
+ for (let s = n; s < 9; s++) {
1833
+ if (s == n)
1834
+ continue;
1835
+ let e2 = getValidType(board, t, [s, A]);
1836
+ if ("block" == e2)
1837
+ break;
1838
+ if (i[A][s] = e2, "eat" == e2)
1839
+ break;
1840
+ }
1841
+ for (let s = n; s >= 0; s--) {
1842
+ if (s == n)
1843
+ continue;
1844
+ let e2 = getValidType(board, t, [s, A]);
1845
+ if ("block" == e2)
1846
+ break;
1847
+ if (i[A][s] = e2, "eat" == e2)
1848
+ break;
1849
+ }
1850
+ for (let s = A; s < 10; s++) {
1851
+ if (s == A)
1852
+ continue;
1853
+ let e2 = getValidType(board, t, [n, s]);
1854
+ if ("block" == e2)
1855
+ break;
1856
+ if (i[s][n] = e2, "eat" == e2)
1857
+ break;
1858
+ }
1859
+ for (let s = A; s >= 0; s--) {
1860
+ if (s == A)
1861
+ continue;
1862
+ let e2 = getValidType(board, t, [n, s]);
1863
+ if ("block" == e2)
1864
+ break;
1865
+ if (i[s][n] = e2, "eat" == e2)
1866
+ break;
1867
+ }
1868
+ return i;
1869
+ }
1870
+ __name(getValidMoveMapRooks, "getValidMoveMapRooks");
1871
+ function getValidType(board, t, e) {
1872
+ let i = getPiece(board, e);
1873
+ return void 0 == i ? "invalid" : "" == i ? "go" : t != getSide(i) ? "eat" : "block";
1874
+ }
1875
+ __name(getValidType, "getValidType");
1876
+ function getValidMoveMapAdvisors(board, t, e) {
1877
+ let i, n, A = getEmptyBoard(), s = e[0], a = e[1];
1878
+ a <= 2 ? (i = 0, n = 2) : a >= 7 ? (i = 7, n = 9) : (i = a - 1, n = a + 1);
1879
+ let o = 3, r = 5;
1880
+ if (s + 1 <= r && a + 1 <= n) {
1881
+ let e2 = getValidType(board, t, [s + 1, a + 1]);
1882
+ "eat" != e2 && "go" != e2 || setMoveMap(A, [s + 1, a + 1], e2);
1883
+ }
1884
+ if (s - 1 >= o && a + 1 <= n) {
1885
+ let e2 = getValidType(board, t, [s - 1, a + 1]);
1886
+ "eat" != e2 && "go" != e2 || setMoveMap(A, [s - 1, a + 1], e2);
1887
+ }
1888
+ if (s + 1 <= r && a - 1 >= i) {
1889
+ let e2 = getValidType(board, t, [s + 1, a - 1]);
1890
+ "eat" != e2 && "go" != e2 || setMoveMap(A, [s + 1, a - 1], e2);
1891
+ }
1892
+ if (s - 1 >= o && a - 1 >= i) {
1893
+ let e2 = getValidType(board, t, [s - 1, a - 1]);
1894
+ "eat" != e2 && "go" != e2 || setMoveMap(A, [s - 1, a - 1], e2);
1895
+ }
1896
+ return A;
1897
+ }
1898
+ __name(getValidMoveMapAdvisors, "getValidMoveMapAdvisors");
1899
+ function setMoveMap(t, e, i) {
1900
+ e[0] < 0 || e[0] > 8 || e[1] < 0 || e[1] > 9 || (t[e[1]][e[0]] = i);
1901
+ }
1902
+ __name(setMoveMap, "setMoveMap");
1903
+ function getValidMoveMapKnights(board, t, e) {
1904
+ let i = getEmptyBoard(), n = e[0], A = e[1];
1905
+ return "" == getPiece(board, [n + 1, A]) && (setMoveMap(i, [n + 2, A + 1], getValidType(board, t, [n + 2, A + 1])), setMoveMap(i, [n + 2, A - 1], getValidType(board, t, [n + 2, A - 1]))), "" == getPiece(board, [n - 1, A]) && (setMoveMap(i, [n - 2, A + 1], getValidType(board, t, [n - 2, A + 1])), setMoveMap(i, [n - 2, A - 1], getValidType(board, t, [n - 2, A - 1]))), "" == getPiece(board, [n, A + 1]) && (setMoveMap(i, [n + 1, A + 2], getValidType(board, t, [n + 1, A + 2])), setMoveMap(i, [n - 1, A + 2], getValidType(board, t, [n - 1, A + 2]))), "" == getPiece(board, [n, A - 1]) && (setMoveMap(i, [n + 1, A - 2], getValidType(board, t, [n + 1, A - 2])), setMoveMap(i, [n - 1, A - 2], getValidType(board, t, [n - 1, A - 2]))), i;
1906
+ }
1907
+ __name(getValidMoveMapKnights, "getValidMoveMapKnights");
1908
+ var Et = [];
1909
+ Et["w"] = [], Et["b"] = [], Et["w"][0] = "进", Et["w"][1] = "退", Et["b"][0] = "退", Et["b"][1] = "进", Et["p"] = "平";
1910
+ var Ht = [];
1911
+ Ht["w"] = [], Ht["b"] = [], Ht["w"][0] = "前", Ht["w"][1] = "后", Ht["b"][0] = "后", Ht["b"][1] = "前", Ht["m"] = "中";
1912
+ var qt = [];
1913
+ qt["k"] = "将", qt["a"] = "士", qt["b"] = "象", qt["r"] = "车", qt["n"] = "马", qt["c"] = "炮", qt["p"] = "卒", qt["K"] = "帅", qt["A"] = "仕", qt["B"] = "相", qt["R"] = "车", qt["N"] = "马", qt["C"] = "炮", qt["P"] = "兵";
1914
+ var Qt = [];
1915
+ Qt["w"] = [], Qt["b"] = [], Qt["w"][0] = "一", Qt["w"][1] = "二", Qt["w"][2] = "三", Qt["w"][3] = "四", Qt["w"][4] = "五", Qt["w"][5] = "六", Qt["w"][6] = "七", Qt["w"][7] = "八", Qt["w"][8] = "九", // Qt["b"][0] = "9",
1916
+ // Qt["b"][1] = "8",
1917
+ // Qt["b"][2] = "7",
1918
+ // Qt["b"][3] = "6",
1919
+ // Qt["b"][4] = "5",
1920
+ // Qt["b"][5] = "4",
1921
+ // Qt["b"][6] = "3",
1922
+ // Qt["b"][7] = "2",
1923
+ // Qt["b"][8] = "1";
1924
+ Qt["b"][0] = "9", Qt["b"][1] = "8", Qt["b"][2] = "7", Qt["b"][3] = "6", Qt["b"][4] = "5", Qt["b"][5] = "4", Qt["b"][6] = "3", Qt["b"][7] = "2", Qt["b"][8] = "1";
1925
+ function parseChessNotation(fen) {
1926
+ let e = [];
1927
+ for (let s = 0; s < 9; s++) {
1928
+ e[s] = [];
1929
+ for (let t = 0; t < 10; t++)
1930
+ e[s][t] = 0;
1931
+ }
1932
+ let i = fen.split(" ")[0].split("/"), n = ["k", "a", "b", "r", "n", "c", "p", "K", "A", "B", "R", "N", "C", "P"], A = 0;
1933
+ for (let s = 0; s < 10; s++) {
1934
+ let t = i[s], a = 0;
1935
+ for (let i2 = 0; i2 < t.length; i2++) {
1936
+ let o = t[i2];
1937
+ if (o >= "0" && o <= "9")
1938
+ a += parseInt(o);
1939
+ else if (-1 != n.indexOf(o)) {
1940
+ let t2 = o >= "a" && o <= "z" ? "b" : "w";
1941
+ e[a][s] = t2 + o + A, a++, A++;
1942
+ }
1943
+ }
1944
+ }
1945
+ return e;
1946
+ }
1947
+ __name(parseChessNotation, "parseChessNotation");
1948
+ function getFigureMoveName(fen, moveString) {
1949
+ let i = parseChessNotation(fen);
1950
+ var n = moveString.charCodeAt(0) - 97, A = 9 - (moveString.charCodeAt(1) - 48), s = moveString.charCodeAt(2) - 97, a = 9 - (moveString.charCodeAt(3) - 48), o = 0, r = 0, l = 0, d = "";
1951
+ if ("A" != i[n][A].charAt(1) && "B" != i[n][A].charAt(1) && "a" != i[n][A].charAt(1) && "b" != i[n][A].charAt(1)) {
1952
+ for (var g = 0; g < 9; g++)
1953
+ if (g != n) {
1954
+ for (var f = 0; f < 10; f++)
1955
+ 0 != i[g][f] && i[g][f].substring(0, 2) == i[n][A].substring(0, 2) && l++;
1956
+ l < 2 && (l = 0);
1957
+ }
1958
+ for (f = 0; f < 10; f++)
1959
+ 0 != i[n][f] && i[n][f].substring(0, 2) == i[n][A].substring(0, 2) && (f < A ? 0 == l ? (d = Ht[i[n][A].charAt(0)][1] + qt[i[n][A].charAt(1)], o++) : (d = Ht[i[n][A].charAt(0)][1] + Qt[i[n][A].charAt(0)][9 - n - 1], o++) : f == A ? 0 == o ? d = qt[i[n][A].charAt(1)] + Qt[i[n][A].charAt(0)][9 - n - 1] : r = o : 0 == l ? 0 == o ? d = Ht[i[n][A].charAt(0)][0] + qt[i[n][A].charAt(1)] : (d = Ht["m"] + qt[i[n][A].charAt(1)], o++) : 0 == o ? d = Ht[i[n][A].charAt(0)][0] + Qt[i[n][A].charAt(0)][9 - n - 1] : (d = Ht["m"] + Qt[i[n][A].charAt(0)][9 - n - 1], o++));
1960
+ o > 2 && o != r && (d = "w" == i[n][A].charAt(0) ? Qt["w"][r] + qt[i[n][A].charAt(1)] : Qt["w"][o - r] + qt[i[n][A].charAt(1)]);
1961
+ } else
1962
+ d = qt[i[n][A].charAt(1)] + Qt[i[n][A].charAt(0)][9 - n - 1];
1963
+ var h2 = "";
1964
+ return h2 = A > a ? n == s ? "w" == i[n][A].charAt(0) ? Et[i[n][A].charAt(0)][0] + Qt[i[n][A].charAt(0)][A - a - 1] : Et[i[n][A].charAt(0)][0] + Qt[i[n][A].charAt(0)][9 - (A - a - 1) - 1] : Et[i[n][A].charAt(0)][0] + Qt[i[n][A].charAt(0)][9 - s - 1] : A == a ? Et["p"] + Qt[i[n][A].charAt(0)][9 - s - 1] : n == s ? "w" == i[n][A].charAt(0) ? Et[i[n][A].charAt(0)][1] + Qt[i[n][A].charAt(0)][a - A - 1] : Et[i[n][A].charAt(0)][1] + Qt[i[n][A].charAt(0)][9 - (a - A - 1) - 1] : Et[i[n][A].charAt(0)][1] + Qt[i[n][A].charAt(0)][9 - s - 1], d + h2;
1965
+ }
1966
+ __name(getFigureMoveName, "getFigureMoveName");
1967
+ function moveToMoveString(move) {
1968
+ const boardLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"];
1969
+ let startSquare = move[0];
1970
+ let endSquare = move[1];
1971
+ let startSquareAlgebraic = boardLetters[startSquare[0]] + (9 - startSquare[1]).toString();
1972
+ let endSquareAlgebraic = boardLetters[endSquare[0]] + (9 - endSquare[1]).toString();
1973
+ return startSquareAlgebraic + endSquareAlgebraic;
1974
+ }
1975
+ __name(moveToMoveString, "moveToMoveString");
1976
+ function moveStringToMove(moveString) {
1977
+ const boardLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"];
1978
+ let startSquareAlgebraic = moveString.substring(0, 2);
1979
+ let endSquareAlgebraic = moveString.substring(2);
1980
+ let startSquare = [boardLetters.indexOf(startSquareAlgebraic[0]), 9 - parseInt(startSquareAlgebraic[1])];
1981
+ let endSquare = [boardLetters.indexOf(endSquareAlgebraic[0]), 9 - parseInt(endSquareAlgebraic[1])];
1982
+ return [startSquare, endSquare];
1983
+ }
1984
+ __name(moveStringToMove, "moveStringToMove");
1985
+ function genRandomId(length) {
1986
+ let id = "";
1987
+ const characters = "abcdefghijklmnopqrstuvwxyz0123456789";
1988
+ for (let i = 0; i < length; i++) {
1989
+ id += characters.charAt(Math.floor(Math.random() * characters.length));
1990
+ }
1991
+ return id;
1992
+ }
1993
+ __name(genRandomId, "genRandomId");
1994
+ async function makeMove(channelId, fromPos, toPos) {
1995
+ const gameRecord = await getGameRecord(channelId);
1996
+ let {
1997
+ turn,
1998
+ board,
1999
+ moveTreePtr,
2000
+ moveList,
2001
+ isHistoryMode,
2002
+ boardAfterLastEat,
2003
+ turnAfterLastEat,
2004
+ movesAfterLastEat
2005
+ } = gameRecord;
2006
+ if (isHistoryMode) {
2007
+ gameRecord.isHistoryMode = false;
2008
+ }
2009
+ const lastMove = [fromPos, toPos];
2010
+ const moveId = genRandomId(8);
2011
+ const pieceAtDestination = board[toPos[1]][toPos[0]] !== "";
2012
+ const side = getSide(getPiece(board, fromPos));
2013
+ const fen = getFen(board, side);
2014
+ if (board[toPos[1]][toPos[0]] === "K" || board[toPos[1]][toPos[0]] === "k") {
2015
+ await ctx.database.set("cchess_game_records", { channelId }, {
2016
+ winSide: board[toPos[1]][toPos[0]] === "K" ? "b" : "w",
2017
+ loseSide: board[toPos[1]][toPos[0]] === "K" ? "w" : "b"
2018
+ });
2019
+ }
2020
+ board[toPos[1]][toPos[0]] = board[fromPos[1]][fromPos[0]];
2021
+ board[fromPos[1]][fromPos[0]] = "";
2022
+ turn = turn === getSide(board[toPos[1]][toPos[0]]) ? turn === "w" ? "b" : "w" : turn;
2023
+ const moveString = moveToMoveString([fromPos, toPos]);
2024
+ const figureMoveName = getFigureMoveName(fen, moveString);
2025
+ const moveData = {
2026
+ moveId,
2027
+ fen: getFen(board, turn),
2028
+ side,
2029
+ moveCord: [fromPos, toPos],
2030
+ move: moveString,
2031
+ chnMoveName: figureMoveName,
2032
+ next: null
2033
+ };
2034
+ moveList.push(moveData);
2035
+ moveTreePtr.next = moveData;
2036
+ moveTreePtr = moveData;
2037
+ if (pieceAtDestination) {
2038
+ boardAfterLastEat = fenToBoard(getFen(board, turn));
2039
+ turnAfterLastEat = turn;
2040
+ movesAfterLastEat = [];
2041
+ } else {
2042
+ movesAfterLastEat.push(moveData);
2043
+ }
2044
+ const updatedGameRecord = {
2045
+ turn,
2046
+ board,
2047
+ lastMove,
2048
+ moveTreePtr,
2049
+ moveList,
2050
+ isHistoryMode,
2051
+ boardAfterLastEat,
2052
+ turnAfterLastEat,
2053
+ movesAfterLastEat
2054
+ };
2055
+ Object.assign(gameRecord, updatedGameRecord);
2056
+ await ctx.database.set("cchess_game_records", { channelId }, updatedGameRecord);
2057
+ }
2058
+ __name(makeMove, "makeMove");
2059
+ function getFen(board, turn) {
2060
+ return boardToFen(board, "w", turn);
2061
+ }
2062
+ __name(getFen, "getFen");
2063
+ function boardToFen(board, side, turn = "w") {
2064
+ if (board === null) {
2065
+ return "";
2066
+ }
2067
+ const ranks = side === "w" ? [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] : [9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
2068
+ let fenString = "";
2069
+ for (const row of ranks) {
2070
+ let emptyCount = 0;
2071
+ for (let col = 0; col < 9; col++) {
2072
+ const piece = board[row][col];
2073
+ if (piece === "") {
2074
+ emptyCount++;
2075
+ } else {
2076
+ if (emptyCount > 0) {
2077
+ fenString += emptyCount;
2078
+ emptyCount = 0;
2079
+ }
2080
+ fenString += piece;
2081
+ }
2082
+ }
2083
+ if (emptyCount > 0) {
2084
+ fenString += emptyCount;
2085
+ }
2086
+ fenString += "/";
2087
+ }
2088
+ fenString = fenString.substring(0, fenString.length - 1) + " " + turn;
2089
+ return fenString;
2090
+ }
2091
+ __name(boardToFen, "boardToFen");
2092
+ function getSide(piece) {
2093
+ let e = "RNBAKCP";
2094
+ return e.includes(piece) ? "w" : "b";
2095
+ }
2096
+ __name(getSide, "getSide");
2097
+ async function getGameRecord(channelId) {
2098
+ let gameRecord = await ctx.database.get("cchess_game_records", { channelId });
2099
+ if (gameRecord.length === 0) {
2100
+ await ctx.database.create("cchess_game_records", {
2101
+ channelId
2102
+ });
2103
+ gameRecord = await ctx.database.get("cchess_game_records", { channelId });
2104
+ }
2105
+ return gameRecord[0];
2106
+ }
2107
+ __name(getGameRecord, "getGameRecord");
2108
+ async function drawChessBoard(channelId) {
2109
+ const gameRecord = await getGameRecord(channelId);
2110
+ let { board, lastMove, moveList, currentMoveId } = gameRecord;
2111
+ const canvas = await ctx.canvas.createCanvas(weight * scale, height * scale);
2112
+ const context = canvas.getContext("2d");
2113
+ const boardImg = await ctx.canvas.loadImage(boardSkinImg);
2114
+ context.drawImage(boardImg, 0, 0, weight * scale, height * scale);
2115
+ const pieceImages = {};
2116
+ const pieceImagePromises = Object.keys(piecesImgResources).map((piece) => {
2117
+ return ctx.canvas.loadImage(piecesImgResources[piece]).then((img) => {
2118
+ pieceImages[piece] = img;
2119
+ });
2120
+ });
2121
+ await Promise.all(pieceImagePromises);
2122
+ for (let row = 0; row < 10; row++) {
2123
+ for (let col = 0; col < 9; col++) {
2124
+ const piece = getPiece(board, [col, row]);
2125
+ if (piece === "")
2126
+ continue;
2127
+ const xPos = ((isFlipBoard ? 8 - col : col) * we + Pe - Be / 2) * scale;
2128
+ const yPos = ((isFlipBoard ? 9 - row : row) * we + Pe - Be / 2) * scale;
2129
+ const pieceImg = pieceImages[piece];
2130
+ context.drawImage(pieceImg, xPos, yPos, Be * scale, Be * scale);
2131
+ }
2132
+ }
2133
+ if (lastMove !== null) {
2134
+ let i = lastMove, n = i[0], A = i[1], s = n[0], a = n[1], o = A[0], r = A[1];
2135
+ let l = s * we + pe, d = a * we + Pe, g = o * we + pe, f = r * we + Pe, h2 = Math.sqrt((l - g) * (l - g) + (d - f) * (d - f)), b = l + (g - l) * (h2 - 30) / h2, c = d + (f - d) * (h2 - 30) / h2;
2136
+ await drawLineArrow(context, l * scale, d * scale, b * scale, c * scale, "rgba(128, 171, 69, 0.7)", 15 * scale);
2137
+ }
2138
+ if (moveList.length > 0) {
2139
+ currentMoveId = moveList[moveList.length - 1].moveId;
2140
+ await ctx.database.set("cchess_game_records", { channelId }, { currentMoveId });
2141
+ }
2142
+ if (config.isChessImageWithOutlineEnabled) {
2143
+ return await createImage(await canvas.toBuffer("image/png"));
2144
+ } else {
2145
+ return await canvas.toBuffer("image/png");
2146
+ }
2147
+ }
2148
+ __name(drawChessBoard, "drawChessBoard");
2149
+ async function drawLineArrow(t, e, i, n, A, s = "black", a = 20) {
2150
+ var o = 0.282 * Math.sqrt((e - n) * (e - n) + (i - A) * (i - A));
2151
+ o = a;
2152
+ var r, l, d = 45, g = 180 * Math.atan2(i - A, e - n) / Math.PI, f = (g + d) * Math.PI / 180, h2 = (g - d) * Math.PI / 180, b = o * Math.cos(f), c = o * Math.sin(f), u = o * Math.cos(h2), v = o * Math.sin(h2), m = e > n, w = i > A;
2153
+ r = n + b, l = A + c;
2154
+ var I = n + u, p = A + v, P = w ? r + 0.25 * Math.abs(I - r) : r - 0.25 * Math.abs(I - r), B = m ? l - 0.25 * Math.abs(p - l) : l + 0.25 * Math.abs(p - l), M = w ? r + 0.75 * Math.abs(I - r) : r - 0.75 * Math.abs(I - r), y = m ? l - 0.75 * Math.abs(p - l) : l + 0.75 * Math.abs(p - l);
2155
+ t.beginPath(), t.moveTo(e, i), t.lineTo(P, B), t.lineTo(r, l), t.lineTo(n, A), t.lineTo(I, p), t.lineTo(M, y), t.lineTo(e, i), t.closePath(), t.strokeStyle = s, t.fillStyle = s, t.fill(), t.stroke();
2156
+ }
2157
+ __name(drawLineArrow, "drawLineArrow");
2158
+ function loadPiecesImageResources(folder, format = "webp") {
2159
+ const imgResources = {};
2160
+ const resources = [
2161
+ { prefix: "w", type: "rnbakcp" },
2162
+ { prefix: "b", type: "rnbakcp" }
2163
+ ];
2164
+ for (const { prefix, type } of resources) {
2165
+ const items = Array.from(type);
2166
+ for (const item of items) {
2167
+ const filename = `${prefix}${item}`;
2168
+ const imgFilePath = path.join(__dirname, "assets", "棋子皮肤", folder, `${filename}.${format}`);
2169
+ const key = prefix === "w" ? item.toUpperCase() : item;
2170
+ imgResources[key] = fs.readFileSync(imgFilePath);
2171
+ }
2172
+ }
2173
+ return imgResources;
2174
+ }
2175
+ __name(loadPiecesImageResources, "loadPiecesImageResources");
2176
+ function fenToBoard(fenString) {
2177
+ let fenParts = fenString.split(" ");
2178
+ let rows = fenParts[0].split("/");
2179
+ let emptyBoard = getEmptyBoard();
2180
+ let pieceTypes = "rnbakRNBAKCPcp".split("");
2181
+ let numbers = "123456789".split("");
2182
+ for (let rowIdx in rows) {
2183
+ let colIdx = 0;
2184
+ let currentRow = rows[rowIdx].split("");
2185
+ for (let i = 0; i < currentRow.length; i++) {
2186
+ if (pieceTypes.includes(currentRow[i])) {
2187
+ emptyBoard[rowIdx][colIdx] = currentRow[i];
2188
+ colIdx++;
2189
+ } else if (numbers.includes(currentRow[i])) {
2190
+ colIdx += Number(currentRow[i]);
2191
+ }
2192
+ }
2193
+ }
2194
+ return emptyBoard;
2195
+ }
2196
+ __name(fenToBoard, "fenToBoard");
2197
+ function getEmptyBoard() {
2198
+ let emptyBoard = [];
2199
+ for (let row = 0; row < 10; row++) {
2200
+ let currentRow = [];
2201
+ for (let col = 0; col < 9; col++) {
2202
+ currentRow.push("");
2203
+ }
2204
+ emptyBoard.push(currentRow);
2205
+ }
2206
+ return emptyBoard;
2207
+ }
2208
+ __name(getEmptyBoard, "getEmptyBoard");
2209
+ function getPiece(board, position) {
2210
+ if (position[0] < 0 || position[0] > 8 || position[1] < 0 || position[1] > 9) {
2211
+ return "invalid";
2212
+ } else {
2213
+ const piece = board[position[1]][position[0]];
2214
+ return piece ? piece : "";
2215
+ }
2216
+ }
2217
+ __name(getPiece, "getPiece");
2218
+ let sentMessages = [];
2219
+ async function sendMessage(session, message) {
2220
+ const { bot, channelId } = session;
2221
+ let messageId;
2222
+ if (config.isTextToImageConversionEnabled) {
2223
+ const lines = message.split("\n");
2224
+ const isOnlyImgTag = lines.length === 1 && lines[0].trim().startsWith("<img");
2225
+ if (isOnlyImgTag) {
2226
+ await session.send(message);
2227
+ } else {
2228
+ const modifiedMessage = lines.map((line) => {
2229
+ if (line.trim() !== "" && !line.includes("<img")) {
2230
+ return `# ${line}`;
2231
+ } else {
2232
+ return line + "\n";
2233
+ }
2234
+ }).join("\n");
2235
+ const imageBuffer = await ctx.markdownToImage.convertToImage(modifiedMessage);
2236
+ [messageId] = await session.send(import_koishi.h.image(imageBuffer, `image/${config.imageType}`));
2237
+ }
2238
+ } else {
2239
+ [messageId] = await session.send(message);
2240
+ }
2241
+ if (config.retractDelay === 0)
2242
+ return;
2243
+ sentMessages.push(messageId);
2244
+ if (sentMessages.length > 1) {
2245
+ const oldestMessageId = sentMessages.shift();
2246
+ setTimeout(async () => {
2247
+ await bot.deleteMessage(channelId, oldestMessageId);
2248
+ }, config.retractDelay * 1e3);
2249
+ }
2250
+ }
2251
+ __name(sendMessage, "sendMessage");
2297
2252
  }
2253
+ __name(apply, "apply");
2254
+ // Annotate the CommonJS export names for ESM import in node:
2255
+ 0 && (module.exports = {
2256
+ Config,
2257
+ apply,
2258
+ inject,
2259
+ name,
2260
+ usage
2261
+ });