Skip to content

ash1shkumar/Checkora

Β 
Β 

Repository files navigation

Checkora

An open-source chess platform with an AI opponent powered by minimax search with alpha-beta pruning.

Built on Django with a high-performance C++ engine and a Python fallback for maximum compatibility.

Python Django C++ License: MIT Tests Issues PRs Welcome Discord

Join our Discord community for updates, support, and games: https://discord.gg/DvW3xVXw8g

Core Maintainers

EDWARD-012
@EDWARD-012
Follow EDWARD-012
triemerge
@triemerge
Follow triemerge

Click a profile or follow badge for release drops, roadmap notes, and engine updates.


Contributors

0rbiT-ai2005rishabhANISHA-RAWATCodeMaster11000EDWARD-012EnKruptosFTS18HarshMrigankKrishKyadaMahalaxmiKannanMouni-SanaboyinaNayansiDuparePRODHOSHPooja-V4Pranav-0440Pranava116Rajal-uiRuchiSheoranRuhanikaChotwaniSaptadeepMondalSara-ThakurSecureAditiShrishagkSiRa111Siddharth-sdeSilverMenaceSoumipal56SrashtiChauhanSreekuttan-007Steel-roger-moondradevVITianYash42Vaishnav-Hub9YashKrTripathiaayushbamalakash3911akashgoudsidduluriakhilmodi29amarpratapsingh2452aniketchauhan16anshiikaa001anwitamishraartiverma-00ash1shkumarasnaassalambh462007chekr-maxdeepsikha-dashdiptipradeepdivya-d510gowthamrdyyharshitkr13itsdakshjainitsmeesnehaajancysenkartik12421khushi-in-techkrishkhinchikush-mehra1manurajgoelmaria-453mittalsonalnipundeeptnishtha-agarwal-211nitish06nkcniy-atiparthc6416parthpatidar03pratyuxxhhradhikaa188rajat552renganathcrichachauhan15rmagdaleena2508-01roneet0916saswatdutta1310shauryaparth1902-blipshreyamahesh07-gitshrutip04shrutisharma-shshubhamjrd4559-sudosreevyaraosricharan-213ssuyashhhhsujithputta02tharunika-19the404packettriemergeunnati-jaiswal24vishwassinfinityyuvraj-k-singhzenowingedzqleslie

Features

Feature Description
AI Opponent Minimax search with alpha-beta pruning for challenging gameplay
Hybrid Engine C++ binary for maximum speed with an automatic Python fallback
Full Move Validation Legal moves enforced for all pieces including castling and promotion (en passant pending β€” see #88)
Game Timer Per-player countdown clocks with pause support
Material Score Panel Live material advantage tracking that updates dynamically during gameplay
REST API Clean JSON endpoints powering a decoupled frontend
PvP & PvE Modes Play against a friend or challenge the AI

Quick Start

# 1. Clone the repository
git clone https://github.com/Checkora/Checkora.git
cd Checkora

# 2. Set up a virtual environment
python -m venv venv
venv\Scripts\activate        # Windows
source venv/bin/activate     # macOS / Linux

Note: Django 6.0 requires Python 3.12 or higher. If you have multiple versions on Windows, use a compatible installed version, for example: py -3.12 -m venv venv

# 3. Install dependencies
pip install -r requirements.txt

# 4. Set up environment variables
# Copy example env file
# Windows (PowerShell)
copy .env.example .env

# macOS / Linux
cp .env.example .env

# Open `.env` and set SECRET_KEY if needed

# 5. Run migrations and start the server
python manage.py migrate
python manage.py runserver

Open http://127.0.0.1:8000/ in your browser and start playing.

Compile the C++ Engine (optional but recommended)

The compiled binary is not committed to the repository. Each contributor compiles for their own platform. If the binary is absent, Checkora automatically falls back to the Python engine.

# Windows
g++ -O2 game/engine/main.cpp -o game/engine/main.exe

# macOS / Linux
g++ -O2 game/engine/main.cpp -o game/engine/main

Project Structure

Checkora follows a modular project structure to separate the frontend, backend, engine logic, and documentation clearly.

An exhaustive file-level overview of the entire repository is detailed below:

Checkora/
β”œβ”€β”€ .github/                       # GitHub configurations
β”‚   β”œβ”€β”€ ISSUE_TEMPLATE/            # Issue blueprints for contributors
β”‚   β”‚   β”œβ”€β”€ bug_report.md          # Form for reporting software bugs
β”‚   β”‚   └── feature_request.md     # Form for proposing feature improvements
β”‚   β”œβ”€β”€ workflows/                 # CI/CD automation pipelines
β”‚   β”‚   β”œβ”€β”€ ci.yml                 # Main test and lint automation workflow
β”‚   β”‚   β”œβ”€β”€ contributors.yml       # Automatically maintains the contributor catalog in README
β”‚   β”‚   └── label-gssoc.yml        # Automatically labels issues for GSSoC contributors
β”‚   └── PULL_REQUEST_TEMPLATE.md   # PR template establishing code quality requirements
β”œβ”€β”€ api/                           # Serverless API configurations
β”‚   └── wsgi.py                    # Vercel-specific WSGI application configuration
β”œβ”€β”€ core/                          # Django project core configuration
β”‚   β”œβ”€β”€ __init__.py                # Package initialization marker
β”‚   β”œβ”€β”€ asgi.py                    # Entry point for ASGI-compatible web servers
β”‚   β”œβ”€β”€ settings.py                # Global settings (DB config, middleware, security headers)
β”‚   β”œβ”€β”€ urls.py                    # Root URL router mapping to views
β”‚   └── wsgi.py                    # Entry point for WSGI-compatible web servers
β”œβ”€β”€ docs/                          # Detailed architecture guides
β”‚   β”œβ”€β”€ API.md                     # Raw technical spec for REST API endpoints
β”‚   β”œβ”€β”€ SECURITY_HEADERS_AUDIT.md  # Deep security analysis and policy audit reports
β”‚   └── engine_architecture.md     # Detailed minimax and communication workflow analysis
β”œβ”€β”€ game/                          # Core Chess application module
β”‚   β”œβ”€β”€ engine/                    # The AI Chess engine directory
β”‚   β”‚   β”œβ”€β”€ main.cpp               # High-performance C++17 Minimax + Alpha-Beta pruning engine
β”‚   β”‚   β”œβ”€β”€ main.py                # Pure Python 3.12 fallback replica of the C++ engine
β”‚   β”‚   └── opening_book.json      # Structured dictionary mapping classic opening moves
β”‚   β”œβ”€β”€ migrations/                # Database schema version histories
β”‚   β”‚   β”œβ”€β”€ 0001_initial.py        # Relational schema for GameResult and Profiles
β”‚   β”‚   β”œβ”€β”€ 0002_add_missing...   # Database schema patch adding draw reason records
β”‚   β”‚   β”œβ”€β”€ 0003_alter_game...     # Migration establishing foreign key user associations
β”‚   β”‚   β”œβ”€β”€ 0004_gameresult...     # Migration adding active game player color records
β”‚   β”‚   └── __init__.py            # Package initialization marker
β”‚   β”œβ”€β”€ selenium_tests/            # UI browser integration tests
β”‚   β”‚   β”œβ”€β”€ __init__.py            # Package initialization marker
β”‚   β”‚   β”œβ”€β”€ base.py                # Setup, teardown, and WebDriver helpers for integration runs
β”‚   β”‚   β”œβ”€β”€ test_boards.py         # Automated UI click-and-drag gameplay flow tests
β”‚   β”‚   └── test_navigation.py     # Automated browser routing and navigation validation tests
β”‚   β”œβ”€β”€ static/                    # Frontend client-side resources
β”‚   β”‚   └── game/                  # Main namespace directory
β”‚   β”‚       β”œβ”€β”€ css/               # Modular stylesheet templates
β”‚   β”‚       β”‚   β”œβ”€β”€ 404.css        # Clean layout styles for page not found errors
β”‚   β”‚       β”‚   β”œβ”€β”€ auth.css       # Forms and secure login layouts
β”‚   β”‚       β”‚   β”œβ”€β”€ board.css      # Chessboard alignments, active highlights, and action panels
β”‚   β”‚       β”‚   β”œβ”€β”€ landing.css    # Interactive hero screens and mode selectors
β”‚   β”‚       β”‚   └── toast.css      # Custom popup and notification toaster styles
β”‚   β”‚       β”œβ”€β”€ js/                # Client-side dynamic scripts
β”‚   β”‚       β”‚   β”œβ”€β”€ auth.js        # Validates dynamic auth form submissions
β”‚   β”‚       β”‚   β”œβ”€β”€ board.js       # Chess grid events, capture drawers, API calls, clock tickers
β”‚   β”‚       β”‚   └── toast.js       # Manages toast alert popups and life-cycles
β”‚   β”‚       β”œβ”€β”€ sounds/            # Gameplay sound effects
β”‚   β”‚       β”‚   β”œβ”€β”€ capture.mp3    # Capture sound alert
β”‚   β”‚       β”‚   β”œβ”€β”€ check.wav      # Check sound warning
β”‚   β”‚       β”‚   β”œβ”€β”€ draw.mp3       # Game draw chime
β”‚   β”‚       β”‚   └── move.wav       # Chess piece move tick
β”‚   β”‚       β”œβ”€β”€ checkora_icon_only.png # Project brand mark
β”‚   β”‚       └── favicon.jpeg       # Small browser favicon
β”‚   β”œβ”€β”€ templates/                 # Server-side HTML render blueprints
β”‚   β”‚   β”œβ”€β”€ 404.html               # Custom 404 error page template
β”‚   β”‚   β”œβ”€β”€ robots.txt             # Web crawler configuration instructions
β”‚   β”‚   β”œβ”€β”€ sitemap.xml            # SEO indexing guide
β”‚   β”‚   └── game/                  # Namespace folder matching Django conventions
β”‚   β”‚       β”œβ”€β”€ includes/          # Reusable UI partial layout blocks
β”‚   β”‚       β”‚   └── messages.html  # Banner rendering Django alert notifications
β”‚   β”‚       β”œβ”€β”€ board.html         # Interactive gameplay chessboard and player cards
β”‚   β”‚       β”œβ”€β”€ landing.html       # Mode lobby selection screen
β”‚   β”‚       β”œβ”€β”€ login.html         # Sign-in form interface
β”‚   β”‚       β”œβ”€β”€ register.html      # Create account interface
β”‚   β”‚       β”œβ”€β”€ verify_otp.html    # Two-factor verification panel
β”‚   β”‚       β”œβ”€β”€ rules.html         # Gameplay and chess educational rules guide
β”‚   β”‚       β”œβ”€β”€ stats.html         # User match metrics, profiles, and scoreboards
β”‚   β”‚       β”œβ”€β”€ password_reset.html # Password reset trigger page
β”‚   β”‚       β”œβ”€β”€ password_reset_complete.html # Confirmation of successful reset
β”‚   β”‚       β”œβ”€β”€ password_reset_confirm.html  # Verification form link target
β”‚   β”‚       β”œβ”€β”€ password_reset_done.html     # Outlines password email delivery status
β”‚   β”‚       β”œβ”€β”€ password_reset_email.html    # HTML layout for reset emails
β”‚   β”‚       └── password_reset_subject.txt   # Email subject text file
β”‚   β”œβ”€β”€ __init__.py                # Package initialization marker
β”‚   β”œβ”€β”€ apps.py                    # Django configuration class definition
β”‚   β”œβ”€β”€ engine.py                  # Translates Python arrays to C++/Python subprocess stdin/stdout
β”‚   β”œβ”€β”€ forms.py                   # Form validation classes for User registration and session keys
β”‚   β”œβ”€β”€ icon.jpeg                  # Main project thumbnail graphic
β”‚   β”œβ”€β”€ models.py                  # Database schemas mapping matches and profiles
β”‚   β”œβ”€β”€ services.py                # Standalone functions managing core business logic
β”‚   β”œβ”€β”€ tests.py                   # 80+ unit and integration test assertions
β”‚   β”œβ”€β”€ urls.py                    # Application level router mapping endpoints
β”‚   └── views.py                   # Django controller layer dispatching API and HTML requests
β”œβ”€β”€ .env.example                   # Baseline local configuration variables blueprint
β”œβ”€β”€ .gitignore                     # Configures Git to ignore builds, caches, and database logs
β”œβ”€β”€ CODE_OF_CONDUCT.md             # Contributor environment code of conduct guidelines
β”œβ”€β”€ CONTRIBUTING.md                # Guide detailing branch formats and pull request rules
β”œβ”€β”€ LICENSE                        # Open-source MIT license deed
β”œβ”€β”€ README.md                      # Primary project overview
β”œβ”€β”€ requirements.txt               # Required Python packages
β”œβ”€β”€ manage.py                      # Django CLI control center script
β”œβ”€β”€ package.json                   # Specifies frontend tooling scripts
β”œβ”€β”€ package-lock.json              # Locked frontend dependency version tree
β”œβ”€β”€ structure.md                   # Extended architectural blueprint documentation
└── vercel.json                    # Configuration for serverless Django routing on Vercel

Architecture

Checkora uses a clean three-layer architecture:

Browser (JS/HTML/CSS)
       |
       v
Django Views (views.py)          <- HTTP request handling & session state
       |
       v
ChessGame Wrapper (engine.py)    <- Translates board state into engine commands
       |
       |---> C++ Binary (main.exe / main)   <- Primary: fast minimax AI
       +---> Python Script (main.py)        <- Fallback: identical logic in Python
Layer Technology Path
Frontend HTML, CSS, JavaScript game/templates/game/board.html
Backend Django 6.x game/views.py, game/engine.py
Engine (Primary) C++17 game/engine/main.cpp
Engine (Fallback) Python 3.12+ game/engine/main.py

For a full deep-dive into the backend components, execution flow, and AI internals, see the Architecture Guide.

How It Works

When a player makes a move, the request flows through three layers:

  1. Browser sends a POST request with the move coordinates
  2. Django (views.py) receives it and delegates to the ChessGame wrapper in engine.py
  3. engine.py serializes the board into a flat 64-character string and spawns the engine as a subprocess, sending commands via stdin and reading responses from stdout

The engine speaks a simple text-based protocol:

Command Example Response
VALIDATE VALIDATE <board64> <rights> <turn> fr fc tr tc VALID / INVALID <reason>
MOVES MOVES <board64> <rights> <turn> row col MOVES tr tc is_capture is_promotion ...
BESTMOVE BESTMOVE <board64> <rights> <turn> <depth> BESTMOVE fr fc tr tc
STATUS STATUS <board64> <rights> <turn> STATUS CHECK / CHECKMATE / STALEMATE / OK
flowchart TD
    A[Browser\nJS / HTML] -->|HTTP POST /api/move/| B[Django Views\nviews.py]
    B -->|delegates to| C[ChessGame Wrapper\nengine.py]
    C -->|board64 + command via stdin| D{Engine}
    D -->|C++ binary\nmain.exe / main| E[Minimax + Alpha-Beta\nPrimary]
    D -->|Python fallback\nmain.py| F[Minimax + Alpha-Beta\nFallback]
    E -->|response via stdout| C
    F -->|response via stdout| C
    C -->|updated state| B
    B -->|JSON response| A
Loading

API Reference

Checkora features a decoupled API layer. Below is the endpoint catalog accompanied by explicit request and response structures to assist frontend integrations.

Note

All state-modifying requests (POST) require a CSRF token passed via the X-CSRFToken HTTP header, except for /api/pause/ which is CSRF-exempt to support page close events via navigator.sendBeacon.

Method Endpoint Description Request Example
GET / Render the board UI N/A (Standard HTML Page)
GET /api/state/ Retrieve full game state from session /api/state/
POST /api/move/ Execute a move on the board /api/move/
GET /api/valid-moves/ Get all legal moves for a selected piece /api/valid-moves/?row=6&col=4
POST /api/new-game/ Start a new PvP or PvE game /api/new-game/
GET /api/check-promotion/ Check if a pawn reaches the promotion rank /api/check-promotion/?from_row=1&from_col=0&to_row=0
POST /api/ai-move/ Request the engine to compute the best move /api/ai-move/
POST /api/pause/ Pause/Resume game timer countdown /api/pause/

Request/Response JSON Examples

1. Retrieve Game State (GET /api/state/)

Called on board load to restore ongoing match positions and clocks.

Response (Success - 200 OK):

{
  "board": [
    ["r", "n", "b", "q", "k", "b", "n", "r"],
    ["p", "p", "p", "p", "p", "p", "p", "p"],
    [null, null, null, null, null, null, null, null],
    [null, null, null, null, null, null, null, null],
    [null, null, null, null, null, null, null, null],
    [null, null, null, null, null, null, null, null],
    ["P", "P", "P", "P", "P", "P", "P", "P"],
    ["R", "N", "B", "Q", "K", "B", "N", "R"]
  ],
  "current_turn": "white",
  "white_time": 600,
  "black_time": 600,
  "paused": true,
  "move_history": [
    {"notation": "e4", "piece": "P", "from": [6, 4], "to": [4, 4], "color": "white"}
  ],
  "captured_pieces": {"white": [], "black": []},
  "mode": "pvp"
}

2. Execute a Move (POST /api/move/)

Triggered when a player releases a piece onto a destination square.

Request Body:

Note: promotion_piece is optional ("q", "r", "b", "n") and required only if check-promotion is true.

{
  "from_row": 6,
  "from_col": 4,
  "to_row": 4,
  "to_col": 4,
  "promotion_piece": "q"
}

Response (Success - 200 OK):

Note: board is an 8x8 array reflecting the updated state. game_status can be "active", "check", "checkmate", "stalemate", or "draw".

{
  "valid": true,
  "message": "Move successful",
  "captured": null,
  "board": [],
  "current_turn": "black",
  "white_time": 595,
  "black_time": 600,
  "move_history": [
    {"notation": "e4", "piece": "P", "from": [6, 4], "to": [4, 4], "color": "white"}
  ],
  "captured_pieces": {"white": [], "black": []},
  "game_status": "active"
}

Response (Error - 400 Bad Request / 200 OK with invalid):

{
  "valid": false,
  "message": "Invalid move: King would be in check"
}

3. Get Valid Moves (GET /api/valid-moves/)

Instructs the frontend UI where the selected piece can legally go.

Request Parameters: ?row=6&col=4

Response (Success - 200 OK):

{
  "valid_moves": [
    {"row": 5, "col": 4, "is_capture": false},
    {"row": 4, "col": 4, "is_capture": false}
  ]
}

4. Request AI Move (POST /api/ai-move/)

Triggers background minimax engine search. Returns the move calculated by the C++/Python engine.

Response (Success - 200 OK):

Note: board is an 8x8 array reflecting the updated state. move_history contains the list of moves.

{
  "valid": true,
  "message": "Move successful",
  "captured": "p",
  "board": [],
  "current_turn": "white",
  "white_time": 600,
  "black_time": 598,
  "move_history": [],
  "captured_pieces": {"white": ["p"], "black": []},
  "ai_move": {
    "from_row": 1,
    "from_col": 3,
    "to_row": 3,
    "to_col": 3
  },
  "game_status": "active"
}

5. Start New Game (POST /api/new-game/)

Resets current session variables and starts a fresh match.

Request Body:

Note: mode can be "pvp" or "ai".

{
  "mode": "ai"
}

Response (Success - 200 OK):

Note: board is an 8x8 array containing the clean initial board configuration.

{
  "board": [],
  "current_turn": "white",
  "move_history": [],
  "captured_pieces": {"white": [], "black": []},
  "mode": "ai"
}

Tests

The test suite runs fully in-memory β€” no compiled engine binary required.

python manage.py test game

28 tests covering all API endpoints, move validation, engine path resolution, promotion logic, and AI mode enforcement.


Troubleshooting Guide

Below are solutions to common setup, installation, and environment issues contributors encounter when getting Checkora running locally.

🐍 1. Python Version Mismatch

Django 6.x is built on modern Python paradigms and strictly requires Python 3.12 or higher. If you run an older version, dependencies in requirements.txt will fail to resolve or throw syntax errors during server boot.

  • Check version:
    python --version
  • Resolution (Windows multiple installations): Use the Python Launcher to explicitly target 3.12+ when creating your virtual environment:
    py -3.12 -m venv venv
  • Resolution (macOS/Linux): Ensure python3 points to a 3.12+ installation (e.g., via Homebrew: brew install python@3.12).

πŸ“¦ 2. Virtual Environment Activation Issues

Depending on your terminal shell or system policies, activating the virtual environment might throw permission or script execution errors.

  • Windows PowerShell execution restriction error: If you see an error like Script execution is disabled on this system, bypass the policy for the active process:

    Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
    venv\Scripts\Activate.ps1
  • Activation commands for different shells:

    Shell Command
    Windows Cmd venv\Scripts\activate.bat
    Windows PowerShell venv\Scripts\Activate.ps1
    Git Bash / WSL / Linux / macOS source venv/bin/activate
    Fish Shell source venv/bin/activate.fish

πŸ› οΈ 3. g++ Compiler Installation & Configuration Problems

Checkora attempts to compile the C++ chess engine locally to maximize Minimax performance. If g++ is missing or not configured correctly, it will throw compilation errors.

Tip

If g++ setup is too tricky for your system, you can skip compiling it! Checkora will automatically detect the absence of the binary and fall back to the Python engine in game/engine/main.py.

  • Check compiler availability:

    g++ --version
  • Resolution (Windows):

    1. Download the MinGW-w64 compiler suite (we recommend the simple, portable w64-devkit).
    2. Add the bin directory (containing g++.exe) to your system's Environment Variables -> PATH list.
    3. Restart your terminal so the new path takes effect.
  • Resolution (macOS): Install the Xcode Command Line Tools:

    xcode-select --install
  • Resolution (Ubuntu/Debian Linux):

    sudo apt update && sudo apt install build-essential

πŸ’Ύ 4. Database Migration Errors

If migrations fail to run, or database models get out of sync, you may encounter relational database exceptions.

  • Resolution: Reset your local SQLite database structure by running:

    # 1. Generate any missing database schema blueprints
    python manage.py makemigrations game
    
    # 2. Safely apply schema blueprints
    python manage.py migrate

    If conflicts persist, delete the local db.sqlite3 file and re-run the commands above to construct a clean database.

πŸ”‘ 5. Missing .env Configuration File

If you attempt to launch the Django server without setting up a local configuration file, Django will throw KeyError or configuration load failures for crucial settings.

  • Resolution: Ensure you clone the template configuration into a new active .env file in the root directory:

    # Windows PowerShell
    copy .env.example .env
    
    # macOS / Linux
    cp .env.example .env

    Open .env and verify you have a robust string under SECRET_KEY.

πŸ”Œ 6. Port Conflicts (Port 8000 Already in Use)

If you already have another service running on your local port 8000, Django will fail to bind and throw Error: That port is already in use.

  • Resolution: Instruct Django to boot the local server on an alternative unoccupied port, for example, 8080 or 8001:

    python manage.py runserver 8080

Contributor Support & Feedback

We want your contribution journey with Checkora to be smooth, welcoming, and productive! If you hit roadblocks or have ideas, please utilize the following channels:

πŸ’¬ 1. Join our Discord Community

Our central hub for live discussions, playtesting matches, roadmap announcements, and direct maintainer support.

  • Invite Link: Join the Checkora Discord Server
  • Active Channels:
    • #setup-help: For environment, dependencies, or local compilation challenges.
    • #engine-chat: For deep-dives into minimax heuristics, board representation, and alpha-beta pruning.
    • #suggestions: For sharing your design mocks, UI improvements, or gameplay feature proposals.

❓ 2. Ask Setup & Installation Questions

If you prefer forum-style threading over live Discord chat:

  • Open a question on our GitHub Discussions page under the Q&A / Help category.
  • Search prior threads; many common setups or dependencies are documented by fellow contributors.

πŸ“š 3. Report Documentation Confusion

If a section of this guide, structure.md, or API.md is unclear, out of date, or missing steps:

  • File a GitHub Issue using the Documentation Confusion template or attach the documentation label.
  • Better yet: Submit a quick pull request correcting the text! We love docs-focused contributions.

πŸ’‘ 4. Share Feature Proposals & Suggestions

Want to introduce a new gameplay timer format, customize themes, or build a matching lobby?

  • Share your proposals in GitHub Discussions Ideas.
  • Align with core maintainers (@EDWARD-012 & @triemerge) before writing significant logic to ensure architectural compatibility.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for branch naming conventions, commit message format, and PR guidelines before submitting.


License

Released under the MIT License.

About

Chess platform with an AI opponent powered by minimax search with alpha-beta pruning, built on Django and a C++ engine.

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Python 35.3%
  • HTML 23.9%
  • JavaScript 21.5%
  • CSS 12.2%
  • C++ 7.1%