--  PantherChess - based on AdaChess Copyright (C) 2017-2018 Bill Zuercher
--
--  AdaChess - Cool Chess Engine
--
--  Copyright (C) 2013-2017 - Alessandro Iavicoli
--  Email: adachess@gmail.com - Web Page: http://www.adachess.com
--
--  This program is free software: you can redistribute it and/or modify
--  it under the terms of the GNU General Public License as published by
--  the Free Software Foundation, either version 3 of the License, or
--  (at your option) any later version.
--
--  This program is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--  GNU General Public License for more details.
--
--  You should have received a copy of the GNU General Public License
--  along with this program.  If not, see <http://www.gnu.org/licenses/>.


with AChess; use AChess;
with ACHash; use ACHash;
with ACPiece; use ACPiece;
with ACCommunication; use ACCommunication;
with Ada.Numerics.Discrete_Random;
with Ada.Text_IO;


package ACChessBoard is

      Debug_BZ     : Ada.Text_IO.File_Type;
      Debug_Opened : boolean := false;

   -- Helps to output moves in the correct way while using
   -- the algebraic notation
   type Notation_Flag_Type is
     (Ambiguous_None, Ambiguous_File, Ambiguous_Rank, Ambiguous_Both)
     with Size => 2;

   -- Flags are 1-bit information that will help the move
   -- generator to perform some operation faster.
   type Flag_Type is
     (Standard_Move, Pawn_Move_Two_Square, Capture_En_Passant,
      Promotion, Castle, Null_Move, No_Move) with Size => 3;

   -- Recognize different type of checks depending
   -- on board position. The information about the
   -- type of check is then used while searching
   -- for the principal variation to sort moves
   -- by looking first at discovery checks and double
   -- checks other than standard checks or normal moves.
   -- SPecial case is the Unknown_Check, that happens
   -- in situation like position generated by fen string
   -- where we see that king is check but we don't know
   -- which kind of check it is.

   type Check_Type is
     (No_Check, Check, Discovery_Check, Double_Check, Checkmate, Unknown_Check)
     with Size => 3;

   -- Cast too boolean a check to see if a move does NOT checks
   function "not" (Checks : in Check_Type) return Boolean is
     (if Checks = No_Check then True else False);

   -- Describe a pin type.
   -- Pins blocks enemy piece.
   -- Consider to search more when find pins
   type Pin_Type is
     (No_Pin, Relative, Absolute) with Size => 2;

   -- Squares are the place where the game is played.
   -- The computer-level representation is the same as integer even
   -- if there are less squares (224) than integers. Anyway,
   -- we can't use other than Integer to loop through chessboard
   -- and other arrays. So, to avoid to perform casts that will
   -- make engine slower, we just use another name that helps
   -- to make code more clear.
   subtype Square_Type is Integer_Type range 0 .. 223;

   -- The History Depth is how many half-moves can we play from the
   -- beginning of the game. A game that is longer that this value
   -- will raise an overflow.
   subtype History_Depth_Type is Integer_Type range 1 .. 512;

   -- The depth is how many deep we can go while thinking and playing moves
   -- It's very rare that we think deeper than 32 ply, so for moves list
   -- we can use a small subset and save memory (and a small improvement)
   subtype Depth_Type is History_Depth_Type range 1 .. 128;

   Frontier_Depth     : constant Depth_Type := Depth_Type'First + 1;
   Pre_Frontier_Depth : constant Depth_Type := Frontier_Depth + 1;


   -- This is the move description in the engine.
   -- Instances of this record will be used more than other
   -- structured types in AdaChess. So, the smaller is this record,
   -- the faster is the engine computation. However, it's a good idea to
   -- keep some interesting information to perform some play/undo operation
   -- faster using a small amount of memory.
   type Move_Type is
      record
         Piece     : Board_Piece_Type;
         Captured  : Board_Piece_Type;
         From      : Square_Type;
	       To        : Square_Type;
	       Flag      : Flag_Type;
	       Promotion : Board_Piece_Type;
         Check     : Check_Type;
         Score     : Integer_Type;
         Pin       : Pin_Type;
         Notation_Flag : Notation_Flag_Type;
      end record;
   pragma Pack (Move_Type);


   -- Storing a position requires some additional
   -- information other than the move information
   type History_Move_Type is --new Move_Type with
      record
         Piece         : Board_Piece_Type;
         Captured      : Board_Piece_Type;
         From          : Square_Type;
         To            : Square_Type;
         Flag          : Flag_Type;
         Promotion     : Board_Piece_Type;
         Check         : Check_Type;
         Score         : Integer_Type;
         Pin           : Pin_Type;
         Notation_Flag : Notation_Flag_Type;
         Hash          : Hash_Type;
      end record;
   pragma Pack (History_Move_Type);

   -- override "=" comparator for moves type
   function "=" (Left, Right : in Move_Type) return Boolean with Inline => True;
   function "=" (Left, Right : in History_Move_Type) return Boolean with Inline => True;
   function "=" (Left : in Move_Type; Right : in History_Move_Type) return Boolean with Inline => True;
   function "=" (Left : in History_Move_Type; Right : in Move_Type) return Boolean with Inline => True;

   Empty_Move : constant Move_Type := Move_Type'(Piece         => Empty,
                                                 Captured      => Empty,
                                                 From          => 0,
                                                 To            => 0,
                                                 Flag          => No_Move,
                                                 Promotion     => Empty,
                                                 Check         => No_Check,
                                                 Score         => 0,
                                                 Pin           => No_Pin,
                                                 Notation_Flag => Ambiguous_None);

   Empty_History_Move : constant History_Move_Type := History_Move_Type'(Piece         => Empty,
                                                                         Captured      => Empty,
                                                                         From          => 0,
                                                                         To            => 0,
                                                                         Flag          => No_Move,
                                                                         Promotion     => Empty,
                                                                         Check         => No_Check,
                                                                         Score         => 0,
                                                                         Pin           => No_Pin,
                                                                         Hash          => 0,
                                                                         Notation_Flag => Ambiguous_None);

   function Move_Is_Tactical (Move : in Move_Type) return Boolean with Inline => True;
   function Move_Is_Quiet (Move : in Move_Type) return Boolean with Inline => True;
   function Move_Is_Strategical (Move : in Move_Type) return Boolean with Inline => True;

   -- The ChessBoard is represented as an array of pieces.
   -- The array is an 80 framed squared with a total of 224
   -- items. The board is centered in the frame.
   type Chessboard_Type is array (Square_Type'Range) of Piece_Type;


   ---------------------
   -- Piece positions --
   ---------------------

   -- Keep track of kings position to avoid to find them
   -- runtime when perform some check like find if king is
   -- in check and similarities.
   White_King_Position : Square_Type;
   Black_King_Position : Square_Type;

   -- Those are array for pieces. We must know the square where
   -- any piece are, then we can pick the right piece from
   -- that square in the ChessBoard. Then, to perform
   -- some fast operation while adding and deleting piece
   -- that comes on captures, promotions and other moves,
   -- we use an auxiliary board, called Piece_Table.
   -- That board is populated with index of the array of the
   -- white and black pieces.
   White_Pieces         : array (Integer_Type range 1 .. 20) of Square_Type;
   White_Pieces_Counter : Integer_Type;
   Black_Pieces         : array (Integer_Type range 1 .. 20) of Square_Type;
   Black_Pieces_Counter : Integer_Type;

   White_Piece_Table    : array (Square_Type'Range) of Square_Type;
   Black_Piece_Table    : array (Square_Type'Range) of Square_Type;

   --------------------------
   -- End of Mobility_Type --
   --------------------------

   -- White and Black castle flags are used to look if both
   -- sides can castle on one or the other side.
   -- Every time a castle has performed the flags are u
   -- pdated according to the castle type and the side who has moved.
   -- Moreover, when a king or a rook are moved, those flags
   -- are also updated according to the chess rules
   White_Castle_Queenside : array (History_Depth_Type'Range) of Boolean;
   White_Castle_Kingside  : array (History_Depth_Type'Range) of Boolean;
   Black_Castle_Queenside : array (History_Depth_Type'Range) of Boolean;
   Black_Castle_Kingside  : array (History_Depth_Type'Range) of Boolean;

   -- Those are other castle flag that I need to know
   -- if at a certain depth every side has castle.
   -- This is widely used in Evaluation to detect
   -- a conveniently King Safety strategy
   White_Has_Castled      : array (History_Depth_Type'Range) of Boolean;
   Black_Has_Castled      : array (History_Depth_Type'Range) of Boolean;

   -- The chessboard is the current representation of the board.
   Chessboard : Chessboard_Type;

   -- An any turn, one or the other player must play its move
   Side_To_Move : Color_Type;

   -- The Moves list is an array in which we save all allowed moves
   -- for the side to move, at any depth. Sometimes, like in Quiescence,
   -- the engine has only to look for captures or other special moves like
   -- promotions or castling. Anyway, to perform a Principal Variation Search
   -- we use a bi-dimensional array. For each depth, we also want to know
   -- how many moves we found. That is for looping from the first to the last
   -- like: for i in 1 .. moves_counter(current_depth) loop ...
   -- The pick moves using Moves_List(Ply, I)
   Moves_List          : array (Depth_Type'Range, Integer_Type range 1 .. 256) of Move_Type;
   Moves_Counter       : array (Depth_Type'Range) of Integer_Type;

   -- The Ply is the half-move counter relative to current depth. I.e.
   -- the Ply is reset any time we call the Think() function.
   Ply                 : Depth_Type;

   -- History Ply is the half-move counter from the beginning of the
   -- game. History is never reset during the game.
   History_Ply         : History_Depth_Type;

   -- This value is the start value for history. In normal situations
   -- the value is History_Depth_Type'First but if we load a position
   -- from FEN string the starting counter would be different.
   -- I need to know the history exact value from FEN and its starting
   -- value in position evaluation (to detect in which phase of the game
   -- we are (opening - middle game - endgame) and in uncoding moves.
   -- Plus, in the output, I print the counter
   History_Start       : History_Depth_Type;

   -- Moves History is our track for moves played during the game.
   -- We need an history for two reasons: to undo moves and to
   -- look back for 3-times repetitions rule.
   Moves_History       : array (History_Depth_Type'Range) of History_Move_Type;

   -- En_Passant keep the en-passant square for
   -- each Ply. When a pawn move two squares, for example
   -- e2-e4, then we set the e3 as en-passant square
   -- for the following ply. So if the move e2-e4 is
   -- played at Ply = 1, then we set en_passant(ply + 1) = e3
   -- In this way, the opponent side can see that at its turn
   -- there's the e3 square where their pawns can capture en-passant
   En_Passant          : array (History_Depth_Type'Range) of Square_Type;

   -- The fifty move counter is incremented at each turn
   -- and its upper limit is 100 that means that each player
   -- plays 50 moves without captures, promotions or pawn moves.
   -- When one of the three kind of moves occurrs, the counter is
   -- reset to zero. On this array, we keep trak of the counter
   -- at each Ply: so we do not need to take care of it when we
   -- undo a move.
   Fifty               : array (History_Depth_Type'Range) of Integer_Type;

   -- Nodes is a counter that is used for both performance measurement
   -- and for taking trace of Branching Factor while performing the
   -- Principal Variation Search. On Perft, nodes give us a proof that
   -- the move generator works well and without bugs.
   Nodes               : Node_Type;

   -- The Validity_Test helps to looks for king in check only
   -- when needed. We will looks for moves that CAN leave king
   -- in check and we don't looks for moves that CAN'T leave
   -- the king in check. To do this, we looks only on moves that are
   -- 1) Castling
   -- 2) En-passant
   -- 3) Moves with absolute pinned piece
   -- in the case of 3) we use a simplified algorithm that looks
   -- on every move from same rank/file/diagonal/anti_diagonal
   -- to another rank/file/diagonal/anti_diagonal
   -- The Force_Test_Validity force the test to be executed on every
   -- move generated from move generator (used when king is in check!)
   Force_Validity_Test : Boolean;

   -- Check if the we have to skip legality test
   -- or if we must look for it (according to
   -- Force_Validity_Test too)
   -- And check if we want to search if the
   -- move checks opponent king
   Check_For_Legal     : Boolean;
   Check_For_Check     : Boolean;
   Check_For_Pins      : Boolean;

   --------------------------
   -- Zobrist Hash methods --
   --------------------------

   -- Hash is a variable that store the Hash value of the
   -- current chess board position. This global variable
   -- will be updated at any moves and used for both finding
   -- moves repetitions and Transposition Tables.
   Hash                : Hash_Type;

   procedure Initialize_Hash;

   -- Update Hash will recalculate
   -- hash based on new ChessBoard state
   procedure Update_Hash with Inline => True;

   -------------------------
   -- Transposition Tables --
   --------------------------

   -- Define the size of the transposition table
   -- as the range of available keys for Transposition Table.
   type Transposition_Table_Key_Type is mod 2 ** 24;

   type Value_Type is
     (Unknown, Exact_Value, Upper_Bound, Lower_Bound) with Size => 2;

   type Transposition_Table_Entry_Type is
      record
         Hash  : Hash_Type;
         Depth : Depth_Type;
         Score : Integer_Type;
         Best  : Move_Type;
         Flag  : Value_Type;
      end record;

   type Transposition_Table_Type is
     array (Transposition_Table_Key_Type'Range) of Transposition_Table_Entry_Type;

   -- Pointer to the table entrues
   type Transposition_Table_Access_Type is access Transposition_Table_Type;

   -- Finally, define our pointer to the transposition table
   Transposition_Table : Transposition_Table_Access_Type;


   -- Empty all transposition table data
   -- and reset everything in it.
   procedure Init_Transposition_Table;
   procedure Clear_Transposition_Table renames Init_Transposition_Table;

   -- Generate a valid Key for the Transposition Table
   function Generate_Key
     return Transposition_Table_Key_Type with Inline => True;

   -- Update value inside the transposition table
   -- If a collision is found, replace old value
   -- with the new one.
   procedure Record_Transposition_Entry
     (Key   : in Transposition_Table_Key_Type;
      Depth : in Depth_Type;
      Score : in Integer_Type;
      Hash  : in Hash_Type;
      Best  : in Move_Type;
      Flag  : in Value_Type) with Inline => True;

   -- Look if the give key exists inside the Transposition table
   -- and, if so, return the corresponding table entry
   function Probe_Transposition_Table
     (Key : in Transposition_Table_Key_Type)
      return Transposition_Table_Entry_Type with Inline => True;

   -- Raise this exception if an invalid data
   -- is found in the table
   Transposition_Lookup_Exception : exception;

   --------------------------------------------------
   -- Variables involved in Zobrist Hash algorithm --
   --------------------------------------------------

   Hash_Pieces          : array (Chess_Piece_Type'Range, ChessBoard'Range) of Hash_Type;
   Hash_En_Passant      : array (ChessBoard'Range) of Hash_Type;
   Hash_Castle          : array (Integer_Type range 1 .. 4) of Hash_Type;
   Hash_Side            : Hash_Type;

   ------------------------------
   -- Procedures and Functions --
   ------------------------------

   -- Initialize ChessBoard, set white to move, reset counter to 0,
   -- and do others stuffs to make the game ready to be played from
   -- the beginning.
   procedure Init;

   -- Print the board on the console. Display should be
   -- set to off when using external GUI like Winboard/Xboard,
   -- Arena or some other with UCI protocol.
   procedure Display;

   -- Show the pieces. Used for debug and testing.
   procedure Display_Piece_Table;

   -- Reset Moves List at current depth.
   -- To make this function as fastest as possible
   -- a small trick is used. In then "Generate_Moves"
   -- function, at the end, a 'zero move' is set.
   -- It works like strings that ends at null characters.
   procedure Clear_Moves_List with
     Inline => True,
     Post => Moves_Counter (Ply) = 0;

   -- Generate all legal moves from the current position. The move generator
   -- does not check for legality of the move. It simply generate them
   procedure Generate_Moves;

   -- If a king is in check I will use a specific
   -- generator to generate move faster than the normal one.
   -- Also, to detect checkmates, I use special copy of the
   -- generate-check-evasion that looks if the king has
   -- at least one esacpe. If not, then it's checkmate
   procedure Generate_Check_Evasion;
   function King_Has_Escapes (Type_Of_Check : in Check_Type) return Boolean;

   -- Alternative move generator using for quiescence search
   -- In quiescence we look for stable positions.
   -- We need to look for captures, promotions,
   -- and, if needed, castles.
   procedure Generate_Quiescence_Moves;

   -- Generate specific moves for See.
   -- The See-Move-Generator generate only
   -- recapture moves, i.e. moves that points
   -- on a target square
   procedure Generate_See_Moves (Target : in Square_Type) with
     Pre => Chessboard (Target) /= Frame;


   -- Save a move in the Moves_List. This is a family of function
   -- that we use to register a moves in that list
   procedure Register_Move (From, To : in Square_Type) with Inline => True;
   procedure Register_Move (From, To : in Square_Type; Flag : in Flag_Type) with Inline => True;
   procedure Register_Move (Move : in Move_Type) with
     Inline => True,
     Pre => Moves_Counter(Ply) < 128;

   -- Make a move in current ChessBoard. The process of making a move
   -- implies to save the move for future undoes, updating counters and
   -- others stuff relate to the move making.
   procedure Play (Move : in Move_Type) with
     Pre => Ply < Depth_Type'Last and History_Ply < History_Depth_Type'Last,
     Post => Ply = Ply'Old + 1 and History_Ply = History_Ply'Old + 1 and Side_To_Move = not Side_To_Move'Old;

   -- Take back a move. Restore the ChessBoard at the state that was
   -- before the last move has played.
   procedure Undo with
     Pre => Ply > Depth_Type'First and History_Ply > History_Start,
     Post => Ply = Ply'Old - 1 and History_Ply = History_Ply'Old - 1 and Side_To_Move = not Side_To_Move'Old;

   -- Those are essentially a copy of play/undo
   -- but without many complicated things. I use
   -- See play/undo  to look for faster evaluate
   -- static exchange
   procedure Play_See_Move (Move : in Move_Type) with
     Inline => True,
     Pre => Move.Captured'Valid; -- in Board_Piece_Type'Range;

   procedure Undo_See_Move with Inline => True;

   -- Play/Undo null moves is just a swap of the
   -- side to move
   procedure Play_Null_Move with
     Inline => True,
     Post => Side_To_Move = not Side_To_Move'Old;

   procedure Undo_Null_Move with
     Inline => True,
     Post => Side_To_Move = not Side_To_Move'Old;

   -- While testing if a move that checks opponent king
   -- also does a checkmate, I use a lighter version
   -- of the make-move and to take it back
   procedure Play_Check_Move (Move : in Move_Type) with Inline => True;
   procedure Undo_Check_Move with Inline => True;

   -- Track the last move played. Useful while searching for recaptures
   function Last_Move_Made return Move_Type with
     Inline => True;
--       Pre => History_Ply > History_Depth_Type'First;

   ------------------
   -- Attacks data --
   ------------------

   type Attack_Type is
      record
         Origin : Square_Type; -- square where the attacks begins
         Piece  : Piece_Type;
      end record;
   pragma Pack (Attack_Type);

   type Attack_Array_Type is array (Integer_Type range 1 .. 9) of Attack_Type;

   -- Collect all the attackers found

   type Attack_Collection_Type is
      record
         Attacker            : Attack_Array_Type;
         Number_Of_Attackers : Integer_Type;
      end record;
   pragma Pack (Attack_Collection_Type);

   -- Attacks functions answer this question:
   -- Does side "Side" attacks square "Square"?
   -- Returns True if the answer is Yes, false otherwise.
   function Attacks (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;

   -- Lookup the square in which stands the attacking piece.
   -- Optionally, it can stop either if a first attacker has found
   -- or it can collect all the attackers on that square.
   function Attacking_Square (Side : in Color_Type; Square : in Square_Type; Only_One : in Boolean) return Attack_Collection_Type with
     Inline => True,
     Pre => Chessboard (Square) /= Frame;
   function Attacking_Piece (Side : in Color_Type; Square : in Square_Type; Only_One : in Boolean) return Attack_Collection_Type renames Attacking_Square;


   -----------------
   -- Defend maps --
   -----------------

   -- detect if a square is protected by pawns of given side
   function Is_Pawn_Protected (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;

   -- Detect if a side has it's own king in check!
   -- The algorithm will look from king position
   -- back to any square around it to find opponent
   -- pieces that can capture king. I.e: looks in
   -- diagonals for Bishops and Queens, looks in
   -- files and ranks for Rook and Queen, and so on
   -- for other pieces. This method will improve
   -- performance and make check-recognition faster
   function Has_King_In_Check (Side : in Color_Type) return Boolean with Inline => True;

--     function White_Has_King_In_Check return Boolean with Inline => True;
--     function Black_Has_King_In_Check return Boolean with Inline => True;


   function White_Has_King_In_Check return Boolean is (Attacks (Black, White_King_Position));
   function Black_Has_King_In_Check return Boolean is (Attacks (White, Black_King_Position));

   -- Detect if the piece on given square is pinned and
   -- it is protecting it's king or not.
   -- If so, return the direction of the attacker
   function Is_Absolute_Pinned (Square : in Square_Type) return Integer_Type with
     Inline => True,
     Pre => (Square /= White_King_Position and Square /= Black_King_Position);

   -- Detect if the move leaves friendly king in
   -- check (i.e, is a legal move).
   function Move_Leaves_King_In_Check (Move : in Move_Type) return Boolean with Inline => True;

   -- Detect if the move will check opponent
   -- king. The idea is the same as the one used
   -- to find if the moves leaves friendly
   -- king in check but in this case
   -- we look for attacking from the
   -- same side to the opponent king instead
   -- of from opponent side to friendly king.
   function Move_Checks_Opponent_King (Move : in Move_Type) return Check_Type with Inline => True;

   -- Detect if the current move is pinning
   -- an opponent piece and also tell us which
   -- kind of pin is (No pin, Relative or absolute)
   function Move_Pin_Opponent_Piece (Move : in Move_Type) return Pin_Type with Inline => True;

   -------------------------------------
   -- Procedure about array of pieces --
   -------------------------------------

   -- Add a piece to the white/black pieces list. The square is needed, the piece
   -- is obtained by looking that square in the ChessBoard
   procedure Add_White_Piece (Square : in Square_Type) with Inline => True;
   procedure Add_Black_Piece (Square : in Square_Type) with Inline => True;

   -- Remove a piece from the white/black pieces list.
   procedure Delete_White_Piece (Square : in Square_Type) with Inline => True;
   procedure Delete_Black_Piece (Square : in Square_Type) with Inline => True;

   -- Move a white/black piece from the current position to a new one
   procedure Update_White_Piece (From, To : in Square_Type) with Inline => True;
   procedure Update_Black_Piece (From, To : in Square_Type) with Inline => True;

   -- Print a move to the console, by using a standard Algebraic Notation
   procedure Print_Move (Move : in Move_Type);

   -- Print a move to the console with the chosen notation.
   procedure Print_Move (Move : in Move_Type; Notation : in Notation_Type);

   -- Print all legal moves to the console, using the standard Algebraic Notation
   procedure Print_Moves_List;


   ------------------
   -- Perft Search --
   ------------------

   -- While perft is ofted used to find how fast a
   -- move generator is, I use it to find if there
   -- are bugs in it or not. Launch pantherchess and
   -- type "perft 5" to understand what are this
   -- data about.

   type Perft_Node_Type is mod 2 ** 37; -- should be enough for testing purpouse

   type Move_Path_Collector_Type is
      record
         Nodes      : Perft_Node_Type;
         Captures   : Perft_Node_Type;
         En_Passant : Perft_Node_Type;
         Castles    : Perft_Node_Type;
         Promotions : Perft_Node_Type;
         Checks     : Perft_Node_Type;
         Checkmates : Perft_Node_Type;
      end record;

   Perft_Move_Paths : Move_Path_Collector_Type;


   -- PERFormance Tester. Used for multiple reasons: performance testing,
   -- finding bugs in move generator and profiling.
   procedure Perft (Depth : in Depth_Type);
   procedure Divide (Depth : in Depth_Type);


   ---------------------------------------------------------------------------
   -- Functions, utilities to find cordinates of a square in the ChessBoard --
   ---------------------------------------------------------------------------

   -- Return the file of the given square
   function File (Square : in Square_Type) return Integer_Type with Inline => True;

   -- Return the Rank of the give square
   function Rank (Square : in Square_Type) return Integer_Type with Inline => True;

   -- Return the Diagonal of the given square
   function Diagonal (Square : in Square_Type) return Integer_Type with Inline => True;

   -- return the Anti-Diagonal of the given square
   function Anti_Diagonal (Square : in Square_Type) return Integer_Type with Inline => True;


   Files : array (Chessboard'Range) of Integer_Type :=
     (-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8, 9, -1, -1, -1,
      -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8, 9, -1, -1, -1,
      -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8, 9, -1, -1, -1,
      -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8, 9, -1, -1, -1,
      -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8, 9, -1, -1, -1,
      -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8, 9, -1, -1, -1,
      -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8, 9, -1, -1, -1,
      -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8, 9, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);

   Ranks : array (Chessboard'Range) of Integer_Type :=
     (-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1,  8,  8,  8,  8,  8,  8,  8,  8, 8, 8, -1, -1, -1,
      -1, -1, -1,  7,  7,  7,  7,  7,  7,  7,  7, 7, 7, -1, -1, -1,
      -1, -1, -1,  6,  6,  6,  6,  6,  6,  6,  6, 6, 6, -1, -1, -1,
      -1, -1, -1,  5,  5,  5,  5,  5,  5,  5,  5, 5, 5, -1, -1, -1,
      -1, -1, -1,  4,  4,  4,  4,  4,  4,  4,  4, 4, 4, -1, -1, -1,
      -1, -1, -1,  3,  3,  3,  3,  3,  3,  3,  3, 3, 3, -1, -1, -1,
      -1, -1, -1,  2,  2,  2,  2,  2,  2,  2,  2, 2, 2, -1, -1, -1,
      -1, -1, -1,  1,  1,  1,  1,  1,  1,  1,  1, 1, 1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);

   Diagonals : array (Chessboard'Range) of Integer_Type :=
     (-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1,  7,  6,  5,  4,  3,  2,  1,  0,  8,  9, -1, -1, -1,
      -1, -1, -1,  6,  5,  4,  3,  2,  1,  0,  8,  9, 10, -1, -1, -1,
      -1, -1, -1,  5,  4,  3,  2,  1,  0,  8,  9, 10, 11, -1, -1, -1,
      -1, -1, -1,  4,  3,  2,  1,  0,  8,  9, 10, 11, 12, -1, -1, -1,
      -1, -1, -1,  3,  2,  1,  0,  8,  9, 10, 11, 12, 13, -1, -1, -1,
      -1, -1, -1,  2,  1,  0,  8,  9, 10, 11, 12, 13, 14, -1, -1, -1,
      -1, -1, -1,  1,  0,  8,  9, 10, 11, 12, 13, 14, 15, -1, -1, -1,
      -1, -1, -1,  0,  8,  9, 10, 11, 12, 13, 14, 15, 16, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);

   Anti_Diagonals : array (Chessboard'Range) of Integer_Type :=
     (-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, -1, -1, -1,
      -1, -1, -1,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, -1, -1, -1,
      -1, -1, -1,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, -1, -1, -1,
      -1, -1, -1,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, -1, -1, -1,
      -1, -1, -1,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, -1, -1, -1,
      -1, -1, -1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, -1, -1, -1,
      -1, -1, -1,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, -1, -1, -1,
      -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);

   Rank_1         : constant Integer_Type := 1;
   Rank_2         : constant Integer_Type := 2;
   Rank_3         : constant Integer_Type := 3;
   Rank_4         : constant Integer_Type := 4;
   Rank_5         : constant Integer_Type := 5;
   Rank_6         : constant Integer_Type := 6;
   Rank_7         : constant Integer_Type := 7;
   Rank_8         : constant Integer_Type := 8;

   File_A         : constant Integer_Type := 0;
   File_B         : constant Integer_Type := 1;
   File_C         : constant Integer_Type := 2;
   File_D         : constant Integer_Type := 3;
   File_E         : constant Integer_Type := 4;
   File_F         : constant Integer_Type := 5;
   File_G         : constant Integer_Type := 6;
   File_H         : constant Integer_Type := 7;
   File_I         : constant Integer_Type := 8;
   File_J         : constant Integer_Type := 9;

   -----------------------------------------------
   -- Offsets for moving piece around the board --
   -----------------------------------------------

--   subtype Direction_Type is Integer_Type range -49 .. +49;
--
--   North            : constant Direction_Type := -16;
--   North_North_East : constant Direction_Type := -31;
--   North_East       : constant Direction_Type := -15;
--   North_East_East  : constant Direction_Type := -14;
--   East             : constant Direction_Type := +1;
--   South_East_East  : constant Direction_Type := +18;
--   South_East       : constant Direction_Type := +17;
--   South_South_East : constant Direction_Type := +33;
--   South            : constant Direction_Type := +16;
--   South_South_West : constant Direction_Type := +31;
--   South_West       : constant Direction_Type := +15;
--   South_West_West  : constant Direction_Type := +14;
--   West             : constant Direction_Type := -1;
--   North_West_West  : constant Direction_Type := -18;
--   North_West       : constant Direction_Type := -17;
--   North_North_West : constant Direction_Type := -33;

   subtype Direction_Type is Integer_Type range -48 .. +48;

   North            : constant Direction_Type := -16;
   North_North_East : constant Direction_Type := -31;
   North_East       : constant Direction_Type := -15;
   North_East_East  : constant Direction_Type := -14;
   East             : constant Direction_Type := +1;
   South_East_East  : constant Direction_Type := +18;
   South_East       : constant Direction_Type := +17;
   South_South_East : constant Direction_Type := +33;
   South            : constant Direction_Type := +16;
   South_South_West : constant Direction_Type := +31;
   South_West       : constant Direction_Type := +15;
   South_West_West  : constant Direction_Type := +14;
   West             : constant Direction_Type := -1;
   North_West_West  : constant Direction_Type := -18;
   North_West       : constant Direction_Type := -17;
   North_North_West : constant Direction_Type := -33;
-- Add Panthers movements
   North_North_North : constant Direction_Type := -48;
   South_South_South : constant Direction_Type := +48;
   East_East_East    : constant Direction_Type := +3;
   West_West_West    : constant Direction_Type := -3;

   subtype Very_Long_Offset_Type is Direction_Type range 1 .. 12;
   subtype Long_Offset_Type is Direction_Type range 1 .. 10;
   subtype Med_Offset_Type is Direction_Type range 1 .. 8;
   subtype Short_Offset_Type is Direction_Type range 1 .. 4;

   Knight_Offsets : array (Med_Offset_Type) of Direction_Type :=
     (North_North_East, North_East_East,
      South_East_East, South_South_East,
      South_South_West, South_West_West,
      North_West_West, North_North_West);

   -- Panther is new Piece: moves as Threeleaper (3,0 leaper) or as Wazir (1 sq. orthogonally)
   Panther_Offsets : array (Med_Offset_Type) of Direction_Type :=
     (North_North_North,
      East_East_East,
      South_South_South,
      West_West_West,
      North, East,
      South, West);

   Bishop_Offsets : array (Short_Offset_Type) of Direction_Type :=
     (North_West, North_East, South_East, South_West);

   Rook_Offsets   : array (Short_Offset_Type) of Direction_Type :=
     (North, East, South, West);

   Queen_Offsets  : array (Med_Offset_Type) of Direction_Type :=
     (North, North_East, East, South_East,
      South, South_West, West, North_West);

   King_Offsets   : array (Med_Offset_Type) of Direction_Type :=
     (North, North_East, East, South_East,
      South, South_West, West, North_West);


   -- Find the direction that a sliding piece from Starting_Square
   -- must be follow to move to Destination_Square.
   -- The direction can be North, South, South_East
   -- and others, 0 if no direct direction has found
   function Find_Sliding_Direction (Origin, Destination : in Square_Type) return Direction_Type
     with Inline => True;
--       Pre => (Origin /= Destination);

   Directions_Table : array (Chessboard_Type'Range, Chessboard_Type'Range) of Direction_Type;

   -- Precalculate all kind of directions
   procedure Preload_Sliding_Direction;

   ----------------------
   -- Square constants --
   ----------------------

   A8 : constant Square_Type := 51;
   B8 : constant Square_Type := 52;
   C8 : constant Square_Type := 53;
   D8 : constant Square_Type := 54;
   E8 : constant Square_Type := 55;
   F8 : constant Square_Type := 56;
   G8 : constant Square_Type := 57;
   H8 : constant Square_Type := 58;
   I8 : constant Square_Type := 59;
   J8 : constant Square_Type := 60;

   A7 : constant Square_Type := 67;
   B7 : constant Square_Type := 68;
   C7 : constant Square_Type := 69;
   D7 : constant Square_Type := 70;
   E7 : constant Square_Type := 71;
   F7 : constant Square_Type := 72;
   G7 : constant Square_Type := 73;
   H7 : constant Square_Type := 74;
   I7 : constant Square_Type := 75;
   J7 : constant Square_Type := 76;

   A6 : constant Square_Type := 83;
   B6 : constant Square_Type := 84;
   C6 : constant Square_Type := 85;
   D6 : constant Square_Type := 86;
   E6 : constant Square_Type := 87;
   F6 : constant Square_Type := 88;
   G6 : constant Square_Type := 89;
   H6 : constant Square_Type := 90;
   I6 : constant Square_Type := 91;
   J6 : constant Square_Type := 92;

   A5 : constant Square_Type := 99;
   B5 : constant Square_Type := 100;
   C5 : constant Square_Type := 101;
   D5 : constant Square_Type := 102;
   E5 : constant Square_Type := 103;
   F5 : constant Square_Type := 104;
   G5 : constant Square_Type := 105;
   H5 : constant Square_Type := 106;
   I5 : constant Square_Type := 107;
   J5 : constant Square_Type := 108;

   A4 : constant Square_Type := 115;
   B4 : constant Square_Type := 116;
   C4 : constant Square_Type := 117;
   D4 : constant Square_Type := 118;
   E4 : constant Square_Type := 119;
   F4 : constant Square_Type := 120;
   G4 : constant Square_Type := 121;
   H4 : constant Square_Type := 122;
   I4 : constant Square_Type := 123;
   J4 : constant Square_Type := 124;

   A3 : constant Square_Type := 131;
   B3 : constant Square_Type := 132;
   C3 : constant Square_Type := 133;
   D3 : constant Square_Type := 134;
   E3 : constant Square_Type := 135;
   F3 : constant Square_Type := 136;
   G3 : constant Square_Type := 137;
   H3 : constant Square_Type := 138;
   I3 : constant Square_Type := 139;
   J3 : constant Square_Type := 140;

   A2 : constant Square_Type := 147;
   B2 : constant Square_Type := 148;
   C2 : constant Square_Type := 149;
   D2 : constant Square_Type := 150;
   E2 : constant Square_Type := 151;
   F2 : constant Square_Type := 152;
   G2 : constant Square_Type := 153;
   H2 : constant Square_Type := 154;
   I2 : constant Square_Type := 155;
   J2 : constant Square_Type := 156;

   A1 : constant Square_Type := 163;
   B1 : constant Square_Type := 164;
   C1 : constant Square_Type := 165;
   D1 : constant Square_Type := 166;
   E1 : constant Square_Type := 167;
   F1 : constant Square_Type := 168;
   G1 : constant Square_Type := 169;
   H1 : constant Square_Type := 170;
   I1 : constant Square_Type := 171;
   J1 : constant Square_Type := 172;

   -------------------------------
   -- Pawn promotion square table--
   -------------------------------

   White_Promotion_Square : constant array (Chessboard'Range) of Square_Type :=
     (0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 0,
      0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 0,
      0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 0,
      0, 0, 0, A8, B8, C8, D8, E8, F8, G8, H8, I8, J8, 0, 0, 0,
      0, 0, 0, A8, B8, C8, D8, E8, F8, G8, H8, I8, J8, 0, 0, 0,
      0, 0, 0, A8, B8, C8, D8, E8, F8, G8, H8, I8, J8, 0, 0, 0,
      0, 0, 0, A8, B8, C8, D8, E8, F8, G8, H8, I8, J8, 0, 0, 0,
      0, 0, 0, A8, B8, C8, D8, E8, F8, G8, H8, I8, J8, 0, 0, 0,
      0, 0, 0, A8, B8, C8, D8, E8, F8, G8, H8, I8, J8, 0, 0, 0,
      0, 0, 0, A8, B8, C8, D8, E8, F8, G8, H8, I8, J8, 0, 0, 0,
      0, 0, 0, A8, B8, C8, D8, E8, F8, G8, H8, I8, J8, 0, 0, 0,
      0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 0,
      0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 0,
      0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 0);

   Black_Promotion_Square : constant array (Chessboard'Range) of Square_Type :=
     (0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 0,
      0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 0,
      0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 0,
      0, 0, 0, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, 0, 0, 0,
      0, 0, 0, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, 0, 0, 0,
      0, 0, 0, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, 0, 0, 0,
      0, 0, 0, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, 0, 0, 0,
      0, 0, 0, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, 0, 0, 0,
      0, 0, 0, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, 0, 0, 0,
      0, 0, 0, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, 0, 0, 0,
      0, 0, 0, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, 0, 0, 0,
      0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 0,
      0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 0,
      0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 0);



   Pc_Sqr : constant array (Integer_Type range 0 .. 223) of String (1 .. 2) :=
     ("  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ",  "  ", "  ",  "  ", "  ",
      "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ",  "  ", "  ",  "  ", "  ",
      "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ",  "  ", "  ",  "  ", "  ",
      "  ", "  ", "  ", "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8", "i8",  "j8", "  ",  "  ", "  ",
      "  ", "  ", "  ", "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7", "i7",  "j7", "  ",  "  ", "  ",
      "  ", "  ", "  ", "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6", "i6",  "j6", "  ",  "  ", "  ",
      "  ", "  ", "  ", "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5", "i5",  "j5", "  ",  "  ", "  ",
      "  ", "  ", "  ", "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4", "i4",  "j4", "  ",  "  ", "  ",
      "  ", "  ", "  ", "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3", "i3",  "j3", "  ",  "  ", "  ",
      "  ", "  ", "  ", "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2", "i2",  "j2", "  ",  "  ", "  ",
      "  ", "  ", "  ", "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1", "i1",  "j1", "  ",  "  ", "  ",
      "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ",  "  ","  ",  "  ", "  ",  "  ", "  ",
      "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ",  "  ","  ",  "  ", "  ",  "  ", "  ",
      "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ",  "  ","  ",  "  ", "  ",  "  ", "  ");

   -- Convert move from/to string notations

   procedure Move_In_String (Move     : in Move_Type;
			     Notation : in Notation_Type;
			     Move_Str : out String;
                             Length   : out Natural);

   -- Convert a move into a string
   function Move_To_String (Move : in Move_Type; Notation : in Notation_Type := Algebraic) return String with Inline => True;

   function Parse_Move (Input : in String) return Move_Type;

   -- In Algebraic notation we need a way to resolve
   -- ambiguous moves where two or more pieces can
   -- move to the same square.
   function Detect_Ambiguous_Move_Notation
     (Move : in Move_Type) return Notation_Flag_Type with Inline => True;


   ----------------------------
   -- Attacks_From functions --
   ----------------------------

   function Attacks_From_North
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_South
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_East
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_West
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_North_East
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_North_West
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_South_East
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_South_West
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_North_North_East
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_North_East_East
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_South_East_East
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_South_South_East
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_South_South_West
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_South_West_West
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_North_West_West
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_North_North_West
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;

   -- For Panther
   function Attacks_From_North_North_North
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_South_South_South
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_East_East_East
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;
   function Attacks_From_West_West_West
     (Side : in Color_Type; Square : in Square_Type) return Boolean with Inline => True;



   -- This function should never be called! It is used
   -- as placeholder because the pointer to functions array is bigger
   -- than needed. "Placeholder" here means exactly that: an empty, useless, placeholder
   function Attacks_From_Placeholder
     (Side : in Color_Type; Square : in Square_Type) return Boolean is (False);

   -- This is the declaration of an access to a function
   -- with two parameters: a side and a square.
   type Move_Direction_Access is access function
     (Side : in Color_Type; Square : in Square_Type) return Boolean;

   -- This is an array of accesses to function .
   -- Here instruction of how to use this array:
   -- When you need to check if the king is in check, there's
   -- no need to look through all moves, it is only required
   -- to look in one direction. This is the idea: while a piece
   -- moves, we look its direction relative to the king and we
   -- use that direction to call the appropriate function
   -- thanks to those pointer to functions.
   -- In the Init function, where we set-up everything
   -- we must fill some Attacks_To with appropriate function
   -- call. I.e._ Attacks_To(North) := Attacks_From_North'Access
   -- and so on for other attacks_from function declared.
   Attacks_To : array (Integer_Type range -48 .. +48) of Move_Direction_Access :=
     (others => Attacks_From_Placeholder'Access);

   -- Initial setup - Random for NBV, but mirror symetric
   -- All pawns protected: Setup_RVNB, Setup_RBVN
   -- Unprotected pawns:   Setup_RVNB, Setup_RBNV, Setup_RNBV, Setup_RNVB
      Type Random_Setup_Type is ( Setup_RVNB, Setup_RBVN, Setup_RVBN, Setup_RBNV, Setup_RNBV, Setup_RNVB );

      --subtype Protected_Random_Setup_Type is Random_Setup_Type range Setup_RVNB .. Setup_RBVN;

      This_Random_Setup : Random_Setup_Type;

      package Random_Setup is new Ada.Numerics.Discrete_Random ( Random_Setup_Type );

   ----------------
   -- Exceptions --
   ----------------

   -- This exception occur if a move has the castle flag
   -- turned on but the move is not a valid castle move.
   Invalid_Castle_Move : exception;


end Acchessboard;
