Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Chess Laravel Package

p-chess/chess

A PHP chess library for Laravel and standalone use. Parse FEN/PGN, generate and validate legal moves, handle castling, en passant and promotion, and detect check, checkmate and stalemate through a clean object-oriented API. Ideal for building chess apps, bots and analysis tools.

Deep Wiki
Context7

Getting Started

Install with Composer and confirm the actual namespace/class names from the installed source before wiring it into application code:

composer require p-chess/chess
php artisan tinker
use PChess\Chess\Chess;

$chess = new Chess();          // starting position
$chess->move('e4');
$chess->move('e5');

echo $chess->fen();            // persist this
print_r($chess->moves());      // legal moves in current position

The source under vendor/p-chess/chess/src is the best first reference; this is a small engine package, not a Laravel-first SDK. Look first for the main Chess/Game class, FEN loading, PGN loading, move application, and legal-move generation.

First practical use case: validate a user-submitted chess move and persist the resulting FEN. Start with a queued or service-layer smoke test rather than embedding engine calls directly in controllers.

$chess = new Chess($fenFromDatabase);

try {
    $move = $chess->move($request->string('move'));
} catch (\Throwable $e) {
    // illegal move, ambiguous SAN, bad notation, etc.
}

if (!$move) {
    // package may return null/false instead of throwing
}

$newFen = $chess->fen();

Implementation Patterns

Use the engine as a domain service, not as a singleton. The Chess object carries mutable board state. Create a fresh instance per game/request/job, hydrate it from FEN or PGN, apply exactly one mutation, then persist the resulting FEN/PGN.

final class ChessMoveService
{
    public function apply(string $fen, string $move): array
    {
        $chess = new Chess($fen);

        $applied = $chess->move($move);

        if (!$applied) {
            throw ValidationException::withMessages([
                'move' => 'Illegal or ambiguous move.',
            ]);
        }

        return [
            'fen' => $chess->fen(),
            'pgn' => $chess->pgn(),
            'turn' => $chess->turn(), // verify method name in installed version
        ];
    }
}

Store FEN as the current snapshot and PGN as the replayable history. A common schema is:

$table->string('fen', 120)->nullable();
$table->longText('pgn')->nullable();
$table->string('status')->default('active');

FEN is cheap to load and ideal for resuming a game. PGN is better for displaying move history and exporting games. Store both if you need fast resume plus full history.

Use a custom validation rule for move input. Keep the rule thin and delegate to the service so tests can target one place.

final class LegalChessMoveRule implements ValidationRule
{
    public function __construct(private string $fen) {}

    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $chess = new Chess($this->fen);

        if (!$chess->move($value)) {
            $fail('The move is not legal in the current position.');
        }
    }
}

Build API resources from engine state. Expose only the fields clients need rather than dumping the entire object graph.

return [
    'fen' => $chess->fen(),
    'turn' => $chess->turn(),
    'legal_moves' => $chess->moves(),
    'in_check' => $chess->inCheck(),
    'game_over' => $chess->gameOver(),
];

Queue heavy work. Move generation and any search/analysis loop are CPU-bound. Do not run iterative analysis in a normal HTTP request. Put it in a job, enforce depth/node/time limits, and return FEN/PGN plus analysis metadata.

final class AnalyzePosition implements ShouldQueue
{
    public function __construct(public string $fen) {}

    public function handle(): void
    {
        $chess = new Chess($this->fen);

        // Bound any loop yourself; this package is not Stockfish.
        foreach ($chess->moves() as $move) {
            // evaluate hypothetical lines on cloned/rehydrated positions
        }
    }
}

Rehydrate for simulations instead of relying on deep cloning. If you explore candidate lines, create a new engine from the current FEN for each branch:

$child = new Chess($parentFen);
$child->move($candidate);

This avoids accidental shared-state bugs and matches the package's FEN-centric design.

Keep a thin application wrapper. Because the package is small and its API may vary between versions, isolate it behind ChessMoveService, ChessGamePresenter, or similar classes. That gives you one place to adjust when method names or exception behavior change.

Gotchas and Tips

  • Move notation matters. SAN (Nf3, e4, O-O, e8=Q) and coordinate notation (g1f3, e2e4) are not interchangeable. Decide which format your API accepts and normalize before calling the engine.
  • Illegal moves may throw or return false/null. Check the installed version’s behavior and handle both patterns defensively in one service.
  • move() mutates the object. Do not reuse a Chess instance across requests, queued jobs, or hypothetical branches without rehydrating from FEN.
  • Clone with care. If you use clone, verify the board and piece objects are actually independent. Rehydrating from FEN is safer and easier to reason about.
  • PGN is not just a move list. Headers, comments, variations, and result markers can affect parsing. Test with real PGNs from Lichess/Chess.com exports, not only engine-generated strings.
  • FEN counters are easy to corrupt. Preserve halfmove clock and fullmove number correctly when persisting; do not rebuild FEN manually from board pieces.
  • En passant and castling rights are stateful. Always load and save the full FEN rather than only piece placement.
  • Check game-over states explicitly. Legal move generation can return an empty list for checkmate and stalemate; distinguish them with inCheck()/gameOver() or the equivalent methods.
  • This is not an analysis engine. Expect legal move generation and game rules, not Stockfish-grade evaluation. Set strict CPU/time budgets for any search loop.
  • No Laravel auto-discovery assumptions. The package likely needs no service provider or config file. If there is no config, do not invent one; wrap settings in your own config.
  • Debug with FEN snapshots. Log FEN before and after every move in staging. When a bug appears, reproduce it by loading the exact FEN into a fresh object.
  • Version-pin in production. A small package can change API details between releases; run your move-validation and PGN round-trip tests after upgrades.
  • Test with fixtures. Cover castling, en passant, promotion, checkmate, stalemate, and ambiguous SAN moves. These are the cases most likely to break an integration.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route