← Chess results

Chess

ProCreations grug 27b GGUF IQ4 · typescript

Initial view of Chess

Browser check: Artifact runtime error. This is a technical check, not a quality review.

Reviews & generation details

Reviews

No human review yet. Unreviewed does not mean unsuccessful.

Generation context

Imported historical artifact. Its exact original instructions and lineage are not known.

Generation prompt · exact text unavailable

See the current prompt for reference. It may differ from the instructions used to generate this artifact.

Inspect original source 59,258 bytes · SHA-256 15986b979a67
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Chess — Rules-complete browser game with AI</title>
<style>
/* ── css: layout ── */
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:'Segoe UI',system-ui,sans-serif;background:#1e1e1e;color:#eee;overflow:hidden}
#layout{display:flex;align-items:center;justify-content:center;height:100vh;gap:24px;padding:16px}
#board-wrap{position:relative;flex-shrink:0}
#board{width:512px;height:512px;display:grid;grid-template-columns:repeat(8,1fr);grid-template-rows:repeat(8,1fr);border:6px solid #4a3525;border-radius:4px}
.square{position:relative;display:flex;align-items:center;justify-content:center;font-size:3.4em;cursor:pointer;user-select:none;transition:background .12s}
.square.light{background:#f0d9b5}
.square.dark{background:#b58863}
.square.last-move.light{background:#f7ec68}
.square.last-move.dark{background:#daa520}
.square.selected.light{background:#f7f769}
.square.selected.dark{background:#baca2b}
.square.legal-dot::after{content:'';position:absolute;width:22px;height:22px;background:rgba(0,0,0,.25);border-radius:50%}
.square.legal-ring::after{content:'';position:absolute;width:100%;height:100%;border:6px solid rgba(0,0,0,.3);border-radius:50%;box-sizing:border-box}
.square.check{box-shadow:inset 0 0 18px 6px rgba(255,40,40,.7)}
.square:hover{filter:brightness(1.08)}
#sidebar{width:260px;height:512px;display:flex;flex-direction:column;gap:12px;padding:12px;background:#2a2a2a;border-radius:8px;overflow:hidden}
#captured-trays{display:flex;flex-direction:column;gap:4px}
.tray{min-height:28px;font-size:1.4em;line-height:1;padding:2px 4px;background:#222;border-radius:4px;word-break:break-all}
#controls{display:flex;flex-direction:column;gap:6px}
#controls button{padding:8px;border:none;border-radius:6px;background:#4a3525;color:#f0d9b5;cursor:pointer;font-size:.9em;transition:background .15s}
#controls button:hover{background:#6b5342}
#controls button.active{background:#daa520;color:#1e1e1e}
#move-list{flex:1;overflow-y:auto;font-family:monospace;font-size:.85em;line-height:1.6;padding:4px;background:#222;border-radius:4px}
.move-entry{padding:2px 4px;border-radius:2px}
.move-entry:hover{background:#333}
#promotion-overlay{position:absolute;background:#2a2a2a;border:3px solid #daa520;border-radius:10px;padding:6px;display:flex;gap:6px;z-index:100;box-shadow:0 4px 12px rgba(0,0,0,.6)}
.promo-choice{width:64px;height:64px;font-size:2.8em;display:flex;align-items:center;justify-content:center;background:#b58863;border-radius:8px;cursor:pointer}
.promo-choice:hover{background:#daa520}
#game-banner{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,.88);color:#daa520;padding:16px 28px;border-radius:12px;font-size:1.3em;z-index:50;text-align:center}
@media(max-width:840px){#layout{flex-direction:column}#sidebar{width:100%;max-width:512px;height:auto}}
</style>
</head>
<body>
<div id="layout">
  <div id="board-wrap"><div id="board"></div></div>
  <aside id="sidebar">
    <div id="captured-trays"></div>
    <div id="controls"></div>
    <div id="move-list"></div>
    <div id="promotion-overlay" hidden=""></div>
    <div id="game-banner" hidden=""></div>
  </aside>
</div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./game":"src/game.ts","./renderer":"src/renderer.ts","./rules":"src/rules.ts","./types":"src/types.ts","./ai":"src/ai.ts"},"src/position.ts":{"./types":"src/types.ts"},"src/rules.ts":{"./types":"src/types.ts"},"src/ai.ts":{"./types":"src/types.ts","./rules":"src/rules.ts"},"src/game.ts":{"./types":"src/types.ts","./position":"src/position.ts","./rules":"src/rules.ts","./ai":"src/ai.ts"},"src/renderer.ts":{"./types":"src/types.ts"}};
function __require(id) {
  if (__cache[id]) return __cache[id].exports;
  var module = __cache[id] = { exports: {} };
  var factory = __mods[id];
  if (!factory) throw new Error("Module not found: " + id);
  factory(module.exports, function (spec) {
    var target = (__map[id] && __map[id][spec]) || spec;
    return __require(target);
  }, module);
  return module.exports;
}

// ── module: src/main.ts ──
__mods["src/main.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const game_1 = require("./game");
const renderer_1 = require("./renderer");
const rules_1 = require("./rules");
const types_1 = require("./types");
const game = new game_1.ChessGameImpl();
const boardElement = document.getElementById('board');
const sidebar = document.getElementById('sidebar');
const controls = document.getElementById('controls');
const capturedTrays = document.getElementById('captured-trays');
const moveList = document.getElementById('move-list');
const banner = document.getElementById('game-banner');
const promotionOverlay = document.getElementById('promotion-overlay');
let flipped = false;
let selectedSquare = null;
let legalDestinations = [];
let playerColor = 'white';
let aiDepth = 3;
let isSoundEnabled = true;
let aiSide = 'black';
let moveInProgress = false;
// Try restore from localStorage
if (!game.loadFromLocalStorage()) {
    game.start();
}
// Create AudioContext after user gesture
let audioContext = null;
document.addEventListener('click', () => {
    if (!audioContext) {
        audioContext = new AudioContext();
    }
}, { once: true });
function playSound(type) {
    if (!isSoundEnabled || !audioContext)
        return;
    const oscillator = audioContext.createOscillator();
    const gain = audioContext.createGain();
    oscillator.connect(gain);
    gain.connect(audioContext.destination);
    switch (type) {
        case 'move':
            oscillator.frequency.value = 400;
            oscillator.type = 'sine';
            gain.gain.value = 0.2;
            oscillator.start();
            oscillator.stop(audioContext.currentTime + 0.1);
            break;
        case 'capture':
            oscillator.frequency.value = 200;
            oscillator.type = 'square';
            gain.gain.value = 0.3;
            oscillator.start();
            oscillator.stop(audioContext.currentTime + 0.2);
            break;
        case 'check':
            oscillator.frequency.value = 600;
            oscillator.type = 'sawtooth';
            gain.gain.value = 0.2;
            oscillator.start();
            oscillator.stop(audioContext.currentTime + 0.3);
            break;
    }
}
function renderBoard() {
    boardElement.innerHTML = '';
    const legalMoves = game.legalMoves();
    for (let rank = 0; rank < 8; rank++) {
        for (let file = 0; file < 8; file++) {
            const squareIndex = flipped ? file * 8 + rank : rank * 8 + file;
            const displayRank = flipped ? 7 - rank : rank;
            const displayFile = flipped ? 7 - file : file;
            const square = displayFile * 8 + displayRank;
            const squareElement = document.createElement('div');
            squareElement.className = 'square ' + ((displayFile + displayRank) % 2 === 0 ? 'light' : 'dark');
            squareElement.dataset.square = square.toString();
            const piece = game.state.board[square];
            squareElement.textContent = (0, renderer_1.pieceUnicode)(piece);
            // Last move highlight
            if (game.state.moveHistory.length > 0) {
                const lastMove = game.state.moveHistory[game.state.moveHistory.length - 1];
                if (lastMove.from === square || lastMove.to === square) {
                    squareElement.classList.add('last-move');
                }
            }
            // Selected square
            if (selectedSquare === square) {
                squareElement.classList.add('selected');
            }
            // Legal move highlights
            if (legalDestinations.includes(square)) {
                const move = legalMoves.find(m => m.from === selectedSquare && m.to === square);
                if (move && move.capture) {
                    squareElement.classList.add('legal-ring');
                }
                else {
                    squareElement.classList.add('legal-dot');
                }
            }
            // Check highlight
            if ((0, rules_1.isCheck)(game.state) && (0, types_1.pieceType)(piece) === 6 && (0, types_1.pieceColor)(piece) === game.state.turn) {
                squareElement.classList.add('check');
            }
            squareElement.addEventListener('click', () => handleClick(square));
            boardElement.appendChild(squareElement);
        }
    }
}
function handleClick(square) {
    if (game.state.result !== 'playing')
        return;
    if (moveInProgress)
        return;
    if (playerColor === 'both')
        return;
    if (game.state.turn !== playerColor)
        return;
    const piece = game.state.board[square];
    if (selectedSquare !== null) {
        if (legalDestinations.includes(square)) {
            const matchingMove = game.legalMoves().find(move => move.from === selectedSquare && move.to === square);
            if (matchingMove) {
                if (matchingMove.promotion) {
                    showPromotionPicker(selectedSquare, square);
                    return;
                }
                applyMove(matchingMove);
                return;
            }
        }
        selectedSquare = null;
        legalDestinations = [];
        renderBoard();
        return;
    }
    if (piece !== 0 && (0, types_1.pieceColor)(piece) === game.state.turn) {
        selectedSquare = square;
        legalDestinations = game.legalMoves().filter(move => move.from === square).map(move => move.to);
        renderBoard();
        return;
    }
}
function showPromotionPicker(from, to) {
    const square = from;
    const squareElement = boardElement.querySelector(`[data-square="${square}"]`);
    if (!squareElement)
        return;
    promotionOverlay.innerHTML = '';
    promotionOverlay.style.left = squareElement.offsetLeft + 'px';
    promotionOverlay.style.top = squareElement.offsetTop + 'px';
    promotionOverlay.hidden = false;
    const pieces = game.state.turn === 'white' ? [5, 4, 3, 2] : [-5, -4, -3, -2];
    for (const piece of pieces) {
        const choice = document.createElement('div');
        choice.className = 'promo-choice';
        choice.textContent = (0, renderer_1.pieceUnicode)(piece);
        choice.addEventListener('click', () => {
            const matchingMove = game.legalMoves().find(move => move.from === from && move.to === to && move.promotion === piece);
            if (matchingMove) {
                matchingMove.promotion = piece;
                applyMove(matchingMove);
            }
            promotionOverlay.hidden = true;
            promotionOverlay.innerHTML = '';
        });
        promotionOverlay.appendChild(choice);
    }
}
function applyMove(move) {
    const lastMove = game.state.moveHistory[game.state.moveHistory.length - 1];
    if (lastMove && lastMove.enPassant) {
        const square = lastMove.from >> 3;
        game.state.board[square * 8 + (lastMove.to & 7) + 1] = 0;
    }
    game.applyMove(move);
    playSound(move.capture ? 'capture' : 'move');
    if ((0, rules_1.isCheck)(game.state)) {
        playSound('check');
    }
    selectedSquare = null;
    legalDestinations = [];
    renderBoard();
    renderMoveList();
    renderCapturedPieces();
    const result = (0, rules_1.detectGameState)(game.state);
    if (result !== 'playing') {
        showGameOver(result);
        return;
    }
    if (playerColor !== 'both' && game.state.turn !== playerColor) {
        makeAiMove();
    }
}
function makeAiMove() {
    moveInProgress = true;
    renderControls();
    const searchResult = game.aiMove(aiDepth, playerColor);
    if (searchResult.move) {
        applyMove(searchResult.move);
    }
    moveInProgress = false;
    renderControls();
}
function showGameOver(result) {
    banner.hidden = false;
    switch (result) {
        case 'white-mate':
            banner.textContent = 'White wins by checkmate!';
            break;
        case 'black-mate':
            banner.textContent = 'Black wins by checkmate!';
            break;
        case 'stalemate':
            banner.textContent = 'Stalemate — draw!';
            break;
        case 'draw-insufficient':
            banner.textContent = 'Draw by insufficient material!';
            break;
        case 'draw-50-move':
            banner.textContent = 'Draw by 50-move rule!';
            break;
        default:
            banner.textContent = 'Game over';
    }
}
function renderMoveList() {
    moveList.innerHTML = '';
    const moves = game.state.moveHistory;
    const notation = moves.map((move, index) => {
        const piece = game.state.board[move.from];
        const squareFrom = ('abcdefgh'[move.from >> 3] + (move.from & 7 + 1));
        const squareTo = ('abcdefgh'[move.to >> 3] + (move.to & 7 + 1));
        return (0, renderer_1.moveNotation)(piece, (0, types_1.pieceType)(piece), squareFrom, squareTo, move.capture, move.promotion, move.enPassant, move.shortCastle, move.longCastle, (0, rules_1.isCheck)(game.state), game.state.result.includes('mate'));
    });
    for (let i = 0; i < notation.length; i += 2) {
        const entry = document.createElement('div');
        entry.className = 'move-entry';
        entry.textContent = `${(i / 2 + 1)}. ${notation[i]} ${notation[i + 1] || ''}`;
        moveList.appendChild(entry);
    }
    moveList.scrollTop = moveList.scrollHeight;
}
function renderCapturedPieces() {
    capturedTrays.innerHTML = '';
    const whiteTray = document.createElement('div');
    whiteTray.className = 'tray';
    whiteTray.textContent = game.capturedWhite.map(renderer_1.pieceUnicode).join(' ');
    const blackTray = document.createElement('div');
    blackTray.className = 'tray';
    blackTray.textContent = game.capturedBlack.map(renderer_1.pieceUnicode).join(' ');
    capturedTrays.appendChild(whiteTray);
    capturedTrays.appendChild(blackTray);
}
function renderControls() {
    controls.innerHTML = '';
    const flipButton = document.createElement('button');
    flipButton.textContent = 'Flip Board';
    flipButton.addEventListener('click', () => {
        flipped = !flipped;
        renderBoard();
    });
    controls.appendChild(flipButton);
    const undoButton = document.createElement('button');
    undoButton.textContent = 'Undo';
    undoButton.addEventListener('click', () => {
        game.undo();
        selectedSquare = null;
        legalDestinations = [];
        renderBoard();
        renderMoveList();
        renderCapturedPieces();
        banner.hidden = true;
    });
    controls.appendChild(undoButton);
    const newButton = document.createElement('button');
    newButton.textContent = 'New Game';
    newButton.addEventListener('click', () => {
        game.newGame();
        selectedSquare = null;
        legalDestinations = [];
        renderBoard();
        renderMoveList();
        renderCapturedPieces();
        banner.hidden = true;
    });
    controls.appendChild(newButton);
    const soundButton = document.createElement('button');
    soundButton.textContent = isSoundEnabled ? '🔊 Sound On' : '🔇 Sound Off';
    soundButton.className = isSoundEnabled ? 'active' : '';
    soundButton.addEventListener('click', () => {
        isSoundEnabled = !isSoundEnabled;
        renderControls();
    });
    controls.appendChild(soundButton);
    const whiteButton = document.createElement('button');
    whiteButton.textContent = 'Play White';
    whiteButton.className = playerColor === 'white' ? 'active' : '';
    whiteButton.addEventListener('click', () => {
        playerColor = 'white';
        aiSide = 'black';
        renderControls();
    });
    controls.appendChild(whiteButton);
    const blackButton = document.createElement('button');
    blackButton.textContent = 'Play Black';
    blackButton.className = playerColor === 'black' ? 'active' : '';
    blackButton.addEventListener('click', () => {
        playerColor = 'black';
        aiSide = 'white';
        renderControls();
    });
    controls.appendChild(blackButton);
    const bothButton = document.createElement('button');
    bothButton.textContent = 'Play Both / Analysis';
    bothButton.className = playerColor === 'both' ? 'active' : '';
    bothButton.addEventListener('click', () => {
        playerColor = 'both';
        renderControls();
    });
    controls.appendChild(bothButton);
    const depth1Button = document.createElement('button');
    depth1Button.textContent = 'Depth 1';
    depth1Button.className = aiDepth === 1 ? 'active' : '';
    depth1Button.addEventListener('click', () => {
        aiDepth = 1;
        renderControls();
    });
    controls.appendChild(depth1Button);
    const depth2Button = document.createElement('button');
    depth2Button.textContent = 'Depth 2';
    depth2Button.className = aiDepth === 2 ? 'active' : '';
    depth2Button.addEventListener('click', () => {
        aiDepth = 2;
        renderControls();
    });
    controls.appendChild(depth2Button);
    const depth3Button = document.createElement('button');
    depth3Button.textContent = 'Depth 3';
    depth3Button.className = aiDepth === 3 ? 'active' : '';
    depth3Button.addEventListener('click', () => {
        aiDepth = 3;
        renderControls();
    });
    controls.appendChild(depth3Button);
}
// Expose debug interface on window
window.game = game;
window.debug = {
    fen: () => game.fen(),
    move: (moveString) => game.move(moveString),
    legalMoves: () => game.legalMoves(),
    state: () => game.state,
    result: () => (0, rules_1.detectGameState)(game.state),
};
game.start();
renderBoard();
renderMoveList();
renderCapturedPieces();
renderControls();
};

// ── module: src/types.ts ──
__mods["src/types.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BLACK_KING = exports.WHITE_KING = exports.BLACK_QUEEN = exports.WHITE_QUEEN = exports.BLACK_ROOK = exports.WHITE_ROOK = exports.BLACK_BISHOP = exports.WHITE_BISHOP = exports.BLACK_KNIGHT = exports.WHITE_KNIGHT = exports.BLACK_PAWN = exports.WHITE_PAWN = exports.EMPTY = void 0;
exports.sq = sq;
exports.squareFile = squareFile;
exports.squareRank = squareRank;
exports.pieceColor = pieceColor;
exports.pieceType = pieceType;
exports.isLegalSquare = isLegalSquare;
exports.sqNotation = sqNotation;
exports.EMPTY = 0;
exports.WHITE_PAWN = 1;
exports.BLACK_PAWN = -1;
exports.WHITE_KNIGHT = 2;
exports.BLACK_KNIGHT = -2;
exports.WHITE_BISHOP = 3;
exports.BLACK_BISHOP = -3;
exports.WHITE_ROOK = 4;
exports.BLACK_ROOK = -4;
exports.WHITE_QUEEN = 5;
exports.BLACK_QUEEN = -5;
exports.WHITE_KING = 6;
exports.BLACK_KING = -6;
function sq(file, rank) {
    return file * 8 + rank;
}
function squareFile(square) {
    return square >> 3;
}
function squareRank(square) {
    return square & 7;
}
function pieceColor(piece) {
    if (piece === exports.EMPTY)
        return 'white';
    return piece > 0 ? 'white' : 'black';
}
function pieceType(piece) {
    return Math.abs(piece);
}
function isLegalSquare(square) {
    const file = square >> 3;
    const rank = square & 7;
    return ((file ^ rank) & 1) === 0 && file >= 0 && file <= 7 && rank >= 0 && rank <= 7;
}
function sqNotation(square) {
    return `${'abcdefgh'[squareFile(square)]}${squareRank(square) + 1}`;
}
};

// ── module: src/position.ts ──
__mods["src/position.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.newInitialPosition = newInitialPosition;
const types_1 = require("./types");
function newInitialPosition() {
    const board = new Array(64).fill(types_1.EMPTY);
    // White pieces
    board[0] = types_1.WHITE_ROOK;
    board[1] = types_1.WHITE_KNIGHT;
    board[2] = types_1.WHITE_BISHOP;
    board[3] = types_1.WHITE_QUEEN;
    board[4] = types_1.WHITE_KING;
    board[5] = types_1.WHITE_BISHOP;
    board[6] = types_1.WHITE_KNIGHT;
    board[7] = types_1.WHITE_ROOK;
    for (let file = 0; file < 8; file++)
        board[file * 8 + 1] = types_1.WHITE_PAWN;
    // Black pieces
    board[64 + 0] = types_1.BLACK_ROOK;
    board[64 + 1] = types_1.BLACK_KNIGHT;
    board[64 + 2] = types_1.BLACK_BISHOP;
    board[64 + 3] = types_1.BLACK_QUEEN;
    board[64 + 4] = types_1.BLACK_KING;
    board[64 + 5] = types_1.BLACK_BISHOP;
    board[64 + 6] = types_1.BLACK_KNIGHT;
    board[64 + 7] = types_1.BLACK_ROOK;
    for (let file = 0; file < 8; file++)
        board[file * 8 + 6] = types_1.BLACK_PAWN;
    return {
        board,
        turn: 'white',
        enPassantSquare: null,
        whiteShortCastle: true,
        whiteLongCastle: true,
        blackShortCastle: true,
        blackLongCastle: true,
        moveHistory: [],
        fiftyMoveClock: 0,
        result: 'playing',
    };
}
};

// ── module: src/rules.ts ──
__mods["src/rules.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.filterLegalMoves = filterLegalMoves;
exports.moveLeavesKingInCheck = moveLeavesKingInCheck;
exports.isCheck = isCheck;
exports.findKing = findKing;
exports.isSquareAttacked = isSquareAttacked;
exports.detectGameState = detectGameState;
const types_1 = require("./types");
function filterLegalMoves(state) {
    return generateAllMoves(state).filter((move) => !moveLeavesKingInCheck(state, move));
}
function generateAllMoves(state) {
    const board = state.board;
    const moves = [];
    const turn = state.turn;
    for (let square = 0; square < 64; square++) {
        const piece = board[square];
        if ((0, types_1.pieceColor)(piece) !== turn)
            continue;
        const type = (0, types_1.pieceType)(piece);
        switch (type) {
            case 1:
                generatePawnMoves(board, square, turn, state.enPassantSquare, moves);
                break;
            case 2:
                generateKnightMoves(board, square, moves);
                break;
            case 3:
                generateSlidingMoves(board, square, [[-1, -1], [-1, 1], [1, -1], [1, 1]], moves);
                break;
            case 4:
                generateSlidingMoves(board, square, [[0, 1], [0, -1], [1, 0], [-1, 0]], moves);
                break;
            case 5:
                generateSlidingMoves(board, square, [[-1, -1], [-1, 1], [1, -1], [1, 1], [0, 1], [0, -1], [1, 0], [-1, 0]], moves);
                break;
            case 6:
                generateKingMoves(board, square, turn, state, moves);
                break;
        }
    }
    return moves;
}
function generateSlidingMoves(board, from, directions, moves) {
    const piece = board[from];
    const file = (0, types_1.squareFile)(from);
    const rank = (0, types_1.squareRank)(from);
    const friendlyColor = (0, types_1.pieceColor)(piece);
    for (const [dFile, dRank] of directions) {
        let f = file + dFile;
        let r = rank + dRank;
        while (f >= 0 && f < 8 && r >= 0 && r < 8) {
            const square = (0, types_1.sq)(f, r);
            const target = board[square];
            const targetColor = (0, types_1.pieceColor)(target);
            if (targetColor === friendlyColor)
                break;
            moves.push({
                from,
                to: square,
                enPassant: false,
                promotion: null,
                shortCastle: false,
                longCastle: false,
                pawnFile: null,
                pawnRank: null,
                capture: target,
            });
            if (targetColor !== friendlyColor)
                break;
            f += dFile;
            r += dRank;
        }
    }
}
function generateKnightMoves(board, from, moves) {
    const file = (0, types_1.squareFile)(from);
    const rank = (0, types_1.squareRank)(from);
    const piece = board[from];
    const friendlyColor = (0, types_1.pieceColor)(piece);
    for (const [dFile, dRank] of [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]]) {
        const f = file + dFile;
        const r = rank + dRank;
        if (f < 0 || f > 7 || r < 0 || r > 7)
            continue;
        const square = (0, types_1.sq)(f, r);
        const target = board[square];
        const targetColor = (0, types_1.pieceColor)(target);
        if (targetColor === friendlyColor)
            continue;
        moves.push({
            from,
            to: square,
            enPassant: false,
            promotion: null,
            shortCastle: false,
            longCastle: false,
            pawnFile: null,
            pawnRank: null,
            capture: target,
        });
    }
}
function generatePawnMoves(board, from, color, enPassantSquare, moves) {
    const file = (0, types_1.squareFile)(from);
    const rank = (0, types_1.squareRank)(from);
    const direction = color === 'white' ? 1 : -1;
    const promotionRank = color === 'white' ? 7 : 0;
    const startRank = color === 'white' ? 1 : 6;
    const forward = (0, types_1.sq)(file, rank + direction);
    const forwardSquare = rank + direction;
    const forward2Square = rank + 2 * direction;
    if ((0, types_1.isLegalSquare)(forward)) {
        if (board[forward] === types_1.EMPTY) {
            if (forwardSquare === promotionRank) {
                for (const promoPiece of [5, 4, 3, 2]) {
                    const sign = color === 'white' ? 1 : -1;
                    moves.push({
                        from,
                        to: forward,
                        enPassant: false,
                        promotion: promoPiece * sign,
                        shortCastle: false,
                        longCastle: false,
                        pawnFile: file,
                        pawnRank: rank,
                        capture: null,
                    });
                }
            }
            else {
                moves.push({
                    from,
                    to: forward,
                    enPassant: false,
                    promotion: null,
                    shortCastle: false,
                    longCastle: false,
                    pawnFile: file,
                    pawnRank: rank,
                    capture: null,
                });
                if (rank === startRank && (0, types_1.isLegalSquare)((0, types_1.sq)(file, forward2Square)) && board[(0, types_1.sq)(file, forward2Square)] === types_1.EMPTY) {
                    moves.push({
                        from,
                        to: (0, types_1.sq)(file, forward2Square),
                        enPassant: false,
                        promotion: null,
                        shortCastle: false,
                        longCastle: false,
                        pawnFile: file,
                        pawnRank: rank,
                        capture: null,
                    });
                }
            }
        }
    }
    for (const captureFile of [file - 1, file + 1]) {
        if (captureFile < 0 || captureFile > 7)
            continue;
        const captureSquare = (0, types_1.sq)(captureFile, forwardSquare);
        if (!(0, types_1.isLegalSquare)(captureSquare))
            continue;
        const targetPiece = board[captureSquare];
        const oppositeColorPawn = targetPiece !== types_1.EMPTY && (0, types_1.pieceColor)(targetPiece) !== color;
        if (oppositeColorPawn) {
            if (forwardSquare === promotionRank) {
                for (const promoPiece of [5, 4, 3, 2]) {
                    const sign = color === 'white' ? 1 : -1;
                    moves.push({
                        from,
                        to: captureSquare,
                        enPassant: false,
                        promotion: promoPiece * sign,
                        shortCastle: false,
                        longCastle: false,
                        pawnFile: file,
                        pawnRank: rank,
                        capture: targetPiece,
                    });
                }
            }
            else {
                moves.push({
                    from,
                    to: captureSquare,
                    enPassant: false,
                    promotion: null,
                    shortCastle: false,
                    longCastle: false,
                    pawnFile: file,
                    pawnRank: rank,
                    capture: targetPiece,
                });
            }
        }
        if (enPassantSquare === captureSquare) {
            moves.push({
                from,
                to: captureSquare,
                enPassant: true,
                promotion: null,
                shortCastle: false,
                longCastle: false,
                pawnFile: file,
                pawnRank: rank,
                capture: color === 'white' ? -1 : 1,
            });
        }
    }
}
function generateKingMoves(board, from, color, state, moves) {
    const file = (0, types_1.squareFile)(from);
    const rank = (0, types_1.squareRank)(from);
    for (const [dFile, dRank] of [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]) {
        const f = file + dFile;
        const r = rank + dRank;
        if (f < 0 || f > 7 || r < 0 || r > 7)
            continue;
        const square = (0, types_1.sq)(f, r);
        const target = board[square];
        const targetColor = (0, types_1.pieceColor)(target);
        if (targetColor === color)
            continue;
        moves.push({
            from,
            to: square,
            enPassant: false,
            promotion: null,
            shortCastle: false,
            longCastle: false,
            pawnFile: null,
            pawnRank: null,
            capture: target,
        });
    }
    if (color === 'white') {
        if (state.whiteShortCastle) {
            const kingFrom = (0, types_1.sq)(4, 0);
            const kingTo = (0, types_1.sq)(6, 0);
            if (board[kingTo] === types_1.EMPTY && board[(0, types_1.sq)(5, 0)] === types_1.EMPTY) {
                moves.push({
                    from: kingFrom,
                    to: kingTo,
                    enPassant: false,
                    promotion: null,
                    shortCastle: true,
                    longCastle: false,
                    pawnFile: null,
                    pawnRank: null,
                    capture: null,
                });
            }
        }
        if (state.whiteLongCastle) {
            const kingFrom = (0, types_1.sq)(4, 0);
            const kingTo = (0, types_1.sq)(2, 0);
            if (board[kingTo] === types_1.EMPTY && board[(0, types_1.sq)(3, 0)] === types_1.EMPTY && board[(0, types_1.sq)(1, 0)] === types_1.EMPTY) {
                moves.push({
                    from: kingFrom,
                    to: kingTo,
                    enPassant: false,
                    promotion: null,
                    shortCastle: false,
                    longCastle: true,
                    pawnFile: null,
                    pawnRank: null,
                    capture: null,
                });
            }
        }
    }
    else {
        if (state.blackShortCastle) {
            const kingFrom = (0, types_1.sq)(4, 7);
            const kingTo = (0, types_1.sq)(6, 7);
            if (board[kingTo] === types_1.EMPTY && board[(0, types_1.sq)(5, 7)] === types_1.EMPTY) {
                moves.push({
                    from: kingFrom,
                    to: kingTo,
                    enPassant: false,
                    promotion: null,
                    shortCastle: true,
                    longCastle: false,
                    pawnFile: null,
                    pawnRank: null,
                    capture: null,
                });
            }
        }
        if (state.blackLongCastle) {
            const kingFrom = (0, types_1.sq)(4, 7);
            const kingTo = (0, types_1.sq)(2, 7);
            if (board[kingTo] === types_1.EMPTY && board[(0, types_1.sq)(3, 7)] === types_1.EMPTY && board[(0, types_1.sq)(1, 7)] === types_1.EMPTY) {
                moves.push({
                    from: kingFrom,
                    to: kingTo,
                    enPassant: false,
                    promotion: null,
                    shortCastle: false,
                    longCastle: true,
                    pawnFile: null,
                    pawnRank: null,
                    capture: null,
                });
            }
        }
    }
}
function moveLeavesKingInCheck(state, move) {
    const next = copyState(state);
    applyMoveToState(next, move);
    return isCheck(next);
}
function isCheck(state) {
    const kingSquare = findKing(state.board, state.turn);
    if (kingSquare < 0)
        return false;
    return isSquareAttacked(state.board, kingSquare, state.turn);
}
function findKing(board, color) {
    const king = color === 'white' ? types_1.WHITE_KING : types_1.BLACK_KING;
    for (let square = 0; square < 64; square++) {
        if (board[square] === king)
            return square;
    }
    return -1;
}
function isSquareAttacked(board, square, color) {
    return !!generateAttackingMoves(board, square).find(move => (0, types_1.pieceColor)(board[move.from]) !== color);
}
function generateAttackingMoves(board, square) {
    const moves = [];
    const rank = (square & 7);
    const file = (square >> 3);
    // Pawn attacks
    const pawnAttackDirections = [[-1, -1], [-1, 1], [1, -1], [1, 1]];
    for (const [dFile, dRank] of pawnAttackDirections) {
        const f = file + dFile;
        const r = rank + dRank;
        if (f >= 0 && f < 8 && r >= 0 && r < 8) {
            const from = f * 8 + r;
            const piece = board[from];
            if ((0, types_1.pieceType)(piece) === 1 && (0, types_1.pieceColor)(piece) === 'white' && dRank > 0 || (0, types_1.pieceType)(piece) === 1 && (0, types_1.pieceColor)(piece) === 'black' && dRank < 0) {
                moves.push({ from, to: square, enPassant: false, promotion: null, shortCastle: false, longCastle: false, pawnFile: null, pawnRank: null, capture: board[square] });
            }
        }
    }
    // Knight attacks
    const knightMoves = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]];
    for (const [dFile, dRank] of knightMoves) {
        const f = file + dFile;
        const r = rank + dRank;
        if (f >= 0 && f < 8 && r >= 0 && r < 8) {
            const from = f * 8 + r;
            if ((0, types_1.pieceType)(board[from]) === 2) {
                moves.push({ from, to: square, enPassant: false, promotion: null, shortCastle: false, longCastle: false, pawnFile: null, pawnRank: null, capture: board[square] });
            }
        }
    }
    // King attacks
    const kingMoves = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]];
    for (const [dFile, dRank] of kingMoves) {
        const f = file + dFile;
        const r = rank + dRank;
        if (f >= 0 && f < 8 && r >= 0 && r < 8) {
            const from = f * 8 + r;
            if ((0, types_1.pieceType)(board[from]) === 6) {
                moves.push({ from, to: square, enPassant: false, promotion: null, shortCastle: false, longCastle: false, pawnFile: null, pawnRank: null, capture: board[square] });
            }
        }
    }
    // Sliding piece attacks
    const slidingDirections = [
        { types: [3, 5], directions: [[-1, -1], [-1, 1], [1, -1], [1, 1]] },
        { types: [4, 5], directions: [[0, 1], [0, -1], [1, 0], [-1, 0]] },
    ];
    for (const sliding of slidingDirections) {
        for (const [dFile, dRank] of sliding.directions) {
            let f = file + dFile;
            let r = rank + dRank;
            while (f >= 0 && f < 8 && r >= 0 && r < 8) {
                const from = f * 8 + r;
                const piece = board[from];
                if ((0, types_1.pieceType)(piece) === 0) {
                    f += dFile;
                    r += dRank;
                    continue;
                }
                if (sliding.types.includes((0, types_1.pieceType)(piece))) {
                    moves.push({ from, to: square, enPassant: false, promotion: null, shortCastle: false, longCastle: false, pawnFile: null, pawnRank: null, capture: board[square] });
                }
                break;
            }
        }
    }
    return moves;
}
function applyMoveToState(state, move) {
    state.board[move.to] = state.board[move.from];
    state.board[move.from] = types_1.EMPTY;
    if (move.enPassant) {
        const rank = (move.to & 7);
        state.board[(rank - 1) + ((move.to >> 3) * 8)] = types_1.EMPTY;
    }
    if (move.promotion) {
        state.board[move.to] = move.promotion;
    }
    if (move.shortCastle) {
        const rank = (move.to & 7);
        const file = (move.to >> 3);
        state.board[(file - 1) * 8 + rank] = state.board[(file + 1) * 8 + rank];
        state.board[(file + 1) * 8 + rank] = types_1.EMPTY;
    }
    if (move.longCastle) {
        const rank = (move.to & 7);
        const file = (move.to >> 3);
        state.board[(file + 1) * 8 + rank] = state.board[(file - 2) * 8 + rank];
        state.board[(file - 2) * 8 + rank] = types_1.EMPTY;
    }
    const nextTurn = state.turn === 'white' ? 'black' : 'white';
    state.turn = nextTurn;
    if (move.pawnFile !== null && move.pawnRank !== null) {
        if (Math.abs((move.to >> 3) - move.pawnFile) === 0 && Math.abs((move.to & 7) - move.pawnRank) === 2) {
            state.enPassantSquare = move.pawnFile * 8 + ((move.to & 7) + move.pawnRank) / 2;
        }
        else {
            state.enPassantSquare = null;
        }
    }
    else {
        state.enPassantSquare = null;
    }
    state.fiftyMoveClock = (move.pawnFile !== null || move.capture !== null || move.promotion !== null) ? 0 : state.fiftyMoveClock + 1;
}
function copyState(state) {
    return {
        board: [...state.board],
        turn: state.turn,
        enPassantSquare: state.enPassantSquare,
        whiteShortCastle: state.whiteShortCastle,
        whiteLongCastle: state.whiteLongCastle,
        blackShortCastle: state.blackShortCastle,
        blackLongCastle: state.blackLongCastle,
        moveHistory: [...state.moveHistory],
        fiftyMoveClock: state.fiftyMoveClock,
        result: state.result,
    };
}
function detectGameState(state) {
    if (state.fiftyMoveClock >= 50)
        return 'draw-50-move';
    if (insufficientMaterial(state.board))
        return 'draw-insufficient';
    const legalMoves = filterLegalMoves(state);
    if (legalMoves.length === 0) {
        if (isCheck(state)) {
            return state.turn === 'white' ? 'black-mate' : 'white-mate';
        }
        return 'stalemate';
    }
    return 'playing';
}
function insufficientMaterial(board) {
    const pieces = board.filter(piece => piece !== types_1.EMPTY);
    const types = pieces.map(types_1.pieceType).sort();
    const colors = pieces.map(types_1.pieceColor);
    if (types.length === 0)
        return true;
    if (types.length === 1)
        return true;
    const whitePieces = pieces.filter(p => (0, types_1.pieceColor)(p) === 'white');
    const blackPieces = pieces.filter(p => (0, types_1.pieceColor)(p) === 'black');
    if (whitePieces.length === 1 && blackPieces.length === 1)
        return true;
    if (whitePieces.length === 1 && blackPieces.length === 2) {
        const blackTypes = blackPieces.map(types_1.pieceType).sort();
        if (blackTypes[1] === 3 || blackTypes[1] === 2)
            return true;
    }
    if (blackPieces.length === 1 && whitePieces.length === 2) {
        const whiteTypes = whitePieces.map(types_1.pieceType).sort();
        if (whiteTypes[1] === 3 || whiteTypes[1] === 2)
            return true;
    }
    return false;
}
};

// ── module: src/ai.ts ──
__mods["src/ai.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.evaluateState = evaluateState;
exports.findBestMove = findBestMove;
const types_1 = require("./types");
const rules_1 = require("./rules");
const MATERIAL_VALUES = {
    pawn: 100,
    knight: 320,
    bishop: 330,
    rook: 500,
    queen: 900,
    king: 0,
};
const PIECE_SQUARE_TABLES = [
    // Pawn tables
    [
        [0, 0, 0, 0, 0, 0, 0, 0],
        [50, 50, 50, 50, 50, 50, 50, 50],
        [10, 10, 20, 30, 30, 20, 10, 10],
        [5, 5, 10, 25, 25, 10, 5, 5],
        [0, 0, 0, 20, 20, 0, 0, 0],
        [5, -5, -10, 0, 0, -10, -5, 5],
        [5, 10, 10, -20, -20, 10, 10, 5],
        [0, 0, 0, 0, 0, 0, 0, 0],
    ],
    // Knight tables
    [
        [-50, -40, -30, -30, -30, -30, -40, -50],
        [-40, -20, 0, 0, 0, 0, -20, -40],
        [-30, 0, 10, 15, 15, 10, 0, -30],
        [-30, 5, 15, 20, 20, 15, 5, -30],
        [-30, 0, 15, 20, 20, 15, 0, -30],
        [-30, 5, 10, 15, 15, 10, 5, -30],
        [-40, -20, 0, 5, 5, 0, -20, -40],
        [-50, -40, -30, -30, -30, -30, -40, -50],
    ],
    // Bishop tables
    [
        [-20, -10, -10, -10, -10, -10, -10, -20],
        [-10, 0, 0, 0, 0, 0, 0, -10],
        [-10, 0, 5, 10, 10, 5, 0, -10],
        [-10, 5, 5, 10, 10, 5, 5, -10],
        [-10, 0, 10, 10, 10, 10, 0, -10],
        [-10, 10, 10, 10, 10, 10, 10, -10],
        [-10, 5, 0, 0, 0, 0, 5, -10],
        [-20, -10, -10, -10, -10, -10, -10, -20],
    ],
    // Rook tables
    [
        [0, 0, 0, 0, 0, 0, 0, 0],
        [5, 10, 10, 10, 10, 10, 10, 5],
        [-5, 0, 0, 0, 0, 0, 0, -5],
        [-5, 0, 0, 0, 0, 0, 0, -5],
        [-5, 0, 0, 0, 0, 0, 0, -5],
        [-5, 0, 0, 0, 0, 0, 0, -5],
        [-5, 0, 0, 0, 0, 0, 0, -5],
        [0, 0, 0, 5, 5, 0, 0, 0],
    ],
    // Queen tables
    [
        [-20, -10, -10, -5, -5, -10, -10, -20],
        [-10, 0, 0, 0, 0, 0, 0, -10],
        [-10, 0, 5, 5, 5, 5, 0, -10],
        [-5, 0, 5, 5, 5, 5, 0, -5],
        [0, 0, 5, 5, 5, 5, 0, -5],
        [-10, 5, 5, 5, 5, 5, 0, -10],
        [-10, 0, 5, 0, 0, 0, 0, -10],
        [-20, -10, -10, -5, -5, -10, -10, -20],
    ],
];
function evaluateState(state) {
    const board = state.board;
    let score = 0;
    for (let square = 0; square < 64; square++) {
        const piece = board[square];
        if (piece === types_1.EMPTY)
            continue;
        const type = (0, types_1.pieceType)(piece);
        const color = (0, types_1.pieceColor)(piece);
        const file = (0, types_1.squareFile)(square);
        const rank = (0, types_1.squareRank)(square);
        const materialValue = materialValueForPiece(type);
        const pstValue = pstValueForPiece(type, file, rank, color);
        if (color === 'white') {
            score += materialValue + pstValue;
        }
        else {
            score -= materialValue + pstValue;
        }
    }
    return score;
}
function materialValueForPiece(type) {
    switch (type) {
        case 1: return MATERIAL_VALUES.pawn;
        case 2: return MATERIAL_VALUES.knight;
        case 3: return MATERIAL_VALUES.bishop;
        case 4: return MATERIAL_VALUES.rook;
        case 5: return MATERIAL_VALUES.queen;
        case 6: return MATERIAL_VALUES.king;
        default: return 0;
    }
}
function pstValueForPiece(type, file, rank, color) {
    if (type === 6)
        return 0;
    const table = PIECE_SQUARE_TABLES[type - 1];
    if (!table)
        return 0;
    const pstRank = color === 'white' ? rank : 7 - rank;
    return table[pstRank][file];
}
function findBestMove(state, depth, side, timeLimit) {
    return minimax(state, depth, side, timeLimit);
}
function minimax(state, depth, side, timeLimit) {
    const startTime = Date.now();
    let bestMove = null;
    let bestScore = -Infinity;
    let alpha = -Infinity;
    let beta = Infinity;
    const legalMoves = (0, rules_1.filterLegalMoves)(state);
    if (legalMoves.length === 0) {
        return { move: null, score: 0 };
    }
    // Move ordering: captures first
    const moves = legalMoves.sort((a, b) => {
        const aCaptureValue = a.capture ? materialValueForPiece((0, types_1.pieceType)(a.capture)) : 0;
        const bCaptureValue = b.capture ? materialValueForPiece((0, types_1.pieceType)(b.capture)) : 0;
        return bCaptureValue - aCaptureValue;
    });
    for (const move of moves) {
        if (timeLimit && Date.now() - startTime > timeLimit) {
            return { move: bestMove, score: bestScore };
        }
        const nextState = applyMoveForSearch(state, move);
        const score = alphaBeta(nextState, depth - 1, alpha, beta, !isMaximizing(state), timeLimit, startTime);
        if (score > bestScore) {
            bestScore = score;
            bestMove = move;
        }
        alpha = Math.max(alpha, score);
        if (timeLimit && Date.now() - startTime > timeLimit) {
            return { move: bestMove, score: bestScore };
        }
    }
    return { move: bestMove, score: bestScore };
}
function alphaBeta(state, depth, alpha, beta, isMax, timeLimit, startTime) {
    if (timeLimit && startTime && Date.now() - startTime > timeLimit) {
        return evaluateState(state);
    }
    if (depth === 0) {
        return quiescence(state, alpha, beta, isMax, timeLimit, startTime);
    }
    const legalMoves = (0, rules_1.filterLegalMoves)(state);
    if (legalMoves.length === 0) {
        return evaluateState(state);
    }
    const moves = legalMoves.sort((a, b) => {
        const aCaptureValue = a.capture ? materialValueForPiece((0, types_1.pieceType)(a.capture)) : 0;
        const bCaptureValue = b.capture ? materialValueForPiece((0, types_1.pieceType)(b.capture)) : 0;
        return bCaptureValue - aCaptureValue;
    });
    if (isMax) {
        let value = -Infinity;
        for (const move of moves) {
            const nextState = applyMoveForSearch(state, move);
            value = Math.max(value, alphaBeta(nextState, depth - 1, alpha, beta, false, timeLimit, startTime));
            alpha = Math.max(alpha, value);
            if (timeLimit && startTime && Date.now() - startTime > timeLimit) {
                return value;
            }
            if (beta <= alpha)
                break;
        }
        return value;
    }
    else {
        let value = Infinity;
        for (const move of moves) {
            const nextState = applyMoveForSearch(state, move);
            value = Math.min(value, alphaBeta(nextState, depth - 1, alpha, beta, true, timeLimit, startTime));
            beta = Math.min(beta, value);
            if (timeLimit && startTime && Date.now() - startTime > timeLimit) {
                return value;
            }
            if (beta <= alpha)
                break;
        }
        return value;
    }
}
function quiescence(state, alpha, beta, isMax, timeLimit, startTime) {
    const currentValue = evaluateState(state);
    if (isMax) {
        if (currentValue >= beta)
            return currentValue;
        if (currentValue > alpha)
            alpha = currentValue;
    }
    else {
        if (currentValue <= alpha)
            return currentValue;
        if (currentValue < beta)
            beta = currentValue;
    }
    const legalMoves = (0, rules_1.filterLegalMoves)(state).filter(move => move.capture);
    if (isMax) {
        for (const move of legalMoves) {
            const nextState = applyMoveForSearch(state, move);
            const score = quiescence(nextState, alpha, beta, false, timeLimit, startTime);
            if (score > alpha)
                alpha = score;
            if (timeLimit && startTime && Date.now() - startTime > timeLimit) {
                return alpha;
            }
            if (beta <= alpha)
                break;
        }
        return alpha;
    }
    else {
        for (const move of legalMoves) {
            const nextState = applyMoveForSearch(state, move);
            const score = quiescence(nextState, alpha, beta, true, timeLimit, startTime);
            if (score < beta)
                beta = score;
            if (timeLimit && startTime && Date.now() - startTime > timeLimit) {
                return beta;
            }
            if (beta <= alpha)
                break;
        }
        return beta;
    }
}
function applyMoveForSearch(state, move) {
    const next = { ...state, board: [...state.board], moveHistory: [...state.moveHistory] };
    next.board[move.to] = next.board[move.from];
    next.board[move.from] = types_1.EMPTY;
    if (move.enPassant) {
        const rank = (move.to & 7);
        next.board[(rank - 1) + ((move.to >> 3) * 8)] = types_1.EMPTY;
    }
    if (move.promotion) {
        next.board[move.to] = move.promotion;
    }
    if (move.shortCastle) {
        const rank = (move.to & 7);
        const file = (move.to >> 3);
        next.board[(file - 1) * 8 + rank] = next.board[(file + 1) * 8 + rank];
        next.board[(file + 1) * 8 + rank] = types_1.EMPTY;
    }
    if (move.longCastle) {
        const rank = (move.to & 7);
        const file = (move.to >> 3);
        next.board[(file + 1) * 8 + rank] = next.board[(file - 2) * 8 + rank];
        next.board[(file - 2) * 8 + rank] = types_1.EMPTY;
    }
    next.turn = state.turn === 'white' ? 'black' : 'white';
    if (move.pawnFile !== null && move.pawnRank !== null) {
        if (Math.abs((move.to >> 3) - move.pawnFile) === 0 && Math.abs((move.to & 7) - move.pawnRank) === 2) {
            next.enPassantSquare = move.pawnFile * 8 + move.pawnRank + 1;
        }
        else {
            next.enPassantSquare = null;
        }
    }
    else {
        next.enPassantSquare = null;
    }
    next.fiftyMoveClock = (move.pawnFile !== null || move.capture !== null || move.promotion !== null) ? 0 : state.fiftyMoveClock + 1;
    return next;
}
function isMaximizing(state) {
    return state.turn === 'white';
}
};

// ── module: src/game.ts ──
__mods["src/game.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChessGameImpl = void 0;
const types_1 = require("./types");
const position_1 = require("./position");
const rules_1 = require("./rules");
const ai_1 = require("./ai");
class ChessGameImpl {
    constructor() {
        this.state = (0, position_1.newInitialPosition)();
        this.capturedWhite = [];
        this.capturedBlack = [];
    }
    start() {
        this.state = (0, position_1.newInitialPosition)();
        this.capturedWhite = [];
        this.capturedBlack = [];
        this.saveToLocalStorage();
    }
    fen() {
        let fen = '';
        for (let rank = 7; rank >= 0; rank--) {
            let emptyCount = 0;
            for (let file = 0; file < 8; file++) {
                const square = (0, types_1.sq)(file, rank);
                const piece = this.state.board[square];
                if (piece === types_1.EMPTY) {
                    emptyCount++;
                }
                else {
                    if (emptyCount > 0) {
                        fen += emptyCount.toString();
                        emptyCount = 0;
                    }
                    fen += pieceToChar(piece);
                }
            }
            if (emptyCount > 0) {
                fen += emptyCount.toString();
            }
            if (rank > 0) {
                fen += '/';
            }
        }
        fen += ' ' + this.state.turn;
        fen += ' ' + this.castlingString();
        fen += ' ' + (this.state.enPassantSquare ? (0, types_1.sqNotation)(this.state.enPassantSquare) : '-');
        fen += ' ' + this.state.fiftyMoveClock;
        fen += ' 1';
        return fen;
    }
    castlingString() {
        let result = '';
        if (this.state.whiteShortCastle)
            result += 'K';
        if (this.state.whiteLongCastle)
            result += 'Q';
        if (this.state.blackShortCastle)
            result += 'k';
        if (this.state.blackLongCastle)
            result += 'q';
        return result || '-';
    }
    move(moveString) {
        const legalMoves = (0, rules_1.filterLegalMoves)(this.state);
        const move = legalMoves.find(m => {
            const notation = (0, types_1.sqNotation)(m.from) + (0, types_1.sqNotation)(m.to) + (m.promotion ? pieceToChar(m.promotion).toUpperCase() : '');
            return notation.toLowerCase() === moveString.toLowerCase();
        });
        if (!move)
            return null;
        this.applyMove(move);
        return move;
    }
    applyMove(move) {
        const board = this.state.board;
        const piece = board[move.from];
        if (move.capture) {
            if ((0, types_1.pieceColor)(move.capture) === 'white') {
                this.capturedWhite.push(move.capture);
            }
            else {
                this.capturedBlack.push(move.capture);
            }
        }
        board[move.to] = piece;
        board[move.from] = types_1.EMPTY;
        if (move.enPassant) {
            const rank = (move.to & 7);
            board[(rank - 1) + ((move.to >> 3) * 8)] = types_1.EMPTY;
        }
        if (move.promotion) {
            board[move.to] = move.promotion;
        }
        if (move.shortCastle) {
            const rank = (move.to & 7);
            const file = (move.to >> 3);
            board[(file - 1) * 8 + rank] = board[(file + 1) * 8 + rank];
            board[(file + 1) * 8 + rank] = types_1.EMPTY;
        }
        if (move.longCastle) {
            const rank = (move.to & 7);
            const file = (move.to >> 3);
            board[(file + 1) * 8 + rank] = board[(file - 2) * 8 + rank];
            board[(file - 2) * 8 + rank] = types_1.EMPTY;
        }
        if ((0, types_1.pieceType)(piece) === 6) {
            if (this.state.turn === 'white') {
                this.state.whiteShortCastle = false;
                this.state.whiteLongCastle = false;
            }
            else {
                this.state.blackShortCastle = false;
                this.state.blackLongCastle = false;
            }
        }
        if ((0, types_1.pieceType)(piece) === 4) {
            if (piece === 4) {
                this.state.whiteShortCastle = false;
                this.state.whiteLongCastle = false;
            }
        }
        this.state.turn = this.state.turn === 'white' ? 'black' : 'white';
        if (move.pawnFile !== null && move.pawnRank !== null) {
            if (Math.abs((move.to >> 3) - move.pawnFile) === 0 && Math.abs((move.to & 7) - move.pawnRank) === 2) {
                this.state.enPassantSquare = move.pawnFile * 8 + move.pawnRank + 1;
            }
            else {
                this.state.enPassantSquare = null;
            }
        }
        else {
            this.state.enPassantSquare = null;
        }
        this.state.fiftyMoveClock = (move.pawnFile !== null || move.capture !== null || move.promotion !== null) ? 0 : this.state.fiftyMoveClock + 1;
        this.state.moveHistory.push(move);
        const result = (0, rules_1.detectGameState)(this.state);
        this.state.result = result;
        this.saveToLocalStorage();
    }
    legalMoves() {
        return (0, rules_1.filterLegalMoves)(this.state);
    }
    undo() {
        if (this.state.moveHistory.length < 2) {
            this.state.moveHistory = [];
            this.state = (0, position_1.newInitialPosition)();
            this.capturedWhite = [];
            this.capturedBlack = [];
        }
        else {
            this.state.moveHistory.pop();
            this.state.moveHistory.pop();
            this.state = (0, position_1.newInitialPosition)();
            const capturedPieces = [...this.capturedWhite, ...this.capturedBlack];
            for (const move of this.state.moveHistory) {
                this.applyMove(move);
            }
            this.capturedWhite = capturedPieces;
            this.capturedBlack = [];
        }
        this.saveToLocalStorage();
    }
    newGame() {
        this.start();
    }
    aiMove(depth, side, timeLimit) {
        return (0, ai_1.findBestMove)(this.state, depth, side, timeLimit);
    }
    saveToLocalStorage() {
        localStorage.setItem('chess-game-state', JSON.stringify({
            state: this.state,
            capturedWhite: this.capturedWhite,
            capturedBlack: this.capturedBlack,
        }));
    }
    loadFromLocalStorage() {
        const saved = localStorage.getItem('chess-game-state');
        if (!saved)
            return false;
        const data = JSON.parse(saved);
        this.state = data.state;
        this.capturedWhite = data.capturedWhite;
        this.capturedBlack = data.capturedBlack;
        return true;
    }
}
exports.ChessGameImpl = ChessGameImpl;
function pieceToChar(piece) {
    switch (piece) {
        case types_1.EMPTY: return '.';
        case 1: return 'P';
        case -1: return 'p';
        case 2: return 'N';
        case -2: return 'n';
        case 3: return 'B';
        case -3: return 'b';
        case 4: return 'R';
        case -4: return 'r';
        case 5: return 'Q';
        case -5: return 'q';
        case 6: return 'K';
        case -6: return 'k';
        default: return '?';
    }
}
};

// ── module: src/renderer.ts ──
__mods["src/renderer.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.pieceUnicode = pieceUnicode;
exports.moveNotation = moveNotation;
function pieceUnicode(piece) {
    switch (piece) {
        case 0: return '';
        case 1: return '♙';
        case -1: return '♟';
        case 2: return '♘';
        case -2: return '♞';
        case 3: return '♗';
        case -3: return '♝';
        case 4: return '♖';
        case -4: return '♜';
        case 5: return '♕';
        case -5: return '♛';
        case 6: return '♔';
        case -6: return '♚';
        default: return '?';
    }
}
function moveNotation(piece, pieceType, squareFrom, squareTo, capture, promotion, enPassant, shortCastle, longCastle, check, mate) {
    if (shortCastle)
        return 'O-O' + (check && !mate ? '+' : '') + (mate ? '#' : '');
    if (longCastle)
        return 'O-O-O' + (check && !mate ? '+' : '') + (mate ? '#' : '');
    let notation = '';
    if (pieceType === 1) {
        notation = capture ? squareFrom[0] + 'x' + squareTo : squareTo;
        if (enPassant)
            notation += ' e.p.';
        if (promotion) {
            notation += '=' + pieceUnicode(promotion).toUpperCase();
        }
    }
    else {
        notation = pieceUnicode(piece).toUpperCase() + (capture ? 'x' : '') + squareTo;
    }
    if (check && !mate)
        notation += '+';
    if (mate)
        notation += '#';
    return notation;
}
};

// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"bartowski/ProCreations_grug-27b-GGUF-IQ4","provider":"brigid","persona":"typescript","sessionId":"aa6ac0ee-e8c6-497f-be60-8f542cfe3bbe","tokensIn":2752943,"tokensOut":33169,"tokensTotal":2786112,"cost":0,"turns":78,"toolCalls":77,"failedToolCalls":3,"timestamp":"2026-08-05T17:15:13.414Z"} -->