versus implementation
This commit is contained in:
parent
ede897c8e2
commit
457554e952
15 changed files with 119 additions and 24 deletions
|
|
@ -1,8 +1,9 @@
|
||||||
import { Controller, Get, Param, Post } from '@nestjs/common';
|
import { Controller, Get, Logger, Param, Post } from '@nestjs/common';
|
||||||
import { GameService } from './game.service';
|
import { GameService } from './game.service';
|
||||||
|
|
||||||
@Controller('game')
|
@Controller('game')
|
||||||
export class GameController {
|
export class GameController {
|
||||||
|
private readonly logger = new Logger(GameController.name);
|
||||||
constructor(private gameService: GameService) {
|
constructor(private gameService: GameService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,4 +31,10 @@ export class GameController {
|
||||||
async playExtraCards() {
|
async playExtraCards() {
|
||||||
return this.gameService.playExtraCards();
|
return this.gameService.playExtraCards();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('simulate-versus')
|
||||||
|
async SimulateVersus() {
|
||||||
|
this.logger.verbose('[SimulateVersus] enter');
|
||||||
|
return this.gameService.simulateVersus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ import {ConfigServiceMock} from "../mocks/config-service.mock";
|
||||||
import {SharedService} from "../shared/shared.service";
|
import {SharedService} from "../shared/shared.service";
|
||||||
import {SharedServiceMock} from "../mocks/shared-service.mock";
|
import {SharedServiceMock} from "../mocks/shared-service.mock";
|
||||||
import {QueryBusMock} from "../mocks/querybus.mock";
|
import {QueryBusMock} from "../mocks/querybus.mock";
|
||||||
|
import {Guest} from "../schemas/guest.schema";
|
||||||
|
import {GuestsService} from "../guests/guests.service";
|
||||||
|
import {GuestsServiceMock} from "../mocks/guests-service.mock";
|
||||||
|
|
||||||
describe('GameService', () => {
|
describe('GameService', () => {
|
||||||
let service: GameService;
|
let service: GameService;
|
||||||
|
|
@ -25,6 +28,7 @@ describe('GameService', () => {
|
||||||
{ provide: ConfigService, useValue: ConfigServiceMock },
|
{ provide: ConfigService, useValue: ConfigServiceMock },
|
||||||
{ provide: SharedService, useValue: SharedServiceMock },
|
{ provide: SharedService, useValue: SharedServiceMock },
|
||||||
{ provide: QueryBus, useValue: QueryBusMock },
|
{ provide: QueryBus, useValue: QueryBusMock },
|
||||||
|
{ provide: GuestsService, useValue: GuestsServiceMock }
|
||||||
],
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import { SharedService } from '../shared/shared.service';
|
||||||
import { SocketEvents } from '../shared/events.consts';
|
import { SocketEvents } from '../shared/events.consts';
|
||||||
import {ConfigService} from "@nestjs/config";
|
import {ConfigService} from "@nestjs/config";
|
||||||
import {gameCards} from "./entities/cards.entities";
|
import {gameCards} from "./entities/cards.entities";
|
||||||
|
import {GuestsService} from "../guests/guests.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GameService implements OnApplicationBootstrap{
|
export class GameService implements OnApplicationBootstrap{
|
||||||
|
|
@ -26,6 +27,7 @@ export class GameService implements OnApplicationBootstrap{
|
||||||
private sharedService: SharedService,
|
private sharedService: SharedService,
|
||||||
private commandBus: CommandBus,
|
private commandBus: CommandBus,
|
||||||
private queryBus: QueryBus,
|
private queryBus: QueryBus,
|
||||||
|
private guestService: GuestsService,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -113,4 +115,24 @@ export class GameService implements OnApplicationBootstrap{
|
||||||
cardInstance.setupHandlers(this.eventBus, this.commandBus, this.queryBus);
|
cardInstance.setupHandlers(this.eventBus, this.commandBus, this.queryBus);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async simulateVersus() {
|
||||||
|
const guests = (await this.guestService.findAll()).slice(0,2).map((guest) => {
|
||||||
|
return {
|
||||||
|
id: guest.telegramId,
|
||||||
|
name: guest.name,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(guests.length < 2) {
|
||||||
|
throw new Error("Can't simulate, in db less than 2 players")
|
||||||
|
}
|
||||||
|
await this.beginVersus(guests[0].id, guests[1].id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async beginVersus(player1: number, player2: number) {
|
||||||
|
this.sharedService.sendSocketNotificationToAllClients(
|
||||||
|
SocketEvents.BEGIN_VERSUS,
|
||||||
|
{ player1, player2 }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
src/guests/guest.types.d.ts
vendored
Normal file
5
src/guests/guest.types.d.ts
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
export interface GuestNamesInCases {
|
||||||
|
SubjectiveCase: string;
|
||||||
|
AccusativeCase: string;
|
||||||
|
GenitiveCase: string;
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import {Inject, Injectable, Logger} from '@nestjs/common';
|
import {Inject, Injectable, Logger} from '@nestjs/common';
|
||||||
import {InjectModel} from '@nestjs/mongoose';
|
import {InjectModel} from '@nestjs/mongoose';
|
||||||
import {Guest, GuestDocument} from '../schemas/guest.schema';
|
import {Guest, GuestDocument} from '../schemas/guest.schema';
|
||||||
import {Model} from 'mongoose';
|
import {Document, Model} from 'mongoose';
|
||||||
import {CreateGuestDto} from './dto/create-guest.dto';
|
import {CreateGuestDto} from './dto/create-guest.dto';
|
||||||
import {QuestionDto} from '../quiz/dto/question.dto';
|
import {QuestionDto} from '../quiz/dto/question.dto';
|
||||||
import {Messages} from '../messaging/tg.text';
|
import {Messages} from '../messaging/tg.text';
|
||||||
|
|
@ -27,6 +27,7 @@ import {DebuffsConsts} from "../game/entities/debuffs.consts";
|
||||||
import {VoiceService} from "../voice/voice.service";
|
import {VoiceService} from "../voice/voice.service";
|
||||||
import {screpaDictManyInvalidAnswersDict} from "../voice/dicts/screpa-dict-many-invalid-answers.dict";
|
import {screpaDictManyInvalidAnswersDict} from "../voice/dicts/screpa-dict-many-invalid-answers.dict";
|
||||||
import {GuestPropertiesConsts} from "../schemas/properties.consts";
|
import {GuestPropertiesConsts} from "../schemas/properties.consts";
|
||||||
|
import {GuestNamesInCases} from "./guest.types";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GuestsService {
|
export class GuestsService {
|
||||||
|
|
@ -312,6 +313,15 @@ export class GuestsService {
|
||||||
await this.guestModel.updateMany({}, { prizeChance: 0 });
|
await this.guestModel.updateMany({}, { prizeChance: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getGuestNameInCases(telegramId: number): Promise<GuestNamesInCases> {
|
||||||
|
const guest = await this.findById(telegramId);
|
||||||
|
return {
|
||||||
|
SubjectiveCase: guest.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameSubjectiveCase)),
|
||||||
|
AccusativeCase: guest.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameAccusativeCase)),
|
||||||
|
GenitiveCase: guest.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameGenitiveCase))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async incrementInvalidAnswersCount(tId: number) {
|
async incrementInvalidAnswersCount(tId: number) {
|
||||||
this.logger.verbose(`Increment invalid answers in the row for ${tId}`);
|
this.logger.verbose(`Increment invalid answers in the row for ${tId}`);
|
||||||
const guest = await this.findById(tId);
|
const guest = await this.findById(tId);
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,6 @@ export class QuizController {
|
||||||
@Get('endgame-extrapoints')
|
@Get('endgame-extrapoints')
|
||||||
async endgameExtrapoints()
|
async endgameExtrapoints()
|
||||||
{
|
{
|
||||||
return await this.quizService.addEndgamePoints();
|
return await this.quizService.calculateEndgamePoints();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import {IncreasePlayerWinningRateCommand} from "../game/commands/increase-player
|
||||||
import {IncreasePlayerScoreCommand} from "../guests/command/increase-player-score.command";
|
import {IncreasePlayerScoreCommand} from "../guests/command/increase-player-score.command";
|
||||||
import {FeatureflagService} from "../featureflag/featureflag.service";
|
import {FeatureflagService} from "../featureflag/featureflag.service";
|
||||||
import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts";
|
import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts";
|
||||||
|
import {QuizEndGameResults} from "./quiz.types";
|
||||||
|
|
||||||
@Injectable({ scope: Scope.TRANSIENT })
|
@Injectable({ scope: Scope.TRANSIENT })
|
||||||
export class QuizService {
|
export class QuizService {
|
||||||
|
|
@ -167,7 +168,7 @@ export class QuizService {
|
||||||
await this.commandBus.execute(new CreateNewQueueItemCommand(targetUser, GameQueueTypes.showresults));
|
await this.commandBus.execute(new CreateNewQueueItemCommand(targetUser, GameQueueTypes.showresults));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async addEndgamePoints() {
|
public async calculateEndgamePoints(): Promise<QuizEndGameResults> {
|
||||||
const maxInvalidAnswersPromise = this.guestService.getModel().find({}).sort({ ['invalidAnswers']: 'desc'}).exec();
|
const maxInvalidAnswersPromise = this.guestService.getModel().find({}).sort({ ['invalidAnswers']: 'desc'}).exec();
|
||||||
const maxRewardsPromise = this.guestService.getModel().find({}).sort({['rewardsReceived']: "desc"}).exec();
|
const maxRewardsPromise = this.guestService.getModel().find({}).sort({['rewardsReceived']: "desc"}).exec();
|
||||||
const maxPenaltiesPromise = this.guestService.getModel().find({}).sort({['penaltiesReceived']: 'desc'}).exec();
|
const maxPenaltiesPromise = this.guestService.getModel().find({}).sort({['penaltiesReceived']: 'desc'}).exec();
|
||||||
|
|
|
||||||
11
src/quiz/quiz.types.d.ts
vendored
Normal file
11
src/quiz/quiz.types.d.ts
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
export interface QuizEndGameResultsDetails {
|
||||||
|
id: number;
|
||||||
|
count: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface QuizEndGameResults {
|
||||||
|
maxInvalidAnswers: QuizEndGameResultsDetails;
|
||||||
|
maxRewards: QuizEndGameResultsDetails;
|
||||||
|
maxPenalties: QuizEndGameResultsDetails;
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,10 @@ import {SharedService} from "../shared/shared.service";
|
||||||
import {SharedServiceMock} from "../mocks/shared-service.mock";
|
import {SharedServiceMock} from "../mocks/shared-service.mock";
|
||||||
import {FeatureflagService} from "../featureflag/featureflag.service";
|
import {FeatureflagService} from "../featureflag/featureflag.service";
|
||||||
import {FeatureflagServiceMock} from "../mocks/featureflag-service.mock";
|
import {FeatureflagServiceMock} from "../mocks/featureflag-service.mock";
|
||||||
|
import {GuestsService} from "../guests/guests.service";
|
||||||
|
import {GuestsServiceMock} from "../mocks/guests-service.mock";
|
||||||
|
import {CommandBus} from "@nestjs/cqrs";
|
||||||
|
import {CommandbusMock} from "../mocks/commandbus.mock";
|
||||||
|
|
||||||
|
|
||||||
describe('SchedulerService', () => {
|
describe('SchedulerService', () => {
|
||||||
|
|
@ -26,7 +30,9 @@ describe('SchedulerService', () => {
|
||||||
{ provide: StateService, useValue: StateServiceMock },
|
{ provide: StateService, useValue: StateServiceMock },
|
||||||
{ provide: QuizService, useValue: QuizServiceMock },
|
{ provide: QuizService, useValue: QuizServiceMock },
|
||||||
{ provide: SharedService, useValue: SharedServiceMock },
|
{ provide: SharedService, useValue: SharedServiceMock },
|
||||||
{ provide: FeatureflagService, useValue: FeatureflagServiceMock }
|
{ provide: FeatureflagService, useValue: FeatureflagServiceMock },
|
||||||
|
{ provide: CommandBus, useValue: CommandbusMock },
|
||||||
|
{ provide: GuestsService, useValue: GuestsServiceMock },
|
||||||
],
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@ import { GiftsService } from '../gifts/gifts.service';
|
||||||
import {SharedService} from '../shared/shared.service';
|
import {SharedService} from '../shared/shared.service';
|
||||||
import {FeatureflagService} from "../featureflag/featureflag.service";
|
import {FeatureflagService} from "../featureflag/featureflag.service";
|
||||||
import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts";
|
import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts";
|
||||||
|
import {CommandBus} from "@nestjs/cqrs";
|
||||||
|
import {EndgameDict} from "../voice/dicts/endgame.dict";
|
||||||
|
import {CreateNewQueueItemCommand} from "../game/commands/create-new-queue-item.command";
|
||||||
|
import {GameQueueTypes} from "../schemas/game-queue.schema";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SchedulerService {
|
export class SchedulerService {
|
||||||
|
|
@ -19,6 +23,7 @@ export class SchedulerService {
|
||||||
private quizService: QuizService,
|
private quizService: QuizService,
|
||||||
private sharedService: SharedService,
|
private sharedService: SharedService,
|
||||||
private featureFlagService: FeatureflagService,
|
private featureFlagService: FeatureflagService,
|
||||||
|
private commandBus: CommandBus,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Cron('* * * * *')
|
@Cron('* * * * *')
|
||||||
|
|
@ -26,6 +31,34 @@ export class SchedulerService {
|
||||||
await this.updateState();
|
await this.updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async finishGame() {
|
||||||
|
if(await this.featureFlagService.getFeatureFlag(FeatureFlagsConsts.EnableEndgamePoints)) {
|
||||||
|
this.logger.verbose(`Feature flag ${FeatureFlagsConsts.EnableEndgamePoints} is enabled`);
|
||||||
|
const endgamePoints = await this.quizService.calculateEndgamePoints();
|
||||||
|
await Promise.all([
|
||||||
|
this.commandBus.execute(
|
||||||
|
new CreateNewQueueItemCommand(endgamePoints.maxInvalidAnswers.id,
|
||||||
|
GameQueueTypes.extra_points,
|
||||||
|
EndgameDict.maxAmountOfInvalidQuestions)),
|
||||||
|
new CreateNewQueueItemCommand(endgamePoints.maxPenalties.id,
|
||||||
|
GameQueueTypes.extra_points,
|
||||||
|
EndgameDict.maxPenalties),
|
||||||
|
new CreateNewQueueItemCommand(endgamePoints.maxRewards.id,
|
||||||
|
GameQueueTypes.extra_points,
|
||||||
|
EndgameDict.maxAmountOfRewards)
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
const state = await this.stateService.setState('main', 'finish');
|
||||||
|
this.sharedService.sendSocketNotificationToAllClients(
|
||||||
|
'state_changed',
|
||||||
|
state,
|
||||||
|
);
|
||||||
|
this.logger.warn(`Gifts is ended, finishing game`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async updateState() {
|
private async updateState() {
|
||||||
this.state = (await this.stateService.getState('main')).value;
|
this.state = (await this.stateService.getState('main')).value;
|
||||||
this.logger.verbose(`Game state is: ${this.state}`);
|
this.logger.verbose(`Game state is: ${this.state}`);
|
||||||
|
|
@ -34,15 +67,7 @@ export class SchedulerService {
|
||||||
async gameStatus() {
|
async gameStatus() {
|
||||||
const giftsLeft = await this.giftsService.getRemainingPrizeCount();
|
const giftsLeft = await this.giftsService.getRemainingPrizeCount();
|
||||||
if (giftsLeft === 0) {
|
if (giftsLeft === 0) {
|
||||||
if(await this.featureFlagService.getFeatureFlag(FeatureFlagsConsts.EnableEndgamePoints)) {
|
await this.finishGame();
|
||||||
this.logger.verbose(`Feature flag ${FeatureFlagsConsts.EnableEndgamePoints} is enabled`);
|
|
||||||
}
|
|
||||||
const state = await this.stateService.setState('main', 'finish');
|
|
||||||
this.sharedService.sendSocketNotificationToAllClients(
|
|
||||||
'state_changed',
|
|
||||||
state,
|
|
||||||
);
|
|
||||||
this.logger.warn(`Gifts is ended, finishing game`);
|
|
||||||
}
|
}
|
||||||
const questionsLeft = await this.quizService.getRemainQuestionCount();
|
const questionsLeft = await this.quizService.getRemainQuestionCount();
|
||||||
this.logger.verbose(
|
this.logger.verbose(
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ export enum GameQueueTypes {
|
||||||
playExtraCard = 'play_extra_card',
|
playExtraCard = 'play_extra_card',
|
||||||
screpaAnounce = 'screpa',
|
screpaAnounce = 'screpa',
|
||||||
showresults = 'show_results',
|
showresults = 'show_results',
|
||||||
|
extra_points = 'extra_points',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GameQueueDocument = GameQueue & Document;
|
export type GameQueueDocument = GameQueue & Document;
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,5 @@ export enum SocketEvents {
|
||||||
GAME_RESUMED = 'game_resumed',
|
GAME_RESUMED = 'game_resumed',
|
||||||
NOTIFICATION = 'notification',
|
NOTIFICATION = 'notification',
|
||||||
FEATURE_FLAG_CHANGED = 'feature_flag_changed',
|
FEATURE_FLAG_CHANGED = 'feature_flag_changed',
|
||||||
|
BEGIN_VERSUS = 'begin_versus',
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
src/voice/dicts/endgame.dict.ts
Normal file
6
src/voice/dicts/endgame.dict.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
export class EndgameDict {
|
||||||
|
static maxAmountOfInvalidQuestions = "За самое большое количество неправильных ответов, 2 балла получает %GenitiveCase%";
|
||||||
|
static maxAmountOfRewards ="За самое большое количество полученных призов %GenitiveCase% получает минус два балла";
|
||||||
|
static maxPenalties = "За самое большое количество наказаний %GenitiveCase% получает 3 балла";
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,6 @@ import { TtsRequestDto, TtsRequestWithVars } from './models/TtsRequestDto';
|
||||||
import { invalidPrefixDict } from './dicts/invalid-prefix.dict';
|
import { invalidPrefixDict } from './dicts/invalid-prefix.dict';
|
||||||
import { validPrefixDict } from './dicts/valid-prefix.dict';
|
import { validPrefixDict } from './dicts/valid-prefix.dict';
|
||||||
import * as translit from 'latin-to-cyrillic';
|
import * as translit from 'latin-to-cyrillic';
|
||||||
import {ConfigService} from "@nestjs/config";
|
|
||||||
import {FeatureflagService} from "../featureflag/featureflag.service";
|
import {FeatureflagService} from "../featureflag/featureflag.service";
|
||||||
import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts";
|
import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts";
|
||||||
@Controller('voice')
|
@Controller('voice')
|
||||||
|
|
@ -22,7 +21,6 @@ export class VoiceController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Get('ssml')
|
@Get('ssml')
|
||||||
@Header('content-type', 'audio/opus')
|
@Header('content-type', 'audio/opus')
|
||||||
@Header('content-disposition', 'inline')
|
@Header('content-disposition', 'inline')
|
||||||
|
|
@ -33,7 +31,6 @@ export class VoiceController {
|
||||||
} else {
|
} else {
|
||||||
return new NotFoundException('Voice disabled');
|
return new NotFoundException('Voice disabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('tts')
|
@Get('tts')
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ export class VoiceService {
|
||||||
}
|
}
|
||||||
this.logger.verbose(`Result is: ${template}`);
|
this.logger.verbose(`Result is: ${template}`);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
|
||||||
template = translit(template);
|
template = translit(template);
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue