koishi-plugin-wordle-game 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export declare const inject: {
4
4
  optional: string[];
5
5
  };
6
6
  export declare const name = "wordle-game";
7
- export declare const usage = "## \uD83C\uDFA3 \u4F7F\u7528\n\n- \u542F\u52A8\u5FC5\u8981\u7684\u670D\u52A1\u3002\u60A8\u9700\u8981\u542F\u7528 `monetary`\uFF0C`database` \u548C `puppeteer` \u63D2\u4EF6\uFF0C\u4EE5\u5B9E\u73B0\u8D27\u5E01\u7CFB\u7EDF\uFF0C\u6570\u636E\u5B58\u50A8\u548C\u56FE\u7247\u751F\u6210\u7684\u529F\u80FD\u3002\n- \u5EFA\u8BAE\u81EA\u884C\u6DFB\u52A0\u6307\u4EE4\u522B\u540D\uFF0C\u4EE5\u65B9\u4FBF\u60A8\u548C\u60A8\u7684\u7528\u6237\u4F7F\u7528\u3002\n- \u4EAB\u53D7\u731C\u5355\u8BCD\u6E38\u620F\u5427\uFF01\uD83D\uDE0A\n\n## \uD83C\uDFB3 \u6E38\u620F\u6307\u4EE4\n\n\u4EE5\u4E0B\u662F\u8BE5\u63D2\u4EF6\u63D0\u4F9B\u7684\u6307\u4EE4\u5217\u8868:\n\n### \u6E38\u620F\u64CD\u4F5C\n\n- `wordleGame.\u52A0\u5165 [money:number]` - \u52A0\u5165\u6E38\u620F\uFF0C\u53EF\u9009\u53C2\u6570\u4E3A\u6295\u5165\u7684\u8D27\u5E01\u6570\u989D\u3002\n- `wordleGame.\u9000\u51FA` - \u9000\u51FA\u6E38\u620F\uFF0C\u53EA\u80FD\u5728\u6E38\u620F\u672A\u5F00\u59CB\u65F6\u4F7F\u7528\u3002\n- `wordleGame.\u7ED3\u675F` - \u7ED3\u675F\u6E38\u620F\uFF0C\u53EA\u80FD\u5728\u6E38\u620F\u5DF2\u5F00\u59CB\u65F6\u4F7F\u7528\u3002\n\n### \u6E38\u620F\u6A21\u5F0F\n\n- `wordleGame.\u5F00\u59CB [guessWordLength:number]` - \u5F00\u59CB\u6E38\u620F\u5F15\u5BFC\uFF0C\u53EF\u9009\u53C2\u6570\u4E3A\u731C\u5355\u8BCD\u7684\u957F\u5EA6\u3002\n- `wordleGame.\u5F00\u59CB.\u7ECF\u5178` - \u5F00\u59CB\u7ECF\u5178\u731C\u5355\u8BCD\u6E38\u620F\uFF0C\u9700\u8981\u6295\u5165\u8D27\u5E01\uFF0C\u8D62\u4E86\u6709\u5956\u52B1\u3002\n - `--hard` - \u6307\u4EE4\u7684\u9009\u9879\uFF0C\u56F0\u96BE\u6A21\u5F0F\uFF0C\u540E\u7EED\u731C\u5355\u8BCD\u5FC5\u987B\u4F7F\u7528\u524D\u9762\u6B63\u786E\u6216\u51FA\u73B0\u7684\u5B57\u6BCD\u3002\n- `wordleGame.\u5F00\u59CB.CET4/6/GMAT/GRE/IELTS/SAT/TOEFL/\u8003\u7814/\u4E13\u516B/\u4E13\u56DB/ALL [guessWordLength:number]` -\n \u5F00\u59CB\u731C\u4E0D\u540C\u8003\u8BD5/\u7C7B\u522B\u7684\u5355\u8BCD\u6E38\u620F\uFF0C\u53EF\u9009\u53C2\u6570\u4E3A\u731C\u5355\u8BCD\u7684\u957F\u5EA6\u3002\n - `--hard` - \u6307\u4EE4\u7684\u9009\u9879\uFF0C\u56F0\u96BE\u6A21\u5F0F\uFF0C\u540E\u7EED\u731C\u5355\u8BCD\u5FC5\u987B\u4F7F\u7528\u524D\u9762\u6B63\u786E\u6216\u51FA\u73B0\u7684\u5B57\u6BCD\u3002\n\n### \u6E38\u620F\u64CD\u4F5C\n\n- `wordleGame.\u731C [inputWord:text]` - \u731C\u5355\u8BCD\uFF0C\u53C2\u6570\u4E3A\u8F93\u5165\u7684\u5355\u8BCD\u3002\n- `wordleGame.\u67E5\u8BE2\u8FDB\u5EA6` - \u67E5\u8BE2\u5F53\u524D\u6E38\u620F\u8FDB\u5EA6\u3002\n\n### \u6570\u636E\u67E5\u8BE2\n\n- `wordleGame.\u67E5\u8BE2\u5355\u8BCD [targetWord:text]` - \u5728 ALL \u8BCD\u5E93\u4E2D\u67E5\u8BE2\u5355\u8BCD\u4FE1\u606F\uFF08\u7FFB\u8BD1\uFF09\u3002\n- `wordleGame.\u67E5\u8BE2\u73A9\u5BB6\u8BB0\u5F55 [targetUser:text]` - \u67E5\u8BE2\u73A9\u5BB6\u8BB0\u5F55\uFF0C\u53EF\u9009\u53C2\u6570\u4E3A\u76EE\u6807\u73A9\u5BB6\u7684 at \u4FE1\u606F\u3002\n- `wordleGame.\u6392\u884C\u699C [number:number]` - \u67E5\u770B\u6392\u884C\u699C\uFF0C\u53EF\u9009\u53C2\u6570\u4E3A\u6392\u884C\u699C\u7684\u4EBA\u6570\u3002\n- `wordleGame.\u6392\u884C\u699C.\u635F\u76CA/\u603B.\u80DC\u573A/\u603B.\u8F93\u573A/\u7ECF\u5178/CET4/CET6/GMAT/GRE/IELTS/SAT/TOEFL/\u8003\u7814/\u4E13\u516B/\u4E13\u56DB/ALL.\u80DC\u573A/\u8F93\u573A [number:number]` -\n \u67E5\u770B\u4E0D\u540C\u6A21\u5F0F\u7684\u73A9\u5BB6\u6392\u884C\u699C\uFF0C\u53EF\u9009\u53C2\u6570\u4E3A\u6392\u884C\u699C\u7684\u4EBA\u6570\u3002";
7
+ export declare const usage = "## \uD83C\uDFA3 \u4F7F\u7528\n\n- \u542F\u52A8\u5FC5\u8981\u7684\u670D\u52A1\u3002\u60A8\u9700\u8981\u542F\u7528 `monetary`\uFF0C`database` \u548C `puppeteer` \u63D2\u4EF6\uFF0C\u4EE5\u5B9E\u73B0\u8D27\u5E01\u7CFB\u7EDF\uFF0C\u6570\u636E\u5B58\u50A8\u548C\u56FE\u7247\u751F\u6210\u7684\u529F\u80FD\u3002\n- \u5EFA\u8BAE\u81EA\u884C\u6DFB\u52A0\u6307\u4EE4\u522B\u540D\uFF0C\u4EE5\u65B9\u4FBF\u60A8\u548C\u60A8\u7684\u7528\u6237\u4F7F\u7528\u3002\n- \u4EAB\u53D7\u731C\u5355\u8BCD\u6E38\u620F\u5427\uFF01\uD83D\uDE0A\n\n## \uD83C\uDFB3 \u6E38\u620F\u6307\u4EE4\n\n\u4EE5\u4E0B\u662F\u8BE5\u63D2\u4EF6\u63D0\u4F9B\u7684\u6307\u4EE4\u5217\u8868:\n\n### \u6E38\u620F\u64CD\u4F5C\n\n- `wordleGame.\u52A0\u5165 [money:number]` - \u52A0\u5165\u6E38\u620F\uFF0C\u53EF\u9009\u53C2\u6570\u4E3A\u6295\u5165\u7684\u8D27\u5E01\u6570\u989D\u3002\n- `wordleGame.\u9000\u51FA` - \u9000\u51FA\u6E38\u620F\uFF0C\u53EA\u80FD\u5728\u6E38\u620F\u672A\u5F00\u59CB\u65F6\u4F7F\u7528\u3002\n- `wordleGame.\u7ED3\u675F` - \u7ED3\u675F\u6E38\u620F\uFF0C\u53EA\u80FD\u5728\u6E38\u620F\u5DF2\u5F00\u59CB\u65F6\u4F7F\u7528\u3002\n\n### \u6E38\u620F\u6A21\u5F0F\n\n- `wordleGame.\u5F00\u59CB [guessWordLength:number]` - \u5F00\u59CB\u6E38\u620F\u5F15\u5BFC\uFF0C\u53EF\u9009\u53C2\u6570\u4E3A\u731C\u5355\u8BCD\u7684\u957F\u5EA6\u3002\n- `wordleGame.\u5F00\u59CB.\u7ECF\u5178` - \u5F00\u59CB\u7ECF\u5178\u731C\u5355\u8BCD\u6E38\u620F\uFF0C\u9700\u8981\u6295\u5165\u8D27\u5E01\uFF0C\u8D62\u4E86\u6709\u5956\u52B1\u3002\n - `--hard` - \u6307\u4EE4\u7684\u9009\u9879\uFF0C\u56F0\u96BE\u6A21\u5F0F\uFF0C\u540E\u7EED\u731C\u5355\u8BCD\u5FC5\u987B\u4F7F\u7528\u524D\u9762\u6B63\u786E\u6216\u51FA\u73B0\u7684\u5B57\u6BCD\u3002\n- `wordleGame.\u5F00\u59CB.CET4/6/GMAT/GRE/IELTS/SAT/TOEFL/\u8003\u7814/\u4E13\u516B/\u4E13\u56DB/ALL [guessWordLength:number]` -\n \u5F00\u59CB\u731C\u4E0D\u540C\u8003\u8BD5/\u7C7B\u522B\u7684\u5355\u8BCD\u6E38\u620F\uFF0C\u53EF\u9009\u53C2\u6570\u4E3A\u731C\u5355\u8BCD\u7684\u957F\u5EA6\u3002\n - `--hard` - \u6307\u4EE4\u7684\u9009\u9879\uFF0C\u56F0\u96BE\u6A21\u5F0F\uFF0C\u540E\u7EED\u731C\u5355\u8BCD\u5FC5\u987B\u4F7F\u7528\u524D\u9762\u6B63\u786E\u6216\u51FA\u73B0\u7684\u5B57\u6BCD\u3002\n\n### \u6E38\u620F\u64CD\u4F5C\n\n- `wordleGame.\u731C [inputWord:text]` - \u731C\u5355\u8BCD\uFF0C\u53C2\u6570\u4E3A\u8F93\u5165\u7684\u5355\u8BCD\u3002\n- `wordleGame.\u67E5\u8BE2\u8FDB\u5EA6` - \u67E5\u8BE2\u5F53\u524D\u6E38\u620F\u8FDB\u5EA6\u3002\n\n### \u6570\u636E\u67E5\u8BE2\n\n- `wordleGame.\u67E5\u8BE2\u5355\u8BCD [targetWord:text]` - \u5728 ALL \u8BCD\u5E93\u4E2D\u67E5\u8BE2\u5355\u8BCD\u4FE1\u606F\uFF08\u7FFB\u8BD1\uFF09\u3002\n- `wordleGame.\u67E5\u8BE2\u73A9\u5BB6\u8BB0\u5F55 [targetUser:text]` - \u67E5\u8BE2\u73A9\u5BB6\u8BB0\u5F55\uFF0C\u53EF\u9009\u53C2\u6570\u4E3A\u76EE\u6807\u73A9\u5BB6\u7684 at \u4FE1\u606F\u3002\n- `wordleGame.\u6392\u884C\u699C [number:number]` - \u67E5\u770B\u6392\u884C\u699C\uFF0C\u53EF\u9009\u53C2\u6570\u4E3A\u6392\u884C\u699C\u7684\u4EBA\u6570\u3002\n- `wordleGame.\u6392\u884C\u699C.\u635F\u76CA/\u603B.\u80DC\u573A/\u603B.\u8F93\u573A/\u7ECF\u5178/CET4/CET6/GMAT/GRE/IELTS/SAT/TOEFL/\u8003\u7814/\u4E13\u516B/\u4E13\u56DB/ALL.\u80DC\u573A/\u8F93\u573A/\u6700\u5FEB\u7528\u65F6 [number:number]` -\n \u67E5\u770B\u4E0D\u540C\u6A21\u5F0F\u7684\u73A9\u5BB6\u6392\u884C\u699C\uFF0C\u53EF\u9009\u53C2\u6570\u4E3A\u6392\u884C\u699C\u7684\u4EBA\u6570\u3002";
8
8
  export interface Config {
9
9
  defaultMaxLeaderboardEntries: number;
10
10
  defaultWordLengthForGuessing: number;
@@ -66,6 +66,7 @@ export interface PlayerRecord {
66
66
  moneyChange: number;
67
67
  wordGuessCount: number;
68
68
  stats: PlayerStats;
69
+ fastestGuessTime: Record<string, number>;
69
70
  }
70
71
  interface PlayerStats {
71
72
  经典?: WinLoseStats;
package/lib/index.js CHANGED
@@ -68,7 +68,7 @@ exports.usage = `## 🎣 使用
68
68
  - \`wordleGame.查询单词 [targetWord:text]\` - 在 ALL 词库中查询单词信息(翻译)。
69
69
  - \`wordleGame.查询玩家记录 [targetUser:text]\` - 查询玩家记录,可选参数为目标玩家的 at 信息。
70
70
  - \`wordleGame.排行榜 [number:number]\` - 查看排行榜,可选参数为排行榜的人数。
71
- - \`wordleGame.排行榜.损益/总.胜场/总.输场/经典/CET4/CET6/GMAT/GRE/IELTS/SAT/TOEFL/考研/专八/专四/ALL.胜场/输场 [number:number]\` -
71
+ - \`wordleGame.排行榜.损益/总.胜场/总.输场/经典/CET4/CET6/GMAT/GRE/IELTS/SAT/TOEFL/考研/专八/专四/ALL.胜场/输场/最快用时 [number:number]\` -
72
72
  查看不同模式的玩家排行榜,可选参数为排行榜的人数。`;
73
73
  exports.Config = koishi_1.Schema.intersect([
74
74
  koishi_1.Schema.object({
@@ -114,6 +114,20 @@ const initialStats = {
114
114
  专四: { win: 0, lose: 0 },
115
115
  ALL: { win: 0, lose: 0 },
116
116
  };
117
+ const initialFastestGuessTime = {
118
+ 经典: 0,
119
+ CET4: 0,
120
+ CET6: 0,
121
+ GMAT: 0,
122
+ GRE: 0,
123
+ IELTS: 0,
124
+ SAT: 0,
125
+ TOEFL: 0,
126
+ 考研: 0,
127
+ 专八: 0,
128
+ 专四: 0,
129
+ ALL: 0,
130
+ };
117
131
  function apply(ctx, config) {
118
132
  // tzb*
119
133
  ctx.model.extend('wordle_game_records', {
@@ -154,7 +168,8 @@ function apply(ctx, config) {
154
168
  win: 'unsigned',
155
169
  moneyChange: 'double',
156
170
  wordGuessCount: 'unsigned',
157
- stats: { type: 'json', initial: initialStats }
171
+ stats: { type: 'json', initial: initialStats },
172
+ fastestGuessTime: { type: 'json', initial: initialFastestGuessTime },
158
173
  }, {
159
174
  primary: 'id',
160
175
  autoInc: true,
@@ -303,6 +318,8 @@ function apply(ctx, config) {
303
318
  if (!gameInfo.isStarted) {
304
319
  return await sendMessage(session, `【@${username}】\n游戏还没开始哦~怎么结束呐?`);
305
320
  }
321
+ // 玩家记录输
322
+ await updatePlayerRecordsLose(channelId, gameInfo);
306
323
  // 结束
307
324
  await endGame(channelId);
308
325
  return await sendMessage(session, `【@${username}】\n由于您执行了操作:【结束】\n游戏已结束!\n${generateGameEndMessage(gameInfo)}`);
@@ -445,8 +462,8 @@ function apply(ctx, config) {
445
462
  return await sendMessage(session, `【@${username}】\n游戏还没开始呢!`);
446
463
  }
447
464
  // 作答时间限制
465
+ const timeDifferenceInSeconds = (timestamp - gameInfo.timestamp) / 1000; // 将时间戳转换为秒
448
466
  if (config.enableWordGuessTimeLimit) {
449
- const timeDifferenceInSeconds = (timestamp - gameInfo.timestamp) / 1000; // 将时间戳转换为秒
450
467
  if (timeDifferenceInSeconds > config.wordGuessTimeLimitInSeconds) {
451
468
  // 生成 html 字符串
452
469
  const emptyGridHtml = generateEmptyGridHtml(gameInfo.remainingGuessesCount, gameInfo.guessWordLength);
@@ -551,7 +568,14 @@ function apply(ctx, config) {
551
568
  await updatePlayerRecordsWin(channelId, gameInfo);
552
569
  // 增加该玩家猜出单词的次数
553
570
  const [playerRecord] = await ctx.database.get('wordle_player_records', { userId });
554
- await ctx.database.set('wordle_player_records', { userId }, { wordGuessCount: playerRecord.wordGuessCount + 1 });
571
+ // 更新最快用时
572
+ if (timeDifferenceInSeconds < playerRecord.fastestGuessTime[gameInfo.gameMode] || playerRecord.fastestGuessTime[gameInfo.gameMode] === 0) {
573
+ playerRecord.fastestGuessTime[gameInfo.gameMode] = Math.floor(timeDifferenceInSeconds);
574
+ }
575
+ await ctx.database.set('wordle_player_records', { userId }, {
576
+ wordGuessCount: playerRecord.wordGuessCount + 1,
577
+ fastestGuessTime: playerRecord.fastestGuessTime
578
+ });
555
579
  await endGame(channelId);
556
580
  return await sendMessage(session, `【@${username}】\n太棒了,你猜出来了!\n${calculateGameDuration(gameInfo.timestamp, timestamp)}\n${koishi_1.h.image(imageBuffer, `image/${config.imageType}`)}\n${generateGameEndMessage(gameInfo)}\n${finalSettlementString === '' ? '' : `最终结算结果如下:\n${finalSettlementString}`}`);
557
581
  }
@@ -567,7 +591,7 @@ function apply(ctx, config) {
567
591
  return await sendMessage(session, `${koishi_1.h.image(imageBuffer, `image/${config.imageType}`)}`);
568
592
  // .action
569
593
  });
570
- // wordleGame.查询玩家记录 cx*
594
+ // wordleGame.查询玩家记录 cx* cxwjjl*
571
595
  ctx.command('wordleGame.查询玩家记录 [targetUser:text]', '查询玩家记录')
572
596
  .action(async ({ session }, targetUser) => {
573
597
  let { userId, username } = session;
@@ -579,34 +603,19 @@ function apply(ctx, config) {
579
603
  }
580
604
  const targetUserRecord = await ctx.database.get('wordle_player_records', { userId });
581
605
  if (targetUserRecord.length === 0) {
582
- await ctx.database.create('wordle_player_records', {
583
- userId,
584
- username,
585
- });
586
- return sendMessage(session, `查询对象:${username}
587
- 无任何游戏记录。`);
606
+ await ctx.database.create('wordle_player_records', { userId, username });
607
+ return sendMessage(session, `查询对象:${username} 无任何游戏记录。`);
588
608
  }
589
- const { win, lose, moneyChange, wordGuessCount, stats } = targetUserRecord[0];
590
- const queryInfo = `
609
+ const { win, lose, moneyChange, wordGuessCount, stats, fastestGuessTime } = targetUserRecord[0];
610
+ const queryInfo = `【@${session.username}】
591
611
  查询对象:${username}
592
612
  猜出单词次数:${wordGuessCount} 次
593
613
  总胜场:${win} 次
594
614
  总输场:${lose} 次
595
615
  损益为:${moneyChange} 点
596
- 详细统计信息:
597
- 经典 - 胜: ${stats.经典?.win}, 负: ${stats.经典?.lose}
598
- CET4 - 胜: ${stats.CET4?.win}, 负: ${stats.CET4?.lose}
599
- CET6 - 胜: ${stats.CET6?.win}, 负: ${stats.CET6?.lose}
600
- GMAT - 胜: ${stats.GMAT?.win}, 负: ${stats.GMAT?.lose}
601
- GRE - 胜: ${stats.GRE?.win}, 负: ${stats.GRE?.lose}
602
- IELTS - 胜: ${stats.IELTS?.win}, 负: ${stats.IELTS?.lose}
603
- SAT - 胜: ${stats.SAT?.win}, 负: ${stats.SAT?.lose}
604
- TOEFL - 胜: ${stats.TOEFL?.win}, 负: ${stats.TOEFL?.lose}
605
- 考研 - 胜: ${stats.考研?.win}, 负: ${stats.考研?.lose}
606
- 专八 - 胜: ${stats.专八?.win}, 负: ${stats.专八?.lose}
607
- 专四 - 胜: ${stats.专四?.win}, 负: ${stats.专四?.lose}
608
- ALL - 胜: ${stats.ALL?.win}, 负: ${stats.ALL?.lose}
609
- `;
616
+ 详细统计信息如下:
617
+ ${generateStatsInfo(stats, fastestGuessTime)}
618
+ `;
610
619
  return sendMessage(session, queryInfo);
611
620
  });
612
621
  // wordleGame.查询单词 cxdc*
@@ -705,7 +714,7 @@ ${rankType.map((type, index) => `${index + 1}. ${type}`).join('\n')}
705
714
  return '请输入大于等于 0 的数字作为排行榜的参数。';
706
715
  }
707
716
  const rankType3 = [
708
- "胜场", "输场"
717
+ "胜场", "输场", "最快用时"
709
718
  ];
710
719
  await sendMessage(session, `当前可查看排行榜如下:
711
720
  ${rankType3.map((type, index) => `${index + 1}. ${type}`).join('\n')}
@@ -763,39 +772,43 @@ ${rankType3.map((type, index) => `${index + 1}. ${type}`).join('\n')}
763
772
  "经典", "CET4", "CET6", "GMAT", "GRE", "IELTS",
764
773
  "SAT", "TOEFL", "考研", "专八", "专四", "ALL"
765
774
  ];
766
- // 注册胜场排行榜指令
775
+ // 注册胜场、输场、用时排行榜指令
767
776
  rankType4.forEach((type) => {
768
777
  ctx.command(`wordleGame.排行榜.${type}.胜场 [number:number]`, `查看${type}胜场排行榜`)
769
778
  .action(async ({ session }, number = config.defaultMaxLeaderboardEntries) => {
770
- if (typeof number !== 'number' || isNaN(number) || number < 0) {
771
- return '请输入大于等于 0 的数字作为排行榜的参数。';
772
- }
773
- const getPlayers = await ctx.database.get('wordle_player_records', {});
774
- // 将 getPlayers 按照当前类型的胜场次数降序排序
775
- getPlayers.sort((a, b) => (b.stats[type]?.win || 0) - (a.stats[type]?.win || 0));
776
- // 形成一个类似于字符串排行榜的数组
777
- const leaderboard = getPlayers.slice(0, number).map((player, index) => `${index + 1}. ${player.username}:${player.stats[type]?.win} 次`);
778
- const result = `${type}模式胜场排行榜:\n${leaderboard.join('\n')}`;
779
- return await sendMessage(session, result);
779
+ return await sendMessage(session, await getLeaderboardWinOrLose(type, number, 'win', '胜场'));
780
780
  });
781
- });
782
- // 注册输场排行榜指令
783
- rankType4.forEach((type) => {
784
781
  ctx.command(`wordleGame.排行榜.${type}.输场 [number:number]`, `查看${type}输场排行榜`)
785
782
  .action(async ({ session }, number = config.defaultMaxLeaderboardEntries) => {
786
- if (typeof number !== 'number' || isNaN(number) || number < 0) {
787
- return '请输入大于等于 0 的数字作为排行榜的参数。';
788
- }
789
- const getPlayers = await ctx.database.get('wordle_player_records', {});
790
- // 将 getPlayers 按照当前类型的输场次数降序排序
791
- getPlayers.sort((a, b) => (b.stats[type]?.lose || 0) - (a.stats[type]?.lose || 0));
792
- // 形成一个类似于字符串排行榜的数组
793
- const leaderboard = getPlayers.slice(0, number).map((player, index) => `${index + 1}. ${player.username}:${player.stats[type]?.lose} 次`);
794
- const result = `${type}模式输场排行榜:\n${leaderboard.join('\n')}`;
795
- return await sendMessage(session, result);
783
+ return await sendMessage(session, await getLeaderboardWinOrLose(type, number, 'lose', '输场'));
784
+ });
785
+ ctx.command(`wordleGame.排行榜.${type}.最快用时 [number:number]`, `查看${type}最快用时排行榜`)
786
+ .action(async ({ session }, number = config.defaultMaxLeaderboardEntries) => {
787
+ return await sendMessage(session, await getLeaderboardFastestGuessTime(type, number));
796
788
  });
797
789
  });
798
790
  // ch*
791
+ async function getLeaderboardWinOrLose(type, number, statKey, label) {
792
+ if (typeof number !== 'number' || isNaN(number) || number < 0) {
793
+ return '请输入大于等于 0 的数字作为排行榜的参数。';
794
+ }
795
+ const getPlayers = await ctx.database.get('wordle_player_records', {});
796
+ // 降序排序
797
+ getPlayers.sort((a, b) => (b.stats[type]?.[statKey] || 0) - (a.stats[type]?.[statKey] || 0));
798
+ const leaderboard = getPlayers.slice(0, number).map((player, index) => `${index + 1}. ${player.username}:${player.stats[type]?.[statKey]} 次`);
799
+ return `${type}模式${label}排行榜:\n${leaderboard.join('\n')}`;
800
+ }
801
+ async function getLeaderboardFastestGuessTime(type, number) {
802
+ const getPlayers = await ctx.database.get('wordle_player_records', {});
803
+ const leaderboard = getPlayers
804
+ .filter(player => player.fastestGuessTime[type] > 0)
805
+ .sort((a, b) => a.fastestGuessTime[type] - b.fastestGuessTime[type])
806
+ .slice(0, number)
807
+ .map((player, index) => `${index + 1}. ${player.username}:${formatGameDuration2(player.fastestGuessTime[type])}`)
808
+ .join('\n');
809
+ return `${type}模式最快用时排行榜:\n${leaderboard}`;
810
+ }
811
+ ;
799
812
  async function generateLetterTilesHtml(wordGuess, inputWord, channelId) {
800
813
  const wordHtml = new Array(inputWord.length);
801
814
  const letterCountMap = {};
@@ -852,7 +865,7 @@ ${rankType3.map((type, index) => `${index + 1}. ${type}`).join('\n')}
852
865
  await ctx.database.set('wordle_game_records', { channelId }, {
853
866
  correctLetters,
854
867
  presentLetters: uniqueSortedLowercaseLetters(presentLetters),
855
- absentLetters: uniqueSortedLowercaseLetters(absentLetters),
868
+ absentLetters: removeLetters(gameInfo.wordGuess, uniqueSortedLowercaseLetters(absentLetters)),
856
869
  });
857
870
  return wordHtml.join("\n");
858
871
  }
@@ -1077,6 +1090,56 @@ ${rankType3.map((type, index) => `${index + 1}. ${type}`).join('\n')}
1077
1090
  }
1078
1091
  exports.apply = apply;
1079
1092
  // hs*
1093
+ function generateStatsInfo(stats, fastestGuessTime) {
1094
+ const gameTypes = [
1095
+ '经典',
1096
+ 'CET4',
1097
+ 'CET6',
1098
+ 'GMAT',
1099
+ 'GRE',
1100
+ 'IELTS',
1101
+ 'SAT',
1102
+ 'TOEFL',
1103
+ '考研',
1104
+ '专八',
1105
+ '专四',
1106
+ 'ALL'
1107
+ ];
1108
+ let statsInfo = '';
1109
+ gameTypes.forEach(type => {
1110
+ const winCount = stats[type]?.win || 0;
1111
+ const loseCount = stats[type]?.lose || 0;
1112
+ const fastestTime = fastestGuessTime[type] || 0;
1113
+ statsInfo += `${type} - 胜:${winCount} 次,负:${loseCount} 次`;
1114
+ statsInfo += fastestTime === 0 ? '' : `,最快${formatGameDuration(fastestTime)}`;
1115
+ statsInfo += '\n';
1116
+ });
1117
+ return statsInfo;
1118
+ }
1119
+ function formatGameDuration(elapsedSeconds) {
1120
+ const minutes = Math.floor(elapsedSeconds / 60);
1121
+ const seconds = elapsedSeconds % 60;
1122
+ if (minutes > 0) {
1123
+ return `用时:${minutes} 分 ${seconds} 秒`;
1124
+ }
1125
+ else {
1126
+ return `用时:${seconds} 秒`;
1127
+ }
1128
+ }
1129
+ function formatGameDuration2(elapsedSeconds) {
1130
+ const minutes = Math.floor(elapsedSeconds / 60);
1131
+ const seconds = elapsedSeconds % 60;
1132
+ if (minutes > 0) {
1133
+ return `${minutes} 分 ${seconds} 秒`;
1134
+ }
1135
+ else {
1136
+ return `${seconds} 秒`;
1137
+ }
1138
+ }
1139
+ function removeLetters(wordAnswer, absentLetters) {
1140
+ const letterSet = new Set(wordAnswer);
1141
+ return absentLetters.split('').filter(letter => !letterSet.has(letter)).join('');
1142
+ }
1080
1143
  function calculateGameDuration(startTime, currentTime) {
1081
1144
  const elapsedMilliseconds = currentTime - startTime;
1082
1145
  const elapsedSeconds = Math.floor(elapsedMilliseconds / 1000);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-wordle-game",
3
3
  "description": "欢迎来到 Wordle 猜单词小游戏,包含经典模式、多种词库(CET4、CET6、考研等)模式、多种游戏设置和排行榜系统。",
4
- "version": "1.2.2",
4
+ "version": "1.2.4",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
package/readme.md CHANGED
@@ -97,7 +97,7 @@ npm install koishi-plugin-wordle-game
97
97
  - `wordleGame.查询单词 [targetWord:text]` - 在 ALL 词库中查询单词信息(翻译)。
98
98
  - `wordleGame.查询玩家记录 [targetUser:text]` - 查询玩家记录,可选参数为目标玩家的 at 信息。
99
99
  - `wordleGame.排行榜 [number:number]` - 查看排行榜,可选参数为排行榜的人数。
100
- - `wordleGame.排行榜.损益/总.胜场/总.输场/经典/CET4/CET6/GMAT/GRE/IELTS/SAT/TOEFL/考研/专八/专四/ALL.胜场/输场 [number:number]` -
100
+ - `wordleGame.排行榜.损益/总.胜场/总.输场/经典/CET4/CET6/GMAT/GRE/IELTS/SAT/TOEFL/考研/专八/专四/ALL.胜场/输场/最快用时 [number:number]` -
101
101
  查看不同模式的玩家排行榜,可选参数为排行榜的人数。
102
102
 
103
103
  ## 🍰 致谢