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 CHANGED
@@ -48,7 +48,7 @@ Proba la demo actual en [Trucoshi](https://trucoshi.com)
48
48
  [x] Unit tests
49
49
  [x] Bitcoin Lightning integration
50
50
  [x] Historial de partidas
51
- [ ] Cantar flor
51
+ [x] Cantar flor
52
52
  [ ] Torneos
53
53
 
54
54
  # Donations
@@ -1,4 +1,4 @@
1
- import { BURNT_CARD, CARDS } from "../../types";
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 (cheat_lots_of_flowers && table.forehandIdx % 2 === 0) {
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
- const first = deck.takeCard();
51
- const second = deck.pick(deck.cards.find((c) => c.charAt(1) === first.charAt(1)));
52
- const third = deck.pick(deck.cards.find((c) => c.charAt(1) === first.charAt(1)));
53
- playerHands[player.idx] = [first, second, third];
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,5 +1,5 @@
1
1
  export interface IQueue {
2
2
  promise: Promise<void>;
3
- queue(operation: () => any): Promise<void>;
3
+ queue<T>(operation: () => Promise<T>): Promise<T>;
4
4
  }
5
5
  export declare const Queue: () => IQueue;
@@ -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
- logger.error(e, "Error in queue operation %o", operation);
12
- resolve();
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
- return table.getPlayerByPosition();
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
- return array.findIndex((p) => p.key === key);
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
- return cut.concat(end);
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
- if (idx !== undefined) {
28
- return array[idx];
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
  }
@@ -1,2 +1,2 @@
1
1
  export * from "./classes";
2
- export * from "./constants";
2
+ export * from "../constants";
package/dist/lib/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  export * from "./classes";
2
- export * from "./constants";
2
+ export * from "../constants";
@@ -1,6 +1,5 @@
1
1
  import { IRound } from "../truco";
2
- import { ICard, IPlayer } from "../types";
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
- ENVIDO = "ENVIDO",
151
+ FALTA_ENVIDO = "FALTA_ENVIDO",
138
152
  REAL_ENVIDO = "REAL_ENVIDO",
139
- FALTA_ENVIDO = "FALTA_ENVIDO"
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: number;
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
- hasSaidFlorPoints: boolean;
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
- saidFlorPoints(): void;
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-alpha.2",
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/cli/autoplay",
37
- "cli:play": "yarn run ts-node src/cli/play",
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"
@@ -1,3 +0,0 @@
1
- export declare const PLAYER_TIMEOUT_GRACE = 500;
2
- export declare const PLAYER_LOBBY_TIMEOUT: number;
3
- export declare const MATCH_FINISHED_CLEANUP_TIMEOUT: number;
@@ -1,3 +0,0 @@
1
- export const PLAYER_TIMEOUT_GRACE = 500;
2
- export const PLAYER_LOBBY_TIMEOUT = 1000 * 10;
3
- export const MATCH_FINISHED_CLEANUP_TIMEOUT = 1000 * 60 * 2;