texas-poker-core 1.0.2 → 1.0.3
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/package.json +5 -1
- package/types/Controller/index.d.ts +20 -0
- package/types/Controller/index.test.d.ts +1 -0
- package/types/Dealer/index.d.ts +37 -0
- package/types/Dealer/index.test.d.ts +1 -0
- package/types/Deck/constant.d.ts +11 -0
- package/types/Deck/core.d.ts +13 -0
- package/types/Deck/core.test.d.ts +1 -0
- package/types/Deck/index.d.ts +20 -0
- package/types/Deck/index.test.d.ts +1 -0
- package/types/Player/constant.d.ts +4 -0
- package/types/Player/index.d.ts +77 -0
- package/types/Player/index.test.d.ts +1 -0
- package/types/Pool/index.d.ts +18 -0
- package/types/Pool/index.test.d.ts +1 -0
- package/types/Room/index.d.ts +25 -0
- package/types/Room/index.test.d.ts +1 -0
- package/types/index.d.ts +2 -0
- package/types/main.d.ts +20 -0
- package/types/main.test.d.ts +1 -0
- package/types/utils/index.d.ts +4 -0
- package/.babelrc +0 -32
- package/.commitlintrc +0 -12
- package/.husky/commit-msg +0 -1
- package/.husky/pre-commit +0 -1
- package/.prettierignore +0 -4
- package/.prettierrc +0 -8
- package/eslint.config.mjs +0 -55
- package/global.env.d.ts +0 -5
- package/jest.config.js +0 -10
- package/jest.setup.js +0 -2
- package/src/Controller/index.test.ts +0 -66
- package/src/Controller/index.ts +0 -131
- package/src/Dealer/index.test.ts +0 -32
- package/src/Dealer/index.ts +0 -359
- package/src/Deck/constant.ts +0 -122
- package/src/Deck/core.test.ts +0 -98
- package/src/Deck/core.ts +0 -245
- package/src/Deck/index.test.ts +0 -100
- package/src/Deck/index.ts +0 -120
- package/src/Player/constant.ts +0 -55
- package/src/Player/index.test.ts +0 -61
- package/src/Player/index.ts +0 -533
- package/src/Pool/index.test.ts +0 -117
- package/src/Pool/index.ts +0 -208
- package/src/Room/index.test.ts +0 -109
- package/src/Room/index.ts +0 -159
- package/src/index.ts +0 -3
- package/src/main.test.ts +0 -22
- package/src/main.ts +0 -58
- package/src/utils/index.ts +0 -38
- package/tsconfig.json +0 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "texas-poker-core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "德州扑克核心功能",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
"prepublishOnly": "tsc --noEmit && pnpm run test",
|
|
15
15
|
"build": "cross-env PROJECT_ENV=prd tsc && babel src --out-dir dist --extensions \".ts\""
|
|
16
16
|
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist/**/*",
|
|
19
|
+
"types/**/*"
|
|
20
|
+
],
|
|
17
21
|
"keywords": [
|
|
18
22
|
"德州",
|
|
19
23
|
"扑克"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import Dealer from '../Dealer';
|
|
2
|
+
import { Player } from '../Player';
|
|
3
|
+
export type Stage = 'pre-flop' | 'flop' | 'turn' | 'river' | 'showdown';
|
|
4
|
+
declare class Controller {
|
|
5
|
+
#private;
|
|
6
|
+
constructor(dealer: Dealer);
|
|
7
|
+
get stage(): Stage;
|
|
8
|
+
setControl(player: Player | null): void;
|
|
9
|
+
transferControlToNext(nextPlayer: Player | null): void;
|
|
10
|
+
get activePlayer(): Player | null;
|
|
11
|
+
tryToAdvanceGameToNextStage(): boolean;
|
|
12
|
+
gameIterator(): Generator<void>;
|
|
13
|
+
start(): void;
|
|
14
|
+
startTimer(): void;
|
|
15
|
+
continue(): void;
|
|
16
|
+
clearTimer(): void;
|
|
17
|
+
end(): void;
|
|
18
|
+
pause(): void;
|
|
19
|
+
}
|
|
20
|
+
export default Controller;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Deck from '@/Deck';
|
|
2
|
+
import { Player } from '@/Player';
|
|
3
|
+
declare class Dealer {
|
|
4
|
+
#private;
|
|
5
|
+
constructor(lowestBetAmount: number);
|
|
6
|
+
start(): void;
|
|
7
|
+
dealCards(): void;
|
|
8
|
+
getDeck(): Deck;
|
|
9
|
+
getHeadPlayer(): Player | null;
|
|
10
|
+
getLowestBetAmount(): number;
|
|
11
|
+
logPlayers(): void;
|
|
12
|
+
setRoleToPlayers(): void;
|
|
13
|
+
pause(): void;
|
|
14
|
+
end(): void;
|
|
15
|
+
settle(): void;
|
|
16
|
+
remove(player: Player): boolean;
|
|
17
|
+
join(player: Player): boolean;
|
|
18
|
+
has(player: Player): boolean;
|
|
19
|
+
log(): void;
|
|
20
|
+
changeButtonToNextPlayer(): void;
|
|
21
|
+
setButton(player?: Player): void;
|
|
22
|
+
setOthers(): void;
|
|
23
|
+
getCurrentStageMaxBetAmount(): number;
|
|
24
|
+
getPlayersCount(): number;
|
|
25
|
+
forEach(callback: (p: Player, i: number) => void): void;
|
|
26
|
+
getTotal: any;
|
|
27
|
+
map<T>(callback: (p: Player, i: number) => T): T[];
|
|
28
|
+
resetCurrentStageTotalAmount(): void;
|
|
29
|
+
resetActionsOfPlayers(): void;
|
|
30
|
+
reset(): void;
|
|
31
|
+
filter(callback: (p: Player, i: number) => boolean): Player[];
|
|
32
|
+
find(callback: (p: Player) => boolean): Player | null;
|
|
33
|
+
loop(callback: (p: Player, i: number) => void, startFrom?: Player | null | undefined): void;
|
|
34
|
+
getTheFirstPlayerToAct(): Player | null;
|
|
35
|
+
init(): void;
|
|
36
|
+
}
|
|
37
|
+
export default Dealer;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const suits: readonly ["h", "s", "d", "c"];
|
|
2
|
+
export declare const ranks: readonly ["2", "3", "4", "5", "6", "7", "8", "9", "t", "j", "q", "k", "a"];
|
|
3
|
+
export type Suit = (typeof suits)[number];
|
|
4
|
+
export type Rank = (typeof ranks)[number];
|
|
5
|
+
export type HandPoke = Poke[];
|
|
6
|
+
export type handPokeType = 'z' | 'y' | 'x' | 'w' | 'v' | 'u' | 't' | 's' | 'r' | 'q';
|
|
7
|
+
export declare const suitsMap: Map<"h" | "s" | "d" | "c", string>;
|
|
8
|
+
export declare const handPokeMap: Map<handPokeType, string>;
|
|
9
|
+
export declare const rankMap: (input: Rank) => number;
|
|
10
|
+
export type Poke = `${Suit}${Rank}`;
|
|
11
|
+
export declare const comboIndices: number[][];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Player } from '@/Player';
|
|
2
|
+
import { Poke, Rank } from './constant';
|
|
3
|
+
export declare const isStraight: (values: Rank[]) => {
|
|
4
|
+
result: boolean;
|
|
5
|
+
max: number;
|
|
6
|
+
};
|
|
7
|
+
export declare const compareFn: (a: Poke[], b: Poke[]) => number;
|
|
8
|
+
export declare const comparePresentation: (p1: string, p2: string) => number;
|
|
9
|
+
export declare function getHandPresentation(input: Poke[]): string;
|
|
10
|
+
export declare function getBestHand(pokes: Poke[], commonPokes: Poke[]): Poke[];
|
|
11
|
+
export declare function getBestPokesPresentation(handPokes: Poke[][], commonPokes: Poke[]): string;
|
|
12
|
+
export declare const formatter: (input: Poke[]) => string;
|
|
13
|
+
export declare const getWinner: (players: Player[]) => Player[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { handPokeType } from './constant';
|
|
2
|
+
declare class Deck {
|
|
3
|
+
#private;
|
|
4
|
+
constructor();
|
|
5
|
+
shuffle(): void;
|
|
6
|
+
dealCards(count: number): {
|
|
7
|
+
handPokes: ("h2" | "h3" | "h4" | "h5" | "h6" | "h7" | "h8" | "h9" | "ht" | "hj" | "hq" | "hk" | "ha" | "s2" | "s3" | "s4" | "s5" | "s6" | "s7" | "s8" | "s9" | "st" | "sj" | "sq" | "sk" | "sa" | "d2" | "d3" | "d4" | "d5" | "d6" | "d7" | "d8" | "d9" | "dt" | "dj" | "dq" | "dk" | "da" | "c2" | "c3" | "c4" | "c5" | "c6" | "c7" | "c8" | "c9" | "ct" | "cj" | "cq" | "ck" | "ca")[][];
|
|
8
|
+
commonPokes: ("h2" | "h3" | "h4" | "h5" | "h6" | "h7" | "h8" | "h9" | "ht" | "hj" | "hq" | "hk" | "ha" | "s2" | "s3" | "s4" | "s5" | "s6" | "s7" | "s8" | "s9" | "st" | "sj" | "sq" | "sk" | "sa" | "d2" | "d3" | "d4" | "d5" | "d6" | "d7" | "d8" | "d9" | "dt" | "dj" | "dq" | "dk" | "da" | "c2" | "c3" | "c4" | "c5" | "c6" | "c7" | "c8" | "c9" | "ct" | "cj" | "cq" | "ck" | "ca")[];
|
|
9
|
+
};
|
|
10
|
+
getPokes(): {
|
|
11
|
+
handPokes: ("h2" | "h3" | "h4" | "h5" | "h6" | "h7" | "h8" | "h9" | "ht" | "hj" | "hq" | "hk" | "ha" | "s2" | "s3" | "s4" | "s5" | "s6" | "s7" | "s8" | "s9" | "st" | "sj" | "sq" | "sk" | "sa" | "d2" | "d3" | "d4" | "d5" | "d6" | "d7" | "d8" | "d9" | "dt" | "dj" | "dq" | "dk" | "da" | "c2" | "c3" | "c4" | "c5" | "c6" | "c7" | "c8" | "c9" | "ct" | "cj" | "cq" | "ck" | "ca")[][];
|
|
12
|
+
commonPokes: ("h2" | "h3" | "h4" | "h5" | "h6" | "h7" | "h8" | "h9" | "ht" | "hj" | "hq" | "hk" | "ha" | "s2" | "s3" | "s4" | "s5" | "s6" | "s7" | "s8" | "s9" | "st" | "sj" | "sq" | "sk" | "sa" | "d2" | "d3" | "d4" | "d5" | "d6" | "d7" | "d8" | "d9" | "dt" | "dj" | "dq" | "dk" | "da" | "c2" | "c3" | "c4" | "c5" | "c6" | "c7" | "c8" | "c9" | "ct" | "cj" | "cq" | "ck" | "ca")[];
|
|
13
|
+
};
|
|
14
|
+
getCards(): ("h2" | "h3" | "h4" | "h5" | "h6" | "h7" | "h8" | "h9" | "ht" | "hj" | "hq" | "hk" | "ha" | "s2" | "s3" | "s4" | "s5" | "s6" | "s7" | "s8" | "s9" | "st" | "sj" | "sq" | "sk" | "sa" | "d2" | "d3" | "d4" | "d5" | "d6" | "d7" | "d8" | "d9" | "dt" | "dj" | "dq" | "dk" | "da" | "c2" | "c3" | "c4" | "c5" | "c6" | "c7" | "c8" | "c9" | "ct" | "cj" | "cq" | "ck" | "ca")[];
|
|
15
|
+
getMax(): {
|
|
16
|
+
type: handPokeType;
|
|
17
|
+
value: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export default Deck;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import Dealer from '@/Dealer';
|
|
2
|
+
import Controller from '@/Controller';
|
|
3
|
+
import { Poke } from '../Deck/constant';
|
|
4
|
+
type PlayerStatus = 'all-in' | 'active' | 'waiting' | 'out';
|
|
5
|
+
type OnlineStatus = 'online' | 'offline';
|
|
6
|
+
interface ActionWithOutPayload {
|
|
7
|
+
type: Extract<ActionType, 'check' | 'fold'>;
|
|
8
|
+
}
|
|
9
|
+
interface ActionWithPayload {
|
|
10
|
+
type: Exclude<ActionType, 'check' | 'fold'>;
|
|
11
|
+
payload: {
|
|
12
|
+
value: number;
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
type Action = ActionWithOutPayload | ActionWithPayload;
|
|
17
|
+
type ActionType = 'check' | 'fold' | 'raise' | 'bet' | 'call' | 'all-in';
|
|
18
|
+
export interface User {
|
|
19
|
+
id: number;
|
|
20
|
+
balance: number;
|
|
21
|
+
}
|
|
22
|
+
export type Role = 'button' | 'small-blind' | 'big-blind' | `under-the-gun${number | ''}` | `middle-position${number | ''}` | 'hi-jack' | 'cut-off';
|
|
23
|
+
export declare class Player {
|
|
24
|
+
#private;
|
|
25
|
+
constructor({ lowestBetAmount, user, lastPlayer, nextPlayer, controller }: {
|
|
26
|
+
lowestBetAmount: number;
|
|
27
|
+
role?: Role;
|
|
28
|
+
user: User;
|
|
29
|
+
lastPlayer?: Player | null;
|
|
30
|
+
nextPlayer?: Player | null;
|
|
31
|
+
handPokes?: Poke[];
|
|
32
|
+
controller: Controller;
|
|
33
|
+
});
|
|
34
|
+
setNextPlayer(player: Player | null): void;
|
|
35
|
+
setPresentation(presentation: string): void;
|
|
36
|
+
getPresentation(): string | undefined;
|
|
37
|
+
getNextPlayer(): Player | null;
|
|
38
|
+
getLastPlayer(): Player | null;
|
|
39
|
+
setLastPlayer(player: Player | null): void;
|
|
40
|
+
getLowestBetAmount(): number;
|
|
41
|
+
setStatus(status: PlayerStatus): void;
|
|
42
|
+
setIsLast(value: boolean): void;
|
|
43
|
+
getCurrentStageTotalAmount(): number;
|
|
44
|
+
getStatus(): PlayerStatus;
|
|
45
|
+
getOnlineStatus(): OnlineStatus;
|
|
46
|
+
reset(): void;
|
|
47
|
+
takeAction(action: Action): void;
|
|
48
|
+
setRole(role: Role): void;
|
|
49
|
+
check(): void;
|
|
50
|
+
fold(): void;
|
|
51
|
+
bet(money: number): number;
|
|
52
|
+
raise(money: number, dealer: Dealer): void;
|
|
53
|
+
call(dealer: Dealer): void;
|
|
54
|
+
allIn(dealer: Dealer): number;
|
|
55
|
+
resetAction(): void;
|
|
56
|
+
getAllowedActions(): ActionType[];
|
|
57
|
+
returnLatestPlayerIf(filter: (player: Player) => boolean): Player | null;
|
|
58
|
+
getAction(): Action | undefined;
|
|
59
|
+
getBalance(): number;
|
|
60
|
+
getRole(): Role | undefined;
|
|
61
|
+
getUserInfo(): User;
|
|
62
|
+
checkIfCanAct(): void;
|
|
63
|
+
toString(): string;
|
|
64
|
+
log(prefix?: string): void;
|
|
65
|
+
setHandPokes(pokes: Poke[]): void;
|
|
66
|
+
getHandPokes(): ("h2" | "h3" | "h4" | "h5" | "h6" | "h7" | "h8" | "h9" | "ht" | "hj" | "hq" | "hk" | "ha" | "s2" | "s3" | "s4" | "s5" | "s6" | "s7" | "s8" | "s9" | "st" | "sj" | "sq" | "sk" | "sa" | "d2" | "d3" | "d4" | "d5" | "d6" | "d7" | "d8" | "d9" | "dt" | "dj" | "dq" | "dk" | "da" | "c2" | "c3" | "c4" | "c5" | "c6" | "c7" | "c8" | "c9" | "ct" | "cj" | "cq" | "ck" | "ca")[];
|
|
67
|
+
earn(money: number): Promise<void>;
|
|
68
|
+
resetCurrentStageTotalAmount(): void;
|
|
69
|
+
clearTimer(): void;
|
|
70
|
+
onStatusChange(): void;
|
|
71
|
+
transferControl(): void;
|
|
72
|
+
continue(): void;
|
|
73
|
+
pause(): void;
|
|
74
|
+
removeControl(): void;
|
|
75
|
+
getControl(): void;
|
|
76
|
+
}
|
|
77
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Player } from '@/Player';
|
|
2
|
+
import { Stage } from '@/Controller';
|
|
3
|
+
declare class Pool {
|
|
4
|
+
#private;
|
|
5
|
+
add(player: Player, amount: number, stage: any): void;
|
|
6
|
+
reset(): void;
|
|
7
|
+
get betRecords(): Map<Stage, Map<Player, number>>;
|
|
8
|
+
get mainPool(): number;
|
|
9
|
+
get pots(): Map<Set<Player>, number>;
|
|
10
|
+
getSpecificPot(key: Set<Player>): number;
|
|
11
|
+
pay(): Promise<void>;
|
|
12
|
+
get totalAmount(): number;
|
|
13
|
+
settle(): Map<Player, number>;
|
|
14
|
+
calculateMainPoolAndSidePots(): void;
|
|
15
|
+
calculateStage(stage: Stage): void;
|
|
16
|
+
calculateSidePot(bets: Map<Player, number>): void;
|
|
17
|
+
}
|
|
18
|
+
export default Pool;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import Dealer from '@/Dealer';
|
|
2
|
+
import { Player } from '@/Player';
|
|
3
|
+
type RoomStatus = 'on' | 'waiting';
|
|
4
|
+
declare class Room {
|
|
5
|
+
#private;
|
|
6
|
+
constructor(dealer: Dealer, allowPlayersToWatch?: boolean, maximumCountOfPlayers?: number);
|
|
7
|
+
ready(): void;
|
|
8
|
+
startGame(): void;
|
|
9
|
+
settle(): void;
|
|
10
|
+
nextGame(): void;
|
|
11
|
+
getDealer(): Dealer;
|
|
12
|
+
getLowestBeAmount(): number;
|
|
13
|
+
getPlayersOnSet(): number;
|
|
14
|
+
getPlayersCount(): number;
|
|
15
|
+
getPlayersInRoomCount(): number;
|
|
16
|
+
addPlayers(...players: Player[]): void;
|
|
17
|
+
addPlayer(player: Player): boolean;
|
|
18
|
+
seat(player: Player): boolean;
|
|
19
|
+
watch(player: Player): boolean;
|
|
20
|
+
getPlayer(player: Player): "hang" | "on-set" | undefined;
|
|
21
|
+
setStatus(status: RoomStatus): void;
|
|
22
|
+
removePlayer(player: Player | null): boolean;
|
|
23
|
+
checkIfCloseRoom(): void;
|
|
24
|
+
}
|
|
25
|
+
export default Room;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/types/index.d.ts
ADDED
package/types/main.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import Room from './Room';
|
|
2
|
+
import Pool from './Pool';
|
|
3
|
+
import Dealer from './Dealer';
|
|
4
|
+
import Controller from './Controller';
|
|
5
|
+
import { User, Player } from './Player';
|
|
6
|
+
interface CreateRoomInputArgs {
|
|
7
|
+
lowestBetAmount: number;
|
|
8
|
+
maximumCountOfPlayers: number;
|
|
9
|
+
allowPlayersToWatch: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare const initialGame: ({ lowestBetAmount, maximumCountOfPlayers, allowPlayersToWatch }: CreateRoomInputArgs) => {
|
|
12
|
+
room: Room;
|
|
13
|
+
pool: Pool;
|
|
14
|
+
dealer: Dealer;
|
|
15
|
+
controller: Controller;
|
|
16
|
+
createPlayer(userInfo: User): Player;
|
|
17
|
+
start(): void;
|
|
18
|
+
settle(): Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
export { initialGame };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const getRandomInt: (min: number, max: number) => number;
|
|
2
|
+
export declare const sum: (a: number, b: number) => number;
|
|
3
|
+
export declare const filterMap: <T, K>(callback: (value: K, key: T) => boolean, map: Map<T, K>) => Map<T, K>;
|
|
4
|
+
export declare const everyMap: <T, K>(callback: (value: K, key: T) => boolean, map: Map<T, K>) => undefined;
|
package/.babelrc
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"ignore": ["**/*.test.ts"],
|
|
3
|
-
"presets": [
|
|
4
|
-
"@babel/preset-typescript",
|
|
5
|
-
[
|
|
6
|
-
"@babel/preset-env",
|
|
7
|
-
{
|
|
8
|
-
"targets": {
|
|
9
|
-
// "node": "current"
|
|
10
|
-
"browsers": "> 0.25%"
|
|
11
|
-
},
|
|
12
|
-
// false标识es module
|
|
13
|
-
"modules": "commonjs",
|
|
14
|
-
// 根据使用的特性引入 polyfills
|
|
15
|
-
"useBuiltIns": "usage",
|
|
16
|
-
// 指定 core-js 版本
|
|
17
|
-
"corejs": { "version": 3, "proposals": true }
|
|
18
|
-
}
|
|
19
|
-
]
|
|
20
|
-
],
|
|
21
|
-
"plugins": [
|
|
22
|
-
[
|
|
23
|
-
"module-resolver",
|
|
24
|
-
{
|
|
25
|
-
"root": ["./src"],
|
|
26
|
-
"alias": {
|
|
27
|
-
"@": "./src"
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
]
|
|
31
|
-
]
|
|
32
|
-
}
|
package/.commitlintrc
DELETED
package/.husky/commit-msg
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
npx --no -- commitlint --edit $1
|
package/.husky/pre-commit
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
npx lint-staged
|
package/.prettierignore
DELETED
package/.prettierrc
DELETED
package/eslint.config.mjs
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import globals from 'globals'
|
|
2
|
-
import pluginJs from '@eslint/js'
|
|
3
|
-
import tseslint from 'typescript-eslint'
|
|
4
|
-
|
|
5
|
-
/** @type {import('eslint').Linter.Config[]} */
|
|
6
|
-
export default [
|
|
7
|
-
{ files: ['**/*.{ts}'], ignores: ['dist', 'types'] },
|
|
8
|
-
{
|
|
9
|
-
languageOptions: { globals: globals.node }
|
|
10
|
-
},
|
|
11
|
-
pluginJs.configs.recommended,
|
|
12
|
-
...tseslint.configs.recommended,
|
|
13
|
-
{
|
|
14
|
-
rules: {
|
|
15
|
-
'no-unused-private-class-members': 'warn',
|
|
16
|
-
'no-unused-vars': 'off',
|
|
17
|
-
'@typescript-eslint/no-unused-vars': 'error',
|
|
18
|
-
'@typescript-eslint/no-explicit-any': 'error',
|
|
19
|
-
'no-undef': 'off',
|
|
20
|
-
'linebreak-style': ['error', 'unix'],
|
|
21
|
-
quotes: ['error', 'single'],
|
|
22
|
-
semi: ['error', 'never'],
|
|
23
|
-
'no-else-return': 'error',
|
|
24
|
-
'comma-spacing': 'error',
|
|
25
|
-
'object-curly-spacing': ['error', 'always'],
|
|
26
|
-
'@typescript-eslint/no-non-null-assertion': 'off',
|
|
27
|
-
'no-console': 'off',
|
|
28
|
-
'no-const-assign': 'error',
|
|
29
|
-
'no-constant-condition': 'error',
|
|
30
|
-
'no-empty': 'warn',
|
|
31
|
-
'no-func-assign': 'error',
|
|
32
|
-
'no-inline-comments': 'error',
|
|
33
|
-
'no-lonely-if': 'error',
|
|
34
|
-
'no-multiple-empty-lines': ['error', { max: 1 }],
|
|
35
|
-
'no-trailing-spaces': 'error',
|
|
36
|
-
camelcase: 'error',
|
|
37
|
-
'no-dupe-keys': 'error',
|
|
38
|
-
'no-nested-ternary': 'error',
|
|
39
|
-
'no-param-reassign': 'error',
|
|
40
|
-
'no-self-compare': 'error',
|
|
41
|
-
'no-unneeded-ternary': 'error',
|
|
42
|
-
'comma-dangle': ['error', 'never'],
|
|
43
|
-
'arrow-spacing': 'error',
|
|
44
|
-
'arrow-parens': 'error',
|
|
45
|
-
// 立即执行函数风格
|
|
46
|
-
'wrap-iife': ['error', 'inside'],
|
|
47
|
-
'key-spacing': [
|
|
48
|
-
'error',
|
|
49
|
-
{
|
|
50
|
-
afterColon: true
|
|
51
|
-
}
|
|
52
|
-
]
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
]
|
package/global.env.d.ts
DELETED
package/jest.config.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
preset: 'ts-jest',
|
|
3
|
-
roots: ['<rootDir>/src'],
|
|
4
|
-
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
|
|
5
|
-
transformIgnorePatterns: ['/node_modules/'],
|
|
6
|
-
moduleNameMapper: {
|
|
7
|
-
// <rootDir>代表jest.config文件所在的根目录
|
|
8
|
-
'@/(.*)$': '<rootDir>/src/$1'
|
|
9
|
-
}
|
|
10
|
-
}
|
package/jest.setup.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import Room from '@/Room'
|
|
2
|
-
import Controller from '.'
|
|
3
|
-
import Dealer from '@/Dealer'
|
|
4
|
-
import { Player } from '@/Player'
|
|
5
|
-
|
|
6
|
-
const dealer = new Dealer(1000)
|
|
7
|
-
const controller = new Controller(dealer)
|
|
8
|
-
const p1 = new Player({
|
|
9
|
-
user: { id: 1, balance: 5000 },
|
|
10
|
-
lowestBetAmount: dealer.getLowestBetAmount(),
|
|
11
|
-
controller
|
|
12
|
-
})
|
|
13
|
-
const room = new Room(dealer)
|
|
14
|
-
|
|
15
|
-
const p2 = new Player({
|
|
16
|
-
lowestBetAmount: 1000,
|
|
17
|
-
user: { id: 2, balance: 30000 },
|
|
18
|
-
controller
|
|
19
|
-
})
|
|
20
|
-
const p3 = new Player({
|
|
21
|
-
lowestBetAmount: 1000,
|
|
22
|
-
user: { id: 3, balance: 10000 },
|
|
23
|
-
controller
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
const p4 = new Player({
|
|
27
|
-
lowestBetAmount: 1000,
|
|
28
|
-
user: { id: 4, balance: 20000 },
|
|
29
|
-
controller
|
|
30
|
-
})
|
|
31
|
-
describe('class Controller', () => {
|
|
32
|
-
test('function transferControl', () => {
|
|
33
|
-
room.addPlayer(p1)
|
|
34
|
-
room.addPlayer(p2)
|
|
35
|
-
room.addPlayer(p3)
|
|
36
|
-
room.addPlayer(p4)
|
|
37
|
-
room.getDealer().setButton(p3)
|
|
38
|
-
// 发牌, 分配角色
|
|
39
|
-
room.ready()
|
|
40
|
-
// room.getDealer().log()
|
|
41
|
-
|
|
42
|
-
controller.start()
|
|
43
|
-
room.getDealer().log()
|
|
44
|
-
expect(controller.activePlayer === p1).toBe(true)
|
|
45
|
-
// p1.log()
|
|
46
|
-
p1.bet(4000)
|
|
47
|
-
// p1.log()
|
|
48
|
-
|
|
49
|
-
expect(controller.activePlayer === p2).toBe(true)
|
|
50
|
-
// p2.log()
|
|
51
|
-
p2.allIn(dealer)
|
|
52
|
-
// p2.log()
|
|
53
|
-
|
|
54
|
-
expect(controller.activePlayer === p3).toBe(true)
|
|
55
|
-
// p3.log()
|
|
56
|
-
p3.allIn(dealer)
|
|
57
|
-
|
|
58
|
-
expect(controller.activePlayer === p4).toBe(true)
|
|
59
|
-
p4.allIn(dealer)
|
|
60
|
-
controller.end()
|
|
61
|
-
expect(p1.getBalance()).toEqual(1000)
|
|
62
|
-
expect(p2.getBalance()).toEqual(10_000)
|
|
63
|
-
expect(p3.getBalance()).toEqual(0)
|
|
64
|
-
expect(p4.getBalance()).toEqual(0)
|
|
65
|
-
})
|
|
66
|
-
})
|
package/src/Controller/index.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
// 控制游戏的进程
|
|
2
|
-
import Dealer from '../Dealer'
|
|
3
|
-
import { Player } from '../Player'
|
|
4
|
-
|
|
5
|
-
export type Stage = 'pre-flop' | 'flop' | 'turn' | 'river' | 'showdown'
|
|
6
|
-
const stages: Stage[] = ['pre-flop', 'flop', 'turn', 'river', 'showdown']
|
|
7
|
-
|
|
8
|
-
class Controller {
|
|
9
|
-
#status: 'on' | 'pause' | 'abort' | 'waiting' = 'waiting'
|
|
10
|
-
#stage: Stage = 'pre-flop'
|
|
11
|
-
#activePlayer: Player | null = null
|
|
12
|
-
#timer: NodeJS.Timeout | null = null
|
|
13
|
-
// 记录游戏的进行时间,单位 second
|
|
14
|
-
#count = 0
|
|
15
|
-
#dealer: Dealer
|
|
16
|
-
constructor(dealer: Dealer) {
|
|
17
|
-
this.#dealer = dealer
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
get stage() {
|
|
21
|
-
return this.#stage
|
|
22
|
-
}
|
|
23
|
-
setControl(player: Player | null) {
|
|
24
|
-
this.#activePlayer = player
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
transferControlToNext(nextPlayer: Player | null) {
|
|
28
|
-
this.setControl(nextPlayer)
|
|
29
|
-
nextPlayer?.getControl()
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get activePlayer() {
|
|
33
|
-
return this.#activePlayer
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// 每个玩家行动之后, 都要调用此方法
|
|
37
|
-
// 推进到新的阶段后, 将控制权交给小盲位
|
|
38
|
-
// 如果小盲位已经出局或者无法行动(all-in), 依次将控制权交给下一个可以行动的玩家
|
|
39
|
-
tryToAdvanceGameToNextStage() {
|
|
40
|
-
if (this.#stage === 'showdown') throw new Error('游戏已经结束')
|
|
41
|
-
|
|
42
|
-
const maxBetAmount = this.#dealer.getCurrentStageMaxBetAmount()
|
|
43
|
-
// this.#dealer.forEach((p) => p.log('ss,'))
|
|
44
|
-
const players = this.#dealer
|
|
45
|
-
// 场上正常下注的玩家, 下注金额需要都等于最大下注金额
|
|
46
|
-
.filter((p) => p.getStatus() === 'waiting')
|
|
47
|
-
|
|
48
|
-
const allPlayersBetThSameAmount = players
|
|
49
|
-
.map((p) => p.getCurrentStageTotalAmount())
|
|
50
|
-
.every((amount) => amount === maxBetAmount)
|
|
51
|
-
|
|
52
|
-
if (allPlayersBetThSameAmount) {
|
|
53
|
-
const index = stages.findIndex((stage) => stage === this.#stage)
|
|
54
|
-
this.#stage = stages[index + 1]
|
|
55
|
-
this.setControl(this.#dealer.getTheFirstPlayerToAct())
|
|
56
|
-
this.#dealer.resetCurrentStageTotalAmount()
|
|
57
|
-
this.#dealer.resetActionsOfPlayers()
|
|
58
|
-
console.log('游戏进入下一个阶段 => ', this.#stage)
|
|
59
|
-
return true
|
|
60
|
-
}
|
|
61
|
-
return false
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// 创建一个迭代器控制游戏进行
|
|
65
|
-
*gameIterator(): Generator<void> {
|
|
66
|
-
while (true) {
|
|
67
|
-
// this.transferControlToNext(this.#dealer.);
|
|
68
|
-
// 暂停,等待玩家行动
|
|
69
|
-
yield
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* @description 开始计时器, 将控制权移交给第一个可以行动的玩家
|
|
75
|
-
*/
|
|
76
|
-
start() {
|
|
77
|
-
// 将控制权给第一个可以行动的玩家
|
|
78
|
-
this.transferControlToNext(this.#dealer.getTheFirstPlayerToAct())
|
|
79
|
-
|
|
80
|
-
this.#status = 'on'
|
|
81
|
-
this.#stage = 'pre-flop'
|
|
82
|
-
this.startTimer()
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
startTimer() {
|
|
86
|
-
// 避免重复开启计时器
|
|
87
|
-
if (this.#timer) return
|
|
88
|
-
|
|
89
|
-
this.#timer = setInterval(() => {
|
|
90
|
-
this.#count++
|
|
91
|
-
}, 1000)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* @description 继续游戏
|
|
96
|
-
*/
|
|
97
|
-
continue() {
|
|
98
|
-
this.#status = 'on'
|
|
99
|
-
this.#activePlayer?.continue()
|
|
100
|
-
this.startTimer()
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
clearTimer() {
|
|
104
|
-
if (this.#timer) {
|
|
105
|
-
clearInterval(this.#timer)
|
|
106
|
-
this.#timer = null
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* @description 结束游戏, 回收控制权, 清除玩家的计时器
|
|
111
|
-
*/
|
|
112
|
-
end() {
|
|
113
|
-
this.clearTimer()
|
|
114
|
-
this.#stage = 'showdown'
|
|
115
|
-
|
|
116
|
-
this.#activePlayer?.removeControl()
|
|
117
|
-
this.#activePlayer?.clearTimer()
|
|
118
|
-
this.#activePlayer = null
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* @description 暂停游戏
|
|
123
|
-
*/
|
|
124
|
-
pause() {
|
|
125
|
-
this.#status = 'pause'
|
|
126
|
-
|
|
127
|
-
this.clearTimer()
|
|
128
|
-
this.activePlayer?.pause()
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
export default Controller
|