trucoshi 0.0.2 → 0.0.5

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.
Files changed (61) hide show
  1. package/.prettierrc.json +4 -0
  2. package/LICENSE +674 -0
  3. package/README.md +37 -0
  4. package/build/lib/classes/Deck.d.ts +2 -0
  5. package/build/lib/classes/Deck.js +27 -0
  6. package/build/lib/classes/Hand.d.ts +2 -0
  7. package/build/lib/classes/Hand.js +233 -0
  8. package/build/lib/classes/Match.d.ts +2 -0
  9. package/build/lib/classes/Match.js +115 -0
  10. package/build/lib/classes/Play.d.ts +2 -0
  11. package/build/lib/classes/Play.js +39 -0
  12. package/build/lib/classes/Player.d.ts +2 -0
  13. package/build/lib/classes/Player.js +38 -0
  14. package/build/lib/classes/Round.d.ts +2 -0
  15. package/build/lib/classes/Round.js +33 -0
  16. package/build/lib/classes/Table.d.ts +2 -0
  17. package/build/lib/classes/Table.js +30 -0
  18. package/build/lib/classes/Team.d.ts +2 -0
  19. package/build/lib/classes/Team.js +42 -0
  20. package/build/lib/classes/Truco.d.ts +2 -0
  21. package/build/lib/classes/Truco.js +110 -0
  22. package/build/lib/constants.d.ts +36 -28
  23. package/build/lib/constants.js +97 -12
  24. package/build/lib/index.d.ts +18 -0
  25. package/build/lib/index.js +161 -0
  26. package/build/lib/types.d.ts +121 -30
  27. package/build/lib/types.js +24 -12
  28. package/build/lib/utils.d.ts +3 -3
  29. package/build/lib/utils.js +11 -18
  30. package/build/server/index.js +13 -5
  31. package/build/server/match.d.ts +0 -0
  32. package/build/server/match.js +1 -0
  33. package/build/server/types.d.ts +11 -0
  34. package/build/server/types.js +15 -0
  35. package/build/test/autoplay.js +52 -31
  36. package/build/test/play.js +146 -81
  37. package/package.json +5 -4
  38. package/src/lib/classes/Deck.ts +25 -0
  39. package/src/lib/classes/Hand.ts +207 -0
  40. package/src/lib/classes/Match.ts +79 -0
  41. package/src/lib/classes/Play.ts +40 -0
  42. package/src/lib/classes/Player.ts +37 -0
  43. package/src/lib/classes/Round.ts +30 -0
  44. package/src/lib/classes/Table.ts +32 -0
  45. package/src/lib/classes/Team.ts +41 -0
  46. package/src/lib/classes/Truco.ts +72 -0
  47. package/src/lib/constants.ts +105 -11
  48. package/src/lib/index.ts +135 -0
  49. package/src/lib/types.ts +186 -80
  50. package/src/lib/utils.ts +50 -53
  51. package/src/server/index.ts +34 -22
  52. package/src/server/match.ts +0 -0
  53. package/src/server/types.ts +12 -0
  54. package/src/test/autoplay.ts +57 -41
  55. package/src/test/play.ts +122 -70
  56. package/build/lib/trucoshi.d.ts +0 -10
  57. package/build/lib/trucoshi.js +0 -363
  58. package/build/test/legacy.d.ts +0 -1
  59. package/build/test/legacy.js +0 -146
  60. package/src/lib/trucoshi.ts +0 -342
  61. package/src/test/legacy.ts +0 -68
@@ -0,0 +1,32 @@
1
+ import { GAME_ERROR, TEAM_SIZE_VALUES } from "../constants"
2
+ import { IPlayer, ITable, ITeam } from "../types"
3
+ import { Match } from "./Match"
4
+ import { Player } from "./Player"
5
+ import { Team } from "./Team"
6
+
7
+ export function Table(players: Array<IPlayer>, teams: Array<ITeam>): ITable {
8
+ const table: ITable = {
9
+ players,
10
+ cards: [],
11
+ forehandIdx: 0,
12
+ nextTurn() {
13
+ if (table.forehandIdx < table.players.length - 1) {
14
+ table.forehandIdx++
15
+ } else {
16
+ table.forehandIdx = 0
17
+ }
18
+ return table.player()
19
+ },
20
+ getPlayerPosition(id) {
21
+ return table.players.findIndex((p) => p.id === id)
22
+ },
23
+ player(idx) {
24
+ if (idx !== undefined) {
25
+ return table.players[idx]
26
+ }
27
+ return table.players[table.forehandIdx]
28
+ },
29
+ }
30
+
31
+ return table
32
+ }
@@ -0,0 +1,41 @@
1
+ import { IPlayer, ITeam } from "../types"
2
+
3
+ export function Team(players: Array<IPlayer>) {
4
+ const team: ITeam = {
5
+ _players: new Map<string, IPlayer>(),
6
+ get players() {
7
+ return Array.from(team._players.values())
8
+ },
9
+ points: {
10
+ buenas: 0,
11
+ malas: 0,
12
+ winner: false,
13
+ },
14
+ isTeamDisabled() {
15
+ return team.players.reduce((prev, curr) => prev && curr.disabled, true)
16
+ },
17
+ disable(player) {
18
+ team._players.get(player.id)?.disable()
19
+ return team.isTeamDisabled()
20
+ },
21
+ addPoints(matchPoint, points) {
22
+ const malas = team.points.malas + points
23
+ const diff = malas - matchPoint
24
+ if (diff > 0) {
25
+ team.points.malas = matchPoint
26
+ team.points.buenas += diff
27
+ if (team.points.buenas >= matchPoint) {
28
+ team.points.winner = true
29
+ }
30
+ } else {
31
+ team.points.malas = malas
32
+ }
33
+
34
+ return team.points
35
+ },
36
+ }
37
+
38
+ players.forEach((player) => team._players.set(player.id, player))
39
+
40
+ return team
41
+ }
@@ -0,0 +1,72 @@
1
+ import { ITruco } from "../types"
2
+
3
+ export function Truco() {
4
+ function* trucoAnswerGeneratorSequence() {
5
+ let i = 0
6
+ while (i < truco.players.length && truco.answer === null) {
7
+ const player = truco.players[truco.turn]
8
+ truco.setCurrentPlayer(player)
9
+ if (player.disabled) {
10
+ truco.setCurrentPlayer(null)
11
+ }
12
+
13
+ if (truco.turn >= truco.players.length - 1) {
14
+ truco.setTurn(0)
15
+ } else {
16
+ truco.setTurn(truco.turn + 1)
17
+ }
18
+
19
+ i++
20
+
21
+ yield truco
22
+ }
23
+ yield truco
24
+ }
25
+
26
+ const truco: ITruco = {
27
+ turn: 0,
28
+ state: 1,
29
+ teamIdx: null,
30
+ answer: null,
31
+ currentPlayer: null,
32
+ generator: trucoAnswerGeneratorSequence(),
33
+ players: [],
34
+ sayTruco(teamIdx, players) {
35
+ truco.teamIdx = teamIdx
36
+ truco.answer = null
37
+ truco.players = players
38
+ truco.generator = trucoAnswerGeneratorSequence()
39
+ return truco
40
+ },
41
+ setPlayers(players) {
42
+ truco.players = players
43
+ },
44
+ setAnswer(answer) {
45
+ if (answer) {
46
+ truco.state++
47
+ }
48
+ if (answer !== null) {
49
+ truco.teamIdx = null
50
+ }
51
+ truco.answer = answer
52
+ return truco
53
+ },
54
+ setTeam(idx: 0 | 1) {
55
+ truco.teamIdx = idx
56
+ return truco.teamIdx
57
+ },
58
+ setTurn(turn) {
59
+ truco.turn = turn
60
+ return truco.turn
61
+ },
62
+ setCurrentPlayer(player) {
63
+ truco.currentPlayer = player
64
+ return truco.currentPlayer
65
+ },
66
+ getNextPlayer() {
67
+ return truco.generator.next()
68
+ },
69
+ }
70
+
71
+ return truco
72
+ }
@@ -1,14 +1,108 @@
1
+ import {
2
+ EEnvidoCommand,
3
+ ESayCommand,
4
+ IEnvidoCalculator,
5
+ IEnvidoCalculatorArgs,
6
+ ITeam,
7
+ TeamPoints,
8
+ } from "./types"
9
+ import { getMaxNumberIndex } from "./utils"
10
+
1
11
  export const CARDS = {
2
- '1e': 14, '1b': 13, '7e': 12, '7o': 11,
3
- '3e': 10, '3o': 10, '3b': 10, '3c': 10,
4
- '2e': 9, '2o': 9, '2b': 8, '2c': 8,
5
- '1o': 7, '1c': 7, 're': 6, 'ro': 6,
6
- 'rb': 6, 'rc': 6, 'ce': 5, 'co': 5,
7
- 'cb': 5, 'cc': 5, 'pe': 4, 'po': 4,
8
- 'pb': 4, 'pc': 4, '7b': 3, '7c': 3,
9
- '6e': 2, '6o': 2, '6b': 2, '6c': 2,
10
- '5e': 1, '5o': 1, '5b': 1, '5c': 1,
11
- '4e': 0, '4o': 0, '4b': 0, '4c': 0
12
+ "1e": 14,
13
+ "1b": 13,
14
+ "7e": 12,
15
+ "7o": 11,
16
+ "3e": 10,
17
+ "3o": 10,
18
+ "3b": 10,
19
+ "3c": 10,
20
+ "2e": 9,
21
+ "2o": 9,
22
+ "2b": 8,
23
+ "2c": 8,
24
+ "1o": 7,
25
+ "1c": 7,
26
+ re: 6,
27
+ ro: 6,
28
+ rb: 6,
29
+ rc: 6,
30
+ ce: 5,
31
+ co: 5,
32
+ cb: 5,
33
+ cc: 5,
34
+ pe: 4,
35
+ po: 4,
36
+ pb: 4,
37
+ pc: 4,
38
+ "7b": 3,
39
+ "7c": 3,
40
+ "6e": 2,
41
+ "6o": 2,
42
+ "6b": 2,
43
+ "6c": 2,
44
+ "5e": 1,
45
+ "5o": 1,
46
+ "5b": 1,
47
+ "5c": 1,
48
+ "4e": 0,
49
+ "4o": 0,
50
+ "4b": 0,
51
+ "4c": 0,
52
+ }
53
+
54
+ export const COLORS = [
55
+ "#9b111",
56
+ "#17c6c6",
57
+ "#8c1d1d",
58
+ "#9f9b9b",
59
+ "#a5a5a5",
60
+ "#f5a623",
61
+ "#f44336",
62
+ "#c2185b",
63
+ ]
64
+
65
+ export const TEAM_SIZE_VALUES = [1, 2, 3]
66
+
67
+ export enum GAME_ERROR {
68
+ UNEXPECTED_TEAM_SIZE = 'UNEXPECTED_TEAM_SIZE',
69
+ TEAM_NOT_READY = 'TEAM_NOT_READY',
70
+ TEAM_IS_FULL = 'TEAM_IS_FULL',
12
71
  }
13
72
 
14
- export const COLORS = ["#9b111", "#17c6c6", "#8c1d1d", "#9f9b9b", "#a5a5a5", "#f5a623", "#f44336", "#c2185b"];
73
+ export const EnvidoCalculator: IEnvidoCalculator = {
74
+ [EEnvidoCommand.ENVIDO]: () => ({
75
+ accept: 2,
76
+ decline: 1,
77
+ next: [EEnvidoCommand.ENVIDO_ENVIDO, EEnvidoCommand.REAL_ENVIDO, EEnvidoCommand.FALTA_ENVIDO],
78
+ }),
79
+ [EEnvidoCommand.ENVIDO_ENVIDO]: () => ({
80
+ accept: 4,
81
+ decline: 2,
82
+ next: [EEnvidoCommand.REAL_ENVIDO, EEnvidoCommand.FALTA_ENVIDO],
83
+ }),
84
+ [EEnvidoCommand.REAL_ENVIDO]: () => ({
85
+ accept: 3,
86
+ decline: 1,
87
+ next: [EEnvidoCommand.FALTA_ENVIDO],
88
+ }),
89
+ [EEnvidoCommand.FALTA_ENVIDO]: (args) => {
90
+ if (!args || !args.teams || !args.matchPoint) {
91
+ return {
92
+ accept: 1,
93
+ decline: 1,
94
+ next: [],
95
+ }
96
+ }
97
+ const { teams, matchPoint } = args
98
+ const totals = teams.map((team) => team.points.malas + team.points.buenas)
99
+ const higher = getMaxNumberIndex(totals)
100
+ const points = teams[higher].points
101
+ const accept = points.buenas > 0 ? matchPoint - points.buenas : matchPoint - points.malas
102
+ return {
103
+ accept,
104
+ decline: 2,
105
+ next: [],
106
+ }
107
+ },
108
+ }
@@ -0,0 +1,135 @@
1
+ import { Match } from "./classes/Match"
2
+ import { Player } from "./classes/Player"
3
+ import { Table } from "./classes/Table"
4
+ import { Team } from "./classes/Team"
5
+ import { GAME_ERROR, TEAM_SIZE_VALUES } from "./constants"
6
+ import { EHandState, IMatch, IPlayInstance, IPrivateTrucoshi, ITeam, ITrucoshi } from "./types"
7
+
8
+ export type IWinnerCallback = (winner: ITeam, teams: [ITeam, ITeam]) => Promise<void>
9
+ export type ITurnCallback = (play: IPlayInstance) => Promise<void>
10
+ export type ITrucoCallback = (play: IPlayInstance) => Promise<void>
11
+
12
+ export interface IGameLoop {
13
+ _onTruco: ITrucoCallback
14
+ _onTurn: ITurnCallback
15
+ _onWinner: IWinnerCallback
16
+ onTurn: (callback: ITurnCallback) => IGameLoop
17
+ onWinner: (callback: IWinnerCallback) => IGameLoop
18
+ onTruco: (callback: ITrucoCallback) => IGameLoop
19
+ begin: () => void
20
+ }
21
+
22
+ const GameLoop = (match: IMatch) => {
23
+ let gameloop: IGameLoop = {
24
+ _onTruco: () => Promise.resolve(),
25
+ _onTurn: () => Promise.resolve(),
26
+ _onWinner: () => Promise.resolve(),
27
+ onTruco: (callback: ITrucoCallback) => {
28
+ gameloop._onTruco = callback
29
+ return gameloop
30
+ },
31
+ onTurn: (callback: ITurnCallback) => {
32
+ gameloop._onTurn = callback
33
+ return gameloop
34
+ },
35
+ onWinner: (callback: IWinnerCallback) => {
36
+ gameloop._onWinner = callback
37
+ return gameloop
38
+ },
39
+ async begin() {
40
+ while (!match.winner) {
41
+ const play = match.play()
42
+
43
+ if (!play || !play.player) {
44
+ continue
45
+ }
46
+
47
+ if (play.state === EHandState.WAITING_FOR_TRUCO_ANSWER) {
48
+ await gameloop._onTruco(play)
49
+ continue
50
+ }
51
+
52
+ if (play.state === EHandState.WAITING_PLAY) {
53
+ await gameloop._onTurn(play)
54
+ continue
55
+ }
56
+ }
57
+
58
+ await gameloop._onWinner(match.winner, match.teams)
59
+ },
60
+ }
61
+
62
+ return gameloop
63
+ }
64
+
65
+ export function Trucoshi(teamSize?: 1 | 2 | 3) {
66
+ const trucoshi: IPrivateTrucoshi = {
67
+ lastTeamIdx: 1,
68
+ _players: new Map(),
69
+ get players() {
70
+ return Array.from(trucoshi._players.values())
71
+ },
72
+ teams: [],
73
+ table: null,
74
+ maxPlayers: teamSize ? teamSize * 2 : 6,
75
+ full: false,
76
+ ready: false,
77
+ calculateReady() {
78
+ trucoshi.ready = trucoshi.players.reduce((prev, curr) => prev && curr.ready, true)
79
+ return trucoshi.ready
80
+ },
81
+ calculateFull() {
82
+ trucoshi.full = trucoshi._players.size >= trucoshi.maxPlayers
83
+ return trucoshi.full
84
+ },
85
+ addPlayer(id, teamIdx) {
86
+ const maxSize = teamSize ? teamSize : 3
87
+ if (trucoshi.full || trucoshi.players.filter((p) => p.teamIdx === teamIdx).length > maxSize) {
88
+ throw new Error(GAME_ERROR.TEAM_IS_FULL)
89
+ }
90
+ const player = Player(id, teamIdx !== undefined ? teamIdx : Number(!trucoshi.lastTeamIdx))
91
+ trucoshi.lastTeamIdx = Number(!trucoshi.lastTeamIdx) as 0 | 1
92
+ trucoshi._players.set(id, player)
93
+ trucoshi.calculateFull()
94
+ trucoshi.calculateReady()
95
+ return player
96
+ },
97
+ removePlayer(id) {
98
+ trucoshi._players.delete(id)
99
+ trucoshi.calculateFull()
100
+ trucoshi.calculateReady()
101
+ return trucoshi
102
+ },
103
+ startMatch(matchPoint = 9) {
104
+ trucoshi.calculateReady()
105
+ const teamSize = trucoshi._players.size / 2
106
+
107
+ if (!TEAM_SIZE_VALUES.includes(teamSize)) {
108
+ throw new Error(GAME_ERROR.UNEXPECTED_TEAM_SIZE)
109
+ }
110
+
111
+ if (!trucoshi.ready) {
112
+ throw new Error(GAME_ERROR.TEAM_NOT_READY)
113
+ }
114
+
115
+ trucoshi.teams.push(Team(trucoshi.players.filter((p) => p.teamIdx === 0)))
116
+ trucoshi.teams.push(Team(trucoshi.players.filter((p) => p.teamIdx === 1)))
117
+
118
+ if (
119
+ trucoshi.teams[0].players.length !== teamSize ||
120
+ trucoshi.teams[1].players.length !== teamSize
121
+ ) {
122
+ throw new Error(GAME_ERROR.UNEXPECTED_TEAM_SIZE)
123
+ }
124
+
125
+ trucoshi.table = Table(trucoshi.players, trucoshi.teams)
126
+ return GameLoop(Match(trucoshi.table, trucoshi.teams, matchPoint))
127
+ },
128
+ }
129
+
130
+ return {
131
+ addPlayer: trucoshi.addPlayer,
132
+ removePlayer: trucoshi.removePlayer,
133
+ startMatch: trucoshi.startMatch,
134
+ }
135
+ }
package/src/lib/types.ts CHANGED
@@ -1,110 +1,216 @@
1
+ import { IGameLoop } from "."
1
2
  import { CARDS } from "./constants"
2
3
 
3
4
  export type ICard = keyof typeof CARDS
4
5
 
5
6
  export interface IDeck {
6
- cards: Array<ICard>
7
- usedCards: Array<ICard>
8
- takeCard(): ICard
9
- shuffle(): IDeck
7
+ cards: Array<ICard>
8
+ usedCards: Array<ICard>
9
+ takeCard(): ICard
10
+ shuffle(): IDeck
10
11
  }
11
12
 
12
13
  export interface IPlayedCard {
13
- player: IPlayer
14
- card: ICard
14
+ player: IPlayer
15
+ card: ICard
15
16
  }
16
17
 
17
18
  export interface IPlayer {
18
- teamIdx: number
19
- id: string
20
- hand: Array<ICard>,
21
- usedHand: Array<ICard>
22
- setHand(hand: Array<ICard>): Array<ICard>
23
- useCard(idx: number): ICard | null
19
+ teamIdx: number
20
+ id: string
21
+ hand: Array<ICard>
22
+ commands: Array<ECommand>
23
+ usedHand: Array<ICard>
24
+ disabled: boolean
25
+ ready: boolean
26
+ enable(): void
27
+ disable(): void
28
+ setReady(ready: boolean): void
29
+ setHand(hand: Array<ICard>): Array<ICard>
30
+ useCard(idx: number): ICard | null
24
31
  }
25
32
 
26
33
  export interface ITeam {
27
- color: string
28
- _players: Map<string, IPlayer>
29
- players: Array<IPlayer>
30
- points: number
31
- addPoints(points: number): number
34
+ _players: Map<string, IPlayer>
35
+ players: Array<IPlayer>
36
+ points: TeamPoints
37
+ isTeamDisabled(): boolean
38
+ disable(player: IPlayer): boolean
39
+ addPoints(matchPoint: number, points: number): TeamPoints
32
40
  }
33
41
 
34
42
  export interface IMatch {
35
- teams: [ITeam, ITeam]
36
- hands: Array<IHand>
37
- winner: ITeam | null
38
- currentHand: IHand | null
39
- table: ITable
40
- play(): IPlayInstance | undefined
41
- addPoints(points: IPoints): void
42
- pushHand(hand: IHand): void
43
- setCurrentHand(hand: IHand | null): IHand | null
44
- setWinner(winner: ITeam): void
45
- getNextTurn(): IteratorResult<IMatch | null, IMatch | null | void>
46
- }
47
-
48
- export type IPoints = {
49
- 0: number // team 0
50
- 1: number // team 1
51
- 2?: number // number of tied rounds
52
- }
53
-
54
- export type IGetNextPlayerResult = { currentPlayer?: IPlayer, currentRound?: IRound, points?: IPoints }
55
-
56
- export enum EHandPlayCommand {
57
- TRUCO,
58
- ENVIDO,
59
- ENVIDO_ENVIDO,
60
- REAL_ENVIDO,
61
- FALTA_ENVIDO,
62
- MAZO,
63
- FLOR,
64
- CONTRAFLOR,
43
+ teams: [ITeam, ITeam]
44
+ hands: Array<IHand>
45
+ winner: ITeam | null
46
+ currentHand: IHand | null
47
+ table: ITable
48
+ play(): IPlayInstance | null
49
+ addPoints(points: HandPoints): [ITeam, ITeam]
50
+ pushHand(hand: IHand): void
51
+ setCurrentHand(hand: IHand | null): IHand | null
52
+ setWinner(winner: ITeam): void
53
+ getNextTurn(): IteratorResult<IMatch | null, IMatch | null | void>
54
+ }
55
+
56
+ export interface TeamPoints {
57
+ buenas: number
58
+ malas: number
59
+ winner: boolean
60
+ }
61
+
62
+ export interface HandPoints {
63
+ 0: number
64
+ 1: number
65
+ }
66
+
67
+ export interface RoundPoints {
68
+ 0: number
69
+ 1: number
70
+ ties: number
71
+ }
72
+
73
+ export enum ESayCommand {
74
+ QUIERO = "QUIERO",
75
+ NO_QUIERO = "NO_QUIERO",
76
+ TRUCO = "TRUCO",
77
+ MAZO = "MAZO",
78
+ FLOR = "FLOR",
79
+ CONTRAFLOR = "CONTRAFLOR",
80
+ }
81
+
82
+ export enum EEnvidoCommand {
83
+ ENVIDO = "ENVIDO",
84
+ ENVIDO_ENVIDO = "ENVIDO_ENVIDO",
85
+ REAL_ENVIDO = "REAL_ENVIDO",
86
+ FALTA_ENVIDO = "FALTA_ENVIDO",
87
+ }
88
+
89
+ export type ECommand = ESayCommand | EEnvidoCommand
90
+
91
+ export interface ITruco {
92
+ state: 1 | 2 | 3 | 4
93
+ teamIdx: 0 | 1 | null
94
+ answer: boolean | null
95
+ turn: number
96
+ players: Array<IPlayer>
97
+ currentPlayer: IPlayer | null
98
+ generator: Generator<ITruco, void, unknown>
99
+ sayTruco(teamIdx: 0 | 1, players: Array<IPlayer>): ITruco
100
+ setPlayers(players: Array<IPlayer>): void
101
+ setAnswer(answer: boolean | null): ITruco
102
+ setTurn(turn: number): number
103
+ setTeam(idx: 0 | 1): 0 | 1
104
+ setCurrentPlayer(player: IPlayer | null): IPlayer | null
105
+ getNextPlayer(): IteratorResult<ITruco, ITruco | void>
106
+ }
107
+
108
+ export interface EnvidoState {
109
+ accept: number
110
+ decline: number
111
+ teamIdx: 0 | 1 | null
65
112
  }
66
113
 
67
114
  export interface IPlayInstance {
68
- handIdx: number
69
- roundIdx: number
70
- player: IPlayer | null
71
- commands: Array<EHandPlayCommand> | null
72
- rounds: Array<IRound> | null
73
- use(idx: number): ICard | null
74
- say(command: EHandPlayCommand): IHand | null
115
+ teams: [ITeam, ITeam]
116
+ handIdx: number
117
+ roundIdx: number
118
+ state: EHandState
119
+ truco: ITruco
120
+ envido: EnvidoState
121
+ player: IPlayer | null
122
+ commands: Array<ECommand> | null
123
+ rounds: Array<IRound> | null
124
+ use(idx: number): ICard | null
125
+ say(command: ECommand): ECommand | null
126
+ }
127
+
128
+ export enum EHandState {
129
+ WAITING_PLAY = "WAITING_PLAY",
130
+ WAITING_FOR_TRUCO_ANSWER = "WAITING_FOR_TRUCO_ANSWER",
131
+ WAITING_ENVIDO_ANSWER = "WAITING_ENVIDO_ANSWER",
132
+ FINISHED = "FINISHED",
133
+ }
134
+
135
+ export type IHandCommands = {
136
+ [key in ECommand]: (player: IPlayer) => void
75
137
  }
76
138
 
77
139
  export interface IHand {
78
- idx: number
79
- turn: number
80
- finished: boolean
81
- points: IPoints
82
- rounds: Array<IRound>
83
- currentPlayer: IPlayer | null
84
- currentRound: IRound | null
85
- play(): IPlayInstance
86
- pushRound(round: IRound): IRound
87
- setTurn(turn: number): IPlayer
88
- addPoints(team: 0 | 1, points: number): void
89
- setCurrentRound(round: IRound | null): IRound | null
90
- setCurrentPlayer(player: IPlayer | null): IPlayer | null
91
- setFinished(finshed: boolean): boolean
92
- getNextPlayer(): IteratorResult<IHand, IHand | void>
140
+ idx: number
141
+ state: EHandState
142
+ turn: number
143
+ points: HandPoints
144
+ truco: ITruco
145
+ envido: EnvidoState
146
+ rounds: Array<IRound>
147
+ _currentPlayer: IPlayer | null
148
+ get currentPlayer(): IPlayer | null
149
+ set currentPlayer(player: IPlayer | null)
150
+ currentRound: IRound | null
151
+ commands: IHandCommands
152
+ finished: () => boolean
153
+ play(): IPlayInstance | null
154
+ nextTurn(): void
155
+ use(idx: number): ICard | null
156
+ pushRound(round: IRound): IRound
157
+ setTurn(turn: number): IPlayer
158
+ addPoints(team: 0 | 1, points: number): void
159
+ disablePlayer(player: IPlayer): void
160
+ setCurrentRound(round: IRound | null): IRound | null
161
+ setCurrentPlayer(player: IPlayer | null): IPlayer | null
162
+ setState(state: EHandState): EHandState
163
+ getNextPlayer(): IteratorResult<IHand, IHand | void>
164
+ }
165
+
166
+ export interface IPrivateTrucoshi {
167
+ lastTeamIdx: 0 | 1
168
+ _players: Map<string, IPlayer>
169
+ get players(): Array<IPlayer>
170
+ teams: Array<ITeam>
171
+ maxPlayers: number
172
+ table: ITable | null
173
+ ready: boolean
174
+ full: boolean
175
+ addPlayer(id: string, teamIdx?: 0 | 1): IPlayer
176
+ removePlayer(id: string): ITrucoshi
177
+ calculateReady(): boolean
178
+ calculateFull(): boolean
179
+ startMatch(matchPoint?: 9 | 12 | 15): IGameLoop
93
180
  }
94
181
 
182
+ export interface ITrucoshi extends Pick<IPrivateTrucoshi, 'addPlayer' | 'removePlayer' | 'startMatch'> {}
183
+
95
184
  export interface ITable {
96
- forehandIdx: number,
97
- cards: Array<Array<IPlayedCard>>,
98
- players: Array<IPlayer>,
99
- nextTurn(): IPlayer,
100
- player(idx?: number): IPlayer,
101
- getPlayerPosition(id: string): number
185
+ forehandIdx: number
186
+ cards: Array<Array<IPlayedCard>>
187
+ players: Array<IPlayer>
188
+ nextTurn(): IPlayer
189
+ player(idx?: number): IPlayer
190
+ getPlayerPosition(id: string): number
102
191
  }
103
192
 
104
193
  export interface IRound {
105
- tie: boolean,
106
- winner: IPlayer | null
107
- highest: number
108
- cards: Array<IPlayedCard>
109
- play(playedCard: IPlayedCard): ICard
194
+ tie: boolean
195
+ winner: IPlayer | null
196
+ highest: number
197
+ cards: Array<IPlayedCard>
198
+ turn: number,
199
+ nextTurn(): void
200
+ use(playedCard: IPlayedCard): ICard
201
+ }
202
+
203
+ export type IEnvidoCalculatorResult = {
204
+ accept: number
205
+ decline: number
206
+ next: Array<ECommand>
207
+ }
208
+
209
+ export type IEnvidoCalculatorArgs = {
210
+ teams: [ITeam, ITeam]
211
+ matchPoint: number
212
+ }
213
+
214
+ export type IEnvidoCalculator = {
215
+ [key in EEnvidoCommand]: (args?: IEnvidoCalculatorArgs) => IEnvidoCalculatorResult
110
216
  }