Commit 9cbde818 authored by nanahira's avatar nanahira

use league-tabulator package

parent c826fe6e
......@@ -9,10 +9,12 @@
"version": "8.2.4",
"license": "MIT",
"dependencies": {
"class-transformer": "^0.4.0",
"class-transformer": "^0.5.1",
"koishi-thirdeye": "^8.3.3",
"league-tabulator": "^1.0.0",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"reflect-metadata": "^0.1.13",
"source-map-support": "^0.5.20"
},
"devDependencies": {
......@@ -2439,9 +2441,9 @@
"dev": true
},
"node_modules/class-transformer": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz",
"integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA=="
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw=="
},
"node_modules/cliui": {
"version": "7.0.4",
......@@ -5196,6 +5198,19 @@
"koishi": "^4.2.2"
}
},
"node_modules/league-tabulator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/league-tabulator/-/league-tabulator-1.0.0.tgz",
"integrity": "sha512-rC83ZCO0rJOgFWOynJbmYHpykoY1U6oMzIs9oad9N+5xIaKRN8+LXH0v2/HhR9uQhhWq2S7y6G8ecJEYmHX7pQ==",
"dependencies": {
"lodash": "^4.17.21",
"moment": "^2.29.1"
},
"peerDependencies": {
"class-transformer": "^0.5.1",
"reflect-metadata": "^0.1.13"
}
},
"node_modules/leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
......@@ -9536,9 +9551,9 @@
"dev": true
},
"class-transformer": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz",
"integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA=="
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw=="
},
"cliui": {
"version": "7.0.4",
......@@ -11628,6 +11643,15 @@
"typed-reflector": "^1.0.9"
}
},
"league-tabulator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/league-tabulator/-/league-tabulator-1.0.0.tgz",
"integrity": "sha512-rC83ZCO0rJOgFWOynJbmYHpykoY1U6oMzIs9oad9N+5xIaKRN8+LXH0v2/HhR9uQhhWq2S7y6G8ecJEYmHX7pQ==",
"requires": {
"lodash": "^4.17.21",
"moment": "^2.29.1"
}
},
"leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
......
import { Random, User } from 'koishi';
import { Type } from 'class-transformer';
import 'reflect-metadata';
import moment from 'moment';
import _ from 'lodash';
export enum ReportScoreResult {
NotFound,
Continue,
NextRound,
Finish,
}
function generateSpaces(n: number) {
return _.range(n)
.map(() => ' ')
.join('');
}
export class Match {
scores: number[];
winner: string;
constructor(public players: string[]) {
if (!players) {
return;
}
this.scores = [0, 0];
}
foo() {
return 'bar';
}
setScore(scores: number[]) {
this.scores = scores;
const [scorea, scoreb] = scores;
if (scorea === scoreb) {
return;
} else if (scorea > scoreb) {
this.winner = this.players[0];
} else {
this.winner = this.players[1];
}
}
reportScore(name: string, self: number, oppo: number) {
const pos = this.players.findIndex(
(p) => name.startsWith(p) || name.endsWith(p),
);
if (pos === -1) {
return false;
}
const score: number[] = [];
score[pos] = self;
score[1 - pos] = oppo;
this.setScore(score);
return true;
}
isFinished() {
return this.winner || this.scores.some((s) => s !== 0);
}
format(leftMaxLength: number, rightMaxLength: number) {
const leftSpace = leftMaxLength - this.players[0].length + 2;
const rightSpace = rightMaxLength - this.players[1].length + 2;
return `${this.players[0]}${generateSpaces(leftSpace)}${this.scores[0]}:${
this.scores[1]
}${generateSpaces(rightSpace)}${this.players[1]}`;
}
}
export class Round {
@Type(() => Match)
matches: Match[];
constructor(_playerLists: string[][]) {
if (!_playerLists) {
return;
}
const playerLists = _playerLists.map((plist) => Random.shuffle(plist));
const matchCount = Math.min(...playerLists.map((l) => l.length));
this.matches = [];
for (let i = 0; i < matchCount; ++i) {
const [lista, listb] = playerLists;
this.matches.push(new Match([lista[i], listb[i]]));
}
}
reportScore(name: string, selfScore: number, oppoScore: number) {
const match = this.matches.find((m) =>
m.players.some((p) => name.startsWith(p) || name.endsWith(p)),
);
if (!match) {
return;
}
return match.reportScore(name, selfScore, oppoScore);
}
isAllFinished() {
return this.matches.every((m) => m.isFinished());
}
format(leftMaxLength: number, rightMaxLength: number) {
return this.matches
.map((m) => m.format(leftMaxLength, rightMaxLength))
.join('\n');
}
}
export class Game {
@Type(() => Round)
rounds: Round[];
constructor(
public location: string,
public rule: string,
public teama: string,
public teamb: string,
public playera: string[],
public playerb: string[],
) {
if (!teama) {
return;
}
this.rounds = [];
this.newRound();
}
newRound() {
if (this.rule === '人头赛' && this.rounds.length) {
return false;
}
const playerLists = [this.playera, this.playerb].map((plist) =>
plist.filter((p) => this.isPlayerAvailable(p)),
);
if (playerLists.some((l) => !l.length)) {
return false;
}
this.rounds.push(new Round(playerLists));
return true;
}
isPlayerAvailable(name: string) {
return !this.rounds.some((round) =>
round.matches.some(
(match) => match.players.includes(name) && match.winner !== name,
),
);
}
reportScore(name: string, selfScore: number, oppoScore: number) {
const round = this.rounds[this.rounds.length - 1];
const result = round.reportScore(name, selfScore, oppoScore);
if (!result) {
return ReportScoreResult.NotFound;
}
if (round.isAllFinished()) {
const nextRoundResult = this.newRound();
if (nextRoundResult) {
return ReportScoreResult.NextRound;
} else {
return ReportScoreResult.Finish;
}
} else {
return ReportScoreResult.Continue;
}
}
format() {
const allMatches = _.flatten(this.rounds.map((r) => r.matches));
const leftMaxLength = Math.max(
..._.map(allMatches, (m) => m.players[0].length),
);
const rightMaxLength = Math.max(
..._.map(allMatches, (m) => m.players[1].length),
);
const lines: string[] = [];
lines.push(`战队: ${this.teama} VS ${this.teamb}`);
lines.push(`时间: ${moment().format('YYYY-MM-DD')}`);
lines.push(`规则: ${this.rule}`);
lines.push(`地点: ${this.location}`);
lines.push('------------第一轮------------');
lines.push(this.rounds[0].format(leftMaxLength, rightMaxLength));
lines.push('------------第二轮------------');
lines.push(
this.rounds
.slice(1)
.map((r) => r.format(leftMaxLength, rightMaxLength))
.join('\n'),
);
return lines.join('\n');
}
getKey() {
return `${this.location}_${this.teama}_${this.teamb}`;
}
includesPendingPlayer(possibleNames: string[]) {
return possibleNames.find((name) =>
this.rounds[this.rounds.length - 1].matches.some((match) =>
match.players.some(
(playerName) =>
name.startsWith(playerName) || name.endsWith(playerName),
),
),
);
}
}
......@@ -6,17 +6,14 @@ import {
InjectConfig,
Inject,
OnApply,
UseEvent,
UseCommand,
CommandUsage,
CommandExample,
PutSession,
PutOption,
CommandOption,
PutArg,
OnConnect,
} from 'koishi-thirdeye';
import { Game, ReportScoreResult } from './def/Match';
import { Game, ReportScoreResult } from 'league-tabulator';
import { classToPlain, plainToClass } from 'class-transformer';
import _ from 'lodash';
export * from './config';
......@@ -117,6 +114,7 @@ export default class TabulatePlugin implements OnApply {
}
const game = new Game(
exactLocation,
new Date(),
useKof ? '2/3【KOF】' : useHead ? '人头赛' : rule,
teama,
teamb,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment