trucoshi 0.1.7 → 0.2.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/LICENSE +674 -674
- package/README.md +60 -37
- package/dist/index.d.ts +2 -0
- package/dist/index.js +18 -18
- package/dist/lib/classes/Deck.d.ts +16 -0
- package/dist/lib/classes/Deck.js +38 -0
- package/dist/lib/classes/GameLoop.d.ts +20 -0
- package/dist/lib/classes/GameLoop.js +61 -0
- package/dist/lib/classes/Hand.d.ts +38 -0
- package/dist/lib/classes/Hand.js +184 -0
- package/dist/lib/classes/Lobby.d.ts +27 -0
- package/dist/lib/classes/Lobby.js +112 -0
- package/dist/lib/classes/Match.d.ts +18 -0
- package/dist/lib/classes/Match.js +72 -0
- package/dist/lib/classes/Play.d.ts +21 -0
- package/dist/lib/classes/Play.js +39 -0
- package/dist/lib/classes/Player.d.ts +26 -0
- package/dist/lib/classes/Player.js +67 -0
- package/dist/lib/classes/Round.d.ts +17 -0
- package/dist/lib/classes/Round.js +33 -0
- package/dist/lib/classes/Table.d.ts +12 -0
- package/dist/lib/classes/Table.js +30 -0
- package/dist/lib/classes/Team.d.ts +19 -0
- package/dist/lib/classes/Team.js +48 -0
- package/dist/lib/classes/Truco.d.ts +18 -0
- package/dist/lib/classes/Truco.js +70 -0
- package/dist/lib/classes/index.d.ts +11 -0
- package/dist/lib/classes/index.js +27 -0
- package/dist/lib/constants.d.ts +45 -0
- package/dist/lib/constants.js +84 -0
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.js +18 -0
- package/dist/lib/types.d.ts +50 -0
- package/dist/lib/types.js +34 -0
- package/dist/lib/utils.d.ts +5 -0
- package/dist/lib/utils.js +58 -0
- package/dist/types.d.ts +133 -0
- package/dist/types.js +65 -0
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -1,37 +1,60 @@
|
|
|
1
|
-
# Trucoshi
|
|
2
|
-
|
|
3
|
-
### English
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
# Trucoshi
|
|
2
|
+
|
|
3
|
+
### English
|
|
4
|
+
|
|
5
|
+
Work in progress
|
|
6
|
+
|
|
7
|
+
Pretends to be an Argentinian Truco game socket server that allows you to put Satoshis on the table ;)
|
|
8
|
+
|
|
9
|
+
Try current demo at [Trucoshi](https://trucoshi.com)
|
|
10
|
+
|
|
11
|
+
### Spanish
|
|
12
|
+
|
|
13
|
+
En construccion
|
|
14
|
+
|
|
15
|
+
Pretende ser un server basado en sockets del juego de Truco Argentino que te permita poner unos Satoshis en la mesa ;)
|
|
16
|
+
|
|
17
|
+
Proba la demo actual en [Trucoshi](https://trucoshi.com)
|
|
18
|
+
|
|
19
|
+
# Test
|
|
20
|
+
|
|
21
|
+
Right now there's only a local CLI way of playing as there is no socket server implementation and its just the game logic.
|
|
22
|
+
|
|
23
|
+
### Installation
|
|
24
|
+
|
|
25
|
+
`yarn`
|
|
26
|
+
|
|
27
|
+
### Build
|
|
28
|
+
|
|
29
|
+
`yarn build`
|
|
30
|
+
|
|
31
|
+
### Play
|
|
32
|
+
|
|
33
|
+
`yarn test:play`
|
|
34
|
+
|
|
35
|
+
### Autoplay
|
|
36
|
+
|
|
37
|
+
`yarn test:autoplay`
|
|
38
|
+
|
|
39
|
+
# Todo
|
|
40
|
+
|
|
41
|
+
[x] Logica de turnos, rondas y battalla de cartas
|
|
42
|
+
[x] Irse al mazo
|
|
43
|
+
[] Cantar truco
|
|
44
|
+
[] Cantar envido
|
|
45
|
+
[] Cantar flor
|
|
46
|
+
[x] Socket server
|
|
47
|
+
[] Bitcoin Lightning integration
|
|
48
|
+
[] Unit tests
|
|
49
|
+
|
|
50
|
+
# Donations
|
|
51
|
+
|
|
52
|
+
Donate Bitcoin at [jfrader.com](https://jfrader.com)
|
|
53
|
+
|
|
54
|
+
# License
|
|
55
|
+
|
|
56
|
+
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
57
|
+
|
|
58
|
+
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
59
|
+
|
|
60
|
+
You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
package/dist/index.d.ts
ADDED
package/dist/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./lib"), exports);
|
|
18
|
-
__exportStar(require("./types"), exports);
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./lib"), exports);
|
|
18
|
+
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { CARDS } from "../constants";
|
|
2
|
+
import { IPlayer, IPublicPlayer } from "./Player";
|
|
3
|
+
export interface IDeck {
|
|
4
|
+
cards: Array<ICard>;
|
|
5
|
+
usedCards: Array<ICard>;
|
|
6
|
+
takeCard(): ICard;
|
|
7
|
+
shuffle(): IDeck;
|
|
8
|
+
}
|
|
9
|
+
export type ICard = keyof typeof CARDS;
|
|
10
|
+
export interface IPlayedCard {
|
|
11
|
+
get key(): string;
|
|
12
|
+
player: IPlayer & IPublicPlayer;
|
|
13
|
+
card: ICard;
|
|
14
|
+
}
|
|
15
|
+
export declare function Deck(): IDeck;
|
|
16
|
+
export declare function PlayedCard(player: IPlayer, card: ICard): IPlayedCard;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PlayedCard = exports.Deck = void 0;
|
|
4
|
+
const constants_1 = require("../constants");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function Deck() {
|
|
7
|
+
const deck = {
|
|
8
|
+
cards: Object.keys(constants_1.CARDS),
|
|
9
|
+
usedCards: [],
|
|
10
|
+
takeCard() {
|
|
11
|
+
const card = deck.cards.shift();
|
|
12
|
+
deck.usedCards.push(card);
|
|
13
|
+
return card;
|
|
14
|
+
},
|
|
15
|
+
shuffle() {
|
|
16
|
+
deck.cards = deck.cards.concat(deck.usedCards);
|
|
17
|
+
deck.usedCards = [];
|
|
18
|
+
deck.cards = (0, utils_1.shuffleArray)(deck.cards);
|
|
19
|
+
if (deck.cards.length !== 40) {
|
|
20
|
+
throw new Error("This is not good");
|
|
21
|
+
}
|
|
22
|
+
return deck;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
return deck;
|
|
26
|
+
}
|
|
27
|
+
exports.Deck = Deck;
|
|
28
|
+
function PlayedCard(player, card) {
|
|
29
|
+
const pc = {
|
|
30
|
+
player,
|
|
31
|
+
card,
|
|
32
|
+
get key() {
|
|
33
|
+
return card + player.session;
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
return pc;
|
|
37
|
+
}
|
|
38
|
+
exports.PlayedCard = PlayedCard;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { IHand } from "./Hand";
|
|
2
|
+
import { IMatch } from "./Match";
|
|
3
|
+
import { IPlayInstance } from "./Play";
|
|
4
|
+
import { ITeam } from "./Team";
|
|
5
|
+
export type IWinnerCallback = (winner: ITeam, teams: [ITeam, ITeam]) => Promise<void>;
|
|
6
|
+
export type ITurnCallback = (play: IPlayInstance) => Promise<void>;
|
|
7
|
+
export type ITrucoCallback = (play: IPlayInstance) => Promise<void>;
|
|
8
|
+
export interface IGameLoop {
|
|
9
|
+
_onTruco: ITrucoCallback;
|
|
10
|
+
_onTurn: ITurnCallback;
|
|
11
|
+
_onWinner: IWinnerCallback;
|
|
12
|
+
teams: Array<ITeam>;
|
|
13
|
+
hands: Array<IHand>;
|
|
14
|
+
winner: ITeam | null;
|
|
15
|
+
onTurn: (callback: ITurnCallback) => IGameLoop;
|
|
16
|
+
onWinner: (callback: IWinnerCallback) => IGameLoop;
|
|
17
|
+
onTruco: (callback: ITrucoCallback) => IGameLoop;
|
|
18
|
+
begin: () => Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export declare const GameLoop: (match: IMatch) => IGameLoop;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.GameLoop = void 0;
|
|
13
|
+
const types_1 = require("../../types");
|
|
14
|
+
const GameLoop = (match) => {
|
|
15
|
+
let gameloop = {
|
|
16
|
+
_onTruco: () => Promise.resolve(),
|
|
17
|
+
_onTurn: () => Promise.resolve(),
|
|
18
|
+
_onWinner: () => Promise.resolve(),
|
|
19
|
+
teams: [],
|
|
20
|
+
winner: null,
|
|
21
|
+
hands: [],
|
|
22
|
+
onTruco: (callback) => {
|
|
23
|
+
gameloop._onTruco = callback;
|
|
24
|
+
return gameloop;
|
|
25
|
+
},
|
|
26
|
+
onTurn: (callback) => {
|
|
27
|
+
gameloop._onTurn = callback;
|
|
28
|
+
return gameloop;
|
|
29
|
+
},
|
|
30
|
+
onWinner: (callback) => {
|
|
31
|
+
gameloop._onWinner = callback;
|
|
32
|
+
return gameloop;
|
|
33
|
+
},
|
|
34
|
+
begin() {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
gameloop.teams = match.teams;
|
|
37
|
+
while (!match.winner) {
|
|
38
|
+
const play = match.play();
|
|
39
|
+
gameloop.hands = match.hands;
|
|
40
|
+
if (!play || !play.player) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (play.state === types_1.EHandState.WAITING_FOR_TRUCO_ANSWER) {
|
|
44
|
+
yield gameloop._onTruco(play);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (play.state === types_1.EHandState.WAITING_PLAY) {
|
|
48
|
+
play.player.setTurn(true);
|
|
49
|
+
yield gameloop._onTurn(play);
|
|
50
|
+
play.player.setTurn(false);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
gameloop.winner = match.winner;
|
|
55
|
+
yield gameloop._onWinner(match.winner, match.teams);
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
return gameloop;
|
|
60
|
+
};
|
|
61
|
+
exports.GameLoop = GameLoop;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { EHandState, EnvidoState, IHandCommands } from "../../types";
|
|
2
|
+
import { ICard, IDeck } from "./Deck";
|
|
3
|
+
import { IMatch } from "./Match";
|
|
4
|
+
import { IPlayInstance } from "./Play";
|
|
5
|
+
import { IPlayer } from "./Player";
|
|
6
|
+
import { IRound } from "./Round";
|
|
7
|
+
import { ITruco } from "./Truco";
|
|
8
|
+
export interface IHandPoints {
|
|
9
|
+
0: number;
|
|
10
|
+
1: number;
|
|
11
|
+
}
|
|
12
|
+
export interface IHand {
|
|
13
|
+
idx: number;
|
|
14
|
+
state: EHandState;
|
|
15
|
+
turn: number;
|
|
16
|
+
points: IHandPoints;
|
|
17
|
+
truco: ITruco;
|
|
18
|
+
envido: EnvidoState;
|
|
19
|
+
rounds: Array<IRound>;
|
|
20
|
+
_currentPlayer: IPlayer | null;
|
|
21
|
+
get currentPlayer(): IPlayer | null;
|
|
22
|
+
set currentPlayer(player: IPlayer | null);
|
|
23
|
+
currentRound: IRound | null;
|
|
24
|
+
commands: IHandCommands;
|
|
25
|
+
finished: () => boolean;
|
|
26
|
+
play(): IPlayInstance | null;
|
|
27
|
+
nextTurn(): void;
|
|
28
|
+
use(idx: number, card: ICard): ICard | null;
|
|
29
|
+
pushRound(round: IRound): IRound;
|
|
30
|
+
setTurn(turn: number): IPlayer;
|
|
31
|
+
addPoints(team: 0 | 1, points: number): void;
|
|
32
|
+
disablePlayer(player: IPlayer): void;
|
|
33
|
+
setCurrentRound(round: IRound | null): IRound | null;
|
|
34
|
+
setCurrentPlayer(player: IPlayer | null): IPlayer | null;
|
|
35
|
+
setState(state: EHandState): EHandState;
|
|
36
|
+
getNextPlayer(): IteratorResult<IHand, IHand | void>;
|
|
37
|
+
}
|
|
38
|
+
export declare function Hand(match: IMatch, deck: IDeck, idx: number): IHand;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Hand = void 0;
|
|
4
|
+
const types_1 = require("../../types");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const Deck_1 = require("./Deck");
|
|
7
|
+
const Play_1 = require("./Play");
|
|
8
|
+
const Round_1 = require("./Round");
|
|
9
|
+
const Truco_1 = require("./Truco");
|
|
10
|
+
function Hand(match, deck, idx) {
|
|
11
|
+
match.teams.forEach((team) => {
|
|
12
|
+
team.players.forEach((player) => {
|
|
13
|
+
const playerHand = [deck.takeCard(), deck.takeCard(), deck.takeCard()];
|
|
14
|
+
player.setHand(playerHand);
|
|
15
|
+
player.enable();
|
|
16
|
+
// player.setHand(["5c", "4c", "6c"])
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
function* roundsGeneratorSequence() {
|
|
20
|
+
let currentRoundIdx = 0;
|
|
21
|
+
let forehandTeamIdx = match.table.player(hand.turn).teamIdx;
|
|
22
|
+
while (currentRoundIdx < 3 && !hand.finished()) {
|
|
23
|
+
const round = (0, Round_1.Round)(0);
|
|
24
|
+
hand.setCurrentRound(round);
|
|
25
|
+
hand.pushRound(round);
|
|
26
|
+
let previousRound = hand.rounds[currentRoundIdx - 1];
|
|
27
|
+
// Put previous round winner as forehand
|
|
28
|
+
if (previousRound && previousRound.winner && !previousRound.tie) {
|
|
29
|
+
const newTurn = match.table.getPlayerPosition(previousRound.winner.id);
|
|
30
|
+
if (newTurn !== -1) {
|
|
31
|
+
hand.setTurn(newTurn);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
while (round.turn < match.table.players.length) {
|
|
35
|
+
while (hand.state === types_1.EHandState.WAITING_FOR_TRUCO_ANSWER) {
|
|
36
|
+
const { value } = hand.truco.getNextPlayer();
|
|
37
|
+
if (value && value.currentPlayer) {
|
|
38
|
+
hand.setCurrentPlayer(value.currentPlayer);
|
|
39
|
+
yield hand;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const player = match.table.player(hand.turn);
|
|
43
|
+
hand.setCurrentPlayer(player);
|
|
44
|
+
if (player.disabled) {
|
|
45
|
+
hand.setCurrentPlayer(null);
|
|
46
|
+
}
|
|
47
|
+
yield hand;
|
|
48
|
+
}
|
|
49
|
+
if (match.teams[0].isTeamDisabled() && match.teams[1].isTeamDisabled()) {
|
|
50
|
+
hand.setState(types_1.EHandState.FINISHED);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
let winnerTeamIdx = (0, utils_1.checkHandWinner)(hand.rounds, forehandTeamIdx);
|
|
54
|
+
if (match.teams[0].isTeamDisabled()) {
|
|
55
|
+
winnerTeamIdx = 1;
|
|
56
|
+
}
|
|
57
|
+
if (match.teams[1].isTeamDisabled()) {
|
|
58
|
+
winnerTeamIdx = 0;
|
|
59
|
+
}
|
|
60
|
+
if (winnerTeamIdx !== null) {
|
|
61
|
+
hand.addPoints(winnerTeamIdx, hand.truco.state);
|
|
62
|
+
hand.setState(types_1.EHandState.FINISHED);
|
|
63
|
+
}
|
|
64
|
+
currentRoundIdx++;
|
|
65
|
+
}
|
|
66
|
+
yield hand;
|
|
67
|
+
}
|
|
68
|
+
const roundsGenerator = roundsGeneratorSequence();
|
|
69
|
+
const commands = {
|
|
70
|
+
[types_1.ESayCommand.MAZO]: (player) => {
|
|
71
|
+
hand.disablePlayer(player);
|
|
72
|
+
},
|
|
73
|
+
[types_1.ESayCommand.TRUCO]: (player) => {
|
|
74
|
+
const { teamIdx } = hand.truco;
|
|
75
|
+
if (teamIdx === null || teamIdx !== player.teamIdx) {
|
|
76
|
+
hand.setState(types_1.EHandState.WAITING_FOR_TRUCO_ANSWER);
|
|
77
|
+
hand.truco.sayTruco(player.teamIdx, match.teams[Number(!player.teamIdx)].players);
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
[types_1.ESayCommand.QUIERO]: () => {
|
|
81
|
+
if (hand.state === types_1.EHandState.WAITING_FOR_TRUCO_ANSWER) {
|
|
82
|
+
hand.truco.setAnswer(true);
|
|
83
|
+
hand.setState(types_1.EHandState.WAITING_PLAY);
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
[types_1.ESayCommand.NO_QUIERO]: (player) => {
|
|
87
|
+
if (hand.state === types_1.EHandState.WAITING_FOR_TRUCO_ANSWER) {
|
|
88
|
+
hand.truco.setAnswer(false);
|
|
89
|
+
hand.setState(types_1.EHandState.WAITING_PLAY);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
[types_1.ESayCommand.FLOR]: () => { },
|
|
93
|
+
[types_1.ESayCommand.CONTRAFLOR]: () => { },
|
|
94
|
+
[types_1.EEnvidoCommand.ENVIDO]: () => { },
|
|
95
|
+
[types_1.EEnvidoCommand.ENVIDO_ENVIDO]: () => { },
|
|
96
|
+
[types_1.EEnvidoCommand.REAL_ENVIDO]: () => { },
|
|
97
|
+
[types_1.EEnvidoCommand.FALTA_ENVIDO]: () => { },
|
|
98
|
+
};
|
|
99
|
+
const hand = {
|
|
100
|
+
idx,
|
|
101
|
+
turn: Number(match.table.forehandIdx),
|
|
102
|
+
state: types_1.EHandState.WAITING_PLAY,
|
|
103
|
+
rounds: [],
|
|
104
|
+
truco: (0, Truco_1.Truco)(),
|
|
105
|
+
envido: {
|
|
106
|
+
accept: 1,
|
|
107
|
+
decline: 2,
|
|
108
|
+
teamIdx: null,
|
|
109
|
+
},
|
|
110
|
+
points: [0, 0],
|
|
111
|
+
currentRound: null,
|
|
112
|
+
_currentPlayer: null,
|
|
113
|
+
set currentPlayer(player) {
|
|
114
|
+
hand._currentPlayer = player;
|
|
115
|
+
},
|
|
116
|
+
get currentPlayer() {
|
|
117
|
+
if (hand.state === types_1.EHandState.WAITING_FOR_TRUCO_ANSWER) {
|
|
118
|
+
return hand.truco.currentPlayer;
|
|
119
|
+
}
|
|
120
|
+
return hand._currentPlayer;
|
|
121
|
+
},
|
|
122
|
+
commands,
|
|
123
|
+
play() {
|
|
124
|
+
return (0, Play_1.PlayInstance)(hand, match.teams);
|
|
125
|
+
},
|
|
126
|
+
use(idx, card) {
|
|
127
|
+
const player = hand.currentPlayer;
|
|
128
|
+
const round = hand.currentRound;
|
|
129
|
+
if (!player || !round) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const playerCard = player.useCard(idx, card);
|
|
133
|
+
if (playerCard) {
|
|
134
|
+
hand.nextTurn();
|
|
135
|
+
return round.use((0, Deck_1.PlayedCard)(player, playerCard));
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
},
|
|
139
|
+
nextTurn() {
|
|
140
|
+
var _a;
|
|
141
|
+
if (hand.turn >= match.table.players.length - 1) {
|
|
142
|
+
hand.setTurn(0);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
hand.setTurn(hand.turn + 1);
|
|
146
|
+
}
|
|
147
|
+
(_a = hand.currentRound) === null || _a === void 0 ? void 0 : _a.nextTurn();
|
|
148
|
+
},
|
|
149
|
+
getNextPlayer() {
|
|
150
|
+
return roundsGenerator.next();
|
|
151
|
+
},
|
|
152
|
+
disablePlayer(player) {
|
|
153
|
+
match.teams[player.teamIdx].disable(player);
|
|
154
|
+
},
|
|
155
|
+
addPoints(team, points) {
|
|
156
|
+
hand.points[team] = hand.points[team] + points;
|
|
157
|
+
},
|
|
158
|
+
pushRound(round) {
|
|
159
|
+
hand.rounds.push(round);
|
|
160
|
+
return round;
|
|
161
|
+
},
|
|
162
|
+
setTurn(turn) {
|
|
163
|
+
hand.turn = turn;
|
|
164
|
+
return match.table.player(hand.turn);
|
|
165
|
+
},
|
|
166
|
+
setCurrentRound(round) {
|
|
167
|
+
hand.currentRound = round;
|
|
168
|
+
return hand.currentRound;
|
|
169
|
+
},
|
|
170
|
+
setCurrentPlayer(player) {
|
|
171
|
+
hand._currentPlayer = player;
|
|
172
|
+
return hand._currentPlayer;
|
|
173
|
+
},
|
|
174
|
+
setState(state) {
|
|
175
|
+
hand.state = state;
|
|
176
|
+
return hand.state;
|
|
177
|
+
},
|
|
178
|
+
finished: () => {
|
|
179
|
+
return hand.state === types_1.EHandState.FINISHED;
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
return hand;
|
|
183
|
+
}
|
|
184
|
+
exports.Hand = Hand;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { IGameLoop } from "./GameLoop";
|
|
2
|
+
import { IPlayer } from "./Player";
|
|
3
|
+
import { ITable } from "./Table";
|
|
4
|
+
import { ITeam } from "./Team";
|
|
5
|
+
export interface IPrivateLobby {
|
|
6
|
+
gameLoop?: IGameLoop;
|
|
7
|
+
lastTeamIdx: 0 | 1;
|
|
8
|
+
_players: Array<IPlayer | {
|
|
9
|
+
id?: undefined;
|
|
10
|
+
session?: undefined;
|
|
11
|
+
}>;
|
|
12
|
+
get players(): Array<IPlayer>;
|
|
13
|
+
teams: Array<ITeam>;
|
|
14
|
+
maxPlayers: number;
|
|
15
|
+
table: ITable | null;
|
|
16
|
+
full: boolean;
|
|
17
|
+
ready: boolean;
|
|
18
|
+
started: boolean;
|
|
19
|
+
addPlayer(id: string, session: string, teamIdx?: 0 | 1, isOwner?: boolean): IPlayer;
|
|
20
|
+
removePlayer(id: string): ILobby;
|
|
21
|
+
calculateReady(): boolean;
|
|
22
|
+
calculateFull(): boolean;
|
|
23
|
+
startMatch(matchPoint?: 9 | 12 | 15): IGameLoop;
|
|
24
|
+
}
|
|
25
|
+
export interface ILobby extends Pick<IPrivateLobby, "addPlayer" | "removePlayer" | "startMatch" | "ready" | "full" | "started" | "teams" | "players" | "gameLoop" | "table" | "maxPlayers" | "calculateReady"> {
|
|
26
|
+
}
|
|
27
|
+
export declare function Lobby(teamSize?: 1 | 2 | 3): ILobby;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Lobby = void 0;
|
|
4
|
+
const constants_1 = require("../constants");
|
|
5
|
+
const types_1 = require("../../types");
|
|
6
|
+
const GameLoop_1 = require("./GameLoop");
|
|
7
|
+
const Match_1 = require("./Match");
|
|
8
|
+
const Player_1 = require("./Player");
|
|
9
|
+
const Table_1 = require("./Table");
|
|
10
|
+
const Team_1 = require("./Team");
|
|
11
|
+
function Lobby(teamSize) {
|
|
12
|
+
const lobby = {
|
|
13
|
+
lastTeamIdx: 1,
|
|
14
|
+
_players: [],
|
|
15
|
+
get players() {
|
|
16
|
+
return lobby._players.filter((player) => Boolean(player && player.id));
|
|
17
|
+
},
|
|
18
|
+
teams: [],
|
|
19
|
+
table: null,
|
|
20
|
+
maxPlayers: teamSize ? teamSize * 2 : 6,
|
|
21
|
+
full: false,
|
|
22
|
+
ready: false,
|
|
23
|
+
started: false,
|
|
24
|
+
gameLoop: undefined,
|
|
25
|
+
calculateReady() {
|
|
26
|
+
const allPlayersReady = lobby.players.reduce((prev, curr) => Boolean(prev && curr && curr.ready), true);
|
|
27
|
+
const teamsSameSize = lobby.players.filter((player) => player.teamIdx === 0).length ===
|
|
28
|
+
lobby.players.filter((player) => player.teamIdx === 1).length;
|
|
29
|
+
const allTeamsComplete = lobby.players.length % 2 === 0;
|
|
30
|
+
lobby.ready = allPlayersReady && allTeamsComplete && teamsSameSize;
|
|
31
|
+
return lobby.ready;
|
|
32
|
+
},
|
|
33
|
+
calculateFull() {
|
|
34
|
+
lobby.full = lobby.players.length >= lobby.maxPlayers;
|
|
35
|
+
return lobby.full;
|
|
36
|
+
},
|
|
37
|
+
addPlayer(id, session, teamIdx, isOwner) {
|
|
38
|
+
const exists = lobby.players.find((player) => player.session === session);
|
|
39
|
+
if (exists) {
|
|
40
|
+
if (exists.teamIdx === teamIdx) {
|
|
41
|
+
return exists;
|
|
42
|
+
}
|
|
43
|
+
lobby.removePlayer(exists.session);
|
|
44
|
+
}
|
|
45
|
+
if (lobby.started) {
|
|
46
|
+
throw new Error(types_1.GAME_ERROR.MATCH_ALREADY_STARTED);
|
|
47
|
+
}
|
|
48
|
+
if (lobby.full) {
|
|
49
|
+
throw new Error(types_1.GAME_ERROR.LOBBY_IS_FULL);
|
|
50
|
+
}
|
|
51
|
+
const maxSize = teamSize ? teamSize : 3;
|
|
52
|
+
if (lobby.full ||
|
|
53
|
+
lobby.players.filter((player) => player.teamIdx === teamIdx).length > maxSize) {
|
|
54
|
+
throw new Error(types_1.GAME_ERROR.TEAM_IS_FULL);
|
|
55
|
+
}
|
|
56
|
+
const player = (0, Player_1.Player)(id, teamIdx !== undefined ? teamIdx : Number(!lobby.lastTeamIdx), isOwner);
|
|
57
|
+
player.setSession(session);
|
|
58
|
+
lobby.lastTeamIdx = Number(!lobby.lastTeamIdx);
|
|
59
|
+
for (let i = 0; i < lobby._players.length; i++) {
|
|
60
|
+
if (!lobby._players[i].id) {
|
|
61
|
+
if (player.teamIdx === 0 && i % 2 === 0) {
|
|
62
|
+
lobby._players[i] = player;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
if (player.teamIdx === 1 && i % 2 !== 0) {
|
|
66
|
+
lobby._players[i] = player;
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
lobby.calculateFull();
|
|
72
|
+
lobby.calculateReady();
|
|
73
|
+
return player;
|
|
74
|
+
},
|
|
75
|
+
removePlayer(session) {
|
|
76
|
+
const idx = lobby._players.findIndex((player) => player && player.session === session);
|
|
77
|
+
if (idx !== -1) {
|
|
78
|
+
lobby._players[idx] = {};
|
|
79
|
+
lobby.calculateFull();
|
|
80
|
+
lobby.calculateReady();
|
|
81
|
+
}
|
|
82
|
+
return lobby;
|
|
83
|
+
},
|
|
84
|
+
startMatch(matchPoint = 9) {
|
|
85
|
+
lobby.calculateReady();
|
|
86
|
+
const actualTeamSize = lobby.players.length / 2;
|
|
87
|
+
if (!constants_1.TEAM_SIZE_VALUES.includes(actualTeamSize)) {
|
|
88
|
+
throw new Error(types_1.GAME_ERROR.UNEXPECTED_TEAM_SIZE);
|
|
89
|
+
}
|
|
90
|
+
if (!lobby.ready) {
|
|
91
|
+
throw new Error(types_1.GAME_ERROR.TEAM_NOT_READY);
|
|
92
|
+
}
|
|
93
|
+
lobby.teams = [
|
|
94
|
+
(0, Team_1.Team)(lobby.players.filter((player) => player.teamIdx === 0)),
|
|
95
|
+
(0, Team_1.Team)(lobby.players.filter((player) => player.teamIdx === 1)),
|
|
96
|
+
];
|
|
97
|
+
if (lobby.teams[0].players.length !== actualTeamSize ||
|
|
98
|
+
lobby.teams[1].players.length !== actualTeamSize) {
|
|
99
|
+
throw new Error(types_1.GAME_ERROR.UNEXPECTED_TEAM_SIZE);
|
|
100
|
+
}
|
|
101
|
+
lobby.table = (0, Table_1.Table)(lobby.players, lobby.teams);
|
|
102
|
+
lobby.gameLoop = (0, GameLoop_1.GameLoop)((0, Match_1.Match)(lobby.table, lobby.teams, matchPoint));
|
|
103
|
+
lobby.started = true;
|
|
104
|
+
return lobby.gameLoop;
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
for (let i = 0; i < lobby.maxPlayers; i++) {
|
|
108
|
+
lobby._players.push({});
|
|
109
|
+
}
|
|
110
|
+
return lobby;
|
|
111
|
+
}
|
|
112
|
+
exports.Lobby = Lobby;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { IHand, IHandPoints } from "./Hand";
|
|
2
|
+
import { IPlayInstance } from "./Play";
|
|
3
|
+
import { ITable } from "./Table";
|
|
4
|
+
import { ITeam } from "./Team";
|
|
5
|
+
export interface IMatch {
|
|
6
|
+
teams: [ITeam, ITeam];
|
|
7
|
+
hands: Array<IHand>;
|
|
8
|
+
winner: ITeam | null;
|
|
9
|
+
currentHand: IHand | null;
|
|
10
|
+
table: ITable;
|
|
11
|
+
play(): IPlayInstance | null;
|
|
12
|
+
addPoints(points: IHandPoints): [ITeam, ITeam];
|
|
13
|
+
pushHand(hand: IHand): void;
|
|
14
|
+
setCurrentHand(hand: IHand | null): IHand | null;
|
|
15
|
+
setWinner(winner: ITeam): void;
|
|
16
|
+
getNextTurn(): IteratorResult<IMatch | null, IMatch | null | void>;
|
|
17
|
+
}
|
|
18
|
+
export declare function Match(table: ITable, teams?: Array<ITeam>, matchPoint?: number): IMatch;
|