jp.ms.common.engine 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base/game-control-player-turn.d.ts +12 -0
- package/dist/base/game-control-player-turn.d.ts.map +1 -0
- package/dist/base/game-control-player-turn.js +27 -0
- package/dist/base/game-control-player-turn.js.map +1 -0
- package/dist/base/game-control-restart.d.ts +10 -0
- package/dist/base/game-control-restart.d.ts.map +1 -0
- package/dist/base/game-control-restart.js +21 -0
- package/dist/base/game-control-restart.js.map +1 -0
- package/dist/base/game-master.d.ts +34 -0
- package/dist/base/game-master.d.ts.map +1 -0
- package/dist/base/game-master.js +83 -0
- package/dist/base/game-master.js.map +1 -0
- package/dist/base/game-player-move.d.ts +13 -0
- package/dist/base/game-player-move.d.ts.map +1 -0
- package/dist/base/game-player-move.js +28 -0
- package/dist/base/game-player-move.js.map +1 -0
- package/dist/base/game-player.d.ts +61 -0
- package/dist/base/game-player.d.ts.map +1 -0
- package/dist/base/game-player.js +140 -0
- package/dist/base/game-player.js.map +1 -0
- package/dist/base/game-room.d.ts +47 -0
- package/dist/base/game-room.d.ts.map +1 -0
- package/dist/base/game-room.js +80 -0
- package/dist/base/game-room.js.map +1 -0
- package/dist/base/game-round.d.ts +28 -0
- package/dist/base/game-round.d.ts.map +1 -0
- package/dist/base/game-round.js +37 -0
- package/dist/base/game-round.js.map +1 -0
- package/dist/base/game-state-machine.d.ts +13 -0
- package/dist/base/game-state-machine.d.ts.map +1 -0
- package/dist/base/game-state-machine.js +21 -0
- package/dist/base/game-state-machine.js.map +1 -0
- package/dist/base/game-table-seat.d.ts +15 -0
- package/dist/base/game-table-seat.d.ts.map +1 -0
- package/dist/base/game-table-seat.js +32 -0
- package/dist/base/game-table-seat.js.map +1 -0
- package/dist/base/game-table-seats.d.ts +21 -0
- package/dist/base/game-table-seats.d.ts.map +1 -0
- package/dist/base/game-table-seats.js +67 -0
- package/dist/base/game-table-seats.js.map +1 -0
- package/dist/base/game-table.d.ts +87 -0
- package/dist/base/game-table.d.ts.map +1 -0
- package/dist/base/game-table.js +130 -0
- package/dist/base/game-table.js.map +1 -0
- package/dist/base/index.d.ts +13 -0
- package/dist/base/index.d.ts.map +1 -0
- package/dist/base/index.js +26 -0
- package/dist/base/index.js.map +1 -0
- package/dist/base/standard-game-state.d.ts +20 -0
- package/dist/base/standard-game-state.d.ts.map +1 -0
- package/dist/base/standard-game-state.js +57 -0
- package/dist/base/standard-game-state.js.map +1 -0
- package/dist/base-rooms/fast-tournament-room.d.ts +14 -0
- package/dist/base-rooms/fast-tournament-room.d.ts.map +1 -0
- package/dist/base-rooms/fast-tournament-room.js +53 -0
- package/dist/base-rooms/fast-tournament-room.js.map +1 -0
- package/dist/base-rooms/index.d.ts +10 -0
- package/dist/base-rooms/index.d.ts.map +1 -0
- package/dist/base-rooms/index.js +14 -0
- package/dist/base-rooms/index.js.map +1 -0
- package/dist/base-rooms/scheduled-tournament-room.d.ts +28 -0
- package/dist/base-rooms/scheduled-tournament-room.d.ts.map +1 -0
- package/dist/base-rooms/scheduled-tournament-room.js +166 -0
- package/dist/base-rooms/scheduled-tournament-room.js.map +1 -0
- package/dist/base-rooms/simple-room.d.ts +9 -0
- package/dist/base-rooms/simple-room.d.ts.map +1 -0
- package/dist/base-rooms/simple-room.js +13 -0
- package/dist/base-rooms/simple-room.js.map +1 -0
- package/dist/base-rooms/tournament-participant.d.ts +6 -0
- package/dist/base-rooms/tournament-participant.d.ts.map +1 -0
- package/dist/base-rooms/tournament-participant.js +3 -0
- package/dist/base-rooms/tournament-participant.js.map +1 -0
- package/dist/base-rooms/tournament-prize.d.ts +7 -0
- package/dist/base-rooms/tournament-prize.d.ts.map +1 -0
- package/dist/base-rooms/tournament-prize.js +3 -0
- package/dist/base-rooms/tournament-prize.js.map +1 -0
- package/dist/base-rooms/tournament-room.d.ts +47 -0
- package/dist/base-rooms/tournament-room.d.ts.map +1 -0
- package/dist/base-rooms/tournament-room.js +111 -0
- package/dist/base-rooms/tournament-room.js.map +1 -0
- package/dist/base-rooms/tournament-state.d.ts +23 -0
- package/dist/base-rooms/tournament-state.d.ts.map +1 -0
- package/dist/base-rooms/tournament-state.js +63 -0
- package/dist/base-rooms/tournament-state.js.map +1 -0
- package/dist/base-rooms/tournament-winner.d.ts +8 -0
- package/dist/base-rooms/tournament-winner.d.ts.map +1 -0
- package/dist/base-rooms/tournament-winner.js +3 -0
- package/dist/base-rooms/tournament-winner.js.map +1 -0
- package/dist/board-game/base/board-cell.d.ts +16 -0
- package/dist/board-game/base/board-cell.d.ts.map +1 -0
- package/dist/board-game/base/board-cell.js +42 -0
- package/dist/board-game/base/board-cell.js.map +1 -0
- package/dist/board-game/base/board-figure.d.ts +16 -0
- package/dist/board-game/base/board-figure.d.ts.map +1 -0
- package/dist/board-game/base/board-figure.js +38 -0
- package/dist/board-game/base/board-figure.js.map +1 -0
- package/dist/board-game/base/board-game-master.d.ts +19 -0
- package/dist/board-game/base/board-game-master.d.ts.map +1 -0
- package/dist/board-game/base/board-game-master.js +36 -0
- package/dist/board-game/base/board-game-master.js.map +1 -0
- package/dist/board-game/base/board-player-move.d.ts +11 -0
- package/dist/board-game/base/board-player-move.d.ts.map +1 -0
- package/dist/board-game/base/board-player-move.js +30 -0
- package/dist/board-game/base/board-player-move.js.map +1 -0
- package/dist/board-game/base/board-player.d.ts +13 -0
- package/dist/board-game/base/board-player.d.ts.map +1 -0
- package/dist/board-game/base/board-player.js +31 -0
- package/dist/board-game/base/board-player.js.map +1 -0
- package/dist/board-game/base/board-table.d.ts +17 -0
- package/dist/board-game/base/board-table.d.ts.map +1 -0
- package/dist/board-game/base/board-table.js +35 -0
- package/dist/board-game/base/board-table.js.map +1 -0
- package/dist/board-game/d1-board-game/d1-board-table.d.ts +19 -0
- package/dist/board-game/d1-board-game/d1-board-table.d.ts.map +1 -0
- package/dist/board-game/d1-board-game/d1-board-table.js +41 -0
- package/dist/board-game/d1-board-game/d1-board-table.js.map +1 -0
- package/dist/board-game/d2-board-game/d2-board-cell.d.ts +12 -0
- package/dist/board-game/d2-board-game/d2-board-cell.d.ts.map +1 -0
- package/dist/board-game/d2-board-game/d2-board-cell.js +26 -0
- package/dist/board-game/d2-board-game/d2-board-cell.js.map +1 -0
- package/dist/board-game/d2-board-game/d2-board-pattern-move-figure.d.ts +29 -0
- package/dist/board-game/d2-board-game/d2-board-pattern-move-figure.d.ts.map +1 -0
- package/dist/board-game/d2-board-game/d2-board-pattern-move-figure.js +51 -0
- package/dist/board-game/d2-board-game/d2-board-pattern-move-figure.js.map +1 -0
- package/dist/board-game/d2-board-game/d2-board-table.d.ts +49 -0
- package/dist/board-game/d2-board-game/d2-board-table.d.ts.map +1 -0
- package/dist/board-game/d2-board-game/d2-board-table.js +184 -0
- package/dist/board-game/d2-board-game/d2-board-table.js.map +1 -0
- package/dist/board-game/d2-board-game/types.d.ts +5 -0
- package/dist/board-game/d2-board-game/types.d.ts.map +1 -0
- package/dist/board-game/d2-board-game/types.js +3 -0
- package/dist/board-game/d2-board-game/types.js.map +1 -0
- package/dist/board-game/dice.d.ts +5 -0
- package/dist/board-game/dice.d.ts.map +1 -0
- package/dist/board-game/dice.js +14 -0
- package/dist/board-game/dice.js.map +1 -0
- package/dist/board-game/index.d.ts +13 -0
- package/dist/board-game/index.d.ts.map +1 -0
- package/dist/board-game/index.js +26 -0
- package/dist/board-game/index.js.map +1 -0
- package/dist/cards-game/cards/card.d.ts +25 -0
- package/dist/cards-game/cards/card.d.ts.map +1 -0
- package/dist/cards-game/cards/card.js +45 -0
- package/dist/cards-game/cards/card.js.map +1 -0
- package/dist/cards-game/cards/cards.d.ts +55 -0
- package/dist/cards-game/cards/cards.d.ts.map +1 -0
- package/dist/cards-game/cards/cards.js +63 -0
- package/dist/cards-game/cards/cards.js.map +1 -0
- package/dist/cards-game/cards/deck36.d.ts +2 -0
- package/dist/cards-game/cards/deck36.d.ts.map +1 -0
- package/dist/cards-game/cards/deck36.js +43 -0
- package/dist/cards-game/cards/deck36.js.map +1 -0
- package/dist/cards-game/cards/deck52.d.ts +2 -0
- package/dist/cards-game/cards/deck52.d.ts.map +1 -0
- package/dist/cards-game/cards/deck52.js +59 -0
- package/dist/cards-game/cards/deck52.js.map +1 -0
- package/dist/cards-game/cards/ranks.d.ts +18 -0
- package/dist/cards-game/cards/ranks.d.ts.map +1 -0
- package/dist/cards-game/cards/ranks.js +23 -0
- package/dist/cards-game/cards/ranks.js.map +1 -0
- package/dist/cards-game/cards/suits.d.ts +8 -0
- package/dist/cards-game/cards/suits.d.ts.map +1 -0
- package/dist/cards-game/cards/suits.js +13 -0
- package/dist/cards-game/cards/suits.js.map +1 -0
- package/dist/cards-game/cards-game-master.d.ts +24 -0
- package/dist/cards-game/cards-game-master.d.ts.map +1 -0
- package/dist/cards-game/cards-game-master.js +65 -0
- package/dist/cards-game/cards-game-master.js.map +1 -0
- package/dist/cards-game/cards-player.d.ts +12 -0
- package/dist/cards-game/cards-player.d.ts.map +1 -0
- package/dist/cards-game/cards-player.js +29 -0
- package/dist/cards-game/cards-player.js.map +1 -0
- package/dist/cards-game/cards-table.d.ts +11 -0
- package/dist/cards-game/cards-table.d.ts.map +1 -0
- package/dist/cards-game/cards-table.js +20 -0
- package/dist/cards-game/cards-table.js.map +1 -0
- package/dist/cards-game/index.d.ts +11 -0
- package/dist/cards-game/index.d.ts.map +1 -0
- package/dist/cards-game/index.js +55 -0
- package/dist/cards-game/index.js.map +1 -0
- package/dist/const.d.ts +3 -0
- package/dist/const.d.ts.map +1 -0
- package/dist/const.js +6 -0
- package/dist/const.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/circle-list.d.ts +29 -0
- package/dist/utils/circle-list.d.ts.map +1 -0
- package/dist/utils/circle-list.js +103 -0
- package/dist/utils/circle-list.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/shuffle.d.ts +3 -0
- package/dist/utils/shuffle.d.ts.map +1 -0
- package/dist/utils/shuffle.js +16 -0
- package/dist/utils/shuffle.js.map +1 -0
- package/dist/utils/tests/circle-list.test.d.ts +2 -0
- package/dist/utils/tests/circle-list.test.d.ts.map +1 -0
- package/dist/utils/tests/circle-list.test.js +60 -0
- package/dist/utils/tests/circle-list.test.js.map +1 -0
- package/package.json +54 -0
- package/readme.md +3 -0
- package/src/base/game-control-player-turn.ts +39 -0
- package/src/base/game-control-restart.ts +30 -0
- package/src/base/game-master.ts +109 -0
- package/src/base/game-player-move.ts +33 -0
- package/src/base/game-player.ts +184 -0
- package/src/base/game-room.ts +127 -0
- package/src/base/game-round.ts +62 -0
- package/src/base/game-state-machine.ts +25 -0
- package/src/base/game-table-seat.ts +37 -0
- package/src/base/game-table-seats.ts +78 -0
- package/src/base/game-table.ts +237 -0
- package/src/base/index.ts +25 -0
- package/src/base/standard-game-state.ts +69 -0
- package/src/base-rooms/fast-tournament-room.ts +59 -0
- package/src/base-rooms/index.ts +19 -0
- package/src/base-rooms/scheduled-tournament-room.ts +181 -0
- package/src/base-rooms/simple-room.ts +15 -0
- package/src/base-rooms/tournament-participant.ts +5 -0
- package/src/base-rooms/tournament-prize.ts +7 -0
- package/src/base-rooms/tournament-room.ts +169 -0
- package/src/base-rooms/tournament-state.ts +78 -0
- package/src/base-rooms/tournament-winner.ts +7 -0
- package/src/board-game/base/board-cell.ts +50 -0
- package/src/board-game/base/board-figure.ts +49 -0
- package/src/board-game/base/board-game-master.ts +56 -0
- package/src/board-game/base/board-player-move.ts +29 -0
- package/src/board-game/base/board-player.ts +43 -0
- package/src/board-game/base/board-table.ts +52 -0
- package/src/board-game/d1-board-game/d1-board-table.ts +56 -0
- package/src/board-game/d2-board-game/d2-board-cell.ts +30 -0
- package/src/board-game/d2-board-game/d2-board-pattern-move-figure.ts +79 -0
- package/src/board-game/d2-board-game/d2-board-table.ts +262 -0
- package/src/board-game/d2-board-game/types.ts +4 -0
- package/src/board-game/dice.ts +9 -0
- package/src/board-game/index.ts +28 -0
- package/src/cards-game/cards/card.ts +60 -0
- package/src/cards-game/cards/cards.ts +86 -0
- package/src/cards-game/cards/deck36.ts +80 -0
- package/src/cards-game/cards/deck52.ts +112 -0
- package/src/cards-game/cards/ranks.ts +19 -0
- package/src/cards-game/cards/suits.ts +10 -0
- package/src/cards-game/cards-game-master.ts +83 -0
- package/src/cards-game/cards-player.ts +40 -0
- package/src/cards-game/cards-table.ts +28 -0
- package/src/cards-game/index.ts +21 -0
- package/src/const.ts +3 -0
- package/src/index.ts +5 -0
- package/src/utils/circle-list.ts +130 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/shuffle.ts +12 -0
- package/src/utils/tests/circle-list.test.ts +72 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { v4 as uidv4 } from 'uuid';
|
|
2
|
+
|
|
3
|
+
export type GameRoundHistoryItem = {
|
|
4
|
+
userId: string;
|
|
5
|
+
fullName: string;
|
|
6
|
+
date: Date;
|
|
7
|
+
action: string;
|
|
8
|
+
state: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface IGameRound<GP> {
|
|
12
|
+
getActivePlayer (): GP;
|
|
13
|
+
|
|
14
|
+
setActivePlayer (activePlayer: GP);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export abstract class GameRound<SM, GP> implements IGameRound<GP> {
|
|
18
|
+
private readonly history: Array<GameRoundHistoryItem>;
|
|
19
|
+
private id: string;
|
|
20
|
+
private pot: number;
|
|
21
|
+
private state: SM;
|
|
22
|
+
private activePlayer: GP;
|
|
23
|
+
|
|
24
|
+
protected constructor () {
|
|
25
|
+
this.id = uidv4();
|
|
26
|
+
this.pot = 0;
|
|
27
|
+
this.history = [];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getState (): SM {
|
|
31
|
+
return this.state;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
setState (state: SM): void {
|
|
35
|
+
this.state = state;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
getHistory (): Array<GameRoundHistoryItem> {
|
|
39
|
+
return this.history;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
addToHistory (item: GameRoundHistoryItem): void {
|
|
43
|
+
this.history.push(item);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
addToPot (amount: number): void {
|
|
47
|
+
this.pot += amount;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
getPot (): number {
|
|
51
|
+
return this.pot;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
getActivePlayer () {
|
|
55
|
+
return this.activePlayer;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
setActivePlayer (activePlayer: GP) {
|
|
59
|
+
this.activePlayer = activePlayer;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type StateMachineConfig = Record<string, { on: Record<string, string> }>
|
|
2
|
+
|
|
3
|
+
export abstract class GameStateMachine<S, A> {
|
|
4
|
+
private readonly initialState: S;
|
|
5
|
+
private currentState: S;
|
|
6
|
+
private config: StateMachineConfig;
|
|
7
|
+
|
|
8
|
+
protected constructor (initialState: S, config: StateMachineConfig) {
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.initialState = initialState;
|
|
11
|
+
this.currentState = this.initialState;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getCurrentState (): S {
|
|
15
|
+
return this.currentState;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
start () {
|
|
19
|
+
this.currentState = this.initialState;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
send (action: A) {
|
|
23
|
+
this.currentState = this.config[this.currentState as string].on[action as string] as S;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { GamePlayer } from './game-player';
|
|
2
|
+
|
|
3
|
+
export class GameTableSeat<GP extends GamePlayer> {
|
|
4
|
+
private player: GP | null = null;
|
|
5
|
+
private role: string | null;
|
|
6
|
+
|
|
7
|
+
constructor (private readonly number: number) {
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public getRole () {
|
|
11
|
+
return this.role;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public setRole (role: string) {
|
|
15
|
+
this.role = role;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public clearRole () {
|
|
19
|
+
this.role = null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getNumber (): number {
|
|
23
|
+
return this.number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getPlayer () {
|
|
27
|
+
return this.player;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
addPlayer (player: GP) {
|
|
31
|
+
this.player = player;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
removePlayer () {
|
|
35
|
+
this.player = null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { compact } from 'lodash';
|
|
2
|
+
|
|
3
|
+
import { CircleList } from '../utils';
|
|
4
|
+
import { TWO_PLAYER_GAME } from '../const';
|
|
5
|
+
|
|
6
|
+
import { GameTableSeat } from './game-table-seat';
|
|
7
|
+
import { GamePlayer } from './game-player';
|
|
8
|
+
|
|
9
|
+
export class GameTableSeats<GP extends GamePlayer> {
|
|
10
|
+
protected readonly seats: CircleList<GameTableSeat<GP>>;
|
|
11
|
+
|
|
12
|
+
constructor (private readonly tableSize: number) {
|
|
13
|
+
this.seats = new CircleList();
|
|
14
|
+
|
|
15
|
+
for (let i = 0; i < this.tableSize; i += 1) {
|
|
16
|
+
this.seats.push(new GameTableSeat<GP>(i + 1));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getSeats (): Array<GameTableSeat<GP>> {
|
|
21
|
+
return this.seats.toArray();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getSeatsWithPlayers (): Array<GameTableSeat<GP>> {
|
|
25
|
+
return this.seats.toArray().filter((item) => !!item.getPlayer());
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getSeat (number: number | null): GameTableSeat<GP> | undefined {
|
|
29
|
+
return this.seats.toArray().find((item) => item.getNumber() === number);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getNextSeat (from: number): GameTableSeat<GP> | undefined {
|
|
33
|
+
return this.seats.get(from - 1)?.getNext()?.getData();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getNextPlayer (from: number): GP | null {
|
|
37
|
+
const nextSeat = this.getNextSeat(from);
|
|
38
|
+
const nextPlayer = nextSeat?.getPlayer();
|
|
39
|
+
|
|
40
|
+
if (!nextPlayer) {
|
|
41
|
+
return this.getNextPlayer(nextSeat?.getNumber() ?? 0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return nextPlayer;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
getPrevSeat (from: number): GameTableSeat<GP> | undefined {
|
|
48
|
+
return this.seats.get(from - 1)?.getPrev()?.getData();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
getPrevPlayer (from: number): GP | null {
|
|
52
|
+
return this.getPrevSeat(from)?.getPlayer() ?? null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getPlayersChain (from: number): Array<GP> {
|
|
56
|
+
const chain = this.seats.getNextChain(from).map((item) => item.getPlayer());
|
|
57
|
+
|
|
58
|
+
return compact(chain);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
getFirstSeatWithPlayer (): GameTableSeat<GP> | null {
|
|
62
|
+
return this.getSeatsWithPlayers()[0] ?? null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
findFreeSeat (): GameTableSeat<GP> | undefined {
|
|
66
|
+
return this.seats.toArray().find((seat) => seat.getPlayer() === null);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
clearAllSeatsRole () {
|
|
70
|
+
this.seats.toArray().forEach((seat) => {
|
|
71
|
+
seat.clearRole();
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
isTwoPlayerGame () {
|
|
76
|
+
return this.getSeatsWithPlayers().length === TWO_PLAYER_GAME;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { compact, first, remove, slice } from 'lodash';
|
|
2
|
+
|
|
3
|
+
import { GamePlayer } from './game-player';
|
|
4
|
+
import { GameTableSeats } from './game-table-seats';
|
|
5
|
+
|
|
6
|
+
export interface IGameTable<GP extends GamePlayer> {
|
|
7
|
+
getId (): string;
|
|
8
|
+
|
|
9
|
+
hasInQueue (PlayerId: string): boolean;
|
|
10
|
+
|
|
11
|
+
hasInWatchers (PlayerId: string): boolean;
|
|
12
|
+
|
|
13
|
+
isFull (): boolean;
|
|
14
|
+
|
|
15
|
+
getSeats (): GameTableSeats<GP>;
|
|
16
|
+
|
|
17
|
+
hasSeats (): boolean;
|
|
18
|
+
|
|
19
|
+
addPlayerToQueue (player: GP);
|
|
20
|
+
|
|
21
|
+
addPlayerToSeat (player: GP);
|
|
22
|
+
|
|
23
|
+
removePlayerFromSeat (player: GP);
|
|
24
|
+
|
|
25
|
+
removePlayerFromQueue (player: GP);
|
|
26
|
+
|
|
27
|
+
removePlayerFromWatchers (player: GP);
|
|
28
|
+
|
|
29
|
+
addPlayerToWatchers (player: GP);
|
|
30
|
+
|
|
31
|
+
getPlayers (): Array<GP>;
|
|
32
|
+
|
|
33
|
+
getPlayerByColor (color: number): GP | undefined;
|
|
34
|
+
|
|
35
|
+
getPlayersWithQueue (): Array<GP>;
|
|
36
|
+
|
|
37
|
+
getEmptyStackPlayers (): Array<GP>;
|
|
38
|
+
|
|
39
|
+
remainOnePlayer (): boolean;
|
|
40
|
+
|
|
41
|
+
startNewRound (): void;
|
|
42
|
+
|
|
43
|
+
getQueue (): Array<GP>;
|
|
44
|
+
|
|
45
|
+
getTableSize (): number;
|
|
46
|
+
|
|
47
|
+
getRedundantQueuers (): Array<GP>;
|
|
48
|
+
|
|
49
|
+
getLastPlayer (): GP | null;
|
|
50
|
+
|
|
51
|
+
getTurnTimeout (): number;
|
|
52
|
+
|
|
53
|
+
getRestartTimeout (): number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type GameTableConfig<GP extends GamePlayer> = {
|
|
57
|
+
roomId: string;
|
|
58
|
+
number: number;
|
|
59
|
+
tableSize: number;
|
|
60
|
+
bet: number;
|
|
61
|
+
rulesType: string;
|
|
62
|
+
turnTimeout: number;
|
|
63
|
+
restartTimeout: number;
|
|
64
|
+
onRoomFinishRound: (table: IGameTable<GP>) => void
|
|
65
|
+
onRoomRestartRound: (table: IGameTable<GP>) => void
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export abstract class GameTable<GP extends GamePlayer, GM, GSR> implements IGameTable<GP> {
|
|
69
|
+
private readonly roomId: string;
|
|
70
|
+
private readonly number: number;
|
|
71
|
+
private readonly tableSize: number;
|
|
72
|
+
private readonly bet: number;
|
|
73
|
+
private readonly turnTimeout: number;
|
|
74
|
+
private readonly restartTimeout: number;
|
|
75
|
+
private readonly queue: Array<GP>;
|
|
76
|
+
private readonly watchers: Array<GP>;
|
|
77
|
+
public readonly seats: GameTableSeats<GP>;
|
|
78
|
+
public master: GM;
|
|
79
|
+
public onRoomFinishRound: (table: IGameTable<GP>) => void;
|
|
80
|
+
public onRoomRestartRound: (table: IGameTable<GP>) => void;
|
|
81
|
+
|
|
82
|
+
protected constructor (config: GameTableConfig<GP>) {
|
|
83
|
+
this.queue = [];
|
|
84
|
+
this.watchers = [];
|
|
85
|
+
this.onRoomFinishRound = config.onRoomFinishRound;
|
|
86
|
+
this.onRoomRestartRound = config.onRoomRestartRound;
|
|
87
|
+
this.roomId = config.roomId;
|
|
88
|
+
this.number = config.number;
|
|
89
|
+
this.tableSize = config.tableSize;
|
|
90
|
+
this.bet = config.bet;
|
|
91
|
+
this.turnTimeout = config.turnTimeout;
|
|
92
|
+
this.restartTimeout = config.restartTimeout;
|
|
93
|
+
this.seats = new GameTableSeats(this.getTableSize());
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
abstract startNewRound (): void
|
|
97
|
+
|
|
98
|
+
getRoomId () {
|
|
99
|
+
return this.roomId;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
getId () {
|
|
103
|
+
return String(this.number);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
getNumber (): number {
|
|
107
|
+
return this.number;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
getTableSize (): number {
|
|
111
|
+
return this.tableSize;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
getBet () {
|
|
115
|
+
return this.bet;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
getHalfBet () {
|
|
119
|
+
return this.bet / 2;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getTurnTimeout () {
|
|
123
|
+
return this.turnTimeout;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
getRestartTimeout () {
|
|
127
|
+
return this.restartTimeout;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
addPlayerToSeat (player: GP): boolean {
|
|
131
|
+
const freeSeat = this.seats.findFreeSeat();
|
|
132
|
+
if (freeSeat) {
|
|
133
|
+
freeSeat.addPlayer(player);
|
|
134
|
+
player.seat(this.getRoomId(), this.getId(), freeSeat.getNumber());
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
removePlayerFromSeat (player: GP): void {
|
|
142
|
+
const seat = this.seats.getSeat(player.getSeatNumber());
|
|
143
|
+
if (seat) {
|
|
144
|
+
seat.removePlayer();
|
|
145
|
+
player.quit();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
getPlayers (): Array<GP> {
|
|
150
|
+
return compact(this.seats.getSeats().map((seat) => seat.getPlayer()));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
getPlayerByColor (color: number): GP | undefined {
|
|
154
|
+
return this.getPlayers().find((item) => item.getColor() === color);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
getPlayersWithQueue (): Array<GP> {
|
|
158
|
+
return [...this.getPlayers(), ...this.queue];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
getLastPlayer (): GP | null {
|
|
162
|
+
return first(this.getPlayers()) ?? null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
remainOnePlayer (): boolean {
|
|
166
|
+
return this.getPlayers().length === 1;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
hasMinPlayers (): boolean {
|
|
170
|
+
return this.getPlayers().length > 1;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
getEmptyStackPlayers (): Array<GP> {
|
|
174
|
+
return this.getPlayers().filter((player) => player.hasEmptyStack());
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
getQueue (): Array<GP> {
|
|
178
|
+
return this.queue;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
getRedundantQueuers (): Array<GP> {
|
|
182
|
+
return slice(this.queue, this.getTableSize() - this.getPlayers().length - 1);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
addPlayerToQueue (player: GP): void {
|
|
186
|
+
this.queue.push(player);
|
|
187
|
+
player.getInTableQueue(this.getRoomId(), this.getId());
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
removePlayerFromQueue (player: GP): void {
|
|
191
|
+
remove(this.queue, (queuer) => queuer.getId() === player.getId());
|
|
192
|
+
player.quit();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
hasInQueue (PlayerId: string): boolean {
|
|
196
|
+
return !!this.getQueue().find((queuer) => queuer.getId() === PlayerId);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
getWatchers (): Array<GP> {
|
|
200
|
+
return this.watchers;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
addPlayerToWatchers (player: GP): void {
|
|
204
|
+
this.watchers.push(player);
|
|
205
|
+
player.watch(this.getRoomId(), this.getId());
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
removePlayerFromWatchers (player: GP): void {
|
|
209
|
+
remove(this.watchers, (watcher) => watcher.getId() === player.getId());
|
|
210
|
+
player.quit();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
hasInWatchers (PlayerId: string): boolean {
|
|
214
|
+
return !!this.getWatchers().find((watcher) => watcher.getId() === PlayerId);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
isFull (): boolean {
|
|
218
|
+
return !this.seats.findFreeSeat();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
getSeats (): GameTableSeats<GP> {
|
|
222
|
+
return this.seats;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
hasSeats (): boolean {
|
|
226
|
+
return !!this.seats.findFreeSeat();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
onFinishRound () {
|
|
230
|
+
this.onRoomFinishRound(this);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
onRestartRound () {
|
|
234
|
+
this.onRoomRestartRound(this);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { GameControlPlayerTurn } from './game-control-player-turn';
|
|
2
|
+
import { GameControlRestart } from './game-control-restart';
|
|
3
|
+
import { GameMaster } from './game-master';
|
|
4
|
+
import { GamePlayer } from './game-player';
|
|
5
|
+
import { GamePlayerMove } from './game-player-move';
|
|
6
|
+
import { GameRoom } from './game-room';
|
|
7
|
+
import { GameRound } from './game-round';
|
|
8
|
+
import { GameStateMachine } from './game-state-machine';
|
|
9
|
+
import { GameTable } from './game-table';
|
|
10
|
+
import { GameTableSeat } from './game-table-seat';
|
|
11
|
+
import { GameTableSeats } from './game-table-seats';
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
GameControlPlayerTurn,
|
|
15
|
+
GameControlRestart,
|
|
16
|
+
GameMaster,
|
|
17
|
+
GamePlayer,
|
|
18
|
+
GamePlayerMove,
|
|
19
|
+
GameRoom,
|
|
20
|
+
GameRound,
|
|
21
|
+
GameStateMachine,
|
|
22
|
+
GameTable,
|
|
23
|
+
GameTableSeat,
|
|
24
|
+
GameTableSeats,
|
|
25
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { GameStateMachine, StateMachineConfig } from './game-state-machine';
|
|
2
|
+
|
|
3
|
+
export enum StandardStateMachineStates {
|
|
4
|
+
STATE_WAITING_FOR_PLAYERS = 'STATE_WAITING_FOR_PLAYERS',
|
|
5
|
+
STATE_IN_PROGRESS = 'STATE_IN_PROGRESS',
|
|
6
|
+
STATE_END = 'STATE_END',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export enum StandardStateMachineActions {
|
|
10
|
+
ACTION_TO_END = 'ACTION_TO_END',
|
|
11
|
+
ACTION_START = 'ACTION_START',
|
|
12
|
+
ACTION_RESTART = 'ACTION_RESTART',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
STATE_WAITING_FOR_PLAYERS,
|
|
17
|
+
STATE_IN_PROGRESS,
|
|
18
|
+
STATE_END,
|
|
19
|
+
} = StandardStateMachineStates;
|
|
20
|
+
|
|
21
|
+
const {
|
|
22
|
+
ACTION_TO_END,
|
|
23
|
+
ACTION_START,
|
|
24
|
+
ACTION_RESTART,
|
|
25
|
+
} = StandardStateMachineActions;
|
|
26
|
+
|
|
27
|
+
const config: StateMachineConfig = {
|
|
28
|
+
[STATE_WAITING_FOR_PLAYERS]: {
|
|
29
|
+
on: {
|
|
30
|
+
[ACTION_START]: STATE_IN_PROGRESS,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
[STATE_IN_PROGRESS]: {
|
|
34
|
+
on: {
|
|
35
|
+
[ACTION_TO_END]: STATE_END,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
[STATE_END]: {
|
|
39
|
+
on: {
|
|
40
|
+
[ACTION_RESTART]: STATE_WAITING_FOR_PLAYERS,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export class StandardGameState extends GameStateMachine<StandardStateMachineStates, StandardStateMachineActions> {
|
|
46
|
+
constructor () {
|
|
47
|
+
super(StandardStateMachineStates.STATE_WAITING_FOR_PLAYERS, config);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
isWaiting () {
|
|
51
|
+
return this.getCurrentState() === StandardStateMachineStates.STATE_WAITING_FOR_PLAYERS;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
isInProgress () {
|
|
55
|
+
return this.getCurrentState() === StandardStateMachineStates.STATE_IN_PROGRESS;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
isEnd () {
|
|
59
|
+
return this.getCurrentState() === StandardStateMachineStates.STATE_END;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
toStart () {
|
|
63
|
+
this.send(StandardStateMachineActions.ACTION_START);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
toFinish () {
|
|
67
|
+
this.send(StandardStateMachineActions.ACTION_TO_END);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { GamePlayer } from '../base';
|
|
2
|
+
import { IGameTable } from '../base/game-table';
|
|
3
|
+
|
|
4
|
+
import { TournamentRoom, TournamentRoomConfig } from './tournament-room';
|
|
5
|
+
|
|
6
|
+
export abstract class FastTournamentRoom<
|
|
7
|
+
GT extends IGameTable<GP>,
|
|
8
|
+
GP extends GamePlayer,
|
|
9
|
+
> extends TournamentRoom<GT, GP> {
|
|
10
|
+
constructor (config: TournamentRoomConfig) {
|
|
11
|
+
super(config);
|
|
12
|
+
this.createTable();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
handleJoinTournament (player: GP) {
|
|
16
|
+
const onlyTable = this.getFirstTable();
|
|
17
|
+
if (this.getState().isWaiting() && onlyTable && onlyTable.hasSeats()) {
|
|
18
|
+
onlyTable.addPlayerToSeat(player);
|
|
19
|
+
if (onlyTable.isFull()) {
|
|
20
|
+
this.startTournament();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
handleLeaveTournament (player: GP) {
|
|
26
|
+
const onlyTable = this.getFirstTable();
|
|
27
|
+
if (onlyTable) {
|
|
28
|
+
if (player.isPlayer()) {
|
|
29
|
+
onlyTable.removePlayerFromSeat(player);
|
|
30
|
+
} else {
|
|
31
|
+
onlyTable.removePlayerFromWatchers(player);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
handleFinishRound = () => {
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
handleRestartRound = () => {
|
|
40
|
+
if (this.isTournamentFinish()) {
|
|
41
|
+
this.finishTournament();
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
startTournament () {
|
|
46
|
+
this.getFirstTable()?.getPlayers().forEach((player) => this.addParticipant(player));
|
|
47
|
+
this.getState().toStart();
|
|
48
|
+
this.getFirstTable()?.startNewRound();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
finishTournament () {
|
|
52
|
+
this.getState().toFinish();
|
|
53
|
+
this.calculateWinners();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
isTournamentFinish (): boolean {
|
|
57
|
+
return this.getFirstTable()?.remainOnePlayer() ?? false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FastTournamentRoom } from './fast-tournament-room';
|
|
2
|
+
import { ScheduledTournamentRoom } from './scheduled-tournament-room';
|
|
3
|
+
import { SimpleRoom } from './simple-room';
|
|
4
|
+
import { ITournamentParticipant } from './tournament-participant';
|
|
5
|
+
import { TournamentPrizes } from './tournament-prize';
|
|
6
|
+
import { TournamentRoom } from './tournament-room';
|
|
7
|
+
import { TournamentState } from './tournament-state';
|
|
8
|
+
import { ITournamentWinner } from './tournament-winner';
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
FastTournamentRoom,
|
|
12
|
+
SimpleRoom,
|
|
13
|
+
ITournamentParticipant,
|
|
14
|
+
TournamentPrizes,
|
|
15
|
+
ScheduledTournamentRoom,
|
|
16
|
+
TournamentRoom,
|
|
17
|
+
TournamentState,
|
|
18
|
+
ITournamentWinner,
|
|
19
|
+
}
|