Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ダイスコマンドの作成(仮あん) #473

Merged
merged 20 commits into from
Sep 22, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/adaptor/random.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { DiceQueen } from '../service/command/dice.js';
import type { RandomGenerator as JudgingRng } from '../service/command/judging.js';
import type { RandomGenerator as PartyRng } from '../service/command/party.js';

export class MathRandomGenerator implements PartyRng, JudgingRng {
export class MathRandomGenerator implements PartyRng, JudgingRng, DiceQueen {
minutes(): number {
return Math.floor(Math.random() * 60);
}
Expand All @@ -20,4 +21,12 @@ export class MathRandomGenerator implements PartyRng, JudgingRng {
to = Math.floor(to);
return Math.floor(Math.random() * (to - from) + from);
}

roll(faces: number, howManyRolls: number): Array<number> {
const diceLog: number[] = [];
for (let i = 0; i < howManyRolls; ++i) {
diceLog.push(this.uniform(1, faces));
}
return diceLog;
}
}
3 changes: 2 additions & 1 deletion src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ if (features.includes('COMMAND')) {
roleRepo: roleManager,
userRepo: stats,
guildRepo: stats,
roleCreateRepo: roleManager
roleCreateRepo: roleManager,
queen: new MathRandomGenerator()
});
}

Expand Down
8 changes: 6 additions & 2 deletions src/service/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from './command/party.js';
import type { Clock, ScheduleRunner } from '../runner/schedule.js';
import { DebugCommand, MessageRepository } from './command/debug.js';
import { DiceCommand, DiceQueen } from './command/dice.js';
import { GetVersionCommand, VersionFetcher } from './command/version.js';
import { GuildInfo, GuildStatsRepository } from './command/guild-info.js';
import { JudgingCommand, RandomGenerator } from './command/judging.js';
Expand Down Expand Up @@ -48,7 +49,8 @@ export const registerAllCommandResponder = ({
roleRepo,
userRepo,
guildRepo,
roleCreateRepo
roleCreateRepo,
queen
}: {
typoRepo: TypoRepository;
reservationRepo: ReservationRepository;
Expand All @@ -68,6 +70,7 @@ export const registerAllCommandResponder = ({
userRepo: UserStatsRepository;
guildRepo: GuildStatsRepository;
roleCreateRepo: RoleCreateManager;
queen: DiceQueen;
}) => {
const allResponders = [
new TypoReporter(typoRepo, clock, scheduleRunner),
Expand All @@ -91,7 +94,8 @@ export const registerAllCommandResponder = ({
new RoleInfo(roleRepo),
new UserInfo(userRepo),
new GuildInfo(guildRepo),
new RoleCreate(roleCreateRepo)
new RoleCreate(roleCreateRepo),
new DiceCommand(queen)
];
for (const responder of allResponders) {
commandRunner.addResponder(
Expand Down
63 changes: 63 additions & 0 deletions src/service/command/dice.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { DiceCommand, DiceQueen } from './dice.js';
import { describe, expect, it, vi } from 'vitest';

import { createMockMessage } from './command-message.js';
import { parseStringsOrThrow } from '../../adaptor/proxy/command/schema.js';

describe('dice', () => {
const diceQueen: DiceQueen = {
roll: (face, num) => [...new Array<undefined>(face)].map(() => num)
};
const diceCommand = new DiceCommand(diceQueen);

it('case of 1d6', async () => {
const roll = vi.spyOn(diceQueen, 'roll');
const fn = vi.fn();

await diceCommand.on(
createMockMessage(
parseStringsOrThrow(['dice', '1d6'], diceCommand.schema),
fn
)
);

expect(fn).toHaveBeenCalledWith({
title: '運命のダイスロール!',
description: '1d6 => 6'
});
expect(roll).toHaveBeenCalledOnce();
});

it('case of defaultValue', async () => {
const roll = vi.spyOn(diceQueen, 'roll');
const fn = vi.fn();

await diceCommand.on(
createMockMessage(parseStringsOrThrow(['dice'], diceCommand.schema), fn)
);

expect(fn).toHaveBeenCalledWith({
title: '運命のダイスロール!',
description: '1d100 => 100'
});
expect(roll).toHaveBeenCalledOnce();
});

it('case of 100D500', async () => {
const roll = vi.spyOn(diceQueen, 'roll');
const fn = vi.fn();

await diceCommand.on(
createMockMessage(
parseStringsOrThrow(['dice', '100D500'], diceCommand.schema),
fn
)
);

expect(fn).toHaveBeenCalledWith({
title: '引数が大きすぎるよ',
description: 'ダイスは100面20個以下、最大値が2000までの処理にしてね。'
});
expect(roll).toBeCalledTimes(0);
});
MikuroXina marked this conversation as resolved.
Show resolved Hide resolved
});
81 changes: 81 additions & 0 deletions src/service/command/dice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type {
CommandMessage,
CommandResponder,
HelpInfo
} from './command-message.js';

/**
* ダイスの管理者。面白いものの味方。
* 今後詳細値がほしい場合があるかも知れないので、各ダイスについてどんな出目が出たかを判断する。
*/
export interface DiceQueen {
/**
*
* @param {number} faces
* @param {number} HowManyRoll
* @return {Array<number>}
*/
roll(faces: number, HowManyRoll: number): Array<number>;
MikuroXina marked this conversation as resolved.
Show resolved Hide resolved
}

const SCHEMA = {
names: ['d', 'dice'],
subCommands: {},
params: [
{
type: 'STRING',
name: 'ダイスロール設定',
description:
'どのダイスを何個振るかの指定。6面ダイス2個であれば ‘!dice 2d6`のように入力してね',
MikuroXina marked this conversation as resolved.
Show resolved Hide resolved
defaultValue: '1d100'
}
]
} as const;

/**
* 'dice' コマンドで
*
* @export
* @class DiceCommand
* @implements {MessageEventResponder<CommandMessage>}
*/
export class DiceCommand implements CommandResponder<typeof SCHEMA> {
help: Readonly<HelpInfo> = {
title: 'ダイスロール',
description: '賽子が振れるみたいだよ'
};
readonly schema = SCHEMA;

constructor(private readonly diceQueen: DiceQueen) {}

async on(message: CommandMessage<typeof SCHEMA>): Promise<void> {
const [arg] = message.args.params;

if (arg.match(/^(?!a-c,e-z)*$/)) {
MikuroXina marked this conversation as resolved.
Show resolved Hide resolved
await message.reply({
title: 'コマンド形式エラー',
description: '引数の形は`<num>d<num>`をとる必要があるよ。'
});
return;
}
const [arg1, arg2] = arg.toLowerCase().split('d', 2);
const diceNum = parseInt(arg1);
const diceFaces = parseInt(arg2);
MikuroXina marked this conversation as resolved.
Show resolved Hide resolved

if (diceFaces * diceNum >= 2000) {
await message.reply({
title: '引数が大きすぎるよ',
description: 'ダイスは100面20個以下、最大値が2000までの処理にしてね。'
MikuroXina marked this conversation as resolved.
Show resolved Hide resolved
});
return;
}

const diceResult = this.diceQueen.roll(diceFaces, diceNum);
const diceSum = diceResult.reduce((a, x) => a + x);

await message.reply({
title: '運命のダイスロール!',
description: `${arg} => ${diceSum}`
MikuroXina marked this conversation as resolved.
Show resolved Hide resolved
});
}
}