Compare commits
10 commits
features/t
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e75fa077d | |||
| a70aa80d67 | |||
| 1f12ef292e | |||
| 682126e043 | |||
| 2073dcff93 | |||
| 2b59393d98 | |||
| 6e7ffe7164 | |||
| c8aab51833 | |||
| df4f1578b6 | |||
| a8a3c6d48a |
18 changed files with 400 additions and 27 deletions
|
|
@ -278,7 +278,7 @@
|
||||||
"a3": "Маджуро",
|
"a3": "Маджуро",
|
||||||
"a4": "Фунафути",
|
"a4": "Фунафути",
|
||||||
"valid": "Нгерулмуд"
|
"valid": "Нгерулмуд"
|
||||||
}
|
},
|
||||||
{
|
{
|
||||||
"question": "Кто из друзей работает массажисткой?",
|
"question": "Кто из друзей работает массажисткой?",
|
||||||
"a1": "Моника",
|
"a1": "Моника",
|
||||||
|
|
@ -351,6 +351,62 @@
|
||||||
"a4": "Апоптоз",
|
"a4": "Апоптоз",
|
||||||
"valid": "Митоз"
|
"valid": "Митоз"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"question": "Как называется город-государство, существовавший в Средиземноморье и разрушенный Римом в результате Третьей Пунической войны?",
|
||||||
|
"a1": "Карфаген",
|
||||||
|
"a2": "Спарта",
|
||||||
|
"a3": "Афины",
|
||||||
|
"a4": "Троя",
|
||||||
|
"valid": "Карфаген"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Какой химический элемент является самым распространённым в земной коре?",
|
||||||
|
"a1": "Кислород",
|
||||||
|
"a2": "Кремний",
|
||||||
|
"a3": "Алюминий",
|
||||||
|
"a4": "Железо",
|
||||||
|
"valid": "Кислород"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Как называется самый крупный орган в теле человека по площади и массе?",
|
||||||
|
"a1": "Печень",
|
||||||
|
"a2": "Кожа",
|
||||||
|
"a3": "Лёгкие",
|
||||||
|
"a4": "Мозг",
|
||||||
|
"valid": "Кожа"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Как называется теория, объединяющая общую теорию относительности и квантовую механику, которая пока не была успешно создана?",
|
||||||
|
"a1": "Теория всего",
|
||||||
|
"a2": "Стандартная модель",
|
||||||
|
"a3": "Суперсимметрия",
|
||||||
|
"a4": "Теория струн",
|
||||||
|
"valid": "Теория всего"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Как называется древний математический трактат, написанный Евклидом около 300 г. до н.э., в котором изложены основы геометрии?",
|
||||||
|
"a1": "Начала",
|
||||||
|
"a2": "Элементы",
|
||||||
|
"a3": "Постулаты",
|
||||||
|
"a4": "Аксиомы",
|
||||||
|
"valid": "Начала"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Какой термин описывает псевдонауку, изучающую мифических существ, таких как йети и лох-несское чудовище?",
|
||||||
|
"a1": "Криптозоология",
|
||||||
|
"a2": "Палеонтология",
|
||||||
|
"a3": "Зоология",
|
||||||
|
"a4": "Антропология",
|
||||||
|
"valid": "Криптозоология"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Как называется лженаучная практика, утверждающая, что разбавление вещества в воде увеличивает его лечебные свойства?",
|
||||||
|
"a1": "Аллопатия",
|
||||||
|
"a2": "Гомеопатия",
|
||||||
|
"a3": "Натуропатия",
|
||||||
|
"a4": "Ароматерапия",
|
||||||
|
"valid": "Гомеопатия"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"question": "Как называется самая продаваемая видеоигра всех времён?",
|
"question": "Как называется самая продаваемая видеоигра всех времён?",
|
||||||
"a1": "Minecraft",
|
"a1": "Minecraft",
|
||||||
|
|
@ -1015,6 +1071,38 @@
|
||||||
"a4": "Нептун",
|
"a4": "Нептун",
|
||||||
"valid": "Сатурн"
|
"valid": "Сатурн"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"question": "Как называется традиционное японское искусство складывания бумаги в фигуры?",
|
||||||
|
"a1": "Киригами",
|
||||||
|
"a2": "Оригами",
|
||||||
|
"a3": "Икебана",
|
||||||
|
"a4": "Суми-э",
|
||||||
|
"valid": "Оригами"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Как называется японское искусство аранжировки цветов?",
|
||||||
|
"a1": "Суми-э",
|
||||||
|
"a2": "Икебана",
|
||||||
|
"a3": "Бонсай",
|
||||||
|
"a4": "Шодо",
|
||||||
|
"valid": "Икебана"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Как называется известная гора в Японии, являющаяся символом страны?",
|
||||||
|
"a1": "Гора Фудзи",
|
||||||
|
"a2": "Гора Кита",
|
||||||
|
"a3": "Гора Окухотаке",
|
||||||
|
"a4": "Гора Тате",
|
||||||
|
"valid": "Гора Фудзи"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Как называется традиционный японский театр с куклами?",
|
||||||
|
"a1": "Но",
|
||||||
|
"a2": "Кабуки",
|
||||||
|
"a3": "Бунраку",
|
||||||
|
"a4": "Кёгэн",
|
||||||
|
"valid": "Бунраку"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"question": "Какое число является следующим в ряде Фибоначчи: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34?",
|
"question": "Какое число является следующим в ряде Фибоначчи: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34?",
|
||||||
"a1": "44",
|
"a1": "44",
|
||||||
|
|
@ -1030,5 +1118,197 @@
|
||||||
"a3": "Число 0",
|
"a3": "Число 0",
|
||||||
"a4": "Число 8",
|
"a4": "Число 8",
|
||||||
"valid": "Число 6"
|
"valid": "Число 6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Как называется гипотеза математики, сформулированная в 1859 году и до сих пор не доказанная, связанная с распределением нулей дзета-функции Римана?",
|
||||||
|
"a1": "Гипотеза Голдбаха",
|
||||||
|
"a2": "Гипотеза Пуанкаре",
|
||||||
|
"a3": "Гипотеза Римана",
|
||||||
|
"a4": "Гипотеза Ходжа",
|
||||||
|
"valid": "Гипотеза Римана"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Как называется редкий химический элемент с атомным номером 61, который не встречается в природе и был впервые получен искусственно?",
|
||||||
|
"a1": "Прометий",
|
||||||
|
"a2": "Технеций",
|
||||||
|
"a3": "Астат",
|
||||||
|
"a4": "Полоний",
|
||||||
|
"valid": "Прометий"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Кто был первым человеком, измерившим окружность Земли с удивительной точностью в третьем веке до нашей эры?",
|
||||||
|
"a1": "Аристотель",
|
||||||
|
"a2": "Эратосфен",
|
||||||
|
"a3": "Гиппарх",
|
||||||
|
"a4": "Архимед",
|
||||||
|
"valid": "Эратосфен"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Как называется самая большая луна Сатурна, обладающая плотной атмосферой и озерами из жидких углеводородов?",
|
||||||
|
"a1": "Европа",
|
||||||
|
"a2": "Титан",
|
||||||
|
"a3": "Ганимед",
|
||||||
|
"a4": "Каллисто",
|
||||||
|
"valid": "Титан"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Как называется самый длинный в мире музыкальный инструмент, который изобрели в Украине?",
|
||||||
|
"a1": "Гудок",
|
||||||
|
"a2": "Кугиклы",
|
||||||
|
"a3": "Трембита",
|
||||||
|
"a4": "Бугай",
|
||||||
|
"valid": "Трембита"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Какой цветок - символ Турции?",
|
||||||
|
"a1": "Ромашка",
|
||||||
|
"a2": "Роза",
|
||||||
|
"a3": "Тюльпан",
|
||||||
|
"a4": "Пион",
|
||||||
|
"valid": "Тюльпан"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Какой металл самый дорогой на Земле?",
|
||||||
|
"a1": "Калифорний",
|
||||||
|
"a2": "Платина",
|
||||||
|
"a3": "Золото",
|
||||||
|
"a4": "Родий",
|
||||||
|
"valid": "Калифорний"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Чью анатомию изучает наука фелинология?",
|
||||||
|
"a1": "Домашних кошек",
|
||||||
|
"a2": "Летучих мышей",
|
||||||
|
"a3": "Крыс",
|
||||||
|
"a4": "Уток",
|
||||||
|
"valid": "Домашних кошек"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Кто создал первую в мире вакцину от вирусной болезни?",
|
||||||
|
"a1": "Эдвард Дженнер",
|
||||||
|
"a2": "Фредерик Туорт",
|
||||||
|
"a3": "Харолд Вармус",
|
||||||
|
"a4": "Люк Монтанье",
|
||||||
|
"valid": "Эдвард Дженнер"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Сколько сортов винограда в Грузии?",
|
||||||
|
"a1": 120,
|
||||||
|
"a2": 150,
|
||||||
|
"a3": 380,
|
||||||
|
"a4": 500,
|
||||||
|
"valid": 500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Какой плод образно называют аллигаторовой грушей?",
|
||||||
|
"a1": "Авокадо",
|
||||||
|
"a2": "Манго",
|
||||||
|
"a3": "Дыня",
|
||||||
|
"a4": "Дуриан",
|
||||||
|
"valid": "Авокадо"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "В каком году умер Наполеон Бонапарт?",
|
||||||
|
"a1": 1817,
|
||||||
|
"a2": 1819,
|
||||||
|
"a3": 1821,
|
||||||
|
"a4": 1829,
|
||||||
|
"valid": 1821
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Под каким псевдонимом творил Франсуа Мари Аруэ?",
|
||||||
|
"a1": "Томас Гоббс",
|
||||||
|
"a2": "Джон Локк",
|
||||||
|
"a3": "Вольтер",
|
||||||
|
"a4": "Сократ",
|
||||||
|
"valid": "Вольтер"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "В каком органе образуется желчь?",
|
||||||
|
"a1": "Печень",
|
||||||
|
"a2": "Мочевой пузырь",
|
||||||
|
"a3": "Желчный пузырь",
|
||||||
|
"a4": "Желудок",
|
||||||
|
"valid": "Печень"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Как звали отца Чиполлино?",
|
||||||
|
"a1": "Чиполитто",
|
||||||
|
"a2": "Чиполонне",
|
||||||
|
"a3": "Чиполетто",
|
||||||
|
"a4": "Чиполоре",
|
||||||
|
"valid": "Чиполонне"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Название какого алкогольного напитка переводится с немецкого как \"полынь\"?",
|
||||||
|
"a1": "Вермут",
|
||||||
|
"a2": "Бренди",
|
||||||
|
"a3": "Виски",
|
||||||
|
"a4": "Коньяк",
|
||||||
|
"valid": "Вермут"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Сколько кубиков в кyбике Рубика?",
|
||||||
|
"a1": 22,
|
||||||
|
"a2": 24,
|
||||||
|
"a3": 26,
|
||||||
|
"a4": 28,
|
||||||
|
"valid": 26
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Для представителей какой профессии были изготовлены самые первые шариковые ручки?",
|
||||||
|
"a1": "Журналисты",
|
||||||
|
"a2": "Летчики",
|
||||||
|
"a3": "Водолазы",
|
||||||
|
"a4": "Учителя",
|
||||||
|
"valid": "Летчики"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Какую пошлину ввели в XII веке в Англии для того, чтобы заставить мужчин пойти на войну?",
|
||||||
|
"a1": "Налог на тунеядство",
|
||||||
|
"a2": "Налог на трусость",
|
||||||
|
"a3": "Налог на отсутсвие сапог",
|
||||||
|
"a4": "Налог на отстутсвие усов",
|
||||||
|
"valid": "Налог на трусость"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Откуда пошло выражение \"Деньги не пахнут\"?",
|
||||||
|
"a1": "От поставщиков парфюмерии",
|
||||||
|
"a2": "От сборов за нестиранные носки",
|
||||||
|
"a3": "От налога на туалеты",
|
||||||
|
"a4": "От испорченной еды",
|
||||||
|
"valid": "От налога на туалеты"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Как, в переводе на русский язык, звучало бы название фильма \"Мимино\"?",
|
||||||
|
"a1": "Медведь",
|
||||||
|
"a2": "Гора",
|
||||||
|
"a3": "Сокол",
|
||||||
|
"a4": "Любовь",
|
||||||
|
"valid": "Сокол"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "В какой из столиц союзных республик раньше всего появилось метро?",
|
||||||
|
"a1": "Минск",
|
||||||
|
"a2": "Тбилиси",
|
||||||
|
"a3": "Баку",
|
||||||
|
"a4": "Ереван",
|
||||||
|
"valid": "Тбилиси"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Первым фильмом Диснея был....?",
|
||||||
|
"a1": "Белоснежка",
|
||||||
|
"a2": "Золушка",
|
||||||
|
"a3": "Рапунцель",
|
||||||
|
"a4": "Микки Маус",
|
||||||
|
"valid": "Белоснежка"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Что такое Измир?",
|
||||||
|
"a1": "Турецкий город",
|
||||||
|
"a2": "Якутский камень",
|
||||||
|
"a3": "Блюдо в ресторане",
|
||||||
|
"a4": "Экзотический фрукт",
|
||||||
|
"valid": "Турецкий город"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -27,7 +27,7 @@ export class GameProceedGameQueueCommandHandler
|
||||||
return this.cmdBus.execute(new NextQuestionCommand());
|
return this.cmdBus.execute(new NextQuestionCommand());
|
||||||
}
|
}
|
||||||
this.sharedService.notifyAllClients<IGameQueueSocketEvent>(ClientNotificationType.GameQueueItem, {
|
this.sharedService.notifyAllClients<IGameQueueSocketEvent>(ClientNotificationType.GameQueueItem, {
|
||||||
_id: item.id,
|
_id: item._id,
|
||||||
completed: item.completed,
|
completed: item.completed,
|
||||||
target: item.target,
|
target: item.target,
|
||||||
type: item.type,
|
type: item.type,
|
||||||
|
|
|
||||||
|
|
@ -250,7 +250,7 @@ export class BanPlayer extends GameCard {
|
||||||
|
|
||||||
async handle() {
|
async handle() {
|
||||||
await this.commandBus.execute(
|
await this.commandBus.execute(
|
||||||
new SelectTargetPlayerCommand(this.telegramId, DebuffsConsts.bannedFor, 2,false)
|
new SelectTargetPlayerCommand(this.telegramId, DebuffsConsts.bannedFor, getRandomInt(2,3), false)
|
||||||
)
|
)
|
||||||
await this.queryBus.execute(new FilterGuestsWithPropertyQuery(null,null,null));
|
await this.queryBus.execute(new FilterGuestsWithPropertyQuery(null,null,null));
|
||||||
this.eventBus.subscribe((data) =>{
|
this.eventBus.subscribe((data) =>{
|
||||||
|
|
@ -262,7 +262,7 @@ export class BanPlayer extends GameCard {
|
||||||
export const gameCards: typeof GameCard[] = [
|
export const gameCards: typeof GameCard[] = [
|
||||||
DoubleTreasureCard,
|
DoubleTreasureCard,
|
||||||
StolePrizeCard,
|
StolePrizeCard,
|
||||||
ShitCard,
|
// ShitCard,
|
||||||
LuckyCard,
|
LuckyCard,
|
||||||
AvoidPenaltyCard,
|
AvoidPenaltyCard,
|
||||||
BanPlayer,
|
BanPlayer,
|
||||||
|
|
|
||||||
4
src/game/events/state-changed.event.ts
Normal file
4
src/game/events/state-changed.event.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
export class StateChangedEvent {
|
||||||
|
constructor(state: string) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -45,4 +45,10 @@ export class GameController {
|
||||||
this.logger.warn(`[clearQueue] enter`);
|
this.logger.warn(`[clearQueue] enter`);
|
||||||
await this.gameService.clearGameQueue();
|
await this.gameService.clearGameQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('simulate-valid-answer')
|
||||||
|
async simulateValidAnswer() {
|
||||||
|
this.logger.verbose(`[simulateValidAnswer] enter`);
|
||||||
|
return await this.gameService.simulateValidAnswer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import {ConfigService} from "@nestjs/config";
|
||||||
import {gameCards} from "./entities/cards.entities";
|
import {gameCards} from "./entities/cards.entities";
|
||||||
import {IEmptyNotification} from "../Consts/types";
|
import {IEmptyNotification} from "../Consts/types";
|
||||||
import {ClientNotificationType} from "../socket/socket.gateway";
|
import {ClientNotificationType} from "../socket/socket.gateway";
|
||||||
|
import {GetGuestQuery} from "../guests/queries/getguest.query";
|
||||||
|
import {ValidAnswerReceivedEvent} from "./events/valid-answer.recieved";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GameService implements OnApplicationBootstrap{
|
export class GameService implements OnApplicationBootstrap{
|
||||||
|
|
@ -50,7 +52,26 @@ export class GameService implements OnApplicationBootstrap{
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGameQueueItem() {
|
async getGameQueueItem() {
|
||||||
return this.gameQueueModel.findOne({ completed: false }).exec();
|
const item = await this.gameQueueModel.aggregate([
|
||||||
|
{
|
||||||
|
$match: { completed: false }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$addFields: {
|
||||||
|
priority: {
|
||||||
|
$cond: [{ $eq: ["$type", "versus"] }, 1, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$sort: { priority: -1 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$limit: 1
|
||||||
|
}
|
||||||
|
]).exec();
|
||||||
|
console.log(item[0]);
|
||||||
|
return item[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
async markQueueAsCompleted(id: string| null) {
|
async markQueueAsCompleted(id: string| null) {
|
||||||
|
|
@ -110,4 +131,8 @@ export class GameService implements OnApplicationBootstrap{
|
||||||
await this.gameQueueModel.deleteMany({}).exec();
|
await this.gameQueueModel.deleteMany({}).exec();
|
||||||
return { result: true };
|
return { result: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async simulateValidAnswer() {
|
||||||
|
this.eventBus.publish(new ValidAnswerReceivedEvent(11178819, 'test', ''));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ import {GuestPropertyNamesConsts} from "../../Consts/guest-property-names.consts
|
||||||
import {SetGuestPropertyCommand} from "../../guests/command/set-guest-property.command";
|
import {SetGuestPropertyCommand} from "../../guests/command/set-guest-property.command";
|
||||||
import {IVersusBeginSocketEvent, IVersusEndSocketEvent} from "../../Consts/types";
|
import {IVersusBeginSocketEvent, IVersusEndSocketEvent} from "../../Consts/types";
|
||||||
import {ClientNotificationType} from "../../socket/socket.gateway";
|
import {ClientNotificationType} from "../../socket/socket.gateway";
|
||||||
|
import {CreateNewQueueItemCommand} from "../commands/create-new-queue-item.command";
|
||||||
|
import {GameQueueTypes} from "../../schemas/game-queue.schema";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class VersusService {
|
export class VersusService {
|
||||||
|
|
@ -42,6 +44,7 @@ export class VersusService {
|
||||||
|
|
||||||
async beginVersus(player1: number, player2: number) {
|
async beginVersus(player1: number, player2: number) {
|
||||||
const [p1data,p2data] = await Promise.all([this.guestService.findById(player1), this.guestService.findById(player2)]);
|
const [p1data,p2data] = await Promise.all([this.guestService.findById(player1), this.guestService.findById(player2)]);
|
||||||
|
await this.cmdBus.execute(new CreateNewQueueItemCommand(player1, GameQueueTypes.versus));
|
||||||
await this.sharedService.setConfig(VersusService.configKeyCurrentAction, JSON.stringify({
|
await this.sharedService.setConfig(VersusService.configKeyCurrentAction, JSON.stringify({
|
||||||
action:'versus',
|
action:'versus',
|
||||||
data: {
|
data: {
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,9 @@ export class GuestsService {
|
||||||
|
|
||||||
async findById(id: number) {
|
async findById(id: number) {
|
||||||
const result = await this.guestModel.findOne({ telegramId: id }).exec();
|
const result = await this.guestModel.findOne({ telegramId: id }).exec();
|
||||||
|
if(!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
delete result.photo;
|
delete result.photo;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
src/quiz/event-handlers/state-changed-event.handler.ts
Normal file
17
src/quiz/event-handlers/state-changed-event.handler.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import {EventsHandler, IEventHandler} from "@nestjs/cqrs";
|
||||||
|
import {StateChangedEvent} from "../../game/events/state-changed.event";
|
||||||
|
import {QuizService} from "../quiz.service";
|
||||||
|
import {Logger} from "@nestjs/common";
|
||||||
|
|
||||||
|
@EventsHandler(StateChangedEvent)
|
||||||
|
export class StateChangedEventHandler implements IEventHandler<StateChangedEvent> {
|
||||||
|
logger = new Logger(StateChangedEventHandler.name);
|
||||||
|
constructor(private quizService: QuizService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
async handle(event: StateChangedEvent) {
|
||||||
|
this.logger.verbose(`[StateChangedEventHandler] enter, event: ${event}}`)
|
||||||
|
await this.quizService.calculateEndgamePoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,11 @@ export class QuizController {
|
||||||
return this.quizService.proceedWithGame();
|
return this.quizService.proceedWithGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('timeout')
|
||||||
|
async Timeout() {
|
||||||
|
return await this.quizService.questionTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
@Post('questions')
|
@Post('questions')
|
||||||
async postQuestion(@Body() questionDto: QuestionDto[]) {
|
async postQuestion(@Body() questionDto: QuestionDto[]) {
|
||||||
return await this.quizService.populateQuestions(questionDto);
|
return await this.quizService.populateQuestions(questionDto);
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,17 @@ import { MarkQuestionsAsUnansweredCommandHandler } from './command-handlers/mark
|
||||||
import { PenaltyModule } from '../penalty/penalty.module';
|
import { PenaltyModule } from '../penalty/penalty.module';
|
||||||
import {ConfigModule, ConfigService} from "@nestjs/config";
|
import {ConfigModule, ConfigService} from "@nestjs/config";
|
||||||
import {Config, ConfigSchema} from "../schemas/config.schema";
|
import {Config, ConfigSchema} from "../schemas/config.schema";
|
||||||
|
import {StateChangedEventHandler} from "./event-handlers/state-changed-event.handler";
|
||||||
|
|
||||||
const cmdHandlers = [
|
const cmdHandlers = [
|
||||||
GameNextQuestionCommandHandler,
|
GameNextQuestionCommandHandler,
|
||||||
MarkQuestionsAsUnansweredCommandHandler,
|
MarkQuestionsAsUnansweredCommandHandler,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const eventHandlers = [
|
||||||
|
StateChangedEventHandler
|
||||||
|
]
|
||||||
|
|
||||||
@Global()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
|
@ -33,6 +38,6 @@ const cmdHandlers = [
|
||||||
],
|
],
|
||||||
controllers: [QuizController],
|
controllers: [QuizController],
|
||||||
exports: [QuizService],
|
exports: [QuizService],
|
||||||
providers: [QuizService,ConfigService, ...cmdHandlers],
|
providers: [QuizService,ConfigService, ...cmdHandlers, ...eventHandlers],
|
||||||
})
|
})
|
||||||
export class QuizModule {}
|
export class QuizModule {}
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ describe('QuizService', () => {
|
||||||
spyOn(featureFlagService,'getFeatureFlag').mockResolvedValue(ffstate);
|
spyOn(featureFlagService,'getFeatureFlag').mockResolvedValue(ffstate);
|
||||||
questionDocumentMock.userAnswers = [{
|
questionDocumentMock.userAnswers = [{
|
||||||
user: 1,
|
user: 1,
|
||||||
time: new Date(new Date().setSeconds(new Date().getSeconds() - 5)),
|
time: new Date(),
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -213,7 +213,7 @@ describe('QuizService', () => {
|
||||||
spyOn(featureFlagService,'getFeatureFlag').mockResolvedValue(ffstate);
|
spyOn(featureFlagService,'getFeatureFlag').mockResolvedValue(ffstate);
|
||||||
questionDocumentMock.userAnswers = [{
|
questionDocumentMock.userAnswers = [{
|
||||||
user: 1,
|
user: 1,
|
||||||
time: new Date(new Date().setSeconds(new Date().getSeconds() - 3)),
|
time: new Date(),
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -236,7 +236,7 @@ describe('QuizService', () => {
|
||||||
questionDocumentMock.scoreCalculated = false;
|
questionDocumentMock.scoreCalculated = false;
|
||||||
questionDocumentMock.userAnswers = [{
|
questionDocumentMock.userAnswers = [{
|
||||||
user: 1,
|
user: 1,
|
||||||
time: new Date(new Date().setSeconds(new Date().getSeconds() - 7)),
|
time: new Date(new Date().setSeconds(new Date().getSeconds() - 5.7)),
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,7 @@ import {BeginVersusCommand} from "../game/commands/begin-versus.command";
|
||||||
|
|
||||||
@Injectable({ scope: Scope.TRANSIENT })
|
@Injectable({ scope: Scope.TRANSIENT })
|
||||||
export class QuizService {
|
export class QuizService {
|
||||||
private readonly answerNumbers = Messages.answerNumbers;
|
|
||||||
private readonly logger = new Logger(QuizService.name);
|
private readonly logger = new Logger(QuizService.name);
|
||||||
private AcceptAnswersFromAllMembers: boolean = true; // TODO: move this to configurable state
|
|
||||||
constructor(
|
constructor(
|
||||||
@InjectModel(Question.name) private questionModel: Model<QuestionDocument>,
|
@InjectModel(Question.name) private questionModel: Model<QuestionDocument>,
|
||||||
@InjectModel(QuestionStorage.name)
|
@InjectModel(QuestionStorage.name)
|
||||||
|
|
@ -62,6 +60,9 @@ export class QuizService {
|
||||||
);
|
);
|
||||||
// check that answer exist
|
// check that answer exist
|
||||||
const shortAnswers = question.answers.map((answer) => answer.substring(0,50));
|
const shortAnswers = question.answers.map((answer) => answer.substring(0,50));
|
||||||
|
if(question.countdownFinished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const shortValidAnswer = question.valid.substring(0,50);
|
const shortValidAnswer = question.valid.substring(0,50);
|
||||||
if(shortAnswers.indexOf(answer) === -1) {
|
if(shortAnswers.indexOf(answer) === -1) {
|
||||||
this.logger.warn(`[validateAnswer] this question is not on game now`);
|
this.logger.warn(`[validateAnswer] this question is not on game now`);
|
||||||
|
|
@ -126,7 +127,7 @@ export class QuizService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const diff = Math.abs(new Date(answers[0].time).getTime() - new Date(answers[1].time).getTime()) / 1000;
|
const diff = Math.abs(new Date(answers[0].time).getTime() - new Date(answers[1].time).getTime()) / 1000;
|
||||||
return diff <= 5;
|
return diff <= 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
async calculateScore() {
|
async calculateScore() {
|
||||||
|
|
@ -150,7 +151,7 @@ export class QuizService {
|
||||||
const winner = sortedAnswers.find((answer) => answer.valid);
|
const winner = sortedAnswers.find((answer) => answer.valid);
|
||||||
let targetUser = 0;
|
let targetUser = 0;
|
||||||
if(winner) {
|
if(winner) {
|
||||||
const totalWinningScore = 80;
|
const totalWinningScore = getRandomInt(40,60);
|
||||||
sortedAnswers.filter(x => x.valid).forEach((answer) => {
|
sortedAnswers.filter(x => x.valid).forEach((answer) => {
|
||||||
this.logger.debug(`Giving 1 point to all who answered right`);
|
this.logger.debug(`Giving 1 point to all who answered right`);
|
||||||
this.commandBus.execute(new IncreasePlayerWinningRateCommand(answer.user,
|
this.commandBus.execute(new IncreasePlayerWinningRateCommand(answer.user,
|
||||||
|
|
@ -167,7 +168,7 @@ export class QuizService {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await this.commandBus.execute(new IncreasePlayerWinningRateCommand(sortedAnswers[0].user, 15));
|
await this.commandBus.execute(new IncreasePlayerWinningRateCommand(sortedAnswers[0].user, getRandomInt(4,9)));
|
||||||
this.logger.debug(`Giving 1 point to first`);
|
this.logger.debug(`Giving 1 point to first`);
|
||||||
await this.commandBus.execute(new IncreasePlayerScoreCommand(winner.user,1));
|
await this.commandBus.execute(new IncreasePlayerScoreCommand(winner.user,1));
|
||||||
targetUser = winner.user;
|
targetUser = winner.user;
|
||||||
|
|
@ -216,6 +217,9 @@ export class QuizService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await this.sharedService.setConfig('endgame-points', JSON.stringify(result));
|
await this.sharedService.setConfig('endgame-points', JSON.stringify(result));
|
||||||
|
await this.commandBus.execute(new IncreasePlayerScoreCommand(result.maxInvalidAnswers.id, 2));
|
||||||
|
await this.commandBus.execute(new IncreasePlayerScoreCommand(result.maxPenalties.id, 2));
|
||||||
|
await this.commandBus.execute(new IncreasePlayerScoreCommand(result.maxRewards.id, -2));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -342,4 +346,11 @@ export class QuizService {
|
||||||
const res = await this.sharedService.getConfig('endgame-points');
|
const res = await this.sharedService.getConfig('endgame-points');
|
||||||
return JSON.parse(res.value);
|
return JSON.parse(res.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async questionTimeout() {
|
||||||
|
const question = await this.get();
|
||||||
|
question.countdownFinished = true;
|
||||||
|
await question.save();
|
||||||
|
return question;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ export enum GameQueueTypes {
|
||||||
screpaAnounce = 'screpa',
|
screpaAnounce = 'screpa',
|
||||||
showresults = 'show_results',
|
showresults = 'show_results',
|
||||||
extra_points = 'extra_points',
|
extra_points = 'extra_points',
|
||||||
|
versus = 'versus',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GameQueueDocument = GameQueue & Document;
|
export type GameQueueDocument = GameQueue & Document;
|
||||||
|
|
|
||||||
|
|
@ -31,5 +31,7 @@ export class Question {
|
||||||
userAnswers: QuestionAnswer[];
|
userAnswers: QuestionAnswer[];
|
||||||
@Prop({ default: false })
|
@Prop({ default: false })
|
||||||
scoreCalculated: boolean;
|
scoreCalculated: boolean;
|
||||||
|
@Prop({ default: false})
|
||||||
|
countdownFinished: boolean;
|
||||||
}
|
}
|
||||||
export const QuestionSchema = SchemaFactory.createForClass(Question);
|
export const QuestionSchema = SchemaFactory.createForClass(Question);
|
||||||
|
|
|
||||||
|
|
@ -38,16 +38,16 @@ export class StateController {
|
||||||
if (setStateDto.value === 'quiz') {
|
if (setStateDto.value === 'quiz') {
|
||||||
this.eventBus.publish(new GameStartedEvent());
|
this.eventBus.publish(new GameStartedEvent());
|
||||||
} else if(setStateDto.value === 'onboarding') {
|
} else if(setStateDto.value === 'onboarding') {
|
||||||
this.telegramService.send<MqtMessageModel,any>(
|
// this.telegramService.send<MqtMessageModel,any>(
|
||||||
{ cmd: CommandsConsts.SetCommands },
|
// { cmd: CommandsConsts.SetCommands },
|
||||||
[
|
// [
|
||||||
{ command: 'start', description: 'главное меню'},
|
// { command: 'start', description: 'главное меню'},
|
||||||
{ command: 'cards', description: 'сыграть карту'},
|
// { command: 'cards', description: 'сыграть карту'},
|
||||||
{ command: 'question', description: 'вернутся к вопросу'}
|
// { command: 'question', description: 'вернутся к вопросу'}
|
||||||
]
|
// ]
|
||||||
).subscribe(() => {
|
// ).subscribe(() => {
|
||||||
this.logger.verbose('Bot commands updated');
|
// this.logger.verbose('Bot commands updated');
|
||||||
});
|
// });
|
||||||
} else {
|
} else {
|
||||||
this.logger.verbose('reset commands');
|
this.logger.verbose('reset commands');
|
||||||
this.telegramService.emit({ cmd: CommandsConsts.ResetCommands }, {});
|
this.telegramService.emit({ cmd: CommandsConsts.ResetCommands }, {});
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { Model } from 'mongoose';
|
||||||
import { EventBus } from '@nestjs/cqrs';
|
import { EventBus } from '@nestjs/cqrs';
|
||||||
import { PrepareGameEvent } from '../game/events/prepare-game.event';
|
import { PrepareGameEvent } from '../game/events/prepare-game.event';
|
||||||
import {IStateInfo} from "../Consts/types";
|
import {IStateInfo} from "../Consts/types";
|
||||||
|
import {StateChangedEvent} from "../game/events/state-changed.event";
|
||||||
|
|
||||||
interface StateDTO {
|
interface StateDTO {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -35,6 +36,8 @@ export class StateService {
|
||||||
if (newValue === 'onboarding') {
|
if (newValue === 'onboarding') {
|
||||||
this.eventBus.publish(new PrepareGameEvent());
|
this.eventBus.publish(new PrepareGameEvent());
|
||||||
}
|
}
|
||||||
|
this.eventBus.publish(new StateChangedEvent(newValue));
|
||||||
|
|
||||||
const stateEntity = await this.getState(name);
|
const stateEntity = await this.getState(name);
|
||||||
stateEntity.value = newValue;
|
stateEntity.value = newValue;
|
||||||
await stateEntity.save();
|
await stateEntity.save();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
export const validPrefixDict = [
|
export const validPrefixDict = [
|
||||||
'Да, %answer%, был правильным ответом, молодец %user%',
|
'Все так, %user%',
|
||||||
'Ура, %answer%, это верно. Забирай очко %user%',
|
|
||||||
'Все так, %user%, и правильный ответ это действительно %answer%',
|
|
||||||
'Выиграл балл - к призу ближе стал',
|
'Выиграл балл - к призу ближе стал',
|
||||||
'Ответил верно - за это можно и выпить',
|
'Ответил верно - за это можно и выпить',
|
||||||
'Уф, какой ты умненький, %user%',
|
'Уф, какой ты умненький, %user%',
|
||||||
|
|
@ -33,4 +31,14 @@ export const validPrefixDict = [
|
||||||
'%user%, откуда ты все знаешь? Ты случаем не эшник, а?',
|
'%user%, откуда ты все знаешь? Ты случаем не эшник, а?',
|
||||||
'молодец, %user%, можешь погладить пёселя',
|
'молодец, %user%, можешь погладить пёселя',
|
||||||
'%user%, у тебя такой склад ума, что хоть сторожа нанимай!',
|
'%user%, у тебя такой склад ума, что хоть сторожа нанимай!',
|
||||||
|
'Отличный ответ, %user%!',
|
||||||
|
'Ты попал в самую точку, %user%!',
|
||||||
|
'Вот это да, %user%, ты знаешь толк!',
|
||||||
|
'Так держать, %user%!',
|
||||||
|
'Твои знания на высоте, %user%!',
|
||||||
|
'Умница, %user%! Всё верно.',
|
||||||
|
'Блестяще, %user%! Продолжай в том же духе.',
|
||||||
|
'Ты меня впечатлил, %user%!',
|
||||||
|
'Не перестаёшь удивлять, %user%!',
|
||||||
|
'Великолепно, %user%! Твой ответ правильный!',
|
||||||
];
|
];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue