A full-stack web-based cricket card battle game featuring single-player and real-time multiplayer modes. Compare stats of 150+ IPL cricketers, battle against CPU or friends, and climb the leaderboard!
| Feature | Description |
|---|---|
| 🎮 Single Player | Battle against CPU with hidden opponent cards |
| 👥 Multiplayer | Real-time 1v1 battles via WebSockets |
| 🔐 Authentication | JWT-based login/signup with bcrypt password hashing |
| 🏆 Leaderboard | Track high scores across all players |
| 🃏 150+ Cricketers | Real IPL player stats with rarity tiers |
| 📱 Responsive UI | Beautiful animations, works on mobile |
| 🎨 Card Rarities | Legendary, Rare, and Common tiers |
| Technology | Purpose |
|---|---|
| FastAPI | High-performance async Python web framework |
| SQLAlchemy 2.0 | ORM with async support |
| PostgreSQL/SQLite | Database (PostgreSQL for production) |
| Pydantic v2 | Data validation and serialization |
| python-jose | JWT token handling |
| passlib + bcrypt | Secure password hashing |
| WebSockets | Real-time multiplayer communication |
| Technology | Purpose |
|---|---|
| React 18 | UI component library |
| Vite | Fast build tool and dev server |
| React Router v6 | Client-side routing |
| CSS Variables | Theming and design tokens |
| WebSocket API | Real-time game state sync |
┌─────────────────────────────────────────────────────────────┐
│ CLIENT │
│ ┌─────────────────┐ ┌───────────────────────────┐ │
│ │ React + Vite │ │ WebSocket Client │ │
│ │ (Port 5173) │ │ (Real-time Multiplayer) │ │
│ └────────┬────────┘ └─────────────┬─────────────┘ │
└───────────┼────────────────────────────────┼────────────────┘
│ HTTP REST API │ WebSocket
▼ ▼
┌───────────────────────────────────────────────────────────────┐
│ SERVER │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ FastAPI (Port 8000) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ /auth │ │ /game │ │/leaderboard│ │ /ws/mp │ │ │
│ │ │ routes │ │ routes │ │ routes │ │ handler │ │ │
│ │ └────┬─────┘ └────┬─────┘ └────┬──────┘ └────┬────┘ │ │
│ │ │ │ │ │ │ │
│ │ ┌────▼─────────────▼─────────────▼──────────────▼────┐ │ │
│ │ │ Services Layer │ │ │
│ │ │ (Business Logic, Game State, Multiplayer Rooms) │ │ │
│ │ └────────────────────────┬───────────────────────────┘ │ │
│ └───────────────────────────┼─────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────▼───────────────────────────────┐│
│ │ SQLAlchemy ORM ││
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ ││
│ │ │ Users │ │ Cricketers │ │ Game Scores │ ││
│ │ │ (accounts) │ │ (150+ cards)│ │ (leaderboard) │ ││
│ │ └──────────────┘ └──────────────┘ └──────────────────┘ ││
│ └────────────────────────────┬──────────────────────────────┘│
└───────────────────────────────┼────────────────────────────────┘
▼
┌───────────────────────┐
│ PostgreSQL / SQLite │
│ (Database) │
└───────────────────────┘
Backend/
├── backend/ # 🐍 FastAPI Backend
│ ├── app/
│ │ ├── api/ # API Endpoints
│ │ │ ├── auth.py # POST /register, /login, /me
│ │ │ ├── game.py # POST /start, /play (single-player)
│ │ │ ├── leaderboard.py # GET /leaderboard
│ │ │ └── websocket.py # WS /multiplayer/ws (real-time)
│ │ │
│ │ ├── core/ # App Configuration
│ │ │ ├── config.py # Settings from env vars
│ │ │ ├── database.py # SQLAlchemy engine/session
│ │ │ └── security.py # JWT tokens, password hashing
│ │ │
│ │ ├── models/ # Database Models
│ │ │ ├── cricketer.py # Cricketer card model
│ │ │ └── user.py # User account model
│ │ │
│ │ ├── schemas/ # Pydantic Schemas
│ │ │ ├── auth.py # Login/Register DTOs
│ │ │ ├── cricketer.py # Card response schema
│ │ │ └── multiplayer.py # WebSocket message schemas
│ │ │
│ │ ├── services/ # Business Logic
│ │ │ └── multiplayer_service.py # Room management, game state
│ │ │
│ │ ├── main.py # FastAPI app entry point
│ │ └── seed_data.py # 150+ cricketers data
│ │
│ ├── requirements.txt # Python dependencies
│ └── .env.example # Environment template
│
├── frontend/ # ⚛️ React Frontend
│ ├── src/
│ │ ├── api/ # API Client
│ │ │ └── client.js # Axios instance + interceptors
│ │ │
│ │ ├── context/ # React Context
│ │ │ └── AuthContext.jsx # Auth state management
│ │ │
│ │ ├── pages/ # Page Components
│ │ │ ├── Home.jsx # Landing page
│ │ │ ├── Home.css
│ │ │ ├── Game.jsx # Single-player mode
│ │ │ ├── Game.css
│ │ │ ├── Multiplayer.jsx # Real-time 1v1
│ │ │ ├── Multiplayer.css
│ │ │ ├── Login.jsx # Auth pages
│ │ │ ├── Register.jsx
│ │ │ └── Auth.css
│ │ │
│ │ ├── App.jsx # Router setup
│ │ ├── main.jsx # React entry point
│ │ └── index.css # Global styles + animations
│ │
│ ├── package.json
│ └── vite.config.js
│
├── docker-compose.yml # Container orchestration
├── .dockerignore
└── README.md # You are here!
- Python 3.10+
- Node.js 18+
- PostgreSQL (optional - SQLite works for development)
# Clone and navigate
cd backend
# Create virtual environment
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Create environment file
cp .env.example .env
# Edit .env with your settings
# Run server (auto-creates database tables)
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000# Navigate to frontend
cd frontend
# Install dependencies
npm install
# Create environment file
echo "VITE_API_URL=http://localhost:8000" > .env
echo "VITE_WS_URL=ws://localhost:8000" >> .env
# Run dev server
npm run dev| Service | URL |
|---|---|
| Frontend | http://localhost:5173 |
| Backend API | http://localhost:8000 |
| API Docs (Swagger) | http://localhost:8000/docs |
| API Docs (ReDoc) | http://localhost:8000/redoc |
# ═══════════════════════════════════════════════════════════
# DATABASE
# ═══════════════════════════════════════════════════════════
# SQLite (development)
DATABASE_URL=sqlite:///./cricket_cards.db
# PostgreSQL (production)
# DATABASE_URL=postgresql://user:password@host:5432/dbname
# ═══════════════════════════════════════════════════════════
# SECURITY
# ═══════════════════════════════════════════════════════════
# Generate: python -c "import secrets; print(secrets.token_urlsafe(32))"
SECRET_KEY=your-super-secret-key-change-in-production
# JWT token expiration (minutes) - default: 7 days
ACCESS_TOKEN_EXPIRE_MINUTES=10080
# ═══════════════════════════════════════════════════════════
# APPLICATION
# ═══════════════════════════════════════════════════════════
DEBUG=true
APP_NAME=Cricket Cards Game
APP_VERSION=1.0.0
# CORS - allowed frontend origins
CORS_ORIGINS=["http://localhost:5173","http://localhost:3000"]VITE_API_URL=http://localhost:8000
VITE_WS_URL=ws://localhost:8000- Start Game → You receive a random card
- Opponent Hidden → CPU's card stats are hidden (shows "???")
- Choose a Stat → Click any stat to compare
- Win → Your stat is higher? Continue to next round!
- Lose → Game over. Try to beat your high score!
Scoring: Each win = 1 point. Streak continues until you lose.
| Phase | Description | Timer |
|---|---|---|
| 1. Lobby | Create room or join with code | - |
| 2. Card Selection | Both players pick 12 cards from 15 dealt | 60s |
| 3. Battle | Alternate turns picking stats | 20s/turn |
| 4. Results | Higher score after 12 rounds wins | - |
Turn System:
- Round 1: Player 1 picks stat
- Round 2: Player 2 picks stat
- Alternates for 12 rounds
| Rarity | Color | Border | Example Players |
|---|---|---|---|
| 🟡 Legendary | Gold | Golden glow | Virat Kohli, MS Dhoni, Rohit Sharma |
| 🟣 Rare | Purple | Purple border | Top performers |
| ⚪ Common | White | Standard | All other players |
| Stat | Description | Better |
|---|---|---|
| Matches | Games played in IPL | Higher ↑ |
| Runs | Total runs scored | Higher ↑ |
| Batting Avg | Runs per dismissal | Higher ↑ |
| Strike Rate | Runs per 100 balls | Higher ↑ |
| Wickets | Total wickets taken | Higher ↑ |
| Economy ↓ | Runs conceded per over | Lower ↓ |
| Endpoint | Method | Description | Auth |
|---|---|---|---|
/api/v1/auth/register |
POST | Create new account | ❌ |
/api/v1/auth/login |
POST | Get JWT token | ❌ |
/api/v1/auth/me |
GET | Get current user | ✅ |
Register Request:
{
"username": "player1",
"email": "player@example.com",
"password": "securepass123"
}Login Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer"
}| Endpoint | Method | Description | Auth |
|---|---|---|---|
/api/v1/game/start |
POST | Start new game | Optional |
/api/v1/game/play |
POST | Play a stat | Optional |
Play Request:
{
"stat": "runs",
"player_card_id": 42,
"cpu_card_id": 17,
"used_card_ids": [42, 17, 5, 8]
}| Endpoint | Method | Description |
|---|---|---|
/api/v1/leaderboard |
GET | Top 10 high scores |
Connect: ws://localhost:8000/api/v1/multiplayer/ws
// Create room
{ "type": "create_room", "player_name": "Player1" }
// Join room
{ "type": "join_room", "room_code": "ABCD", "player_name": "Player2" }
// Select cards (12 from 15)
{ "type": "select_cards", "selected_card_ids": [1, 5, 8, ...] }
// Play a stat
{ "type": "play_stat", "stat": "runs" }
// Ready for next round
{ "type": "continue" }// Room created
{ "type": "room_created", "room_code": "ABCD" }
// Cards dealt (15 total)
{ "type": "cards_dealt", "cards": [...], "selection_time": 60 }
// Round start
{
"type": "round_start",
"round_number": 1,
"your_card": {...},
"opponent_card_hidden": {...}, // Hidden stats for non-active player
"your_turn": true,
"turn_time": 20
}
// Round result
{
"type": "round_result",
"winner": "player1",
"stat_used": "runs",
"your_value": 6628,
"opponent_value": 4500
}
// Game over
{
"type": "game_over",
"winner": "player1",
"your_score": 8,
"opponent_score": 4
}The app auto-detects database type from DATABASE_URL. No code changes needed!
- Create account at supabase.com
- New Project → Choose region → Set password
- Get connection string: Settings → Database → Connection string
- Update
.env:DATABASE_URL=postgresql://postgres:[PASSWORD]@db.xxxx.supabase.co:5432/postgres
- Create account at neon.tech
- Create Project → Copy connection string
- Update
.envwith connection string
- Create account at railway.app
- New Project → Add PostgreSQL
- Variables → Copy
DATABASE_URL
| Provider | Storage | Features |
|---|---|---|
| Supabase | 500MB | Auth, Realtime, Edge Functions |
| Neon | 512MB | Serverless, Auto-scaling |
| Railway | $5 credit | Simple, CLI deploy |
| ElephantSQL | 20MB | Basic (too small) |
# Build and run all services
docker-compose up --build
# Run in background
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose downversion: '3.8'
services:
backend:
build: ./backend
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/cricket
- SECRET_KEY=${SECRET_KEY}
depends_on:
- db
frontend:
build: ./frontend
ports:
- "3000:80"
db:
image: postgres:15
environment:
- POSTGRES_DB=cricket
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:# Backend tests
cd backend
pytest
# Frontend tests
cd frontend
npm test# Backend - format with black
black app/
# Frontend - format with prettier
npm run formatBoth servers support hot reload:
- Backend:
uvicorn app.main:app --reload - Frontend:
npm run dev(Vite HMR)
| Problem | Solution |
|---|---|
| CORS errors | Check CORS_ORIGINS in backend .env |
| WebSocket fails | Ensure VITE_WS_URL uses ws:// not http:// |
| Database locked (SQLite) | Restart server, or switch to PostgreSQL |
| JWT expired | Login again to get new token |
| Port in use | Kill process: lsof -ti:8000 | xargs kill |
Enable detailed logging:
DEBUG=trueCheck backend logs for SQL queries and errors.
MIT License - feel free to use for personal or commercial projects.
- IPL Player Data: Compiled from public cricket statistics
- Icons: Emoji-based for simplicity
- Animations: Pure CSS with Vite bundling
Made with ❤️ for cricket fans