Skip to content

Commit

Permalink
feat: Judging の強化 (#222)
Browse files Browse the repository at this point in the history
* feat: Rename into Judging

* feat: Add JudgingStatus

* feat: Add waitingJudgingEmoji

* fix: Fix as hasNoTestCases

* feat: Enforce JudgingCommand

* fix: Update test

* fix: Make emoji high resolution

* fix: Replace with internal emoji
  • Loading branch information
MikuroXina authored May 31, 2022
1 parent 36fcb44 commit 732d56a
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 43 deletions.
4 changes: 2 additions & 2 deletions src/adaptor/random.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { RandomGenerator as JudgementRng } from '../service/judgement';
import type { RandomGenerator as JudgingRng } from '../service/judging';
import type { RandomGenerator as PartyRng } from '../service/party';

export class MathRandomGenerator implements PartyRng, JudgementRng {
export class MathRandomGenerator implements PartyRng, JudgingRng {
minutes(): number {
return Math.floor(Math.random() * 60);
}
Expand Down
43 changes: 43 additions & 0 deletions src/model/judging-status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export const judgingStatuses = [
'CE',
'MLE',
'TLE',
'RE',
'OLE',
'IE',
'WA',
'AC'
] as const;

export type JudgingStatus = typeof judgingStatuses[number];

export function isJudgingStatus(str: string): str is JudgingStatus {
return (judgingStatuses as readonly string[]).includes(str);
}

export function hasNoTestCases(status: JudgingStatus): boolean {
return status === 'CE';
}

export function emojiOf(status: JudgingStatus): string {
switch (status) {
case 'CE':
return '<:CE:981118707264811018>';
case 'MLE':
return '<:MLE:981118706916675614>';
case 'TLE':
return '<:TLE:714879875969712193>';
case 'RE':
return '<:RE:981118707222872084>';
case 'OLE':
return '<:OLE:981118707088637962>';
case 'IE':
return '<:IE:981118706920865802>';
case 'WA':
return '<:WA:714879905111736320>';
case 'AC':
return '<:AC:714879672353161236>';
}
}

export const waitingJudgingEmoji = '<:WJ:714879935256461355>';
4 changes: 2 additions & 2 deletions src/service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from '../runner';
import type { CommandMessage, CommandResponder } from './command-message';
import { type DeletionObservable, DeletionRepeater } from './deletion-repeater';
import { JudgementCommand, type RandomGenerator } from './judgement';
import { JudgingCommand, type RandomGenerator } from './judging';
import {
KaereCommand,
type KaereMusicKey,
Expand Down Expand Up @@ -73,7 +73,7 @@ export const registerAllCommandResponder = (
scheduleRunner,
reservationRepo
),
new JudgementCommand(random),
new JudgingCommand(random),
new Meme(),
new HelpCommand(commandRunner),
new KokuseiChousa(stats),
Expand Down
39 changes: 20 additions & 19 deletions src/service/judgement.test.ts → src/service/judging.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { emojiOf, waitingJudgingEmoji } from '../model/judging-status';
import type { EmbedMessage } from '../model/embed-message';
import { JudgementCommand } from './judgement';
import { JudgingCommand } from './judging';
import { createMockMessage } from './command-message';

test('use case of jd', async () => {
const responder = new JudgementCommand({
const responder = new JudgingCommand({
sleep: () => Promise.resolve(),
uniform: () => 2
});
Expand All @@ -17,8 +18,8 @@ test('use case of jd', async () => {
},
(embed) => {
expect(embed).toStrictEqual({
title: '***†HARACHO ONLINE JUDGEMENT SYSTEM†***',
description: '0 / 5 WJ'
title: '***†HARACHO ONLINE JUDGING SYSTEM†***',
description: `0 / 5 ${waitingJudgingEmoji}`
});
return Promise.resolve({ edit: fn });
}
Expand All @@ -28,18 +29,18 @@ test('use case of jd', async () => {
expect(fn).toBeCalledTimes(5);
for (let i = 0; i < 4; ++i) {
expect(fn.mock.calls[i][0]).toStrictEqual({
title: '***†HARACHO ONLINE JUDGEMENT SYSTEM†***',
description: `${i + 1} / 5 WJ`
title: '***†HARACHO ONLINE JUDGING SYSTEM†***',
description: `${i + 1} / 5 ${waitingJudgingEmoji}`
});
}
expect(fn.mock.calls[4][0]).toStrictEqual({
title: '***†HARACHO ONLINE JUDGEMENT SYSTEM†***',
description: `5 / 5 AC`
title: '***†HARACHO ONLINE JUDGING SYSTEM†***',
description: `5 / 5 ${emojiOf('AC')}`
});
});

test('use case of judge', async () => {
const responder = new JudgementCommand({
const responder = new JudgingCommand({
sleep: () => Promise.resolve(),
uniform: () => 0
});
Expand All @@ -49,12 +50,12 @@ test('use case of judge', async () => {
'CREATE',
createMockMessage(
{
args: ['judge', '1', 'WA']
args: ['judge', '1', 'WWW']
},
(embed) => {
expect(embed).toStrictEqual({
title: '***†HARACHO ONLINE JUDGEMENT SYSTEM†***',
description: '0 / 1 WJ'
title: '***†HARACHO ONLINE JUDGING SYSTEM†***',
description: `0 / 1 ${waitingJudgingEmoji}`
});
return Promise.resolve({ edit: fn });
}
Expand All @@ -63,13 +64,13 @@ test('use case of judge', async () => {

expect(fn).toBeCalledTimes(1);
expect(fn.mock.calls[0][0]).toStrictEqual({
title: '***†HARACHO ONLINE JUDGEMENT SYSTEM†***',
description: `1 / 1 WA`
title: '***†HARACHO ONLINE JUDGING SYSTEM†***',
description: `1 / 1 WWW`
});
});

test('max number of cases', async () => {
const responder = new JudgementCommand({
const responder = new JudgingCommand({
sleep: () => Promise.resolve(),
uniform: () => 1
});
Expand All @@ -82,8 +83,8 @@ test('max number of cases', async () => {
},
(embed) => {
expect(embed).toStrictEqual({
title: '***†HARACHO ONLINE JUDGEMENT SYSTEM†***',
description: '0 / 1 WJ'
title: '***†HARACHO ONLINE JUDGING SYSTEM†***',
description: `0 / 1 ${waitingJudgingEmoji}`
});
return Promise.resolve({ edit: () => Promise.resolve() });
}
Expand All @@ -97,8 +98,8 @@ test('max number of cases', async () => {
},
(embed) => {
expect(embed).toStrictEqual({
title: '***†HARACHO ONLINE JUDGEMENT SYSTEM†***',
description: '0 / 64 WJ'
title: '***†HARACHO ONLINE JUDGING SYSTEM†***',
description: `0 / 64 ${waitingJudgingEmoji}`
});
return Promise.resolve({ edit: () => Promise.resolve() });
}
Expand Down
58 changes: 38 additions & 20 deletions src/service/judgement.ts → src/service/judging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ import type {
CommandResponder,
HelpInfo
} from './command-message';
import {
emojiOf,
hasNoTestCases,
isJudgingStatus,
waitingJudgingEmoji
} from '../model/judging-status';
import type { MessageEvent } from '../runner';

/**
* `JudgementCommand` のための乱数生成器。
* `JudgingCommand` のための乱数生成器。
*
* @export
* @interface RandomGenerator
Expand All @@ -31,18 +37,18 @@ export interface RandomGenerator {
uniform(from: number, to: number): number;
}

const JUDGEMENT_TITLE = '***†HARACHO ONLINE JUDGEMENT SYSTEM†***';
const JUDGING_TITLE = '***†HARACHO ONLINE JUDGING SYSTEM†***';

/**
* `judge` コマンドで競技プログラミングの判定をシミュレートする。
*
* @export
* @class JudgementCommand
* @class JudgingCommand
* @implements {MessageEventResponder<CommandMessage>}
*/
export class JudgementCommand implements CommandResponder {
export class JudgingCommand implements CommandResponder {
help: Readonly<HelpInfo> = {
title: JUDGEMENT_TITLE,
title: JUDGING_TITLE,
description: 'プログラムが適格かどうか判定してあげるよ',
commandName: ['jd', 'judge'],
argsFormat: [
Expand Down Expand Up @@ -78,31 +84,41 @@ export class JudgementCommand implements CommandResponder {
});
return;
}
const willBeAccepted = result === 'AC';

if (willBeAccepted) {
await this.accept(message, count);
} else {
if (!isJudgingStatus(result)) {
await this.reject(message, count, errorFromStartArg, result);
return;
}
if (result === 'AC') {
await this.accept(message, count);
return;
}
if (hasNoTestCases(result)) {
await message.reply({
title: JUDGING_TITLE,
description: emojiOf(result)
});
return;
}
await this.reject(message, count, errorFromStartArg, emojiOf(result));
}

private async accept(message: CommandMessage, count: number) {
const sent = await message.reply({
title: JUDGEMENT_TITLE,
description: `0 / ${count} WJ`
title: JUDGING_TITLE,
description: `0 / ${count} ${waitingJudgingEmoji}`
});

for (let i = 1; i <= count - 1; ++i) {
await sent.edit({
title: JUDGEMENT_TITLE,
description: `${i} / ${count} WJ`
title: JUDGING_TITLE,
description: `${i} / ${count} ${waitingJudgingEmoji}`
});
await this.rng.sleep();
}
await sent.edit({
title: JUDGEMENT_TITLE,
description: `${count} / ${count} AC`
title: JUDGING_TITLE,
description: `${count} / ${count} ${emojiOf('AC')}`
});
}

Expand All @@ -113,22 +129,24 @@ export class JudgementCommand implements CommandResponder {
result: string
) {
const sent = await message.reply({
title: JUDGEMENT_TITLE,
description: `0 / ${count} WJ`
title: JUDGING_TITLE,
description: `0 / ${count} ${waitingJudgingEmoji}`
});

const errorFromStart = errorFromStartArg == '-all';
const errorAt = errorFromStart ? 1 : this.rng.uniform(1, count + 1);

for (let i = 1; i <= count - 1; ++i) {
await sent.edit({
title: JUDGEMENT_TITLE,
description: `${i} / ${count} ${errorAt <= i ? result : 'WJ'}`
title: JUDGING_TITLE,
description: `${i} / ${count} ${
errorAt <= i ? result : waitingJudgingEmoji
}`
});
await this.rng.sleep();
}
await sent.edit({
title: JUDGEMENT_TITLE,
title: JUDGING_TITLE,
description: `${count} / ${count} ${result}`
});
}
Expand Down

0 comments on commit 732d56a

Please sign in to comment.