trucoshi 7.0.0-alpha.2 → 7.0.0-rc.10
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/README.md +1 -1
- package/dist/lib/classes/Deck.js +20 -6
- package/dist/lib/classes/Queue.d.ts +1 -1
- package/dist/lib/classes/Queue.js +4 -3
- package/dist/lib/classes/Table.js +21 -7
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +1 -1
- package/dist/lib/utils.d.ts +1 -2
- package/dist/lib/utils.js +0 -17
- package/dist/types.d.ts +34 -12
- package/dist/types.js +3 -3
- package/package.json +3 -3
- package/dist/server/constants.d.ts +0 -3
- package/dist/server/constants.js +0 -3
package/README.md
CHANGED
package/dist/lib/classes/Deck.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BURNT_CARD, CARDS } from "
|
|
1
|
+
import { BURNT_CARD, CARDS } from "../constants";
|
|
2
2
|
import { Random } from "./Random";
|
|
3
3
|
export function Deck() {
|
|
4
4
|
const deck = {
|
|
@@ -37,6 +37,8 @@ export function Deck() {
|
|
|
37
37
|
export const getAllCards = () => Object.keys(CARDS);
|
|
38
38
|
export function dealCards(table, deck) {
|
|
39
39
|
const cheat_lots_of_flowers = process.env.APP_CHEAT_LOTS_OF_FLOWERS_FOR_TESTING === "1";
|
|
40
|
+
const cheat_cards = process.env.APP_CHEAT_CARDS &&
|
|
41
|
+
JSON.parse(process.env.APP_CHEAT_CARDS);
|
|
40
42
|
const playerHands = [];
|
|
41
43
|
const players = table.getPlayersForehandFirst();
|
|
42
44
|
for (let i = 0; i < 3; i++) {
|
|
@@ -44,13 +46,25 @@ export function dealCards(table, deck) {
|
|
|
44
46
|
playerHands[player.idx] = [...(playerHands[player.idx] || []), deck.takeCard()];
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
|
-
if (
|
|
49
|
+
if (cheat_cards) {
|
|
50
|
+
deck.shuffle(players[0].idx);
|
|
51
|
+
for (const [key, player] of players.entries()) {
|
|
52
|
+
playerHands[player.idx] = cheat_cards[key]
|
|
53
|
+
? cheat_cards[key].map((c) => deck.pick(c) || deck.takeCard())
|
|
54
|
+
: deck.takeThree();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (cheat_lots_of_flowers) {
|
|
48
58
|
deck.shuffle(players[0].idx);
|
|
49
59
|
for (const player of players) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
if (Math.random() > 0.5) {
|
|
61
|
+
const first = deck.takeCard();
|
|
62
|
+
const second = deck.pick(deck.cards.find((c) => c.charAt(1) === first.charAt(1)));
|
|
63
|
+
const third = deck.pick(deck.cards.find((c) => c.charAt(1) === first.charAt(1)));
|
|
64
|
+
playerHands[player.idx] = [first, second, third];
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
playerHands[player.idx] = deck.takeThree();
|
|
54
68
|
}
|
|
55
69
|
}
|
|
56
70
|
for (const [key, player] of table.players.entries()) {
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import logger from "../../utils/logger";
|
|
2
|
+
const log = logger.child({ class: "Queue" });
|
|
2
3
|
export const Queue = () => {
|
|
3
4
|
const queue = {
|
|
4
5
|
promise: Promise.resolve(),
|
|
5
6
|
queue(operation) {
|
|
6
|
-
return new Promise((resolve) => {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
7
8
|
queue.promise = queue.promise
|
|
8
9
|
.then(operation)
|
|
9
10
|
.then(resolve)
|
|
10
11
|
.catch((e) => {
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
log.error(e, "Error in queue operation %o", operation);
|
|
13
|
+
reject(e);
|
|
13
14
|
});
|
|
14
15
|
});
|
|
15
16
|
},
|
|
@@ -1,34 +1,48 @@
|
|
|
1
|
+
import logger from "../../utils/logger";
|
|
2
|
+
const log = logger.child({ class: "Table" });
|
|
1
3
|
export function Table(players) {
|
|
4
|
+
log.trace({ playerKeys: players.map((p) => p.key) }, "Creating new table");
|
|
2
5
|
const table = {
|
|
3
6
|
players,
|
|
4
7
|
cards: [],
|
|
5
8
|
forehandIdx: 0,
|
|
6
9
|
nextHand() {
|
|
10
|
+
log.trace({ currentForehandIdx: table.forehandIdx }, "nextHand called");
|
|
7
11
|
if (table.forehandIdx < table.players.length - 1) {
|
|
8
12
|
table.forehandIdx++;
|
|
9
13
|
}
|
|
10
14
|
else {
|
|
11
15
|
table.forehandIdx = 0;
|
|
12
16
|
}
|
|
13
|
-
|
|
17
|
+
log.trace({ newForehandIdx: table.forehandIdx }, "nextHand updated");
|
|
18
|
+
const nextPlayer = table.getPlayerByPosition();
|
|
19
|
+
log.trace({ playerKey: nextPlayer.key }, "nextHand returning player");
|
|
20
|
+
return nextPlayer;
|
|
14
21
|
},
|
|
15
22
|
getPlayerPosition(key, forehandFirst = false) {
|
|
23
|
+
log.trace({ key, forehandFirst }, "getPlayerPosition called");
|
|
16
24
|
const array = forehandFirst ? table.getPlayersForehandFirst() : table.players;
|
|
17
|
-
|
|
25
|
+
const position = array.findIndex((p) => p.key === key);
|
|
26
|
+
log.trace({ key, position }, "getPlayerPosition result");
|
|
27
|
+
return position;
|
|
18
28
|
},
|
|
19
29
|
getPlayersForehandFirst(forehand) {
|
|
20
30
|
const idx = forehand !== undefined ? forehand : table.forehandIdx;
|
|
31
|
+
log.trace({ forehandIdx: idx }, "getPlayersForehandFirst called");
|
|
21
32
|
const cut = players.slice(idx, table.players.length);
|
|
22
33
|
const end = players.slice(0, idx);
|
|
23
|
-
|
|
34
|
+
const result = cut.concat(end);
|
|
35
|
+
log.trace({ playerKeys: result.map((p) => p.key) }, "getPlayersForehandFirst result");
|
|
36
|
+
return result;
|
|
24
37
|
},
|
|
25
38
|
getPlayerByPosition(idx, forehandFirst = false) {
|
|
39
|
+
log.trace({ idx, forehandFirst }, "getPlayerByPosition called");
|
|
26
40
|
const array = forehandFirst ? table.getPlayersForehandFirst() : table.players;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return array[0];
|
|
41
|
+
const player = idx !== undefined ? array[idx] : array[0];
|
|
42
|
+
log.trace({ playerKey: player.key }, "getPlayerByPosition result");
|
|
43
|
+
return player;
|
|
31
44
|
},
|
|
32
45
|
};
|
|
46
|
+
log.trace({ forehandIdx: table.forehandIdx }, "Table initialization complete");
|
|
33
47
|
return table;
|
|
34
48
|
}
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from "./classes";
|
|
2
|
-
export * from "
|
|
2
|
+
export * from "../constants";
|
package/dist/lib/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from "./classes";
|
|
2
|
-
export * from "
|
|
2
|
+
export * from "../constants";
|
package/dist/lib/utils.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { IRound } from "../truco";
|
|
2
|
-
import { ICard
|
|
3
|
-
export declare function calculateFlorPoints(player: IPlayer): number;
|
|
2
|
+
import { ICard } from "../types";
|
|
4
3
|
export declare function getMaxNumberIndex<T = number>(array: Array<T>): number;
|
|
5
4
|
export declare function getMinNumberIndex<T = number>(array: Array<T>): number;
|
|
6
5
|
export declare function getCardValue(card: ICard): number;
|
package/dist/lib/utils.js
CHANGED
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
import { splitCardvalues } from "../truco";
|
|
2
1
|
import { CARDS } from "./constants";
|
|
3
|
-
// Calculates the Flor points for a player's hand.
|
|
4
|
-
// Returns the sum of the envidoValue of three cards of the same suit plus 20, or 0 if no Flor exists.
|
|
5
|
-
export function calculateFlorPoints(player) {
|
|
6
|
-
if (!player.hasFlor) {
|
|
7
|
-
return 0;
|
|
8
|
-
}
|
|
9
|
-
const hand = [...player.hand, ...player.usedHand].map(splitCardvalues);
|
|
10
|
-
// Verify that all cards share the same suit (should be true if player.hasFlor is set)
|
|
11
|
-
const sameSuit = hand.every((card) => card.palo === hand[0].palo);
|
|
12
|
-
if (!sameSuit) {
|
|
13
|
-
return 0;
|
|
14
|
-
}
|
|
15
|
-
// Sum the envidoValue of all cards (figures are 0)
|
|
16
|
-
const points = hand.reduce((sum, card) => sum + card.value, 20);
|
|
17
|
-
return points;
|
|
18
|
-
}
|
|
19
2
|
export function getMaxNumberIndex(array) {
|
|
20
3
|
return array.reduce((accumulator, current, index) => {
|
|
21
4
|
return current > array[accumulator] ? index : accumulator;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
export * from "./events";
|
|
2
|
-
export { CARDS, CARDS_HUMAN_READABLE, BURNT_CARD } from "./lib/constants";
|
|
3
2
|
import { User } from "lightning-accounts";
|
|
4
|
-
import { CARDS } from "./lib";
|
|
5
3
|
import { Match, MatchPlayer, MatchHand, UserStats } from "@trucoshi/prisma";
|
|
6
4
|
import { IHand } from "./truco";
|
|
5
|
+
import { CARDS } from "./lib/constants";
|
|
7
6
|
export declare enum EMatchState {
|
|
8
7
|
UNREADY = "UNREADY",
|
|
9
8
|
READY = "READY",
|
|
@@ -39,6 +38,16 @@ export interface ISaidCommand {
|
|
|
39
38
|
player: IPlayer | IPublicPlayer;
|
|
40
39
|
command: ECommand | number;
|
|
41
40
|
}
|
|
41
|
+
export interface IMatchFlorBattle {
|
|
42
|
+
matchSessionId: string;
|
|
43
|
+
playersWithFlor: {
|
|
44
|
+
idx: number;
|
|
45
|
+
cards?: ICard[];
|
|
46
|
+
points: number;
|
|
47
|
+
}[];
|
|
48
|
+
winnerTeamIdx: 0 | 1 | null;
|
|
49
|
+
winner: IPublicPlayer | null;
|
|
50
|
+
}
|
|
42
51
|
export interface IMatchPreviousHand {
|
|
43
52
|
envido: {
|
|
44
53
|
winner: IPublicPlayer;
|
|
@@ -48,6 +57,7 @@ export interface IMatchPreviousHand {
|
|
|
48
57
|
};
|
|
49
58
|
} | null;
|
|
50
59
|
flor: {
|
|
60
|
+
winner: IPublicPlayer | null;
|
|
51
61
|
data: Array<{
|
|
52
62
|
idx: number;
|
|
53
63
|
value: number;
|
|
@@ -64,8 +74,10 @@ export interface IPublicMatch {
|
|
|
64
74
|
busy: boolean;
|
|
65
75
|
state: EMatchState;
|
|
66
76
|
handState: EHandState | null;
|
|
77
|
+
florBattle: IMatchFlorBattle | null;
|
|
67
78
|
winner: ITeam | null;
|
|
68
79
|
matchSessionId: string;
|
|
80
|
+
forehandIdx: number;
|
|
69
81
|
ownerKey: string;
|
|
70
82
|
teams: Array<IPublicTeam>;
|
|
71
83
|
players: Array<IPublicPlayer>;
|
|
@@ -89,11 +101,13 @@ export interface IChatMessage {
|
|
|
89
101
|
user: {
|
|
90
102
|
name: string;
|
|
91
103
|
key: string;
|
|
104
|
+
teamIdx?: 0 | 1;
|
|
92
105
|
};
|
|
93
106
|
system?: boolean;
|
|
94
107
|
command?: boolean;
|
|
95
108
|
card?: boolean;
|
|
96
109
|
content: string;
|
|
110
|
+
sound: string | boolean;
|
|
97
111
|
}
|
|
98
112
|
export interface IChatRoom {
|
|
99
113
|
id: string;
|
|
@@ -101,10 +115,10 @@ export interface IChatRoom {
|
|
|
101
115
|
socket: {
|
|
102
116
|
emit(socket: string): void;
|
|
103
117
|
};
|
|
104
|
-
send(user: IChatMessage["user"], message: string): void;
|
|
105
|
-
card(user: IChatMessage["user"], card: ICard): void;
|
|
106
|
-
command(team: 0 | 1, command: ECommand | number): void;
|
|
107
|
-
system(message: string): void;
|
|
118
|
+
send(user: IChatMessage["user"], message: string, sound?: string | boolean): void;
|
|
119
|
+
card(user: IChatMessage["user"], card: ICard, sound?: string | boolean): void;
|
|
120
|
+
command(team: 0 | 1, command: ECommand | number, sound?: string | boolean): void;
|
|
121
|
+
system(message: string, sound?: string | boolean): void;
|
|
108
122
|
emit(message?: IChatMessage): void;
|
|
109
123
|
}
|
|
110
124
|
export declare enum EChatSystem {
|
|
@@ -134,9 +148,9 @@ export declare enum EEnvidoAnswerCommand {
|
|
|
134
148
|
SON_BUENAS = "SON_BUENAS"
|
|
135
149
|
}
|
|
136
150
|
export declare enum EEnvidoCommand {
|
|
137
|
-
|
|
151
|
+
FALTA_ENVIDO = "FALTA_ENVIDO",
|
|
138
152
|
REAL_ENVIDO = "REAL_ENVIDO",
|
|
139
|
-
|
|
153
|
+
ENVIDO = "ENVIDO"
|
|
140
154
|
}
|
|
141
155
|
export declare enum EHandState {
|
|
142
156
|
WAITING_PLAY = "WAITING_PLAY",
|
|
@@ -144,6 +158,7 @@ export declare enum EHandState {
|
|
|
144
158
|
WAITING_ENVIDO_ANSWER = "WAITING_ENVIDO_ANSWER",
|
|
145
159
|
WAITING_ENVIDO_POINTS_ANSWER = "WAITING_ENVIDO_POINTS_ANSWER",
|
|
146
160
|
WAITING_FLOR_ANSWER = "WAITING_FLOR_ANSWER",
|
|
161
|
+
DISPLAY_FLOR_BATTLE = "DISPLAY_FLOR_BATTLE",
|
|
147
162
|
BEFORE_FINISHED = "BEFORE_FINISHED",
|
|
148
163
|
FINISHED = "FINISHED"
|
|
149
164
|
}
|
|
@@ -248,10 +263,10 @@ export type IPublicTeam = Pick<ITeam, "points" | "id" | "name"> & {
|
|
|
248
263
|
export interface IPlayer {
|
|
249
264
|
idx: number;
|
|
250
265
|
secret: string;
|
|
251
|
-
teamIdx:
|
|
266
|
+
teamIdx: 0 | 1;
|
|
252
267
|
accountId: number | undefined;
|
|
253
268
|
matchPlayerId: number | undefined;
|
|
254
|
-
avatarUrl: string | undefined;
|
|
269
|
+
avatarUrl: string | undefined | null;
|
|
255
270
|
name: string;
|
|
256
271
|
key: string;
|
|
257
272
|
session: string;
|
|
@@ -270,15 +285,21 @@ export interface IPlayer {
|
|
|
270
285
|
turnExpiresAt: number | null;
|
|
271
286
|
turnExtensionExpiresAt: number | null;
|
|
272
287
|
hasFlor: boolean;
|
|
273
|
-
|
|
288
|
+
flor: {
|
|
289
|
+
value: number;
|
|
290
|
+
cards: ICard[];
|
|
291
|
+
} | null;
|
|
292
|
+
hasSaidFlor: boolean;
|
|
274
293
|
hasSaidEnvidoPoints: boolean;
|
|
294
|
+
hasSaidTruco: boolean;
|
|
275
295
|
isEnvidoTurn: boolean;
|
|
276
296
|
isOwner: boolean;
|
|
277
297
|
disabled: boolean;
|
|
278
298
|
abandoned: boolean;
|
|
279
299
|
ready: boolean;
|
|
280
300
|
saidEnvidoPoints(): void;
|
|
281
|
-
|
|
301
|
+
saidFlor(): void;
|
|
302
|
+
saidTruco(): void;
|
|
282
303
|
resetCommands(): void;
|
|
283
304
|
calculateEnvido(): Array<{
|
|
284
305
|
value: number;
|
|
@@ -307,6 +328,7 @@ export interface ITeam {
|
|
|
307
328
|
name: string;
|
|
308
329
|
players: Array<IPlayer>;
|
|
309
330
|
points: ITeamPoints;
|
|
331
|
+
setPlayers(players: IPlayer[]): ITeam;
|
|
310
332
|
pointsToWin(matchPoint: number): number;
|
|
311
333
|
getPublicTeam(playerSession?: string): IPublicTeam;
|
|
312
334
|
isTeamDisabled(): boolean;
|
package/dist/types.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export * from "./events";
|
|
2
|
-
export { CARDS, CARDS_HUMAN_READABLE, BURNT_CARD } from "./lib/constants";
|
|
3
2
|
export var EMatchState;
|
|
4
3
|
(function (EMatchState) {
|
|
5
4
|
EMatchState["UNREADY"] = "UNREADY";
|
|
@@ -41,9 +40,9 @@ export var EEnvidoAnswerCommand;
|
|
|
41
40
|
})(EEnvidoAnswerCommand || (EEnvidoAnswerCommand = {}));
|
|
42
41
|
export var EEnvidoCommand;
|
|
43
42
|
(function (EEnvidoCommand) {
|
|
44
|
-
EEnvidoCommand["ENVIDO"] = "ENVIDO";
|
|
45
|
-
EEnvidoCommand["REAL_ENVIDO"] = "REAL_ENVIDO";
|
|
46
43
|
EEnvidoCommand["FALTA_ENVIDO"] = "FALTA_ENVIDO";
|
|
44
|
+
EEnvidoCommand["REAL_ENVIDO"] = "REAL_ENVIDO";
|
|
45
|
+
EEnvidoCommand["ENVIDO"] = "ENVIDO";
|
|
47
46
|
})(EEnvidoCommand || (EEnvidoCommand = {}));
|
|
48
47
|
export var EHandState;
|
|
49
48
|
(function (EHandState) {
|
|
@@ -52,6 +51,7 @@ export var EHandState;
|
|
|
52
51
|
EHandState["WAITING_ENVIDO_ANSWER"] = "WAITING_ENVIDO_ANSWER";
|
|
53
52
|
EHandState["WAITING_ENVIDO_POINTS_ANSWER"] = "WAITING_ENVIDO_POINTS_ANSWER";
|
|
54
53
|
EHandState["WAITING_FLOR_ANSWER"] = "WAITING_FLOR_ANSWER";
|
|
54
|
+
EHandState["DISPLAY_FLOR_BATTLE"] = "DISPLAY_FLOR_BATTLE";
|
|
55
55
|
EHandState["BEFORE_FINISHED"] = "BEFORE_FINISHED";
|
|
56
56
|
EHandState["FINISHED"] = "FINISHED";
|
|
57
57
|
})(EHandState || (EHandState = {}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trucoshi",
|
|
3
|
-
"version": "7.0.0-
|
|
3
|
+
"version": "7.0.0-rc.10",
|
|
4
4
|
"description": "Lightning Truco Server",
|
|
5
5
|
"main": "dist/types.js",
|
|
6
6
|
"license": "GPL-3.0",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"test:e2e": "prisma db push --force-reset && dotenv -e .env.test -- ts-mocha --exit ./test/**/*.ts -t 60000",
|
|
34
34
|
"profiler": "node --prof ./bin/trucoshi-server",
|
|
35
35
|
"prepublishOnly": "yarn test && yarn build:dist",
|
|
36
|
-
"cli:autoplay": "yarn run ts-node src/
|
|
37
|
-
"cli:play": "yarn run ts-node src/
|
|
36
|
+
"cli:autoplay": "APP_DEBUG_LEVEL=warn yarn run ts-node src/utils/scripts/autoplay",
|
|
37
|
+
"cli:play": "APP_DEBUG_LEVEL=warn yarn run ts-node src/utils/scripts/play",
|
|
38
38
|
"db:push": "prisma db push",
|
|
39
39
|
"db:studio": "prisma studio",
|
|
40
40
|
"db:migrate": "prisma migrate dev"
|
package/dist/server/constants.js
DELETED