@hellacardgames/speed 0.14.0 → 0.14.2
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/dist/manager/index.cjs +1 -1
- package/dist/manager/index.d.cts.map +1 -1
- package/dist/manager/index.d.mts.map +1 -1
- package/dist/manager/index.mjs +1 -1
- package/dist/{manager-C8wqbmrE.mjs → manager-BNAk0ZFh.mjs} +273 -189
- package/dist/manager-BNAk0ZFh.mjs.map +1 -0
- package/dist/{manager-DdpdgNfz.cjs → manager-Sw5jTzl2.cjs} +272 -188
- package/dist/manager-Sw5jTzl2.cjs.map +1 -0
- package/dist/server/index.cjs +1 -1
- package/dist/server/index.mjs +1 -1
- package/package.json +2 -2
- package/dist/manager-C8wqbmrE.mjs.map +0 -1
- package/dist/manager-DdpdgNfz.cjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager-Sw5jTzl2.cjs","names":["emitEvent","takeLastItemFromCollection","updatePlayer","addItemToCollection","emitEventToPlayer","getClientStateAndClearEventsFactory","addItemToCollection","emitEvent","requirePlayer","removeItemFromCollection","emitEvent","requirePlayer","requirePlayer","updatePlayer","requirePlayer","emitEvent","updatePlayer","removeItemFromCollection","addItemToCollection","requirePlayer","takeLastItemFromCollection","updatePlayer","addItemToCollection","emitEvent","requirePlayer","updatePlayer","emitEvent","requirePlayer","updatePlayer","emitEvent","emitEvent","updatePlayer","shuffle","requirePlayer","updatePlayer","emitEvent","requirePlayer","updatePlayer","emitEventToPlayer","emitEvent","shuffle","emitEvent","createManagerFactory"],"sources":["../src/game/constants.ts","../src/game/actions/createGame.ts","../src/game/actions/drawCard.ts","../src/game/actions/getClientStateAndClearEvents.ts","../src/game/actions/joinGame.ts","../src/game/lib/removePlayerFromGame.ts","../src/game/lib/transitionGameToForfeited.ts","../src/game/actions/leaveGame.ts","../src/game/lib/isCardPlayable.ts","../src/game/lib/requireOtherPlayer.ts","../src/game/lib/hasPlayableCard.ts","../src/game/lib/clearHasNoPlayableCardsIfNotApplicable.ts","../src/game/lib/isOutOfCards.ts","../src/game/lib/transitionGameToCompleted.ts","../src/game/actions/playCard.ts","../src/game/lib/drawCardFromSidePileToCenterPile.ts","../src/game/lib/initializeCenterPile.ts","../src/game/lib/initializeSidePile.ts","../src/game/actions/reportNoPlayableCards.ts","../src/game/lib/initializeDrawPile.ts","../src/game/lib/initializeHand.ts","../src/game/lib/transitionGameToStarted.ts","../src/game/actions/startGame.ts","../src/manager/createManager.ts"],"sourcesContent":["import type { Card } from \"./types/Card.js\";\n\nexport const EXPIRY_EXTENSION_MS = 300000; // 5 minutes\nexport const MIN_PLAYERS = 2;\nexport const MAX_PLAYERS = 2;\nexport const MAX_HAND_SIZE = 5;\nexport const INITIAL_HAND_SIZE = 5;\nexport const INITIAL_DRAW_PILE_SIZE = 15;\nexport const INITIAL_SIDE_PILE_SIZE = 5;\nexport const CAN_PLAY_AT_DELAY_MS = 3000;\n\nexport const CARDS: readonly Card[] = [\n { id: crypto.randomUUID(), rank: 2, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"spades\" },\n];\n","import { EXPIRY_EXTENSION_MS } from \"../constants.js\";\nimport type { CreatedGame } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function createGame(userId: string, username: string) {\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n\n const createdAt = Date.now();\n\n const game: CreatedGame = {\n status: \"created\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n canPlayAt: 0,\n };\n\n return { game, playerId: player.id } as const;\n}\n","import {\n addItemToCollection,\n emitEvent,\n emitEventToPlayer,\n takeLastItemFromCollection,\n updatePlayer,\n} from \"@hellacardgames/lib\";\nimport { EXPIRY_EXTENSION_MS, MAX_HAND_SIZE } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function drawCard(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" } as const;\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" } as const;\n }\n\n game = { ...game, expiresAt: Date.now() + EXPIRY_EXTENSION_MS };\n game = emitEvent(game, {\n type: \"expirationUpdated\",\n expiresAt: game.expiresAt,\n });\n\n const { collection: newDrawPile, item: card } = takeLastItemFromCollection(\n player.drawPile,\n );\n\n game = updatePlayer(game, player.id, (p) => ({\n ...p,\n drawPile: newDrawPile,\n hand: addItemToCollection(p.hand, card),\n }));\n\n game = emitEventToPlayer(game, player.id, { type: \"drewCard\", card });\n game = emitEvent(game, { type: \"playerDrewCard\", username: player.username });\n\n return { success: true, game } as const;\n}\n","import { getClientStateAndClearEventsFactory } from \"@hellacardgames/lib\";\nimport type { ClientState } from \"../types/ClientState.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport const getClientStateAndClearEvents = getClientStateAndClearEventsFactory<\n Game,\n ClientState\n>((game, player) => ({\n status: game.status,\n gameId: game.id,\n playerId: player.id,\n username: player.username,\n players: game.players.map((p) => ({\n username: p.username,\n handSize: p.hand.length,\n drawPileSize: p.drawPile.length,\n sidePileSize: p.sidePile.length,\n centerPileTopCard: p.centerPile.length\n ? p.centerPile[p.centerPile.length - 1]!\n : null,\n })),\n expiresAt: game.expiresAt,\n chatMessages: game.chatMessages,\n hand: player.hand,\n canPlayAt: game.status === \"started\" ? game.canPlayAt : null,\n}));\n","import { addItemToCollection, emitEvent } from \"@hellacardgames/lib\";\nimport { MAX_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function joinGame(game: Game, userId: string, username: string) {\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" } as const;\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" } as const;\n }\n\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n\n game = { ...game, players: addItemToCollection(game.players, player) };\n game = emitEvent(game, { type: \"playerJoined\", username });\n\n return { success: true, game, playerId: player.id } as const;\n}\n","import { removeItemFromCollection, requirePlayer } from \"@hellacardgames/lib\";\n\ntype Game = {\n readonly players: readonly {\n readonly id: string;\n }[];\n};\n\nexport function removePlayerFromGame<TGame extends Game>(\n game: TGame,\n playerId: string,\n): TGame {\n const { player } = requirePlayer(game, playerId);\n game = { ...game, players: removeItemFromCollection(game.players, player) };\n return game;\n}\n","import type { ForfeitedGame, StartedGame } from \"../types/Game.js\";\n\nexport function transitionGameToForfeited(game: StartedGame): ForfeitedGame {\n return { ...game, status: \"forfeited\" };\n}\n","import { emitEvent } from \"@hellacardgames/lib\";\nimport { EXPIRY_EXTENSION_MS, MIN_PLAYERS } from \"../constants.js\";\nimport { removePlayerFromGame } from \"../lib/removePlayerFromGame.js\";\nimport { transitionGameToForfeited } from \"../lib/transitionGameToForfeited.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function leaveGame(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n\n game = emitEvent(game, { type: \"playerLeft\", username: player.username });\n game = removePlayerFromGame(game, player.id);\n\n if (game.status === \"started\" && game.players.length < MIN_PLAYERS) {\n game = transitionGameToForfeited(game);\n game = { ...game, expiresAt: Date.now() + EXPIRY_EXTENSION_MS };\n game = emitEvent(game, { type: \"gameForfeited\" });\n game = emitEvent(game, {\n type: \"expirationUpdated\",\n expiresAt: game.expiresAt,\n });\n }\n\n return { success: true, game } as const;\n}\n","import type { Card } from \"../types/Card.js\";\n\nexport function isCardPlayable(card: Card, targetPile: readonly Card[]) {\n const targetCard = targetPile[targetPile.length - 1]!;\n const diff = Math.abs(card.rank - targetCard.rank) % 11;\n return diff === 1;\n}\n","import type { Game } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function requireOtherPlayer(game: Game, playerId: string): Player {\n const otherPlayer = game.players.find((p) => p.id !== playerId);\n if (!otherPlayer) {\n throw new Error(\"Other player not found.\");\n }\n\n return otherPlayer;\n}\n","import { requirePlayer } from \"@hellacardgames/lib\";\nimport { isCardPlayable } from \"./isCardPlayable.js\";\nimport { requireOtherPlayer } from \"./requireOtherPlayer.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function hasPlayableCard(game: Game, playerId: string) {\n const { player } = requirePlayer(game, playerId);\n const otherPlayer = requireOtherPlayer(game, player.id);\n const targetPile1 = player.centerPile;\n const targetPile2 = otherPlayer.centerPile;\n for (const card of player.hand) {\n if (\n isCardPlayable(card, targetPile1) ||\n isCardPlayable(card, targetPile2)\n ) {\n return true;\n }\n }\n return false;\n}\n","import { requirePlayer, updatePlayer } from \"@hellacardgames/lib\";\nimport { hasPlayableCard } from \"./hasPlayableCard.js\";\nimport type { StartedGame } from \"../types/Game.js\";\n\nexport function clearHasNoPlayableCardsIfNotApplicable(\n game: StartedGame,\n playerId: string,\n): StartedGame {\n const { player } = requirePlayer(game, playerId);\n\n if (player.hasNoPlayableCards && hasPlayableCard(game, player.id)) {\n game = updatePlayer(game, player.id, (p) => ({\n ...p,\n hasNoPlayableCards: false,\n }));\n }\n\n return game;\n}\n","import { requirePlayer } from \"@hellacardgames/lib\";\nimport type { StartedGame } from \"../types/Game.js\";\n\nexport function isOutOfCards(game: StartedGame, playerId: string): boolean {\n const { player } = requirePlayer(game, playerId);\n return player.hand.length === 0 && player.drawPile.length === 0;\n}\n","import type { CompletedGame, StartedGame } from \"../types/Game.js\";\n\nexport function transitionGameToCompleted(game: StartedGame): CompletedGame {\n return { ...game, status: \"completed\" };\n}\n","import {\n addItemToCollection,\n emitEvent,\n removeItemFromCollection,\n updatePlayer,\n} from \"@hellacardgames/lib\";\nimport { EXPIRY_EXTENSION_MS } from \"../constants.js\";\nimport { clearHasNoPlayableCardsIfNotApplicable } from \"../lib/clearHasNoPlayableCardsIfNotApplicable.js\";\nimport { isCardPlayable } from \"../lib/isCardPlayable.js\";\nimport { isOutOfCards } from \"../lib/isOutOfCards.js\";\nimport { requireOtherPlayer } from \"../lib/requireOtherPlayer.js\";\nimport { transitionGameToCompleted } from \"../lib/transitionGameToCompleted.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function playCard(\n game: Game,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n const card = player.hand.find((c) => c.id === cardId);\n if (!card) {\n return { success: false, error: \"cardNotFound\" } as const;\n }\n const otherPlayer = requireOtherPlayer(game, player.id);\n const targetPlayer = isForOtherPlayerPile ? otherPlayer : player;\n if (!isCardPlayable(card, targetPlayer.centerPile)) {\n return { success: false, error: \"cardNotPlayable\" } as const;\n }\n\n game = { ...game, expiresAt: Date.now() + EXPIRY_EXTENSION_MS };\n game = emitEvent(game, {\n type: \"expirationUpdated\",\n expiresAt: game.expiresAt,\n });\n\n game = updatePlayer(game, player.id, (p) => ({\n ...p,\n hand: removeItemFromCollection(p.hand, card),\n }));\n\n game = updatePlayer(game, targetPlayer.id, (p) => ({\n ...p,\n centerPile: addItemToCollection(p.centerPile, card),\n }));\n\n game = emitEvent(game, {\n type: \"cardPlayed\",\n username: player.username,\n card,\n isForOtherPlayerPile,\n });\n\n game = clearHasNoPlayableCardsIfNotApplicable(game, otherPlayer.id);\n\n if (isOutOfCards(game, player.id)) {\n game = transitionGameToCompleted(game);\n game = emitEvent(game, { type: \"gameCompleted\" });\n }\n\n return { success: true, game } as const;\n}\n","import {\n addItemToCollection,\n emitEvent,\n requirePlayer,\n takeLastItemFromCollection,\n updatePlayer,\n} from \"@hellacardgames/lib\";\nimport type { StartedGame } from \"../types/Game.js\";\n\nexport function drawCardFromSidePileToCenterPile(\n game: StartedGame,\n playerId: string,\n): StartedGame {\n const { player } = requirePlayer(game, playerId);\n\n const { collection: newSidePile, item: card } = takeLastItemFromCollection(\n player.sidePile,\n );\n\n game = updatePlayer(game, player.id, (p) => ({\n ...p,\n sidePile: newSidePile,\n centerPile: addItemToCollection(p.centerPile, card),\n }));\n\n game = emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: player.username,\n card,\n });\n\n return game;\n}\n","import { emitEvent, requirePlayer, updatePlayer } from \"@hellacardgames/lib\";\nimport type { Card } from \"../types/Card.js\";\nimport type { StartedGame } from \"../types/Game.js\";\n\ntype InitializeCenterPileResult = {\n readonly game: StartedGame;\n readonly cards: readonly Card[];\n};\n\nexport function initializeCenterPile(\n game: StartedGame,\n playerId: string,\n cards: readonly Card[],\n): InitializeCenterPileResult {\n const { player } = requirePlayer(game, playerId);\n\n const card = cards[0];\n if (!card) {\n throw new Error(\"Not enough cards.\");\n }\n\n cards = cards.slice(1);\n\n game = updatePlayer(game, player.id, (p) => ({ ...p, centerPile: [card] }));\n game = emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card,\n });\n\n return { game, cards };\n}\n","import { emitEvent, requirePlayer, updatePlayer } from \"@hellacardgames/lib\";\nimport { INITIAL_SIDE_PILE_SIZE } from \"../constants.js\";\nimport type { Card } from \"../types/Card.js\";\nimport type { StartedGame } from \"../types/Game.js\";\n\ntype InitializeSidePileResult = {\n readonly game: StartedGame;\n readonly cards: readonly Card[];\n};\n\nexport function initializeSidePile(\n game: StartedGame,\n playerId: string,\n cards: readonly Card[],\n): InitializeSidePileResult {\n if (cards.length < INITIAL_SIDE_PILE_SIZE) {\n throw new Error(\"Not enough cards.\");\n }\n\n const { player } = requirePlayer(game, playerId);\n\n const sidePile = cards.slice(0, INITIAL_SIDE_PILE_SIZE);\n cards = cards.slice(INITIAL_SIDE_PILE_SIZE);\n\n game = updatePlayer(game, player.id, (p) => ({ ...p, sidePile }));\n game = emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: sidePile.length,\n });\n\n return { game, cards };\n}\n","import { emitEvent, shuffle, updatePlayer } from \"@hellacardgames/lib\";\nimport {\n CAN_PLAY_AT_DELAY_MS,\n EXPIRY_EXTENSION_MS,\n MAX_HAND_SIZE,\n} from \"../constants.js\";\nimport { drawCardFromSidePileToCenterPile } from \"../lib/drawCardFromSidePileToCenterPile.js\";\nimport { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport { initializeCenterPile } from \"../lib/initializeCenterPile.js\";\nimport { initializeSidePile } from \"../lib/initializeSidePile.js\";\nimport { requireOtherPlayer } from \"../lib/requireOtherPlayer.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function reportNoPlayableCards(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" } as const;\n }\n if (hasPlayableCard(game, player.id)) {\n return { success: false, error: \"hasPlayableCard\" } as const;\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" } as const;\n }\n\n game = { ...game, expiresAt: Date.now() + EXPIRY_EXTENSION_MS };\n game = emitEvent(game, {\n type: \"expirationUpdated\",\n expiresAt: game.expiresAt,\n });\n\n game = updatePlayer(game, player.id, (p) => ({\n ...p,\n hasNoPlayableCards: true,\n }));\n\n const otherPlayer = requireOtherPlayer(game, player.id);\n\n if (otherPlayer.hasNoPlayableCards) {\n if (player.sidePile.length === 0 && otherPlayer.sidePile.length === 0) {\n let cards = [...player.centerPile, ...otherPlayer.centerPile] as const;\n cards = shuffle(cards);\n\n ({ game, cards } = initializeSidePile(game, player.id, cards));\n ({ game, cards } = initializeCenterPile(game, player.id, cards));\n ({ game, cards } = initializeCenterPile(game, otherPlayer.id, cards));\n ({ game } = initializeSidePile(game, otherPlayer.id, cards));\n } else {\n game = drawCardFromSidePileToCenterPile(game, player.id);\n game = drawCardFromSidePileToCenterPile(game, otherPlayer.id);\n }\n\n game = updatePlayer(game, player.id, (p) => ({\n ...p,\n hasNoPlayableCards: false,\n }));\n game = updatePlayer(game, otherPlayer.id, (p) => ({\n ...p,\n hasNoPlayableCards: false,\n }));\n\n game = { ...game, canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS };\n game = emitEvent(game, {\n type: \"canPlayAtUpdated\",\n canPlayAt: game.canPlayAt,\n });\n }\n\n return { success: true, game } as const;\n}\n","import { emitEvent, requirePlayer, updatePlayer } from \"@hellacardgames/lib\";\nimport { INITIAL_DRAW_PILE_SIZE } from \"../constants.js\";\nimport type { Card } from \"../types/Card.js\";\nimport type { StartedGame } from \"../types/Game.js\";\n\ntype InitializeDrawPileResult = {\n readonly game: StartedGame;\n readonly cards: readonly Card[];\n};\n\nexport function initializeDrawPile(\n game: StartedGame,\n playerId: string,\n cards: readonly Card[],\n): InitializeDrawPileResult {\n if (cards.length < INITIAL_DRAW_PILE_SIZE) {\n throw new Error(\"Not enough cards.\");\n }\n\n const { player } = requirePlayer(game, playerId);\n\n const drawPile = cards.slice(0, INITIAL_DRAW_PILE_SIZE);\n cards = cards.slice(INITIAL_DRAW_PILE_SIZE);\n\n game = updatePlayer(game, player.id, (p) => ({ ...p, drawPile }));\n game = emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: player.username,\n numCards: drawPile.length,\n });\n\n return { game, cards };\n}\n","import {\n emitEvent,\n emitEventToPlayer,\n requirePlayer,\n updatePlayer,\n} from \"@hellacardgames/lib\";\nimport { INITIAL_HAND_SIZE } from \"../constants.js\";\nimport type { Card } from \"../types/Card.js\";\nimport type { StartedGame } from \"../types/Game.js\";\n\ntype InitializeHandResult = {\n readonly game: StartedGame;\n readonly cards: readonly Card[];\n};\n\nexport function initializeHand(\n game: StartedGame,\n playerId: string,\n cards: readonly Card[],\n): InitializeHandResult {\n if (cards.length < INITIAL_HAND_SIZE) {\n throw new Error(\"Not enough cards.\");\n }\n\n const { player } = requirePlayer(game, playerId);\n\n const hand = cards.slice(0, INITIAL_HAND_SIZE);\n cards = cards.slice(INITIAL_HAND_SIZE);\n\n game = updatePlayer(game, player.id, (p) => ({ ...p, hand }));\n\n game = emitEventToPlayer(game, player.id, {\n type: \"handInitialized\",\n cards: hand,\n });\n game = emitEvent(game, {\n type: \"playerHandInitialized\",\n username: player.username,\n numCards: hand.length,\n });\n\n return { game, cards };\n}\n","import type { CreatedGame, StartedGame } from \"../types/Game.js\";\n\nexport function transitionGameToStarted(game: CreatedGame): StartedGame {\n return { ...game, status: \"started\" };\n}\n","import { emitEvent, shuffle } from \"@hellacardgames/lib\";\nimport {\n CAN_PLAY_AT_DELAY_MS,\n CARDS,\n EXPIRY_EXTENSION_MS,\n MIN_PLAYERS,\n} from \"../constants.js\";\nimport { initializeCenterPile } from \"../lib/initializeCenterPile.js\";\nimport { initializeDrawPile } from \"../lib/initializeDrawPile.js\";\nimport { initializeHand } from \"../lib/initializeHand.js\";\nimport { initializeSidePile } from \"../lib/initializeSidePile.js\";\nimport { requireOtherPlayer } from \"../lib/requireOtherPlayer.js\";\nimport { transitionGameToStarted } from \"../lib/transitionGameToStarted.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function startGame(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" } as const;\n }\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" } as const;\n }\n\n game = transitionGameToStarted(game);\n\n const otherPlayer = requireOtherPlayer(game, player.id);\n\n let cards = [...CARDS] as const;\n cards = shuffle(cards);\n\n ({ game, cards } = initializeSidePile(game, player.id, cards));\n ({ game, cards } = initializeCenterPile(game, player.id, cards));\n\n ({ game, cards } = initializeCenterPile(game, otherPlayer.id, cards));\n ({ game, cards } = initializeSidePile(game, otherPlayer.id, cards));\n\n ({ game, cards } = initializeDrawPile(game, player.id, cards));\n ({ game, cards } = initializeHand(game, player.id, cards));\n\n ({ game, cards } = initializeDrawPile(game, otherPlayer.id, cards));\n ({ game } = initializeHand(game, otherPlayer.id, cards));\n\n game = { ...game, expiresAt: Date.now() + EXPIRY_EXTENSION_MS };\n game = emitEvent(game, {\n type: \"expirationUpdated\",\n expiresAt: game.expiresAt,\n });\n\n game = { ...game, canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS };\n game = emitEvent(game, {\n type: \"canPlayAtUpdated\",\n canPlayAt: game.canPlayAt,\n });\n\n game = emitEvent(game, { type: \"gameStarted\" });\n\n return { success: true, game } as const;\n}\n","import { createManagerFactory } from \"@hellacardgames/lib\";\nimport {\n createGame,\n drawCard,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n MAX_PLAYERS,\n playCard,\n reportNoPlayableCards,\n sendChat,\n startGame,\n} from \"../game/index.js\";\n\nexport type Manager = ReturnType<typeof createManager>;\n\nexport const createManager = createManagerFactory({\n maxPlayers: MAX_PLAYERS,\n createGame,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n sendChat,\n startGame,\n gameplayActions: {\n drawCard,\n playCard,\n reportNoPlayableCards,\n },\n});\n"],"mappings":"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"}
|
package/dist/server/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_manager = require("../manager-
|
|
2
|
+
const require_manager = require("../manager-Sw5jTzl2.cjs");
|
|
3
3
|
let _hellacardgames_lib = require("@hellacardgames/lib");
|
|
4
4
|
let zod = require("zod");
|
|
5
5
|
//#region src/server/createServer.ts
|
package/dist/server/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hellacardgames/speed",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.2",
|
|
4
4
|
"description": "A TypeScript library implementing the Speed card game.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"vitest": "^4.1.9"
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
|
-
"@hellacardgames/lib": "^0.17.
|
|
89
|
+
"@hellacardgames/lib": "^0.17.1",
|
|
90
90
|
"zod": "^4.4.3"
|
|
91
91
|
}
|
|
92
92
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manager-C8wqbmrE.mjs","names":[],"sources":["../src/game/constants.ts","../src/game/actions/createGame.ts","../src/game/lib/emitEvent.ts","../src/game/lib/emitEventToPlayer.ts","../src/game/actions/drawCard.ts","../src/game/actions/getClientStateAndClearEvents.ts","../src/game/actions/joinGame.ts","../src/game/actions/leaveGame.ts","../src/game/lib/isCardPlayable.ts","../src/game/lib/hasPlayableCard.ts","../src/game/actions/playCard.ts","../src/game/lib/shuffleCards.ts","../src/game/actions/reportNoPlayableCards.ts","../src/game/actions/startGame.ts","../src/manager/createManager.ts"],"sourcesContent":["import type { Card } from \"./types/Card.js\";\n\nexport const EXPIRY_EXTENSION_MS = 300000; // 5 minutes\nexport const MIN_PLAYERS = 2;\nexport const MAX_PLAYERS = 2;\nexport const MAX_HAND_SIZE = 5;\nexport const CAN_PLAY_AT_DELAY_MS = 3000;\n\nexport const CARDS: readonly Card[] = [\n { id: crypto.randomUUID(), rank: 2, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"spades\" },\n];\n","import { EXPIRY_EXTENSION_MS } from \"../constants.js\";\nimport type { CreatedGame } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function createGame(userId: string, username: string) {\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n\n const createdAt = Date.now();\n\n const game: CreatedGame = {\n status: \"created\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n };\n\n return { game, playerId: player.id } as const;\n}\n","type Game = {\n readonly players: {\n readonly events: { readonly id: string }[];\n }[];\n};\n\ntype OmitId<T> = T extends unknown ? Omit<T, \"id\"> : never;\n\nexport function emitEvent<T extends Game>(\n game: T,\n data: OmitId<T[\"players\"][number][\"events\"][number]>,\n): void {\n const event = { ...data, id: crypto.randomUUID() };\n for (const p of game.players) {\n p.events.push(event);\n }\n}\n","type Player = {\n readonly events: { readonly id: string }[];\n};\n\ntype OmitId<T> = T extends unknown ? Omit<T, \"id\"> : never;\n\nexport function emitEventToPlayer<T extends Player>(\n player: T,\n data: OmitId<T[\"events\"][number]>,\n): void {\n player.events.push({ ...data, id: crypto.randomUUID() });\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { emitEventToPlayer } from \"../lib/emitEventToPlayer.js\";\nimport { EXPIRY_EXTENSION_MS, MAX_HAND_SIZE } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function drawCard(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" } as const;\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" } as const;\n }\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n const card = player.drawPile.pop()!;\n player.hand.push(card);\n emitEventToPlayer(player, { type: \"drewCard\", card });\n emitEvent(game, { type: \"playerDrewCard\", username: player.username });\n return { success: true, game } as const;\n}\n","import { getClientStateAndClearEventsFactory } from \"@hellacardgames/lib\";\nimport type { ClientState } from \"../types/ClientState.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport const getClientStateAndClearEvents = getClientStateAndClearEventsFactory<\n Game,\n ClientState\n>((game, player) => ({\n status: game.status,\n gameId: game.id,\n playerId: player.id,\n username: player.username,\n players: game.players.map((p) => ({\n username: p.username,\n handSize: p.hand.length,\n drawPileSize: p.drawPile.length,\n sidePileSize: p.sidePile.length,\n centerPileTopCard: p.centerPile.length\n ? p.centerPile[p.centerPile.length - 1]!\n : null,\n })),\n expiresAt: game.expiresAt,\n chatMessages: game.chatMessages,\n hand: player.hand,\n canPlayAt: game.status === \"started\" ? game.canPlayAt : null,\n}));\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { MAX_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function joinGame(game: Game, userId: string, username: string) {\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" } as const;\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" } as const;\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n game.players.push(player);\n emitEvent(game, { type: \"playerJoined\", username });\n return { success: true, game, playerId: player.id } as const;\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { EXPIRY_EXTENSION_MS, MIN_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function leaveGame(game: Game, playerId: string) {\n const playerIndex = game.players.findIndex((p) => p.id === playerId);\n if (playerIndex === -1) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n\n const player = game.players[playerIndex]!;\n emitEvent(game, { type: \"playerLeft\", username: player.username });\n\n game.players.splice(playerIndex, 1);\n\n if (game.status === \"started\" && game.players.length < MIN_PLAYERS) {\n const forfeitedGame: Game = {\n ...game,\n status: \"forfeited\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n };\n // this.games.set(game.id, forfeitedGame);\n emitEvent(forfeitedGame, { type: \"gameForfeited\" });\n emitEvent(forfeitedGame, {\n type: \"expirationUpdated\",\n expiresAt: forfeitedGame.expiresAt,\n });\n return { success: true, game: forfeitedGame } as const;\n }\n return { success: true, game } as const;\n}\n","import type { Card } from \"../types/Card.js\";\n\nexport function isCardPlayable(card: Card, targetPile: Card[]) {\n const targetCard = targetPile[targetPile.length - 1]!;\n const diff = Math.abs(card.rank - targetCard.rank) % 11;\n return diff === 1;\n}\n","import { isCardPlayable } from \"./isCardPlayable.js\";\nimport type { Game } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function hasPlayableCard(player: Player, game: Game) {\n const otherPlayer = game.players.find((p) => p !== player)!;\n const targetPile1 = player.centerPile;\n const targetPile2 = otherPlayer.centerPile;\n for (const card of player.hand) {\n if (\n isCardPlayable(card, targetPile1) ||\n isCardPlayable(card, targetPile2)\n ) {\n return true;\n }\n }\n return false;\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { EXPIRY_EXTENSION_MS } from \"../constants.js\";\nimport { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport { isCardPlayable } from \"../lib/isCardPlayable.js\";\nimport type { CompletedGame, Game } from \"../types/Game.js\";\n\nexport function playCard(\n game: Game,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n const cardIndex = player.hand.findIndex((c) => c.id === cardId);\n if (cardIndex === -1) {\n return { success: false, error: \"cardNotFound\" } as const;\n }\n const otherPlayer = game.players.find((p) => p !== player)!;\n const targetPile = isForOtherPlayerPile\n ? otherPlayer.centerPile\n : player.centerPile;\n const card = player.hand[cardIndex]!;\n if (!isCardPlayable(card, targetPile)) {\n return { success: false, error: \"cardNotPlayable\" } as const;\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hand.splice(cardIndex, 1);\n targetPile.push(card);\n emitEvent(game, {\n type: \"cardPlayed\",\n username: player.username,\n card,\n isForOtherPlayerPile,\n });\n\n if (otherPlayer.hasNoPlayableCards && hasPlayableCard(otherPlayer, game)) {\n otherPlayer.hasNoPlayableCards = false;\n }\n\n if (player.hand.length === 0 && player.drawPile.length === 0) {\n emitEvent(game, { type: \"gameCompleted\" });\n const completedGame: CompletedGame = {\n ...game,\n status: \"completed\",\n };\n return { success: true, game: completedGame } as const;\n }\n\n return { success: true, game } as const;\n}\n","type Card = { readonly id: string };\n\nexport function shuffleCards<T extends Card>(cards: T[]): void {\n for (let i = cards.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [cards[i], cards[j]] = [cards[j]!, cards[i]!];\n }\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { shuffleCards } from \"../lib/shuffleCards.js\";\nimport {\n CAN_PLAY_AT_DELAY_MS,\n EXPIRY_EXTENSION_MS,\n MAX_HAND_SIZE,\n} from \"../constants.js\";\nimport { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function reportNoPlayableCards(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" } as const;\n }\n if (hasPlayableCard(player, game)) {\n return { success: false, error: \"hasPlayableCard\" } as const;\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" } as const;\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hasNoPlayableCards = true;\n\n const otherPlayer = game.players.find((p) => p !== player)!;\n if (otherPlayer.hasNoPlayableCards) {\n if (player.sidePile.length === 0 && otherPlayer.sidePile.length === 0) {\n const cards = [...player.centerPile, ...otherPlayer.centerPile];\n shuffleCards(cards);\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n } else {\n const playerSidePileCard = player.sidePile.pop()!;\n player.centerPile.push(playerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: player.username,\n card: playerSidePileCard,\n });\n const otherPlayerSidePileCard = otherPlayer.sidePile.pop()!;\n otherPlayer.centerPile.push(otherPlayerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: otherPlayer.username,\n card: otherPlayerSidePileCard,\n });\n }\n player.hasNoPlayableCards = false;\n otherPlayer.hasNoPlayableCards = false;\n game.canPlayAt = Date.now() + CAN_PLAY_AT_DELAY_MS;\n emitEvent(game, {\n type: \"canPlayAtUpdated\",\n canPlayAt: game.canPlayAt,\n });\n }\n\n return { success: true, game } as const;\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { emitEventToPlayer } from \"../lib/emitEventToPlayer.js\";\nimport { shuffleCards } from \"../lib/shuffleCards.js\";\nimport {\n CAN_PLAY_AT_DELAY_MS,\n CARDS,\n EXPIRY_EXTENSION_MS,\n MIN_PLAYERS,\n} from \"../constants.js\";\nimport type { Game, StartedGame } from \"../types/Game.js\";\n\nexport function startGame(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" } as const;\n }\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" } as const;\n }\n const otherPlayer = game.players[1]!;\n const cards = [...CARDS];\n shuffleCards(cards);\n\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n\n player.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: player.username,\n numCards: player.drawPile.length,\n });\n\n player.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(player, { type: \"handInitialized\", cards: player.hand });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: player.username,\n numCards: player.hand.length,\n });\n\n otherPlayer.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.drawPile.length,\n });\n\n otherPlayer.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(otherPlayer, {\n type: \"handInitialized\",\n cards: otherPlayer.hand,\n });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.hand.length,\n });\n\n const startedGame: StartedGame = {\n ...game,\n status: \"started\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS,\n };\n // this.games.set(game.id, startedGame);\n emitEvent(startedGame, { type: \"gameStarted\" });\n emitEvent(startedGame, {\n type: \"expirationUpdated\",\n expiresAt: startedGame.expiresAt,\n });\n emitEvent(startedGame, {\n type: \"canPlayAtUpdated\",\n canPlayAt: startedGame.canPlayAt,\n });\n return { success: true, game: startedGame } as const;\n}\n","import { createManagerFactory } from \"@hellacardgames/lib\";\nimport {\n createGame,\n drawCard,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n MAX_PLAYERS,\n playCard,\n reportNoPlayableCards,\n sendChat,\n startGame,\n} from \"../game/index.js\";\n\nexport type Manager = ReturnType<typeof createManager>;\n\nexport const createManager = createManagerFactory({\n maxPlayers: MAX_PLAYERS,\n createGame,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n sendChat,\n startGame,\n gameplayActions: {\n drawCard,\n playCard,\n reportNoPlayableCards,\n },\n});\n"],"mappings":";;AAEA,MAAa,sBAAsB;AAInC,MAAa,uBAAuB;AAEpC,MAAa,QAAyB;CACpC;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;AACvD;;;ACzDA,SAAgB,WAAW,QAAgB,UAAkB;CAC3D,MAAM,SAAiB;EACrB,IAAI,OAAO,WAAW;EACtB;EACA;EACA,QAAQ,CAAC;EACT,MAAM,CAAC;EACP,UAAU,CAAC;EACX,UAAU,CAAC;EACX,YAAY,CAAC;EACb,oBAAoB;CACtB;CAEA,MAAM,YAAY,KAAK,IAAI;CAW3B,OAAO;EAAE,MAAA;GARP,QAAQ;GACR,IAAI,OAAO,WAAW;GACtB;GACA,WAAW,YAAY;GACvB,cAAc,CAAC;GACf,SAAS,CAAC,MAAM;EAGN;EAAG,UAAU,OAAO;CAAG;AACrC;;;ACrBA,SAAgB,UACd,MACA,MACM;CACN,MAAM,QAAQ;EAAE,GAAG;EAAM,IAAI,OAAO,WAAW;CAAE;CACjD,KAAK,MAAM,KAAK,KAAK,SACnB,EAAE,OAAO,KAAK,KAAK;AAEvB;;;ACVA,SAAgB,kBACd,QACA,MACM;CACN,OAAO,OAAO,KAAK;EAAE,GAAG;EAAM,IAAI,OAAO,WAAW;CAAE,CAAC;AACzD;;;ACNA,SAAgB,SAAS,MAAY,UAAkB;CACrD,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;CACzD,IAAI,CAAC,QACH,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,IAAI,IAAI,KAAK,WACpB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAsB;CAExD,IAAI,OAAO,KAAK,UAAA,GACd,OAAO;EAAE,SAAS;EAAO,OAAO;CAAW;CAE7C,IAAI,OAAO,SAAS,WAAW,GAC7B,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,KAAK,YAAY,KAAK,IAAI,IAAI;CAC9B,UAAU,MAAM;EAAE,MAAM;EAAqB,WAAW,KAAK;CAAU,CAAC;CACxE,MAAM,OAAO,OAAO,SAAS,IAAI;CACjC,OAAO,KAAK,KAAK,IAAI;CACrB,kBAAkB,QAAQ;EAAE,MAAM;EAAY;CAAK,CAAC;CACpD,UAAU,MAAM;EAAE,MAAM;EAAkB,UAAU,OAAO;CAAS,CAAC;CACrE,OAAO;EAAE,SAAS;EAAM;CAAK;AAC/B;;;ACzBA,MAAa,+BAA+B,qCAGzC,MAAM,YAAY;CACnB,QAAQ,KAAK;CACb,QAAQ,KAAK;CACb,UAAU,OAAO;CACjB,UAAU,OAAO;CACjB,SAAS,KAAK,QAAQ,KAAK,OAAO;EAChC,UAAU,EAAE;EACZ,UAAU,EAAE,KAAK;EACjB,cAAc,EAAE,SAAS;EACzB,cAAc,EAAE,SAAS;EACzB,mBAAmB,EAAE,WAAW,SAC5B,EAAE,WAAW,EAAE,WAAW,SAAS,KACnC;CACN,EAAE;CACF,WAAW,KAAK;CAChB,cAAc,KAAK;CACnB,MAAM,OAAO;CACb,WAAW,KAAK,WAAW,YAAY,KAAK,YAAY;AAC1D,EAAE;;;ACpBF,SAAgB,SAAS,MAAY,QAAgB,UAAkB;CACrE,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,QAAQ,WAAA,GACf,OAAO;EAAE,SAAS;EAAO,OAAO;CAAoB;CAEtD,IAAI,KAAK,QAAQ,MAAM,MAAM,EAAE,WAAW,MAAM,GAC9C,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,MAAM,SAAiB;EACrB,IAAI,OAAO,WAAW;EACtB;EACA;EACA,QAAQ,CAAC;EACT,MAAM,CAAC;EACP,UAAU,CAAC;EACX,UAAU,CAAC;EACX,YAAY,CAAC;EACb,oBAAoB;CACtB;CACA,KAAK,QAAQ,KAAK,MAAM;CACxB,UAAU,MAAM;EAAE,MAAM;EAAgB;CAAS,CAAC;CAClD,OAAO;EAAE,SAAS;EAAM;EAAM,UAAU,OAAO;CAAG;AACpD;;;ACzBA,SAAgB,UAAU,MAAY,UAAkB;CACtD,MAAM,cAAc,KAAK,QAAQ,WAAW,MAAM,EAAE,OAAO,QAAQ;CACnE,IAAI,gBAAgB,IAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAGnD,MAAM,SAAS,KAAK,QAAQ;CAC5B,UAAU,MAAM;EAAE,MAAM;EAAc,UAAU,OAAO;CAAS,CAAC;CAEjE,KAAK,QAAQ,OAAO,aAAa,CAAC;CAElC,IAAI,KAAK,WAAW,aAAa,KAAK,QAAQ,SAAA,GAAsB;EAClE,MAAM,gBAAsB;GAC1B,GAAG;GACH,QAAQ;GACR,WAAW,KAAK,IAAI,IAAI;EAC1B;EAEA,UAAU,eAAe,EAAE,MAAM,gBAAgB,CAAC;EAClD,UAAU,eAAe;GACvB,MAAM;GACN,WAAW,cAAc;EAC3B,CAAC;EACD,OAAO;GAAE,SAAS;GAAM,MAAM;EAAc;CAC9C;CACA,OAAO;EAAE,SAAS;EAAM;CAAK;AAC/B;;;AC5BA,SAAgB,eAAe,MAAY,YAAoB;CAC7D,MAAM,aAAa,WAAW,WAAW,SAAS;CAElD,OADa,KAAK,IAAI,KAAK,OAAO,WAAW,IAAI,IAAI,OACrC;AAClB;;;ACFA,SAAgB,gBAAgB,QAAgB,MAAY;CAC1D,MAAM,cAAc,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM;CACzD,MAAM,cAAc,OAAO;CAC3B,MAAM,cAAc,YAAY;CAChC,KAAK,MAAM,QAAQ,OAAO,MACxB,IACE,eAAe,MAAM,WAAW,KAChC,eAAe,MAAM,WAAW,GAEhC,OAAO;CAGX,OAAO;AACT;;;ACXA,SAAgB,SACd,MACA,UACA,QACA,sBACA;CACA,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;CACzD,IAAI,CAAC,QACH,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,IAAI,IAAI,KAAK,WACpB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAsB;CAExD,MAAM,YAAY,OAAO,KAAK,WAAW,MAAM,EAAE,OAAO,MAAM;CAC9D,IAAI,cAAc,IAChB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAe;CAEjD,MAAM,cAAc,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM;CACzD,MAAM,aAAa,uBACf,YAAY,aACZ,OAAO;CACX,MAAM,OAAO,OAAO,KAAK;CACzB,IAAI,CAAC,eAAe,MAAM,UAAU,GAClC,OAAO;EAAE,SAAS;EAAO,OAAO;CAAkB;CAGpD,KAAK,YAAY,KAAK,IAAI,IAAI;CAC9B,UAAU,MAAM;EAAE,MAAM;EAAqB,WAAW,KAAK;CAAU,CAAC;CAExE,OAAO,KAAK,OAAO,WAAW,CAAC;CAC/B,WAAW,KAAK,IAAI;CACpB,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB;EACA;CACF,CAAC;CAED,IAAI,YAAY,sBAAsB,gBAAgB,aAAa,IAAI,GACrE,YAAY,qBAAqB;CAGnC,IAAI,OAAO,KAAK,WAAW,KAAK,OAAO,SAAS,WAAW,GAAG;EAC5D,UAAU,MAAM,EAAE,MAAM,gBAAgB,CAAC;EAKzC,OAAO;GAAE,SAAS;GAAM,MAAM;IAH5B,GAAG;IACH,QAAQ;GAEgC;EAAE;CAC9C;CAEA,OAAO;EAAE,SAAS;EAAM;CAAK;AAC/B;;;AC3DA,SAAgB,aAA6B,OAAkB;CAC7D,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,IAAI,GAAG,KAAK;EACzC,MAAM,IAAI,KAAK,MAAM,KAAK,OAAO,KAAK,IAAI,EAAE;EAC5C,CAAC,MAAM,IAAI,MAAM,MAAM,CAAC,MAAM,IAAK,MAAM,EAAG;CAC9C;AACF;;;ACGA,SAAgB,sBAAsB,MAAY,UAAkB;CAClE,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;CACzD,IAAI,CAAC,QACH,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,IAAI,IAAI,KAAK,WACpB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAsB;CAExD,IAAI,OAAO,oBACT,OAAO;EAAE,SAAS;EAAO,OAAO;CAAkB;CAEpD,IAAI,gBAAgB,QAAQ,IAAI,GAC9B,OAAO;EAAE,SAAS;EAAO,OAAO;CAAkB;CAEpD,IAAI,OAAO,SAAS,SAAS,KAAK,OAAO,KAAK,SAAA,GAC5C,OAAO;EAAE,SAAS;EAAO,OAAO;CAAU;CAG5C,KAAK,YAAY,KAAK,IAAI,IAAI;CAC9B,UAAU,MAAM;EAAE,MAAM;EAAqB,WAAW,KAAK;CAAU,CAAC;CAExE,OAAO,qBAAqB;CAE5B,MAAM,cAAc,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM;CACzD,IAAI,YAAY,oBAAoB;EAClC,IAAI,OAAO,SAAS,WAAW,KAAK,YAAY,SAAS,WAAW,GAAG;GACrE,MAAM,QAAQ,CAAC,GAAG,OAAO,YAAY,GAAG,YAAY,UAAU;GAC9D,aAAa,KAAK;GAClB,OAAO,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;GAC1C,UAAU,MAAM;IACd,MAAM;IACN,UAAU,OAAO;IACjB,UAAU,OAAO,SAAS;GAC5B,CAAC;GACD,OAAO,WAAW,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;GAC5C,UAAU,MAAM;IACd,MAAM;IACN,UAAU,OAAO;IACjB,MAAM,OAAO,WAAW,OAAO,WAAW,SAAS;GACrD,CAAC;GACD,YAAY,WAAW,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;GACjD,UAAU,MAAM;IACd,MAAM;IACN,UAAU,YAAY;IACtB,MAAM,YAAY,WAAW,YAAY,WAAW,SAAS;GAC/D,CAAC;GACD,YAAY,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;GAC/C,UAAU,MAAM;IACd,MAAM;IACN,UAAU,YAAY;IACtB,UAAU,YAAY,SAAS;GACjC,CAAC;EACH,OAAO;GACL,MAAM,qBAAqB,OAAO,SAAS,IAAI;GAC/C,OAAO,WAAW,KAAK,kBAAkB;GACzC,UAAU,MAAM;IACd,MAAM;IACN,UAAU,OAAO;IACjB,MAAM;GACR,CAAC;GACD,MAAM,0BAA0B,YAAY,SAAS,IAAI;GACzD,YAAY,WAAW,KAAK,uBAAuB;GACnD,UAAU,MAAM;IACd,MAAM;IACN,UAAU,YAAY;IACtB,MAAM;GACR,CAAC;EACH;EACA,OAAO,qBAAqB;EAC5B,YAAY,qBAAqB;EACjC,KAAK,YAAY,KAAK,IAAI,IAAI;EAC9B,UAAU,MAAM;GACd,MAAM;GACN,WAAW,KAAK;EAClB,CAAC;CACH;CAEA,OAAO;EAAE,SAAS;EAAM;CAAK;AAC/B;;;AChFA,SAAgB,UAAU,MAAY,UAAkB;CACtD,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;CACzD,IAAI,CAAC,QACH,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,QAAQ,QAAQ,MAAM,MAAM,GACnC,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,QAAQ,SAAA,GACf,OAAO;EAAE,SAAS;EAAO,OAAO;CAAuB;CAEzD,MAAM,cAAc,KAAK,QAAQ;CACjC,MAAM,QAAQ,CAAC,GAAG,KAAK;CACvB,aAAa,KAAK;CAElB,OAAO,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CAC1C,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB,UAAU,OAAO,SAAS;CAC5B,CAAC;CAED,OAAO,WAAW,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CAC5C,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB,MAAM,OAAO,WAAW,OAAO,WAAW,SAAS;CACrD,CAAC;CAED,YAAY,WAAW,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CACjD,UAAU,MAAM;EACd,MAAM;EACN,UAAU,YAAY;EACtB,MAAM,YAAY,WAAW,YAAY,WAAW,SAAS;CAC/D,CAAC;CAED,YAAY,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CAC/C,UAAU,MAAM;EACd,MAAM;EACN,UAAU,YAAY;EACtB,UAAU,YAAY,SAAS;CACjC,CAAC;CAED,OAAO,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,EAAE,CAAC;CAC3C,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB,UAAU,OAAO,SAAS;CAC5B,CAAC;CAED,OAAO,KAAK,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CACtC,kBAAkB,QAAQ;EAAE,MAAM;EAAmB,OAAO,OAAO;CAAK,CAAC;CACzE,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB,UAAU,OAAO,KAAK;CACxB,CAAC;CAED,YAAY,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,EAAE,CAAC;CAChD,UAAU,MAAM;EACd,MAAM;EACN,UAAU,YAAY;EACtB,UAAU,YAAY,SAAS;CACjC,CAAC;CAED,YAAY,KAAK,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CAC3C,kBAAkB,aAAa;EAC7B,MAAM;EACN,OAAO,YAAY;CACrB,CAAC;CACD,UAAU,MAAM;EACd,MAAM;EACN,UAAU,YAAY;EACtB,UAAU,YAAY,KAAK;CAC7B,CAAC;CAED,MAAM,cAA2B;EAC/B,GAAG;EACH,QAAQ;EACR,WAAW,KAAK,IAAI,IAAI;EACxB,WAAW,KAAK,IAAI,IAAI;CAC1B;CAEA,UAAU,aAAa,EAAE,MAAM,cAAc,CAAC;CAC9C,UAAU,aAAa;EACrB,MAAM;EACN,WAAW,YAAY;CACzB,CAAC;CACD,UAAU,aAAa;EACrB,MAAM;EACN,WAAW,YAAY;CACzB,CAAC;CACD,OAAO;EAAE,SAAS;EAAM,MAAM;CAAY;AAC5C;;;AC1FA,MAAa,gBAAgB,qBAAqB;CAChD,YAAA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,iBAAiB;EACf;EACA;EACA;CACF;AACF,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manager-DdpdgNfz.cjs","names":["getClientStateAndClearEventsFactory","createManagerFactory"],"sources":["../src/game/constants.ts","../src/game/actions/createGame.ts","../src/game/lib/emitEvent.ts","../src/game/lib/emitEventToPlayer.ts","../src/game/actions/drawCard.ts","../src/game/actions/getClientStateAndClearEvents.ts","../src/game/actions/joinGame.ts","../src/game/actions/leaveGame.ts","../src/game/lib/isCardPlayable.ts","../src/game/lib/hasPlayableCard.ts","../src/game/actions/playCard.ts","../src/game/lib/shuffleCards.ts","../src/game/actions/reportNoPlayableCards.ts","../src/game/actions/startGame.ts","../src/manager/createManager.ts"],"sourcesContent":["import type { Card } from \"./types/Card.js\";\n\nexport const EXPIRY_EXTENSION_MS = 300000; // 5 minutes\nexport const MIN_PLAYERS = 2;\nexport const MAX_PLAYERS = 2;\nexport const MAX_HAND_SIZE = 5;\nexport const CAN_PLAY_AT_DELAY_MS = 3000;\n\nexport const CARDS: readonly Card[] = [\n { id: crypto.randomUUID(), rank: 2, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"spades\" },\n];\n","import { EXPIRY_EXTENSION_MS } from \"../constants.js\";\nimport type { CreatedGame } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function createGame(userId: string, username: string) {\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n\n const createdAt = Date.now();\n\n const game: CreatedGame = {\n status: \"created\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n };\n\n return { game, playerId: player.id } as const;\n}\n","type Game = {\n readonly players: {\n readonly events: { readonly id: string }[];\n }[];\n};\n\ntype OmitId<T> = T extends unknown ? Omit<T, \"id\"> : never;\n\nexport function emitEvent<T extends Game>(\n game: T,\n data: OmitId<T[\"players\"][number][\"events\"][number]>,\n): void {\n const event = { ...data, id: crypto.randomUUID() };\n for (const p of game.players) {\n p.events.push(event);\n }\n}\n","type Player = {\n readonly events: { readonly id: string }[];\n};\n\ntype OmitId<T> = T extends unknown ? Omit<T, \"id\"> : never;\n\nexport function emitEventToPlayer<T extends Player>(\n player: T,\n data: OmitId<T[\"events\"][number]>,\n): void {\n player.events.push({ ...data, id: crypto.randomUUID() });\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { emitEventToPlayer } from \"../lib/emitEventToPlayer.js\";\nimport { EXPIRY_EXTENSION_MS, MAX_HAND_SIZE } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function drawCard(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" } as const;\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" } as const;\n }\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n const card = player.drawPile.pop()!;\n player.hand.push(card);\n emitEventToPlayer(player, { type: \"drewCard\", card });\n emitEvent(game, { type: \"playerDrewCard\", username: player.username });\n return { success: true, game } as const;\n}\n","import { getClientStateAndClearEventsFactory } from \"@hellacardgames/lib\";\nimport type { ClientState } from \"../types/ClientState.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport const getClientStateAndClearEvents = getClientStateAndClearEventsFactory<\n Game,\n ClientState\n>((game, player) => ({\n status: game.status,\n gameId: game.id,\n playerId: player.id,\n username: player.username,\n players: game.players.map((p) => ({\n username: p.username,\n handSize: p.hand.length,\n drawPileSize: p.drawPile.length,\n sidePileSize: p.sidePile.length,\n centerPileTopCard: p.centerPile.length\n ? p.centerPile[p.centerPile.length - 1]!\n : null,\n })),\n expiresAt: game.expiresAt,\n chatMessages: game.chatMessages,\n hand: player.hand,\n canPlayAt: game.status === \"started\" ? game.canPlayAt : null,\n}));\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { MAX_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function joinGame(game: Game, userId: string, username: string) {\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" } as const;\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" } as const;\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n game.players.push(player);\n emitEvent(game, { type: \"playerJoined\", username });\n return { success: true, game, playerId: player.id } as const;\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { EXPIRY_EXTENSION_MS, MIN_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function leaveGame(game: Game, playerId: string) {\n const playerIndex = game.players.findIndex((p) => p.id === playerId);\n if (playerIndex === -1) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n\n const player = game.players[playerIndex]!;\n emitEvent(game, { type: \"playerLeft\", username: player.username });\n\n game.players.splice(playerIndex, 1);\n\n if (game.status === \"started\" && game.players.length < MIN_PLAYERS) {\n const forfeitedGame: Game = {\n ...game,\n status: \"forfeited\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n };\n // this.games.set(game.id, forfeitedGame);\n emitEvent(forfeitedGame, { type: \"gameForfeited\" });\n emitEvent(forfeitedGame, {\n type: \"expirationUpdated\",\n expiresAt: forfeitedGame.expiresAt,\n });\n return { success: true, game: forfeitedGame } as const;\n }\n return { success: true, game } as const;\n}\n","import type { Card } from \"../types/Card.js\";\n\nexport function isCardPlayable(card: Card, targetPile: Card[]) {\n const targetCard = targetPile[targetPile.length - 1]!;\n const diff = Math.abs(card.rank - targetCard.rank) % 11;\n return diff === 1;\n}\n","import { isCardPlayable } from \"./isCardPlayable.js\";\nimport type { Game } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function hasPlayableCard(player: Player, game: Game) {\n const otherPlayer = game.players.find((p) => p !== player)!;\n const targetPile1 = player.centerPile;\n const targetPile2 = otherPlayer.centerPile;\n for (const card of player.hand) {\n if (\n isCardPlayable(card, targetPile1) ||\n isCardPlayable(card, targetPile2)\n ) {\n return true;\n }\n }\n return false;\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { EXPIRY_EXTENSION_MS } from \"../constants.js\";\nimport { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport { isCardPlayable } from \"../lib/isCardPlayable.js\";\nimport type { CompletedGame, Game } from \"../types/Game.js\";\n\nexport function playCard(\n game: Game,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n const cardIndex = player.hand.findIndex((c) => c.id === cardId);\n if (cardIndex === -1) {\n return { success: false, error: \"cardNotFound\" } as const;\n }\n const otherPlayer = game.players.find((p) => p !== player)!;\n const targetPile = isForOtherPlayerPile\n ? otherPlayer.centerPile\n : player.centerPile;\n const card = player.hand[cardIndex]!;\n if (!isCardPlayable(card, targetPile)) {\n return { success: false, error: \"cardNotPlayable\" } as const;\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hand.splice(cardIndex, 1);\n targetPile.push(card);\n emitEvent(game, {\n type: \"cardPlayed\",\n username: player.username,\n card,\n isForOtherPlayerPile,\n });\n\n if (otherPlayer.hasNoPlayableCards && hasPlayableCard(otherPlayer, game)) {\n otherPlayer.hasNoPlayableCards = false;\n }\n\n if (player.hand.length === 0 && player.drawPile.length === 0) {\n emitEvent(game, { type: \"gameCompleted\" });\n const completedGame: CompletedGame = {\n ...game,\n status: \"completed\",\n };\n return { success: true, game: completedGame } as const;\n }\n\n return { success: true, game } as const;\n}\n","type Card = { readonly id: string };\n\nexport function shuffleCards<T extends Card>(cards: T[]): void {\n for (let i = cards.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [cards[i], cards[j]] = [cards[j]!, cards[i]!];\n }\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { shuffleCards } from \"../lib/shuffleCards.js\";\nimport {\n CAN_PLAY_AT_DELAY_MS,\n EXPIRY_EXTENSION_MS,\n MAX_HAND_SIZE,\n} from \"../constants.js\";\nimport { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function reportNoPlayableCards(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" } as const;\n }\n if (hasPlayableCard(player, game)) {\n return { success: false, error: \"hasPlayableCard\" } as const;\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" } as const;\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hasNoPlayableCards = true;\n\n const otherPlayer = game.players.find((p) => p !== player)!;\n if (otherPlayer.hasNoPlayableCards) {\n if (player.sidePile.length === 0 && otherPlayer.sidePile.length === 0) {\n const cards = [...player.centerPile, ...otherPlayer.centerPile];\n shuffleCards(cards);\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n } else {\n const playerSidePileCard = player.sidePile.pop()!;\n player.centerPile.push(playerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: player.username,\n card: playerSidePileCard,\n });\n const otherPlayerSidePileCard = otherPlayer.sidePile.pop()!;\n otherPlayer.centerPile.push(otherPlayerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: otherPlayer.username,\n card: otherPlayerSidePileCard,\n });\n }\n player.hasNoPlayableCards = false;\n otherPlayer.hasNoPlayableCards = false;\n game.canPlayAt = Date.now() + CAN_PLAY_AT_DELAY_MS;\n emitEvent(game, {\n type: \"canPlayAtUpdated\",\n canPlayAt: game.canPlayAt,\n });\n }\n\n return { success: true, game } as const;\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { emitEventToPlayer } from \"../lib/emitEventToPlayer.js\";\nimport { shuffleCards } from \"../lib/shuffleCards.js\";\nimport {\n CAN_PLAY_AT_DELAY_MS,\n CARDS,\n EXPIRY_EXTENSION_MS,\n MIN_PLAYERS,\n} from \"../constants.js\";\nimport type { Game, StartedGame } from \"../types/Game.js\";\n\nexport function startGame(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" } as const;\n }\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" } as const;\n }\n const otherPlayer = game.players[1]!;\n const cards = [...CARDS];\n shuffleCards(cards);\n\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n\n player.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: player.username,\n numCards: player.drawPile.length,\n });\n\n player.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(player, { type: \"handInitialized\", cards: player.hand });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: player.username,\n numCards: player.hand.length,\n });\n\n otherPlayer.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.drawPile.length,\n });\n\n otherPlayer.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(otherPlayer, {\n type: \"handInitialized\",\n cards: otherPlayer.hand,\n });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.hand.length,\n });\n\n const startedGame: StartedGame = {\n ...game,\n status: \"started\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS,\n };\n // this.games.set(game.id, startedGame);\n emitEvent(startedGame, { type: \"gameStarted\" });\n emitEvent(startedGame, {\n type: \"expirationUpdated\",\n expiresAt: startedGame.expiresAt,\n });\n emitEvent(startedGame, {\n type: \"canPlayAtUpdated\",\n canPlayAt: startedGame.canPlayAt,\n });\n return { success: true, game: startedGame } as const;\n}\n","import { createManagerFactory } from \"@hellacardgames/lib\";\nimport {\n createGame,\n drawCard,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n MAX_PLAYERS,\n playCard,\n reportNoPlayableCards,\n sendChat,\n startGame,\n} from \"../game/index.js\";\n\nexport type Manager = ReturnType<typeof createManager>;\n\nexport const createManager = createManagerFactory({\n maxPlayers: MAX_PLAYERS,\n createGame,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n sendChat,\n startGame,\n gameplayActions: {\n drawCard,\n playCard,\n reportNoPlayableCards,\n },\n});\n"],"mappings":";;AAEA,MAAa,sBAAsB;AAInC,MAAa,uBAAuB;AAEpC,MAAa,QAAyB;CACpC;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;AACvD;;;ACzDA,SAAgB,WAAW,QAAgB,UAAkB;CAC3D,MAAM,SAAiB;EACrB,IAAI,OAAO,WAAW;EACtB;EACA;EACA,QAAQ,CAAC;EACT,MAAM,CAAC;EACP,UAAU,CAAC;EACX,UAAU,CAAC;EACX,YAAY,CAAC;EACb,oBAAoB;CACtB;CAEA,MAAM,YAAY,KAAK,IAAI;CAW3B,OAAO;EAAE,MAAA;GARP,QAAQ;GACR,IAAI,OAAO,WAAW;GACtB;GACA,WAAW,YAAY;GACvB,cAAc,CAAC;GACf,SAAS,CAAC,MAAM;EAGN;EAAG,UAAU,OAAO;CAAG;AACrC;;;ACrBA,SAAgB,UACd,MACA,MACM;CACN,MAAM,QAAQ;EAAE,GAAG;EAAM,IAAI,OAAO,WAAW;CAAE;CACjD,KAAK,MAAM,KAAK,KAAK,SACnB,EAAE,OAAO,KAAK,KAAK;AAEvB;;;ACVA,SAAgB,kBACd,QACA,MACM;CACN,OAAO,OAAO,KAAK;EAAE,GAAG;EAAM,IAAI,OAAO,WAAW;CAAE,CAAC;AACzD;;;ACNA,SAAgB,SAAS,MAAY,UAAkB;CACrD,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;CACzD,IAAI,CAAC,QACH,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,IAAI,IAAI,KAAK,WACpB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAsB;CAExD,IAAI,OAAO,KAAK,UAAA,GACd,OAAO;EAAE,SAAS;EAAO,OAAO;CAAW;CAE7C,IAAI,OAAO,SAAS,WAAW,GAC7B,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,KAAK,YAAY,KAAK,IAAI,IAAI;CAC9B,UAAU,MAAM;EAAE,MAAM;EAAqB,WAAW,KAAK;CAAU,CAAC;CACxE,MAAM,OAAO,OAAO,SAAS,IAAI;CACjC,OAAO,KAAK,KAAK,IAAI;CACrB,kBAAkB,QAAQ;EAAE,MAAM;EAAY;CAAK,CAAC;CACpD,UAAU,MAAM;EAAE,MAAM;EAAkB,UAAU,OAAO;CAAS,CAAC;CACrE,OAAO;EAAE,SAAS;EAAM;CAAK;AAC/B;;;ACzBA,MAAa,gCAAA,GAA+BA,oBAAAA,oCAAAA,EAGzC,MAAM,YAAY;CACnB,QAAQ,KAAK;CACb,QAAQ,KAAK;CACb,UAAU,OAAO;CACjB,UAAU,OAAO;CACjB,SAAS,KAAK,QAAQ,KAAK,OAAO;EAChC,UAAU,EAAE;EACZ,UAAU,EAAE,KAAK;EACjB,cAAc,EAAE,SAAS;EACzB,cAAc,EAAE,SAAS;EACzB,mBAAmB,EAAE,WAAW,SAC5B,EAAE,WAAW,EAAE,WAAW,SAAS,KACnC;CACN,EAAE;CACF,WAAW,KAAK;CAChB,cAAc,KAAK;CACnB,MAAM,OAAO;CACb,WAAW,KAAK,WAAW,YAAY,KAAK,YAAY;AAC1D,EAAE;;;ACpBF,SAAgB,SAAS,MAAY,QAAgB,UAAkB;CACrE,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,QAAQ,WAAA,GACf,OAAO;EAAE,SAAS;EAAO,OAAO;CAAoB;CAEtD,IAAI,KAAK,QAAQ,MAAM,MAAM,EAAE,WAAW,MAAM,GAC9C,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,MAAM,SAAiB;EACrB,IAAI,OAAO,WAAW;EACtB;EACA;EACA,QAAQ,CAAC;EACT,MAAM,CAAC;EACP,UAAU,CAAC;EACX,UAAU,CAAC;EACX,YAAY,CAAC;EACb,oBAAoB;CACtB;CACA,KAAK,QAAQ,KAAK,MAAM;CACxB,UAAU,MAAM;EAAE,MAAM;EAAgB;CAAS,CAAC;CAClD,OAAO;EAAE,SAAS;EAAM;EAAM,UAAU,OAAO;CAAG;AACpD;;;ACzBA,SAAgB,UAAU,MAAY,UAAkB;CACtD,MAAM,cAAc,KAAK,QAAQ,WAAW,MAAM,EAAE,OAAO,QAAQ;CACnE,IAAI,gBAAgB,IAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAGnD,MAAM,SAAS,KAAK,QAAQ;CAC5B,UAAU,MAAM;EAAE,MAAM;EAAc,UAAU,OAAO;CAAS,CAAC;CAEjE,KAAK,QAAQ,OAAO,aAAa,CAAC;CAElC,IAAI,KAAK,WAAW,aAAa,KAAK,QAAQ,SAAA,GAAsB;EAClE,MAAM,gBAAsB;GAC1B,GAAG;GACH,QAAQ;GACR,WAAW,KAAK,IAAI,IAAI;EAC1B;EAEA,UAAU,eAAe,EAAE,MAAM,gBAAgB,CAAC;EAClD,UAAU,eAAe;GACvB,MAAM;GACN,WAAW,cAAc;EAC3B,CAAC;EACD,OAAO;GAAE,SAAS;GAAM,MAAM;EAAc;CAC9C;CACA,OAAO;EAAE,SAAS;EAAM;CAAK;AAC/B;;;AC5BA,SAAgB,eAAe,MAAY,YAAoB;CAC7D,MAAM,aAAa,WAAW,WAAW,SAAS;CAElD,OADa,KAAK,IAAI,KAAK,OAAO,WAAW,IAAI,IAAI,OACrC;AAClB;;;ACFA,SAAgB,gBAAgB,QAAgB,MAAY;CAC1D,MAAM,cAAc,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM;CACzD,MAAM,cAAc,OAAO;CAC3B,MAAM,cAAc,YAAY;CAChC,KAAK,MAAM,QAAQ,OAAO,MACxB,IACE,eAAe,MAAM,WAAW,KAChC,eAAe,MAAM,WAAW,GAEhC,OAAO;CAGX,OAAO;AACT;;;ACXA,SAAgB,SACd,MACA,UACA,QACA,sBACA;CACA,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;CACzD,IAAI,CAAC,QACH,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,IAAI,IAAI,KAAK,WACpB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAsB;CAExD,MAAM,YAAY,OAAO,KAAK,WAAW,MAAM,EAAE,OAAO,MAAM;CAC9D,IAAI,cAAc,IAChB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAe;CAEjD,MAAM,cAAc,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM;CACzD,MAAM,aAAa,uBACf,YAAY,aACZ,OAAO;CACX,MAAM,OAAO,OAAO,KAAK;CACzB,IAAI,CAAC,eAAe,MAAM,UAAU,GAClC,OAAO;EAAE,SAAS;EAAO,OAAO;CAAkB;CAGpD,KAAK,YAAY,KAAK,IAAI,IAAI;CAC9B,UAAU,MAAM;EAAE,MAAM;EAAqB,WAAW,KAAK;CAAU,CAAC;CAExE,OAAO,KAAK,OAAO,WAAW,CAAC;CAC/B,WAAW,KAAK,IAAI;CACpB,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB;EACA;CACF,CAAC;CAED,IAAI,YAAY,sBAAsB,gBAAgB,aAAa,IAAI,GACrE,YAAY,qBAAqB;CAGnC,IAAI,OAAO,KAAK,WAAW,KAAK,OAAO,SAAS,WAAW,GAAG;EAC5D,UAAU,MAAM,EAAE,MAAM,gBAAgB,CAAC;EAKzC,OAAO;GAAE,SAAS;GAAM,MAAM;IAH5B,GAAG;IACH,QAAQ;GAEgC;EAAE;CAC9C;CAEA,OAAO;EAAE,SAAS;EAAM;CAAK;AAC/B;;;AC3DA,SAAgB,aAA6B,OAAkB;CAC7D,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,IAAI,GAAG,KAAK;EACzC,MAAM,IAAI,KAAK,MAAM,KAAK,OAAO,KAAK,IAAI,EAAE;EAC5C,CAAC,MAAM,IAAI,MAAM,MAAM,CAAC,MAAM,IAAK,MAAM,EAAG;CAC9C;AACF;;;ACGA,SAAgB,sBAAsB,MAAY,UAAkB;CAClE,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;CACzD,IAAI,CAAC,QACH,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,IAAI,IAAI,KAAK,WACpB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAsB;CAExD,IAAI,OAAO,oBACT,OAAO;EAAE,SAAS;EAAO,OAAO;CAAkB;CAEpD,IAAI,gBAAgB,QAAQ,IAAI,GAC9B,OAAO;EAAE,SAAS;EAAO,OAAO;CAAkB;CAEpD,IAAI,OAAO,SAAS,SAAS,KAAK,OAAO,KAAK,SAAA,GAC5C,OAAO;EAAE,SAAS;EAAO,OAAO;CAAU;CAG5C,KAAK,YAAY,KAAK,IAAI,IAAI;CAC9B,UAAU,MAAM;EAAE,MAAM;EAAqB,WAAW,KAAK;CAAU,CAAC;CAExE,OAAO,qBAAqB;CAE5B,MAAM,cAAc,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM;CACzD,IAAI,YAAY,oBAAoB;EAClC,IAAI,OAAO,SAAS,WAAW,KAAK,YAAY,SAAS,WAAW,GAAG;GACrE,MAAM,QAAQ,CAAC,GAAG,OAAO,YAAY,GAAG,YAAY,UAAU;GAC9D,aAAa,KAAK;GAClB,OAAO,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;GAC1C,UAAU,MAAM;IACd,MAAM;IACN,UAAU,OAAO;IACjB,UAAU,OAAO,SAAS;GAC5B,CAAC;GACD,OAAO,WAAW,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;GAC5C,UAAU,MAAM;IACd,MAAM;IACN,UAAU,OAAO;IACjB,MAAM,OAAO,WAAW,OAAO,WAAW,SAAS;GACrD,CAAC;GACD,YAAY,WAAW,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;GACjD,UAAU,MAAM;IACd,MAAM;IACN,UAAU,YAAY;IACtB,MAAM,YAAY,WAAW,YAAY,WAAW,SAAS;GAC/D,CAAC;GACD,YAAY,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;GAC/C,UAAU,MAAM;IACd,MAAM;IACN,UAAU,YAAY;IACtB,UAAU,YAAY,SAAS;GACjC,CAAC;EACH,OAAO;GACL,MAAM,qBAAqB,OAAO,SAAS,IAAI;GAC/C,OAAO,WAAW,KAAK,kBAAkB;GACzC,UAAU,MAAM;IACd,MAAM;IACN,UAAU,OAAO;IACjB,MAAM;GACR,CAAC;GACD,MAAM,0BAA0B,YAAY,SAAS,IAAI;GACzD,YAAY,WAAW,KAAK,uBAAuB;GACnD,UAAU,MAAM;IACd,MAAM;IACN,UAAU,YAAY;IACtB,MAAM;GACR,CAAC;EACH;EACA,OAAO,qBAAqB;EAC5B,YAAY,qBAAqB;EACjC,KAAK,YAAY,KAAK,IAAI,IAAI;EAC9B,UAAU,MAAM;GACd,MAAM;GACN,WAAW,KAAK;EAClB,CAAC;CACH;CAEA,OAAO;EAAE,SAAS;EAAM;CAAK;AAC/B;;;AChFA,SAAgB,UAAU,MAAY,UAAkB;CACtD,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;CACzD,IAAI,CAAC,QACH,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,QAAQ,QAAQ,MAAM,MAAM,GACnC,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,QAAQ,SAAA,GACf,OAAO;EAAE,SAAS;EAAO,OAAO;CAAuB;CAEzD,MAAM,cAAc,KAAK,QAAQ;CACjC,MAAM,QAAQ,CAAC,GAAG,KAAK;CACvB,aAAa,KAAK;CAElB,OAAO,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CAC1C,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB,UAAU,OAAO,SAAS;CAC5B,CAAC;CAED,OAAO,WAAW,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CAC5C,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB,MAAM,OAAO,WAAW,OAAO,WAAW,SAAS;CACrD,CAAC;CAED,YAAY,WAAW,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CACjD,UAAU,MAAM;EACd,MAAM;EACN,UAAU,YAAY;EACtB,MAAM,YAAY,WAAW,YAAY,WAAW,SAAS;CAC/D,CAAC;CAED,YAAY,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CAC/C,UAAU,MAAM;EACd,MAAM;EACN,UAAU,YAAY;EACtB,UAAU,YAAY,SAAS;CACjC,CAAC;CAED,OAAO,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,EAAE,CAAC;CAC3C,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB,UAAU,OAAO,SAAS;CAC5B,CAAC;CAED,OAAO,KAAK,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CACtC,kBAAkB,QAAQ;EAAE,MAAM;EAAmB,OAAO,OAAO;CAAK,CAAC;CACzE,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB,UAAU,OAAO,KAAK;CACxB,CAAC;CAED,YAAY,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,EAAE,CAAC;CAChD,UAAU,MAAM;EACd,MAAM;EACN,UAAU,YAAY;EACtB,UAAU,YAAY,SAAS;CACjC,CAAC;CAED,YAAY,KAAK,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CAC3C,kBAAkB,aAAa;EAC7B,MAAM;EACN,OAAO,YAAY;CACrB,CAAC;CACD,UAAU,MAAM;EACd,MAAM;EACN,UAAU,YAAY;EACtB,UAAU,YAAY,KAAK;CAC7B,CAAC;CAED,MAAM,cAA2B;EAC/B,GAAG;EACH,QAAQ;EACR,WAAW,KAAK,IAAI,IAAI;EACxB,WAAW,KAAK,IAAI,IAAI;CAC1B;CAEA,UAAU,aAAa,EAAE,MAAM,cAAc,CAAC;CAC9C,UAAU,aAAa;EACrB,MAAM;EACN,WAAW,YAAY;CACzB,CAAC;CACD,UAAU,aAAa;EACrB,MAAM;EACN,WAAW,YAAY;CACzB,CAAC;CACD,OAAO;EAAE,SAAS;EAAM,MAAM;CAAY;AAC5C;;;AC1FA,MAAa,iBAAA,GAAgBC,oBAAAA,qBAAAA,CAAqB;CAChD,YAAA;CACA;CACA;CACA,+BAAA,oBAAA;CACA;CACA;CACA,UAAA,oBAAA;CACA;CACA,iBAAiB;EACf;EACA;EACA;CACF;AACF,CAAC"}
|