Package Exports
- @devarshmavani/card-engine
- @devarshmavani/card-engine/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@devarshmavani/card-engine) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Card Engine
A reusable, type-safe card game engine library for TypeScript. Build card games like Rummy, Teen Patti, Do Teen Panch, Poker, and more with fully typed game states and events.
Features
- 🎯 Fully Type-Safe - Generic game states and events with complete TypeScript support
- 🎮 Game Agnostic - Build any card game by extending the RuleEngine
- 📦 Tree-Shakeable - Import only what you need
- 🔄 Serializable - Full game state serialization for multiplayer/persistence
- 🎪 Event-Driven - Type-safe event system for UI synchronization
- 🌐 Universal - Works in Node.js and browser environments
- 📝 Pure Logic - No DOM/UI dependencies
Installation
npm install @devarsh-mavani-19/card-engineQuick Start
import { Game, Player, RuleEngine, GameState } from '@devarsh-mavani-19/card-engine';
// Define your game state
interface MyGameState extends GameState {
currentRound: number;
tricks: number;
}
// Create your game rules
class MyGameRules extends RuleEngine<MyGameState> {
getInitialCardCount(): number {
return 5;
}
canPlayCard(player: Player, card: Card, state: MyGameState): boolean {
// Your game logic
return true;
}
// ... implement other required methods
}
// Create and start a game
const game = new Game<MyGameState>(new MyGameRules());
game.addPlayer(new Player('p1', 'Alice'));
game.addPlayer(new Player('p2', 'Bob'));
// Listen to type-safe events
game.on('gameStarted', (data) => {
console.log(`Game started with ${data.players.length} players`);
console.log(`Round: ${data.state.currentRound}`);
});
game.start();Core Classes
Card
Represents a single card with rank, suit, and optional metadata.
import { Card } from '@devarsh-mavani-19/card-engine';
const card = new Card('A', 'hearts');
console.log(card.toString()); // "A of hearts"Deck
Manages a deck of cards with shuffle, draw, and reset operations.
import { Deck } from '@devarsh-mavani-19/card-engine';
const deck = Deck.createStandardDeck(); // 52 cards
deck.shuffle();
const cards = deck.draw(5); // Draw 5 cardsPlayer
Represents a player with a hand of cards.
import { Player } from '@devarsh-mavani-19/card-engine';
const player = new Player('p1', 'Alice');
player.receiveCard(card);
const playedCard = player.playCard(card);RuleEngine
Abstract class for implementing game-specific rules.
import { RuleEngine, GameState } from '@devarsh-mavani-19/card-engine';
interface MyState extends GameState {
// Your game state
}
class MyRules extends RuleEngine<MyState> {
canPlayCard(player, card, state) { /* ... */ }
isWinningHand(player, state) { /* ... */ }
onCardPlayed(player, card, state) { /* ... */ }
validateMove(move, state) { /* ... */ }
getInitialCardCount() { /* ... */ }
getWinners(state) { /* ... */ }
isGameOver(state) { /* ... */ }
}Game
Main game controller with turn management and state handling.
import { Game } from '@devarsh-mavani-19/card-engine';
const game = new Game<MyState>(new MyRules());
game.addPlayer(player);
game.start();
game.playCard(card);
game.nextTurn();Type-Safe Events
All events are fully typed based on your game state:
game.on('gameStarted', (data) => {
// data: { players: Player[]; state: MyState }
});
game.on('cardPlayed', (data) => {
// data: { player: Player; card: Card }
});
game.on('turnStarted', (player) => {
// player: Player
});
game.on('gameEnded', (data) => {
// data: { winners: string[]; state: MyState }
});Serialization
Save and restore complete game state:
// Serialize
const serialized = game.serialize();
const json = JSON.stringify(serialized);
// Deserialize
const restored = Game.deserialize(JSON.parse(json), new MyRules());Example: Do Teen Panch
import { Game, Player, RuleEngine, GameState, Card } from '@devarsh-mavani-19/card-engine';
interface DoTeenPanchState extends GameState {
roundNumber: number;
currentSuit?: string;
tricks: { playerId: string; card: Card }[];
playerScores: Map<string, number>;
}
class DoTeenPanchRules extends RuleEngine<DoTeenPanchState> {
getInitialCardCount() {
return 5;
}
canPlayCard(player: Player, card: Card, state: DoTeenPanchState): boolean {
if (!state.currentSuit) return true;
const hasSuit = player.getHand().some(c => c.suit === state.currentSuit);
return !hasSuit || card.suit === state.currentSuit;
}
// ... implement other methods
}
const game = new Game<DoTeenPanchState>(new DoTeenPanchRules());
game.addPlayer(new Player('p1', 'Alice'));
game.addPlayer(new Player('p2', 'Bob'));
game.start();Architecture
card-engine/
├── core/
│ ├── Game.ts # Main game controller
│ ├── RuleEngine.ts # Abstract rule engine
│ └── EventEmitter.ts # Type-safe event system
├── models/
│ ├── Card.ts # Card representation
│ ├── Deck.ts # Deck management
│ └── Player.ts # Player management
└── index.ts # Public exportsLicense
MIT
Author
devarsh-mavani-19 (devarshmavani19@gmail.com)
Contributing
Issues and pull requests are welcome on GitHub.