<commit_before>/*
    flywheel.ts  -  a TypeScript chess engine by <NAME>.
    https://github.com/cosinekitty/flywheel

    The MIT License (MIT)

    Copyright (c) 2015 <NAME>

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
*/

module Flywheel {
    export enum Square {
        Empty,
        WhitePawn,  WhiteKnight,  WhiteBishop,  WhiteRook,  WhiteQueen,  WhiteKing,
        BlackPawn,  BlackKnight,  BlackBishop,  BlackRook,  BlackQueen,  BlackKing,
        OffBoard
    }

    export enum NeutralPiece {      // represents a chess piece without specifying whether it is Black or White
        Empty,
        Pawn, Knight, Bishop, Rook, Queen, King
    }

    export enum Side {
        White, Black
    }

    class Utility {
        public static IsInitialized:boolean = Utility.StaticInit();
        public static WhitePieces: { [neutral:number]: Square };
        public static BlackPieces: { [neutral:number]: Square };
        public static SidePieces: { [side:number]: { [neutral:number]: Square } };
        public static Neutral: { [square:number]: NeutralPiece };
        public static PieceSide: { [square:number]: Side };

        private static StaticInit():boolean {
            Utility.PieceSide = {};
            Utility.WhitePieces = {};
            Utility.BlackPieces = {};
            Utility.SidePieces = {};
            Utility.Neutral = {};

            Utility.PieceSide[ Utility.WhitePieces[NeutralPiece.Pawn]   = Square.WhitePawn   ] = Side.White;
            Utility.PieceSide[ Utility.WhitePieces[NeutralPiece.Knight] = Square.WhiteKnight ] = Side.White;
            Utility.PieceSide[ Utility.WhitePieces[NeutralPiece.Bishop] = Square.WhiteBishop ] = Side.White;
            Utility.PieceSide[ Utility.WhitePieces[NeutralPiece.Rook]   = Square.WhiteRook   ] = Side.White;
            Utility.PieceSide[ Utility.WhitePieces[NeutralPiece.Queen]  = Square.WhiteQueen  ] = Side.White;
            Utility.PieceSide[ Utility.WhitePieces[NeutralPiece.King]   = Square.WhiteKing   ] = Side.White;

            Utility.PieceSide[ Utility.BlackPieces[NeutralPiece.Pawn]   = Square.BlackPawn   ] = Side.Black;
            Utility.PieceSide[ Utility.BlackPieces[NeutralPiece.Knight] = Square.BlackKnight ] = Side.Black;
            Utility.PieceSide[ Utility.BlackPieces[NeutralPiece.Bishop] = Square.BlackBishop ] = Side.Black;
            Utility.PieceSide[ Utility.BlackPieces[NeutralPiece.Rook]   = Square.BlackRook   ] = Side.Black;
            Utility.PieceSide[ Utility.BlackPieces[NeutralPiece.Queen]  = Square.BlackQueen  ] = Side.Black;
            Utility.PieceSide[ Utility.BlackPieces[NeutralPiece.King]   = Square.BlackKing   ] = Side.Black;

            Utility.Neutral[Square.WhitePawn]   = Utility.Neutral[Square.BlackPawn]   = NeutralPiece.Pawn;
            Utility.Neutral[Square.WhiteKnight] = Utility.Neutral[Square.BlackKnight] = NeutralPiece.Knight;
            Utility.Neutral[Square.WhiteBishop] = Utility.Neutral[Square.BlackBishop] = NeutralPiece.Bishop;
            Utility.Neutral[Square.WhiteRook]   = Utility.Neutral[Square.BlackRook]   = NeutralPiece.Rook;
            Utility.Neutral[Square.WhiteQueen]  = Utility.Neutral[Square.BlackQueen]  = NeutralPiece.Queen;
            Utility.Neutral[Square.WhiteKing]   = Utility.Neutral[Square.BlackKing]   = NeutralPiece.King;

            Utility.SidePieces[Side.White] = Utility.WhitePieces;
            Utility.SidePieces[Side.Black] = Utility.BlackPieces;

            return true;
        }

        public static SidedPieceCharacter(p:Square):string {
            switch (p) {
                case Square.Empty:          return '.';
                case Square.WhitePawn:      return 'P';
                case Square.WhiteKnight:    return 'N';
                case Square.WhiteBishop:    return 'B';
                case Square.WhiteRook:      return 'R';
                case Square.WhiteQueen:     return 'Q';
                case Square.WhiteKing:      return 'K';
                case Square.BlackPawn:      return 'p';
                case Square.BlackKnight:    return 'n';
                case Square.BlackBishop:    return 'b';
                case Square.BlackRook:      return 'r';
                case Square.BlackQueen:     return 'q';
                case Square.BlackKing:      return 'k';
                default:
                    throw 'Invalid square contents: ' + p;
            }
        }
    }

    export class Move {
        public source: number;          // the board offset of the piece being moved
        public dest: number;            // the board offset where the piece will end up
        public prom: NeutralPiece;      // if not a pawn promotion, Empty. otherwise, the piece being promoted to
        public score: number;           // if defined, how good/bad the move is from the moving side's point of view
        public ply: number;             // sanity check that the move pertains to the same ply counter on the board

        public constructor(source:number, dest:number, prom:NeutralPiece = NeutralPiece.Empty) {
            this.source = source;
            this.dest = dest;
            this.prom = prom;
            // Leave score undefined until something wants to assign a value to it later.
        }

        public toString(): string {      // convert the move to long algebraic form: 'e2e4' or 'e7e8q' (promotion)
            var notation:string = Board.Algebraic(this.source) + Board.Algebraic(this.dest);
            switch (this.prom) {
                case NeutralPiece.Empty:   break;
                case NeutralPiece.Queen:   notation += 'q';    break;
                case NeutralPiece.Rook:    notation += 'r';    break;
                case NeutralPiece.Bishop:  notation += 'b';    break;
                case NeutralPiece.Knight:  notation += 'n';    break;
                default:    throw 'Invalid pawn promotion piece ' + this.prom;
            }
            return notation;
        }
    }

    class MoveState {       // represents the information needed to undo a move from the chess board
        public move: Move;
        public capture: Square;
        public whiteCanCastleKingSide: boolean;
        public whiteCanCastleQueenSide: boolean;
        public blackCanCastleKingSide: boolean;
        public blackCanCastleQueenSide: boolean;
        public epCaptureOffset: number;     // if the move was an en passant capture, where the pawn was removed
        public castlingRookSource: number;  // if castling move, where the rook came from
        public castlingRookDest: number;    // if castling move, where the rook landed
        public playerWasInCheck: boolean;
        public lastCapOrPawnPly: number;

        public constructor(move:Move, capture:Square, wkc:boolean, wqc:boolean, bkc:boolean, bqc:boolean, check:boolean, lastCapPawn:number) {
            this.move = move;
            this.capture = capture;
            this.whiteCanCastleKingSide = wkc;
            this.whiteCanCastleQueenSide = wqc;
            this.blackCanCastleKingSide = bkc;
            this.blackCanCastleQueenSide = bqc;
            this.playerWasInCheck = check;
            this.lastCapOrPawnPly = lastCapPawn;
        }
    }

    /*
        The 8x8 chess board is represented as a one-dimensional array.
        This allows for a very simple and efficient way of representing
        locations and directions of things on the board, using only a single integer index.
        To simplify bounds checking, there is a belt of "OffBoard" values surrounding
        the 8x8 board squares.  Because of the way knights move, the board is represented
        as 10 columns and 12 rows, such that a knight on the inside 8x8 grid can never
        jump outside the array.

        +-------------------------------------------+
        |  110 111 112 113 114 115 116 117 118 119  |
        |  100 101 102 103 104 105 106 107 108 109  |
        |   90  91  92  93  94  95  96  97  98  99  |  8
        |   80  81  82  83  84  85  86  87  88  89  |  7
        |   70  71  72  73  74  75  76  77  78  79  |  6
        |   60  61  62  63  64  65  66  67  68  69  |  5
        |   50  51  52  53  54  55  56  57  58  59  |  4
        |   40  41  42  43  44  45  46  47  48  49  |  3
        |   30  31  32  33  34  35  36  37  38  39  |  2
        |   20  21  22  23  24  25  26  27  28  29  |  1
        |   10  11  12  13  14  15  16  17  18  19  |  ^-- ranks
        |    0   1   2   3   4   5   6   7   8   9  |
        +-------------------------------------------+
                 a   b   c   d   e   f   g   h   <-- files
    */

    export enum Direction {     // values that can be added to an offset to obtain another offset in the board
        East        =   1,
        NorthEast   =  11,
        North       =  10,
        NorthWest   =   9,
        West        =  -1,
        SouthWest   = -11,
        South       = -10,
        SouthEast   =  -9,

        Knight1     =  12,
        Knight2     =  21,
        Knight3     =  19,
        Knight4     =   8,
        Knight5     = -12,
        Knight6     = -21,
        Knight7     = -19,
        Knight8     =  -8,
    }<commit_msg>Added spaces to board diagram in comments to make the structure clearer.<commit_after>/*
    flywheel.ts  -  a TypeScript chess engine by <NAME>.
    https://github.com/cosinekitty/flywheel

    The MIT License (MIT)

    Copyright (c) 2015 <NAME>

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
*/

module Flywheel {
    export enum Square {
        Empty,
        WhitePawn,  WhiteKnight,  WhiteBishop,  WhiteRook,  WhiteQueen,  WhiteKing,
        BlackPawn,  BlackKnight,  BlackBishop,  BlackRook,  BlackQueen,  BlackKing,
        OffBoard
    }

    export enum NeutralPiece {      // represents a chess piece without specifying whether it is Black or White
        Empty,
        Pawn, Knight, Bishop, Rook, Queen, King
    }

    export enum Side {
        White, Black
    }

    class Utility {
        public static IsInitialized:boolean = Utility.StaticInit();
        public static WhitePieces: { [neutral:number]: Square };
        public static BlackPieces: { [neutral:number]: Square };
        public static SidePieces: { [side:number]: { [neutral:number]: Square } };
        public static Neutral: { [square:number]: NeutralPiece };
        public static PieceSide: { [square:number]: Side };

        private static StaticInit():boolean {
            Utility.PieceSide = {};
            Utility.WhitePieces = {};
            Utility.BlackPieces = {};
            Utility.SidePieces = {};
            Utility.Neutral = {};

            Utility.PieceSide[ Utility.WhitePieces[NeutralPiece.Pawn]   = Square.WhitePawn   ] = Side.White;
            Utility.PieceSide[ Utility.WhitePieces[NeutralPiece.Knight] = Square.WhiteKnight ] = Side.White;
            Utility.PieceSide[ Utility.WhitePieces[NeutralPiece.Bishop] = Square.WhiteBishop ] = Side.White;
            Utility.PieceSide[ Utility.WhitePieces[NeutralPiece.Rook]   = Square.WhiteRook   ] = Side.White;
            Utility.PieceSide[ Utility.WhitePieces[NeutralPiece.Queen]  = Square.WhiteQueen  ] = Side.White;
            Utility.PieceSide[ Utility.WhitePieces[NeutralPiece.King]   = Square.WhiteKing   ] = Side.White;

            Utility.PieceSide[ Utility.BlackPieces[NeutralPiece.Pawn]   = Square.BlackPawn   ] = Side.Black;
            Utility.PieceSide[ Utility.BlackPieces[NeutralPiece.Knight] = Square.BlackKnight ] = Side.Black;
            Utility.PieceSide[ Utility.BlackPieces[NeutralPiece.Bishop] = Square.BlackBishop ] = Side.Black;
            Utility.PieceSide[ Utility.BlackPieces[NeutralPiece.Rook]   = Square.BlackRook   ] = Side.Black;
            Utility.PieceSide[ Utility.BlackPieces[NeutralPiece.Queen]  = Square.BlackQueen  ] = Side.Black;
            Utility.PieceSide[ Utility.BlackPieces[NeutralPiece.King]   = Square.BlackKing   ] = Side.Black;

            Utility.Neutral[Square.WhitePawn]   = Utility.Neutral[Square.BlackPawn]   = NeutralPiece.Pawn;
            Utility.Neutral[Square.WhiteKnight] = Utility.Neutral[Square.BlackKnight] = NeutralPiece.Knight;
            Utility.Neutral[Square.WhiteBishop] = Utility.Neutral[Square.BlackBishop] = NeutralPiece.Bishop;
            Utility.Neutral[Square.WhiteRook]   = Utility.Neutral[Square.BlackRook]   = NeutralPiece.Rook;
            Utility.Neutral[Square.WhiteQueen]  = Utility.Neutral[Square.BlackQueen]  = NeutralPiece.Queen;
            Utility.Neutral[Square.WhiteKing]   = Utility.Neutral[Square.BlackKing]   = NeutralPiece.King;

            Utility.SidePieces[Side.White] = Utility.WhitePieces;
            Utility.SidePieces[Side.Black] = Utility.BlackPieces;

            return true;
        }

        public static SidedPieceCharacter(p:Square):string {
            switch (p) {
                case Square.Empty:          return '.';
                case Square.WhitePawn:      return 'P';
                case Square.WhiteKnight:    return 'N';
                case Square.WhiteBishop:    return 'B';
                case Square.WhiteRook:      return 'R';
                case Square.WhiteQueen:     return 'Q';
                case Square.WhiteKing:      return 'K';
                case Square.BlackPawn:      return 'p';
                case Square.BlackKnight:    return 'n';
                case Square.BlackBishop:    return 'b';
                case Square.BlackRook:      return 'r';
                case Square.BlackQueen:     return 'q';
                case Square.BlackKing:      return 'k';
                default:
                    throw 'Invalid square contents: ' + p;
            }
        }
    }

    export class Move {
        public source: number;          // the board offset of the piece being moved
        public dest: number;            // the board offset where the piece will end up
        public prom: NeutralPiece;      // if not a pawn promotion, Empty. otherwise, the piece being promoted to
        public score: number;           // if defined, how good/bad the move is from the moving side's point of view
        public ply: number;             // sanity check that the move pertains to the same ply counter on the board

        public constructor(source:number, dest:number, prom:NeutralPiece = NeutralPiece.Empty) {
            this.source = source;
            this.dest = dest;
            this.prom = prom;
            // Leave score undefined until something wants to assign a value to it later.
        }

        public toString(): string {      // convert the move to long algebraic form: 'e2e4' or 'e7e8q' (promotion)
            var notation:string = Board.Algebraic(this.source) + Board.Algebraic(this.dest);
            switch (this.prom) {
                case NeutralPiece.Empty:   break;
                case NeutralPiece.Queen:   notation += 'q';    break;
                case NeutralPiece.Rook:    notation += 'r';    break;
                case NeutralPiece.Bishop:  notation += 'b';    break;
                case NeutralPiece.Knight:  notation += 'n';    break;
                default:    throw 'Invalid pawn promotion piece ' + this.prom;
            }
            return notation;
        }
    }

    class MoveState {       // represents the information needed to undo a move from the chess board
        public move: Move;
        public capture: Square;
        public whiteCanCastleKingSide: boolean;
        public whiteCanCastleQueenSide: boolean;
        public blackCanCastleKingSide: boolean;
        public blackCanCastleQueenSide: boolean;
        public epCaptureOffset: number;     // if the move was an en passant capture, where the pawn was removed
        public castlingRookSource: number;  // if castling move, where the rook came from
        public castlingRookDest: number;    // if castling move, where the rook landed
        public playerWasInCheck: boolean;
        public lastCapOrPawnPly: number;

        public constructor(move:Move, capture:Square, wkc:boolean, wqc:boolean, bkc:boolean, bqc:boolean, check:boolean, lastCapPawn:number) {
            this.move = move;
            this.capture = capture;
            this.whiteCanCastleKingSide = wkc;
            this.whiteCanCastleQueenSide = wqc;
            this.blackCanCastleKingSide = bkc;
            this.blackCanCastleQueenSide = bqc;
            this.playerWasInCheck = check;
            this.lastCapOrPawnPly = lastCapPawn;
        }
    }

    /*
        The 8x8 chess board is represented as a one-dimensional array.
        This allows for a very simple and efficient way of representing
        locations and directions of things on the board, using only a single integer index.
        To simplify bounds checking, there is a belt of "OffBoard" values surrounding
        the 8x8 board squares.  Because of the way knights move, the board is represented
        as 10 columns and 12 rows, such that a knight on the inside 8x8 grid can never
        jump outside the array.

        +-----------------------------------------------+
        |  110   111 112 113 114 115 116 117 118   119  |
        |  100   101 102 103 104 105 106 107 108   109  |
        |                                               |
        |   90    91  92  93  94  95  96  97  98    99  |  8
        |   80    81  82  83  84  85  86  87  88    89  |  7
        |   70    71  72  73  74  75  76  77  78    79  |  6
        |   60    61  62  63  64  65  66  67  68    69  |  5
        |   50    51  52  53  54  55  56  57  58    59  |  4
        |   40    41  42  43  44  45  46  47  48    49  |  3
        |   30    31  32  33  34  35  36  37  38    39  |  2
        |   20    21  22  23  24  25  26  27  28    29  |  1
        |                                               |
        |   10    11  12  13  14  15  16  17  18    19  |  ^-- ranks
        |    0     1   2   3   4   5   6   7   8     9  |
        +-----------------------------------------------+
                   a   b   c   d   e   f   g   h   <-- files
    */

    export enum Direction {     // values that can be added to an offset to obtain another offset in the board
        East        =   1,
        NorthEast   =  11,
        North       =  10,
        NorthWest   =   9,
        West        =  -1,
        SouthWest   = -11,
        South       = -10,
        SouthEast   =  -9,

        Knight1     =  12,
        Knight2     =  21,
        Knight3     =  19,
        Knight4     =   8,
        Knight5     = -12,
        Knight6     = -21,
        Knight7     = -19,
        Knight8     =  -8,
    }
{'fraction_non_alphanumeric': 0.0843630372631681, 'fraction_numerical': 0.030043126423414255, 'mean_word_length': 1.8715736746904132, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 30, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5347061', 'n_tokens_mistral': 6476, 'n_tokens_neox': 5822, 'n_words': 1851}