SimCricketX

Probabilistic ball-by-ball cricket simulation — run a full match, a series, or a whole tournament in your browser.

CI/CD Pipeline License: MIT Python 3.9+

▶ Try it live at simcricketx.app

SimCricketX demo

**Live match simulation Tournament management Admin panel REST-style API Full test suite**

Why This Project

SimCricketX demonstrates end-to-end engineering across the full stack — probabilistic simulation, concurrency-safe state management, relational schema design, and a security-hardened admin system. It is not a toy: it serves real concurrent users, persists structured match data, enforces authentication and authorization at multiple layers, and ships with CI/CD and Docker deployment configuration.


List A match lengths

List A supports 40 or 50 overs per side in standalone matches, tournaments, custom series, and tours. Choose the innings length during setup; 50 remains the default. Forty-over matches allow eight overs per bowler and use fielding phases of 8/24/8 overs. Both lengths share List A squads, ratings, ground settings, and career totals. List A statistics offer All / 40 / 50 filters based on the original scheduled length, even when rain shortens play.

This variant retains the existing List A Super Over and rain policies, including the 20-over minimum for a rain-affected result. It is not the complete ECB recreational competition ruleset.

Before deploying, run python -m migrations.precheck (or the usual python migrate.py). The idempotent scheduled-length migration also runs during normal startup. Legacy List A matches/tournaments become 50-over records; existing scores and career aggregates are preserved.

Reproduce the 320-match, 16-seed comparison across five pitches and day/day-night:

python scripts/bench_lista_lengths.py --out reports/lista_lengths.json

The compact baseline is saved in tests/fixtures/lista_length_baseline.json. The detailed generated report includes both innings, phase scoring, boundaries, and each bowler’s legal-ball usage. Forty-over par targets are scaled from the 50-over model; simulated totals remain dependent on squads, pitch, and match state.

Contributing

Contributions are welcome — start with the Contributing Guide for setup, test, and code-style instructions, then pick up a good first issue.

The engine/, routes/, and tests/ directories are the most self-contained places to start.


Technical Deep-Dive

The rest of this README documents the internals: how the simulation works, how the app is structured, and how to run it yourself.

A full-stack cricket simulation platform built with Flask, featuring a probabilistic ball-outcome engine, real-time WebSocket updates, role-based access control, and a multi-format tournament system. The project spans ~21,700 lines of Python across a modular monolith architecture with 126 tested API routes and production-grade deployment configuration.


Tech Stack

Layer Technology
Backend Python 3.9+, Flask 2.0
ORM / DB SQLAlchemy, SQLite
Auth Flask-Login, Werkzeug (bcrypt), Flask-WTF (CSRF)
Real-time Flask-SocketIO 5.3+, simple-websocket
Rate Limiting Flask-Limiter
Data Pandas, PyYAML, JSON
Templating Jinja2, HTML5/CSS3, JavaScript
Testing pytest, pytest-flask, pytest-cov, pytest-mock, Faker, factory-boy
Code Quality flake8, black, isort, bandit, safety
Deployment Docker (Python 3.9-slim), Gunicorn (1 worker, 4 threads), Waitress
CI/CD GitHub Actions (Ubuntu + Windows, Python 3.9–3.11)

Architecture Overview

SimCricketX/
├── app.py                  # App factory, route registration, thread-safe match state
├── database/
│   ├── models.py           # 13 SQLAlchemy models (491 lines)
│   └── __init__.py         # db instance
├── routes/                 # Modular route registration (5,308 lines, 126 endpoints)
│   ├── auth_routes.py
│   ├── team_routes.py
│   ├── match_routes.py
│   ├── tournament_routes.py
│   ├── stats_routes.py
│   └── admin_routes.py     # 64+ admin endpoints
├── engine/                 # Simulation core (11,740 lines)
│   ├── match.py            # Ball-by-ball driver (6,500+ lines)
│   ├── ball_outcome.py     # Probabilistic outcome model
│   ├── game_state_engine.py# Momentum & par-score curves
│   ├── pressure_engine.py  # Psychological pressure factors
│   ├── scenario_engine.py  # Scripted dramatic outcomes
│   ├── tournament_engine.py# Multi-format tournament logic (2,400+ lines)
│   ├── commentary_engine.py# Ball-by-ball narrative generation
│   └── stats_service.py    # Match stat persistence & aggregation
├── auth/
│   └── user_auth.py        # Auth functions, password policy, audit logging
├── utils/                  # Config loading, logging helpers
├── tests/                  # 126 routes tested (8 test files)
├── Dockerfile
├── gunicorn.conf.py
├── pytest.ini
└── migrations/

Key Architectural Decisions

Single-worker Gunicorn with 4 threads — Match state lives in a Python in-memory dict (MATCH_INSTANCES). Multiple workers would cause state divergence, so the deployment intentionally uses one worker with thread-level concurrency protected by threading.Lock() per match instance. This is a deliberate trade-off documented in gunicorn.conf.py.

Modular route registration — Each route module exports a register_*_routes(app, db, limiter) function. This dependency-injection pattern keeps modules decoupled and makes it straightforward to add or remove feature areas without modifying the app factory.

Thread-safe match file I/O — Per-match threading.Lock objects stored in _match_file_locks prevent race conditions when concurrent requests read/write the same match’s JSON archive. Global MATCH_INSTANCES_LOCK guards the dict itself.

Graceful Socket.IO degradation — The app imports flask-socketio inside a try/except. If the package is absent, Socket.IO features are silently disabled and all routes serve over standard HTTP.


Simulation Engine

The engine is the core intellectual contribution of this project. It models a cricket match at the individual delivery level using a multi-layer probability pipeline.

Ball Outcome Pipeline

Each delivery passes through four sequential modifier stages:

Base probability matrix
  (batting_rating × bowling_rating × pitch_type)
        ↓
Phase multipliers
  (powerplay / middle overs / death overs)
        ↓
Game state vector
  (momentum, par score delta, RRR pressure)
        ↓
Pressure factors
  (toss advantage, wickets lost, target pressure)
        ↓
Final outcome
  (Dot | 1 | 2 | 3 | 4 | 6 | Wicket | Wide | NoBall | Byes | LegBye)

Momentum model (game_state_engine.py) — Tracks the last 18 deliveries with exponential decay (factor: 0.88). Computes a “game state vector” that encodes whether the batting team is ahead or behind par score. Multipliers are clamped to [0.35, 3.00] to prevent runaway probabilities.

Par score curves — Pre-computed expected scores for all 20 overs per pitch type (Green, Dead, Balanced, High-scoring). Used to calculate whether a batting team is under- or over-performing.

Scenario engine (scenario_engine.py) — Supports scripted dramatic templates: last-ball-six, win-by-1-run thriller, and super-over climax. These are applied as probability overrides when conditions match.


Tournament Engine

Supports 7+ tournament formats:

Standings are recalculated after each fixture using points (W=2, T=1, L=0) and Net Run Rate. Playoff qualification threshold is configurable per tournament.


Database Design

13 SQLAlchemy models across two categories:

Business tables — users, teams, players, matches, match_scorecards, match_partnerships, tournaments, tournament_teams, tournament_fixtures, tournament_player_stats_cache

Security tables — admin_audit_log, failed_login_attempts, blocked_ips, active_sessions, login_history, ip_whitelist, site_counters

Notable design choices:

Player Pool Migration Runbook (Prod)

Use this when migrating an existing DB from team-scoped players to the global/user pool model.

  1. Backup DB
    cp cricket_sim.db cricket_sim.pre_migration_backup.db
    
  2. Dry-run schema precheck
    python3 scripts/precheck_dry_run.py --db ./cricket_sim.db
    
  3. Apply idempotent schema migrations
    python3 -m migrations.precheck
    
  4. Cleanup orphaned stats (after add_scorecard_cascade)
    python3 -m migrations.cleanup_orphaned_stats --apply
    
  5. Verify post-migration state
    python3 scripts/precheck_dry_run.py --db ./cricket_sim.db
    

Expected result after successful migration: 0 pending checks and cleanup_orphaned_stats marked applied.

Linking Existing Players to Pool

After schema migration, link legacy players rows to master_players / user_players:

python3 -m migrations.link_players_to_pool --dry-run
python3 -m migrations.link_players_to_pool --commit

Behavior during linkage:

This fallback is intentional and protects user squads when names are typo variants or absent from global pool.


Security Implementation

Authentication and authorization are not bolted on — they are integrated at every layer.

Authentication

Authorization

Rate Limiting

IP-level Controls

Audit Trail

Exception Observability (DB + GitHub)

CSRF


API Surface (126 Routes)

Module Endpoints Notes
Core 6 Home, ground conditions CRUD
Auth 7 Register, login, logout, display name
Teams 4 List, create, edit, delete
Matches 20 Setup, toss, ball simulation, scorecard, export
Tournaments 5 Create, view, re-simulate fixture, delete
Statistics 8 Player comparison, CSV/JSON export, partnership analysis
Admin 64+ User management, DB backup/restore, IP controls, audit log, system monitoring

The admin panel alone covers: user CRUD, ban/unban, password reset, email change, database integrity checks, live system metrics (via psutil), configuration editing, maintenance mode toggle, session management, and user impersonation for support workflows.


Testing

tests/
├── conftest.py               # Fixtures: app, client, authenticated_client, admin_client,
│                             #           regular_user, admin_user, banned_user,
│                             #           test_team, test_team_2, test_tournament
├── test_auth_routes.py       # 7 auth endpoints
├── test_core_routes.py       # 6 core endpoints
├── test_team_routes.py       # 4 team endpoints
├── test_match_routes.py      # 20 match endpoints
├── test_tournament_routes.py # 5 tournament endpoints
├── test_stats_routes.py      # 8 stats endpoints
├── test_admin_routes.py      # 64+ admin endpoints
└── test_admin_security.py    # Authorization boundary tests

Test tooling: pytest with pytest-flask, pytest-cov (HTML + terminal report), pytest-mock, Faker for synthetic data, factory-boy for ORM fixtures.

Test database: In-memory SQLite spun up per test session via app factory. Each test gets a clean state through fixture teardown.

Coverage targets: Overall 80%+, critical routes 90%+, core business logic 95%+.

# Run full suite with coverage
pytest --cov=. --cov-report=html

# Run by marker
pytest -m admin
pytest -m "auth or security"

Local Sanity Check

Run the focused route suite before shipping small Flask changes:

pytest tests/test_core_routes.py tests/test_auth_routes.py tests/test_team_routes.py

CI/CD

GitHub Actions pipeline runs on every push:


Running Locally

Prerequisites: Python 3.9+, Git

git clone https://github.com/ManishYelam/SimCricketX.git
cd SimCricketX

python -m venv venv
source venv/bin/activate        # Windows: venv\Scripts\activate

pip install -r requirements.txt

python app.py
# → http://127.0.0.1:5000

With Docker:

docker build -t simcricketx .
docker run -p 7860:7860 simcricketx

Run tests:

pytest

Optional: Auto-create GitHub issues for exceptions

Configure .env with:

GITHUB_ISSUE_ON_EXCEPTION_ENABLED=true
GITHUB_TOKEN=your_token_here
GITHUB_REPOSITORY=owner/repo
GITHUB_ISSUE_TITLE_PREFIX=[Auto Exception]
GITHUB_ISSUE_LABELS=auto-exception
GITHUB_ISSUE_ASSIGNEES=

Token permissions:


Project Scale

Metric Count
Total Python lines ~21,700
Simulation engine lines 11,740
Route handler lines 5,308
SQLAlchemy models 13
API endpoints 126
Admin-only endpoints 64+
Test files 8
Tournament formats supported 7+
CI matrix configurations 6 (2 OS × 3 Python versions)

Engineering Concepts Demonstrated


T10 setup, rules, calibration and extension notes: T10 preset.

License

MIT — see LICENSE