all repos — emchess @ 582b0387fa0b9b6f7b51a8a13c4fee17764ffb39

src/game/state.js (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
import { Chess } from "chess.js";
export class Game {
    constructor(fen) {
        this.chess = new Chess(fen);
    }
    get fen() {
        return this.chess.fen();
    }
    get turn() {
        return this.chess.turn();
    }
    board() {
        return this.chess.board();
    }
    legalFrom(square) {
        return this.chess.moves({ square, verbose: true });
    }
    legalTargets(square) {
        return this.legalFrom(square);
    }
    allMoves() {
        return this.chess.moves({ verbose: true });
    }
    legalUci() {
        return this.allMoves().map((m) => m.from + m.to + (m.promotion ?? ""));
    }
    // Accepts a UCI-style from/to (plus promotion) and returns the applied move, or null.
    play(from, to, promotion) {
        try {
            return this.chess.move({ from, to, promotion: promotion ?? "q" });
        }
        catch {
            return null;
        }
    }
    playUci(uci) {
        const from = uci.slice(0, 2);
        const to = uci.slice(2, 4);
        const promo = uci.length > 4 ? uci[4] : undefined;
        return this.play(from, to, promo);
    }
    undo() {
        return this.chess.undo();
    }
    history() {
        return this.chess.history({ verbose: true });
    }
    inCheck() {
        return this.chess.inCheck();
    }
    get(square) {
        return this.chess.get(square);
    }
    attackers(square, color) {
        return this.chess.attackers(square, color);
    }
    clone() {
        return new Game(this.fen);
    }
    pieces(color) {
        const out = [];
        for (const row of this.chess.board()) {
            for (const cell of row) {
                if (cell && cell.color === color)
                    out.push({ square: cell.square, type: cell.type });
            }
        }
        return out;
    }
    // The square of the side-to-move's king, used to paint the check marker.
    kingSquare(color) {
        for (const row of this.chess.board()) {
            for (const cell of row) {
                if (cell && cell.type === "k" && cell.color === color)
                    return cell.square;
            }
        }
        return null;
    }
    outcome() {
        if (!this.chess.isGameOver())
            return { over: false };
        if (this.chess.isCheckmate()) {
            return { over: true, reason: "checkmate", winner: this.turn === "w" ? "b" : "w" };
        }
        if (this.chess.isStalemate())
            return { over: true, reason: "stalemate" };
        if (this.chess.isInsufficientMaterial())
            return { over: true, reason: "insufficient" };
        if (this.chess.isThreefoldRepetition())
            return { over: true, reason: "repetition" };
        if (this.chess.isDrawByFiftyMoves?.())
            return { over: true, reason: "fifty" };
        return { over: true, reason: "draw" };
    }
    pgn() {
        return this.chess.pgn();
    }
    loadPgn(pgn) {
        try {
            this.chess.loadPgn(pgn);
            return true;
        }
        catch {
            return false;
        }
    }
    load(fen) {
        try {
            this.chess.load(fen);
            return true;
        }
        catch {
            return false;
        }
    }
}