Template
feat : guess word
This commit is contained in:
+1
-1
Submodule events updated: 22656ba608...fc3f0e1677
@@ -139,6 +139,12 @@ export class GamesController {
|
|||||||
if (!player) {
|
if (!player) {
|
||||||
throw new HttpException('You are not in this game', HttpStatus.FORBIDDEN);
|
throw new HttpException('You are not in this game', HttpStatus.FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
if (player.hasGuessed) {
|
||||||
|
throw new HttpException(
|
||||||
|
'You cannot send messages if you have already guessed the word',
|
||||||
|
HttpStatus.FORBIDDEN,
|
||||||
|
);
|
||||||
|
}
|
||||||
await this.gameService.postMessage(game, player, value);
|
await this.gameService.postMessage(game, player, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,18 +49,17 @@ export class Game {
|
|||||||
turn: number = 0;
|
turn: number = 0;
|
||||||
|
|
||||||
@OneToMany(() => ConceptInTurn, (cit) => cit.game, {
|
@OneToMany(() => ConceptInTurn, (cit) => cit.game, {
|
||||||
onDelete: 'CASCADE',
|
|
||||||
eager: true,
|
eager: true,
|
||||||
})
|
})
|
||||||
currentConcepts: ConceptInTurn[];
|
currentConcepts: ConceptInTurn[];
|
||||||
|
|
||||||
@OneToMany(() => Message, (msg) => msg.game, {
|
@OneToMany(() => Message, (msg) => msg.game, {
|
||||||
onDelete: 'CASCADE',
|
|
||||||
eager: true,
|
eager: true,
|
||||||
})
|
})
|
||||||
_messages: Message[];
|
_messages: Message[];
|
||||||
|
|
||||||
get messages() {
|
get messages() {
|
||||||
return this._messages.sort((a, b) => a.id - b.id);
|
if (!this._messages) return [];
|
||||||
|
return [...this._messages].sort((a, b) => a.id - b.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ export class Message {
|
|||||||
value: string;
|
value: string;
|
||||||
|
|
||||||
@JoinColumn({ name: 'authorId' })
|
@JoinColumn({ name: 'authorId' })
|
||||||
@ManyToOne(() => Player, { eager: true })
|
@ManyToOne(() => Player, { onDelete: 'CASCADE', eager: true, nullable: true })
|
||||||
author: Player;
|
author?: Player;
|
||||||
|
|
||||||
get authorId() {
|
get authorId() {
|
||||||
return this.author.userId;
|
return this.author?.userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ManyToOne(() => Game)
|
@ManyToOne(() => Game, { onDelete: 'CASCADE' })
|
||||||
game: Promise<Game>;
|
game: Promise<Game>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,4 +29,7 @@ export class Player {
|
|||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
score: number = 0;
|
score: number = 0;
|
||||||
|
|
||||||
|
@Column({ default: false })
|
||||||
|
hasGuessed: boolean = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ import { User } from 'src/users/entities/user.entity';
|
|||||||
|
|
||||||
import { WordService } from 'src/word/services/word.service';
|
import { WordService } from 'src/word/services/word.service';
|
||||||
import {
|
import {
|
||||||
|
GameEndTurnEvent,
|
||||||
GameMessageDeleteEvent,
|
GameMessageDeleteEvent,
|
||||||
GameMessageEvent,
|
GameMessageEvent,
|
||||||
GameStartEvent,
|
GameStartEvent,
|
||||||
} from 'events/game.events';
|
} from 'events/game.events';
|
||||||
import random from 'random';
|
import random from 'random';
|
||||||
import { platform } from 'os';
|
|
||||||
import { Message } from '../entities/message.entity';
|
import { Message } from '../entities/message.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -27,6 +27,7 @@ export class GameService {
|
|||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Game) private gameRepository: Repository<Game>,
|
@InjectRepository(Game) private gameRepository: Repository<Game>,
|
||||||
@InjectRepository(Message) private messageResporitory: Repository<Message>,
|
@InjectRepository(Message) private messageResporitory: Repository<Message>,
|
||||||
|
@InjectRepository(Player) private playerRepository: Repository<Player>,
|
||||||
private readonly wordService: WordService,
|
private readonly wordService: WordService,
|
||||||
private eventEmitter: EventEmitter2,
|
private eventEmitter: EventEmitter2,
|
||||||
) {}
|
) {}
|
||||||
@@ -35,8 +36,8 @@ export class GameService {
|
|||||||
const rng = random.clone(game.seed);
|
const rng = random.clone(game.seed);
|
||||||
game.started = true;
|
game.started = true;
|
||||||
game.currentPlayer = rng.choice(game.players);
|
game.currentPlayer = rng.choice(game.players);
|
||||||
const words = await this.wordService.listActive();
|
const words = await this.getShuffledWordList(game);
|
||||||
game.currentWord = rng.choice(words);
|
game.currentWord = words[0];
|
||||||
|
|
||||||
await this.gameRepository.save(game);
|
await this.gameRepository.save(game);
|
||||||
this.eventEmitter.emit(
|
this.eventEmitter.emit(
|
||||||
@@ -47,30 +48,87 @@ export class GameService {
|
|||||||
|
|
||||||
async postMessage(game: Game, author: Player, value: string) {
|
async postMessage(game: Game, author: Player, value: string) {
|
||||||
const message = this.messageResporitory.create();
|
const message = this.messageResporitory.create();
|
||||||
message.author = author;
|
|
||||||
message.game = Promise.resolve(game);
|
message.game = Promise.resolve(game);
|
||||||
|
|
||||||
|
if (
|
||||||
|
value.toLowerCase() == game.currentWord.value.toLowerCase() &&
|
||||||
|
author.id != game.currentPlayer.id
|
||||||
|
) {
|
||||||
|
message.value = author.userId;
|
||||||
|
author.hasGuessed = true;
|
||||||
|
author.score++;
|
||||||
|
game.currentPlayer.score++;
|
||||||
|
await this.playerRepository.save([author, game.currentPlayer]);
|
||||||
|
} else {
|
||||||
|
message.author = author;
|
||||||
message.value = value;
|
message.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
await this.messageResporitory.save(message);
|
await this.messageResporitory.save(message);
|
||||||
this.eventEmitter.emit(
|
this.eventEmitter.emit(
|
||||||
'sse.game.' + game.id,
|
'sse.game.' + game.id,
|
||||||
new GameMessageEvent(message),
|
new GameMessageEvent(message),
|
||||||
);
|
);
|
||||||
const oldMessage = game.messages[0];
|
|
||||||
const oldMessageId = oldMessage.id;
|
|
||||||
if (game.messages.length > 3) {
|
if (game.messages.length > 3) {
|
||||||
await this.messageResporitory.remove(oldMessage);
|
await this.deleteMessage(game, game.messages[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
game.players
|
||||||
|
.filter((p) => p.id != game.currentPlayer.id)
|
||||||
|
.every((p) => p.hasGuessed)
|
||||||
|
) {
|
||||||
|
await this.endTurn(game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async deleteMessage(game: Game, message: Message) {
|
||||||
|
const oldMessageId = message.id;
|
||||||
|
await this.messageResporitory.remove(message);
|
||||||
this.eventEmitter.emit(
|
this.eventEmitter.emit(
|
||||||
'sse.game.' + game.id,
|
'sse.game.' + game.id,
|
||||||
new GameMessageDeleteEvent(oldMessageId),
|
new GameMessageDeleteEvent(oldMessageId),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async endTurn(game: Game) {
|
||||||
|
const smartPlayers = game.players.filter((p) => p.hasGuessed);
|
||||||
|
smartPlayers.forEach((p) => (p.hasGuessed = false));
|
||||||
|
|
||||||
|
const wordList = await this.getShuffledWordList(game);
|
||||||
|
game.turn++;
|
||||||
|
game.currentWord = wordList[game.turn % wordList.length];
|
||||||
|
const playerIndex = game.players.findIndex(
|
||||||
|
(p) => p.userId == game.currentPlayer.userId,
|
||||||
|
);
|
||||||
|
game.currentPlayer = game.players[(playerIndex + 1) % game.players.length];
|
||||||
|
|
||||||
|
// await this.currentConceptReporitory.remove(game.currentConcept)
|
||||||
|
await this.gameRepository.save(game);
|
||||||
|
await this.playerRepository.save(smartPlayers);
|
||||||
|
|
||||||
|
await this.messageResporitory.delete({ game });
|
||||||
|
|
||||||
|
this.eventEmitter.emit(
|
||||||
|
'sse.game.' + game.id,
|
||||||
|
new GameEndTurnEvent(game.currentPlayer),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shuffles the word list using a per-game seeded rng
|
||||||
|
*/
|
||||||
|
async getShuffledWordList(game: Game) {
|
||||||
|
const rng = random.clone(game.seed);
|
||||||
|
const words = await this.wordService.listActive();
|
||||||
|
return words
|
||||||
|
.map((value) => ({ value, sort: rng.float() }))
|
||||||
|
.sort((a, b) => a.sort - b.sort)
|
||||||
|
.map(({ value }) => value);
|
||||||
|
}
|
||||||
|
|
||||||
async end(game: Game, winner: Player) {
|
async end(game: Game, winner: Player) {
|
||||||
throw Error('Not Implemented');
|
throw Error('Not Implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
async guessWord(game: Game, user: User, word: string) {
|
|
||||||
throw Error('Not Implemented');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user