Skip to content
CAI
Software that uses CAICheck a score

lichess-org/scalachess

55.2

Adequate · 28 September 2026

14.6k

lines of production code

Scala

primary language

2

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

This system is a high-performance, multi-variant chess engine library written in Scala 3. It provides core capabilities for move validation, position hashing, and game state management across standard chess and numerous variants like Crazyhouse, Chess960, and Atomic. The library also includes robust tools for parsing and serializing game data in FEN, PGN, and UCI formats, alongside an integrated opening book database. Additionally, it features a dedicated rating module that calculates Elo and Glicko scores with support for FIDE regulations and first-move color advantage.

How it got here

2012–2023 — Chess engine core and test suite

16 changes.

The project established a foundational Scala 3 chess engine with bitboard-based data structures, clocking systems, and support for user-chosen promotions. This core implementation was accompanied by the removal of legacy formats and the creation of an extensive test suite covering multiple chess variants, PGN serialization, and performance benchmarks.

2024–2026 — Core engine refactoring and rating module extraction

15 changes.

This period focused on rebuilding the core chess engine with a new Position-centric API, introducing foundational types like Bitboard and supporting extended variants such as Crazyhouse and Chess960. Concurrently, rating logic was extracted into a dedicated module to implement updated FIDE rules and Glicko color advantage adjustments, while comprehensive test coverage was added for rating and tiebreak systems.

Features

Added Play JSON serialization support for chess domain models

This change introduces a new \Json.scala\ file in the \playJson\ module that provides Play Framework JSON readers and writers for various chess-related types. Users can now serialize and deserialize objects such as \Uci\, \Square\, \Crazyhouse\ state, \Opening\ details, \Division\, \CorrespondenceClock\, and bitboard destination maps directly to and from JSON format. The implementation leverages existing \scalalib.json\ utilities for basic types and defines custom writers for complex structures like \Map\[Square, Bitboard\]\ and \Crazyhouse.Pocket\.

playJson · high confidence

Core chess engine types and move validation logic introduced

The core engine module now includes foundational types for representing chess state, including Bitboard, Square, File, Rank, Color, and Castles, along with the CanPlay typeclass that enables parsing and validating moves from UCI and SAN formats. This change introduces the ability to apply moves to a position and receive the resulting state, while also providing utilities for evaluating insufficient mating material and computing position hashes for repetition detection.

core/src/main/scala · high confidence

Initial project scaffolding and developer tooling setup

This change establishes the foundational structure for the project, introducing configuration files for code formatting (scalafmt 3.11.5) and static analysis (scalafix with Scala 3 dialect), alongside a .gitignore for IDE and build artifacts. It adds a LICENSE file (MIT), a README with build and benchmark instructions, and a Nix flake for reproducible development environments using Java 21, Scala 3, and sbt 2.0.0. Additionally, it includes a Python script to sync chess opening data and a jitpack configuration to ensure correct JDK usage during builds.

(repo-wide) · high confidence

Introduces new core chess engine data structures and clocking system

This change adds the foundational data structures for the chess engine, including the \Board\ representation using bitboards, and new generic containers \ByColor\ and \ByRole\ for handling piece and color-specific data. It also introduces the \Clock\ and \CorrespondenceClock\ classes to manage game timing, lag tracking, and increment logic, alongside \MoveMetrics\ for client-side performance data. The \Game\ model is updated to use a \Position\ for state and integrates the new clocking system, while \MoveOrDrop\ and \History\ are refactored to support the new board representation and move validation logic.

repository · high confidence

New compile-time PGN and UCI literals and comprehensive test arbitraries

The test-kit now provides compile-time validated literals for PGN and UCI strings via the \pgn\ and \uci\ string interpolators (defined in \chess/macros.scala\), ensuring syntax correctness at compile time. Additionally, a comprehensive set of Scalacheck \Arbitrary\ and \Cogen\ instances has been added for core chess types (including \Node\, \Move.Castle\, \Centis\, \Crazyhouse.Data\, and \Bitboard\) to facilitate robust property-based testing of the chess engine logic.

test-kit/src/main · high confidence

New opening book database integration

The application now includes a built-in opening database (OpeningDb) that allows users to identify chess openings by FEN or by a sequence of moves. The system searches for matches against a comprehensive dataset generated from lichess-org/chess-openings, supporting up to 40 plies and requiring a minimum of 20 pieces on the board to ensure valid opening identification.

core/src/main/scala/opening · high confidence

Removals

Removal of legacy visual board format implementation

The \Format\ trait and the \Visual\ object, which handled the parsing and rendering of chess boards into a specific ASCII visual representation, have been removed from the \src/main/scala/format\ package. This eliminates the code responsible for converting board states to and from the multi-line text format used for visual display, simplifying the format handling layer by discarding this specific serialization method.

src/main/scala/format · high confidence

Behavioural changes

Chess model refactored to support user-chosen promotions

The core chess model in src/main/scala/model has been restructured to allow players to choose which piece to promote to (Queen, Rook, Bishop, or Knight) instead of using a default. This change involves removing the old Actor, Board, and Situation classes and introducing new Move and Role abstractions that handle promotion logic with user input, while also removing the longRange property from the Role trait to simplify piece movement calculations.

src/main/scala/model · high confidence

Extracted DirectEncounter tiebreak logic into a dedicated module

The implementation for the DirectEncounter tiebreak method has been moved from its previous location into a new, dedicated file (DirectEncounter.scala). This refactoring isolates the logic that ranks tied players based on their head-to-head results, making the codebase more modular without changing the external behavior of the tiebreak system.

tiebreak · high confidence

Glicko rating calculator now accounts for first-move color advantage

The Glicko rating implementation has been updated to support color-based rating adjustments. The new GlickoCalculator accepts a colorAdvantage parameter, allowing the system to account for the statistical advantage of moving first (White) when calculating player ratings. This change is part of the broader rating module reorganization in v16.5.0, which moves Elo and Glicko logic into a dedicated module and introduces the foundational structures for rating color advantage.

rating/src/main/scala/glicko · high confidence

Glicko rating system now accounts for first-move advantage

The Glicko rating calculation engine has been updated to factor in the statistical advantage of playing as White. The \RatingCalculator\ now accepts a \ColorAdvantage\ parameter, which is applied to player ratings when computing expected scores and rating deviations. This ensures that game outcomes are evaluated against a baseline that reflects the historical edge associated with the first move, rather than treating all games as symmetric.

rating/src/main/scala/glicko/impl · high confidence

New compact binary move encoding and refined PGN parsing

The PGN format module now includes a new Binary encoder/decoder that compresses SAN moves into a compact byte array for efficient storage or transmission, alongside a new Dumper for generating SAN strings from game data. The Parser has been updated to support parsing PGN tags and a mainline-only mode, while also fixing issues with nested variations in SAN parsing and sanitizing tags to handle malformed PGN files more robustly.

core/src/main/scala/format/pgn · high confidence

Rating logic moved to new module with FIDE rule updates

The rating calculation logic has been extracted into a new \rating\ module (version 16.5.0), introducing new opaque types for Elo, KFactor, and Rating. The Elo implementation now adheres to updated FIDE regulations, specifically removing the ±400 rating difference cap for players rated 2650 and above in Standard time controls, and enforcing a new unrated condition for Rapid/Blitz games involving players above 2600 when the rating difference is 600 or more. The module also includes a comprehensive FIDE conversion table for expected score calculations.

rating/src/main/scala · high confidence

Refactored FEN and UCI format handling with new Position-centric API

The format module has been rewritten to operate on the new Position model, replacing the previous Situation-based approach. FEN parsing and generation now support extended notations including Crazyhouse pockets and ThreeCheck counts, with dedicated opaque types for Full, Standard, and Board FENs. UCI move serialization has been updated to use the actual rook square for Chess960 castling by default, while retaining legacy standard castling output (king-to-king-square) via an optional flag for compatibility. A new UciPath type provides a compact, opaque string representation for navigating game tree nodes using concatenated UCI character pairs.

core/src/main/scala/format · high confidence

Refactored Variant API and move validation logic

The Variant class has been refactored to improve performance and clarity in move validation and game-end detection. The \validMovesAt\ method is now defined directly within the base Variant class, replacing the previous approach of generating all legal moves to find a specific one, which optimizes move lookup. Additionally, the logic for determining insufficient material has been restructured: \playerHasInsufficientMaterial\ and \opponentHasInsufficientMaterial\ are now distinct methods that delegate to \InsufficientMatingMaterial\, allowing variants to override specific behaviors (such as for Horde) rather than relying on a single shared implementation. The \Situation\ class has been removed in favor of using \Position\ directly, simplifying the API surface.

core/src/main/scala/variant · high confidence

Removal of legacy lila.chess package object

The \lila.chess\ package object, which previously aggregated various Scalaz typeclass mixins (such as \OrnicarValidation\, \Lists\, and \Booleans\) and provided implicit conversions like \stringToFailures\, has been removed. This change eliminates a centralized source of implicit imports for the chess module, requiring consumers to manage their own imports or rely on more granular package structures.

src/main/scala · high confidence

Fixes

Fixes bitboard attack table initialization crash

The bitboard attack tables in the core module are now initialized using the @static annotation to ensure they are populated before any code attempts to read them. This change fixes a runtime NullPointerException that occurred during application startup when the initialization order of static fields was not guaranteed, ensuring stable and crash-free loading of chess move generation data.

core/src/main/scala/bitboard · high confidence

Test coverage

Add JMH benchmarks for chess engine components; Added comprehensive test coverage for PGN parsing, rendering, and binary serialization; Added perft test suite for chess variants; Added property-based tests for Bitboard and Board logic; Added test coverage for chess format serialization and utilities; Added test coverage for tiebreak algorithms; Added tests for Glicko rating calculator and color advantage; Added tests for opening book search and starting position validation; Added unit tests for Elo rating calculations; Added unit tests for the Glicko rating calculator; Comprehensive test suite for chess variants and core engine logic; Deleted legacy chess model test suite; Expanded test suite with new chess variants and tournament data.

Dependencies

Initial project setup with Scala 3.9 and updated dependencies

The project is initialized with a new build configuration targeting Scala 3.9.0 and version 17.17.1. The core library dependencies have been updated to include cats-core and alleycats-core at 2.13.0, cats-parse at 1.1.0, kittens at 3.5.0, and monocle-core at 3.3.0, alongside scalalib-core and scalalib-model at 11.11.0. The play-json module now depends on play-json 3.0.6. Test dependencies in the testKit module have been upgraded to munit 1.3.6, munit-scalacheck 1.3.1, weaver-cats/weaver-scalacheck 0.13.0, and fs2-core/fs2-io 3.14.0. Additionally, a Pipfile has been added to define Python 3.12 as the required runtime and include the chess library version 1.10.0 as a development dependency.

(dependencies) · high confidence

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

How this codebase got here

Score

  • CAI 63 → 55 (-8.1)
  • Rubric changed (rubric-2026.09.8 → rubric-2026.09.16) — scores are not directly comparable.

Lenses

  • Code Health 93 → 93 (+0.0)
  • Architecture 99 → 81 (-18.6)
  • Maturity 42 → 40 (-2.3)
  • Readiness 69 → 50 (-18.9)
  • Security 95 → 96 (+1.3)

Resolved (4)

  • Hotspot: core/src/main/scala/Position.scala (core/src/main/scala/Position.scala)
  • Hotspot: core/src/main/scala/variant/Horde.scala (core/src/main/scala/variant/Horde.scala)
  • Off-boarding risk: anonymized user #1
  • Off-boarding risk: anonymized user #2

New (7)

  • Documentation: no architecture or design documentation
  • Documentation: no project overview (README.md)
  • Documentation: no usage examples (README.md)
  • Documentation: other issue (README.md)
  • Off-boarding risk: anonymized user #1
  • Off-boarding risk: anonymized user #2
  • Projects may be oversized for their cohesion

Changes since last survey

  • 10 commits — 7 feature/other, 3 fixes

By area

  • (repo) — 4 commits
  • test-kit/src — 2 commits
  • (root) — 1 commit
  • core/src — 1 commit
  • project/build.properties — 1 commit
  • project/plugins.sbt — 1 commit

Notable commits

  • fix: Merge pull request #888 from Simek/glyph-typgraphy-fix
  • fix: add failing regression test
  • fix: bump scalaVersion to match scalalib to fix ci
  • change: Merge pull request #885 from scala-steward/update/scalalib-core-11.11.0
  • change: Merge pull request #889 from scala-steward/update/sbt-scalafix-0.14.9
  • change: Merge pull request #890 from scala-steward/update/sbt-2.0.9
  • change: Update sbt to 2.0.9
  • change: Update sbt-scalafix to 0.14.9
  • change: unify returned glyph symbol in PGN format
  • change: when a test fails, change the test :smart:

Architecture

  • Unchanged — 0 containers · 1 contexts · 0 edges

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

lichess-org/scalachess was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.

About this page

  • The score is its most recent published measurement, taken on 28 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
  • Measured at commit 57d3483869abde8a7dbd867520fe78f8f7e87d79 — the exact code this score is about.
  • Scored under rubric-2026.09.16 — the same rubric and the same method as every other entry in this index.
  • Measured by watchdog.canine.dev using codehealth-analyzer preprod-2d9048c36d26.