Skip to content

Commit

Permalink
feat(players): distinct player groups in game
Browse files Browse the repository at this point in the history
  • Loading branch information
antoinezanardi committed Oct 6, 2024
1 parent 9096494 commit 8572e75
Show file tree
Hide file tree
Showing 14 changed files with 18,654 additions and 18,355 deletions.
4 changes: 4 additions & 0 deletions src/modules/game/dto/create-game/create-game.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ class CreateGameDto {
@CompositionHasTwoGroupsWithPrejudicedManipulator()
public players: CreateGamePlayerDto[];

@ApiHideProperty()
@IsOptional()
public playerGroups?: string[];

@ApiHideProperty()
@IsOptional()
public currentPlay: GamePlay;
Expand Down
5 changes: 5 additions & 0 deletions src/modules/game/helpers/game.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ function getPlayerWithNameOrThrow(playerName: string, game: Game, exception: Err
return player;
}

function getDistinctPlayerGroups(game: CreateGameDto): string[] {
return [...new Set(game.players.map(({ group }) => group))].filter(Boolean) as string[];
}

function getAdditionalCardWithId(cards: GameAdditionalCard[] | undefined, id: Types.ObjectId): GameAdditionalCard | undefined {
return cards?.find(({ _id }) => _id.equals(id));
}
Expand Down Expand Up @@ -237,6 +241,7 @@ export {
getPlayersWithIds,
getPlayerWithName,
getPlayerWithNameOrThrow,
getDistinctPlayerGroups,
getAdditionalCardWithId,
areAllWerewolvesAlive,
areAllVillagersAlive,
Expand Down
3 changes: 3 additions & 0 deletions src/modules/game/providers/services/game.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { MakeGamePlayDto } from "@/modules/game/dto/make-game-play/make-gam
import { isGamePhaseOver } from "@/modules/game/helpers/game-phase/game-phase.helpers";
import { createMakeGamePlayDtoWithRelations } from "@/modules/game/helpers/game-play/game-play.helpers";
import { createGame as createGameFromFactory } from "@/modules/game/helpers/game.factory";
import { getDistinctPlayerGroups } from "@/modules/game/helpers/game.helpers";
import { GameRepository } from "@/modules/game/providers/repositories/game.repository";
import { GameEventsGeneratorService } from "@/modules/game/providers/services/game-event/game-events-generator.service";
import { GameFeedbackService } from "@/modules/game/providers/services/game-feedback/game-feedback.service";
Expand Down Expand Up @@ -55,10 +56,12 @@ export class GameService {
}
const currentPlay = upcomingPlays[0];
upcomingPlays.shift();
const distinctPlayerGroups = getDistinctPlayerGroups(game);
const gameToCreate = plainToInstance(CreateGameDto, {
...game,
currentPlay,
upcomingPlays,
playerGroups: distinctPlayerGroups.length ? distinctPlayerGroups : undefined,
});
let createdGame = await this.gameRepository.create(gameToCreate) as GameWithCurrentPlay;
createdGame = await this.gamePlayService.augmentCurrentGamePlay(createdGame);
Expand Down
11 changes: 10 additions & 1 deletion src/modules/game/schemas/game.schema.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ const GAME_FIELDS_SPECS = {
minItems: 4,
maxItems: 40,
},
playerGroups: {
required: false,
minItems: 2,
default: undefined,
},
currentPlay: {
required: true,
type: GAME_PLAY_SCHEMA,
Expand Down Expand Up @@ -112,6 +117,10 @@ const GAME_API_PROPERTIES: ReadonlyDeep<Record<keyof Game, ApiPropertyOptions>>
description: "Players of the game",
...convertMongoosePropOptionsToApiPropertyOptions(GAME_FIELDS_SPECS.players),
},
playerGroups: {
description: "Players unique groups. Not set if prejudiced manipulator is not in the game",
...convertMongoosePropOptionsToApiPropertyOptions(GAME_FIELDS_SPECS.playerGroups),
},
currentPlay: {
description: "Current play which needs to be performed",
...convertMongoosePropOptionsToApiPropertyOptions(GAME_FIELDS_SPECS.currentPlay),
Expand All @@ -129,7 +138,7 @@ const GAME_API_PROPERTIES: ReadonlyDeep<Record<keyof Game, ApiPropertyOptions>>
...convertMongoosePropOptionsToApiPropertyOptions(GAME_FIELDS_SPECS.options),
},
additionalCards: {
description: "Game's additional cards. Not set if thief is not in the game",
description: "Game's additional cards. Not set if thief or actor are not in the game",
...convertMongoosePropOptionsToApiPropertyOptions(GAME_FIELDS_SPECS.additionalCards),
},
victory: {
Expand Down
5 changes: 5 additions & 0 deletions src/modules/game/schemas/game.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ class Game {
@Expose()
public players: Player[];

@ApiProperty(GAME_API_PROPERTIES.playerGroups as ApiPropertyOptions)
@Prop(GAME_FIELDS_SPECS.playerGroups)
@Expose()
public playerGroups?: string[];

@ApiProperty(GAME_API_PROPERTIES.currentPlay as ApiPropertyOptions)
@Prop(GAME_FIELDS_SPECS.currentPlay)
@Type(() => GamePlay)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Feature: 🔫 Hunter role
| JB | villager |
| Maxime | villager |
Then the request should have succeeded with status code 201
And the game should not have any player group
And the game's current play should be werewolves to eat

When the werewolves eat the player named Antoine
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ Feature: 👺 Prejudiced Manipulator role
| Thomas | villager | girl |
| Maxime | villager | girl |
Then the request should have succeeded with status code 201
And the game should have the following player groups
| group |
| boy |
| girl |
And the game's current play should be werewolves to eat

When the werewolves eat the player named Antoine
Expand Down
10 changes: 10 additions & 0 deletions tests/acceptance/features/game/step-definitions/game.then-steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ Then(/^the game's status should be (?<phase>playing|over|canceled)$/u, function(
expect(this.game.status).toBe(status);
});

Then(/^the game should not have any player group$/u, function(this: CustomWorld): void {
expect(this.game.playerGroups).toBeUndefined();
});

Then(/^the game should have the following player groups$/u, function(this: CustomWorld, playerGroups: DataTable): void {
const expectedPlayerGroups = playerGroups.rows().map(([group]) => group);

expect(this.game.playerGroups).toStrictEqual(expectedPlayerGroups);
});

Then(/^the game's last game history record should be null$/u, function(this: CustomWorld): void {
expect(this.game.lastGameHistoryRecord).toBeNull();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ function createFakeCreateGameDto(createGameDto: Partial<CreateGameDto> = {}, ove
turn: createGameDto.turn ?? 1,
phase: createGameDto.phase ?? DEFAULT_GAME_PHASE,
players: createGameDto.players ?? [],
playerGroups: createGameDto.playerGroups,
upcomingPlays: createGameDto.upcomingPlays ?? [],
currentPlay: createGameDto.currentPlay ?? null,
additionalCards: createGameDto.additionalCards ?? undefined,
Expand Down
1 change: 1 addition & 0 deletions tests/factories/game/schemas/game.schema.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function createFakeGame(game: Partial<Game> = {}, override: object = {}): Game {
return plainToInstance(Game, {
_id: game._id ?? createFakeObjectId(),
players: game.players ?? [],
playerGroups: game.playerGroups,
currentPlay: game.currentPlay ?? null,
upcomingPlays: game.upcomingPlays ?? [],
events: game.events,
Expand Down
Loading

0 comments on commit 8572e75

Please sign in to comment.