versus implementation

This commit is contained in:
Kirill Ivlev 2024-11-12 02:23:12 +04:00
parent ede897c8e2
commit 457554e952
15 changed files with 119 additions and 24 deletions

View file

@ -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';
@Controller('game')
export class GameController {
private readonly logger = new Logger(GameController.name);
constructor(private gameService: GameService) {
}
@ -30,4 +31,10 @@ export class GameController {
async playExtraCards() {
return this.gameService.playExtraCards();
}
@Post('simulate-versus')
async SimulateVersus() {
this.logger.verbose('[SimulateVersus] enter');
return this.gameService.simulateVersus();
}
}

View file

@ -11,6 +11,9 @@ import {ConfigServiceMock} from "../mocks/config-service.mock";
import {SharedService} from "../shared/shared.service";
import {SharedServiceMock} from "../mocks/shared-service.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', () => {
let service: GameService;
@ -25,6 +28,7 @@ describe('GameService', () => {
{ provide: ConfigService, useValue: ConfigServiceMock },
{ provide: SharedService, useValue: SharedServiceMock },
{ provide: QueryBus, useValue: QueryBusMock },
{ provide: GuestsService, useValue: GuestsServiceMock }
],
}).compile();

View file

@ -13,6 +13,7 @@ import { SharedService } from '../shared/shared.service';
import { SocketEvents } from '../shared/events.consts';
import {ConfigService} from "@nestjs/config";
import {gameCards} from "./entities/cards.entities";
import {GuestsService} from "../guests/guests.service";
@Injectable()
export class GameService implements OnApplicationBootstrap{
@ -26,6 +27,7 @@ export class GameService implements OnApplicationBootstrap{
private sharedService: SharedService,
private commandBus: CommandBus,
private queryBus: QueryBus,
private guestService: GuestsService,
) {
}
@ -113,4 +115,24 @@ export class GameService implements OnApplicationBootstrap{
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
View file

@ -0,0 +1,5 @@
export interface GuestNamesInCases {
SubjectiveCase: string;
AccusativeCase: string;
GenitiveCase: string;
}

View file

@ -1,7 +1,7 @@
import {Inject, Injectable, Logger} from '@nestjs/common';
import {InjectModel} from '@nestjs/mongoose';
import {Guest, GuestDocument} from '../schemas/guest.schema';
import {Model} from 'mongoose';
import {Document, Model} from 'mongoose';
import {CreateGuestDto} from './dto/create-guest.dto';
import {QuestionDto} from '../quiz/dto/question.dto';
import {Messages} from '../messaging/tg.text';
@ -27,6 +27,7 @@ import {DebuffsConsts} from "../game/entities/debuffs.consts";
import {VoiceService} from "../voice/voice.service";
import {screpaDictManyInvalidAnswersDict} from "../voice/dicts/screpa-dict-many-invalid-answers.dict";
import {GuestPropertiesConsts} from "../schemas/properties.consts";
import {GuestNamesInCases} from "./guest.types";
@Injectable()
export class GuestsService {
@ -312,6 +313,15 @@ export class GuestsService {
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) {
this.logger.verbose(`Increment invalid answers in the row for ${tId}`);
const guest = await this.findById(tId);

View file

@ -54,6 +54,6 @@ export class QuizController {
@Get('endgame-extrapoints')
async endgameExtrapoints()
{
return await this.quizService.addEndgamePoints();
return await this.quizService.calculateEndgamePoints();
}
}

View file

@ -18,6 +18,7 @@ import {IncreasePlayerWinningRateCommand} from "../game/commands/increase-player
import {IncreasePlayerScoreCommand} from "../guests/command/increase-player-score.command";
import {FeatureflagService} from "../featureflag/featureflag.service";
import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts";
import {QuizEndGameResults} from "./quiz.types";
@Injectable({ scope: Scope.TRANSIENT })
export class QuizService {
@ -167,7 +168,7 @@ export class QuizService {
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 maxRewardsPromise = this.guestService.getModel().find({}).sort({['rewardsReceived']: "desc"}).exec();
const maxPenaltiesPromise = this.guestService.getModel().find({}).sort({['penaltiesReceived']: 'desc'}).exec();

11
src/quiz/quiz.types.d.ts vendored Normal file
View file

@ -0,0 +1,11 @@
export interface QuizEndGameResultsDetails {
id: number;
count: number;
name: string;
}
export interface QuizEndGameResults {
maxInvalidAnswers: QuizEndGameResultsDetails;
maxRewards: QuizEndGameResultsDetails;
maxPenalties: QuizEndGameResultsDetails;
}

View file

@ -10,6 +10,10 @@ import {SharedService} from "../shared/shared.service";
import {SharedServiceMock} from "../mocks/shared-service.mock";
import {FeatureflagService} from "../featureflag/featureflag.service";
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', () => {
@ -26,7 +30,9 @@ describe('SchedulerService', () => {
{ provide: StateService, useValue: StateServiceMock },
{ provide: QuizService, useValue: QuizServiceMock },
{ provide: SharedService, useValue: SharedServiceMock },
{ provide: FeatureflagService, useValue: FeatureflagServiceMock }
{ provide: FeatureflagService, useValue: FeatureflagServiceMock },
{ provide: CommandBus, useValue: CommandbusMock },
{ provide: GuestsService, useValue: GuestsServiceMock },
],
}).compile();

View file

@ -1,11 +1,15 @@
import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { StateService } from '../state/state.service';
import { QuizService } from '../quiz/quiz.service';
import { GiftsService } from '../gifts/gifts.service';
import { SharedService } from '../shared/shared.service';
import {Injectable, Logger} from '@nestjs/common';
import {Cron} from '@nestjs/schedule';
import {StateService} from '../state/state.service';
import {QuizService} from '../quiz/quiz.service';
import {GiftsService} from '../gifts/gifts.service';
import {SharedService} from '../shared/shared.service';
import {FeatureflagService} from "../featureflag/featureflag.service";
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()
export class SchedulerService {
@ -19,6 +23,7 @@ export class SchedulerService {
private quizService: QuizService,
private sharedService: SharedService,
private featureFlagService: FeatureflagService,
private commandBus: CommandBus,
) {}
@Cron('* * * * *')
@ -26,6 +31,34 @@ export class SchedulerService {
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() {
this.state = (await this.stateService.getState('main')).value;
this.logger.verbose(`Game state is: ${this.state}`);
@ -34,15 +67,7 @@ export class SchedulerService {
async gameStatus() {
const giftsLeft = await this.giftsService.getRemainingPrizeCount();
if (giftsLeft === 0) {
if(await this.featureFlagService.getFeatureFlag(FeatureFlagsConsts.EnableEndgamePoints)) {
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`);
await this.finishGame();
}
const questionsLeft = await this.quizService.getRemainQuestionCount();
this.logger.verbose(

View file

@ -8,6 +8,7 @@ export enum GameQueueTypes {
playExtraCard = 'play_extra_card',
screpaAnounce = 'screpa',
showresults = 'show_results',
extra_points = 'extra_points',
}
export type GameQueueDocument = GameQueue & Document;

View file

@ -13,4 +13,5 @@ export enum SocketEvents {
GAME_RESUMED = 'game_resumed',
NOTIFICATION = 'notification',
FEATURE_FLAG_CHANGED = 'feature_flag_changed',
BEGIN_VERSUS = 'begin_versus',
}

View file

@ -0,0 +1,6 @@
export class EndgameDict {
static maxAmountOfInvalidQuestions = "За самое большое количество неправильных ответов, 2 балла получает %GenitiveCase%";
static maxAmountOfRewards ="За самое большое количество полученных призов %GenitiveCase% получает минус два балла";
static maxPenalties = "За самое большое количество наказаний %GenitiveCase% получает 3 балла";
}

View file

@ -4,7 +4,6 @@ import { TtsRequestDto, TtsRequestWithVars } from './models/TtsRequestDto';
import { invalidPrefixDict } from './dicts/invalid-prefix.dict';
import { validPrefixDict } from './dicts/valid-prefix.dict';
import * as translit from 'latin-to-cyrillic';
import {ConfigService} from "@nestjs/config";
import {FeatureflagService} from "../featureflag/featureflag.service";
import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts";
@Controller('voice')
@ -22,7 +21,6 @@ export class VoiceController {
}
@Get('ssml')
@Header('content-type', 'audio/opus')
@Header('content-disposition', 'inline')
@ -33,7 +31,6 @@ export class VoiceController {
} else {
return new NotFoundException('Voice disabled');
}
}
@Get('tts')

View file

@ -30,7 +30,6 @@ export class VoiceService {
}
this.logger.verbose(`Result is: ${template}`);
// eslint-disable-next-line @typescript-eslint/no-var-requires
template = translit(template);
return template;
}