npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@devarshmavani/card-engine

v0.1.1

Published

A reusable, type-safe card game engine library for TypeScript. Build card games like Rummy, Teen Patti, Poker with fully typed game states and events.

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-engine

Quick 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 cards

Player

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 exports

License

MIT

Author

devarsh-mavani-19 ([email protected])

Contributing

Issues and pull requests are welcome on GitHub.