/// <summary>
        /// Parses a regular move (without promotion information) fron its CAN.
        /// </summary>
        /// <param name="can"></param>
        /// <returns></returns>
        public static Move ParseRegularCAN(string can)
        {
            Move m = new Move();

            try
            {
                if (can != null && can.Length >= 4)
                {
                    m.from = (byte)((('8' - can[1]) << 3) + can[0] - 'a');
                    m.to = (byte)((('8' - can[3]) << 3) + can[2] - 'a');
                }
            }
            catch
            {
            }

            return m;
        }
        /// <summary>
        /// Tries to make a pseudo-legal move.
        /// Returns true if the move has been actually made, false otherwise.
        /// </summary>
        private bool Make(Move move)
        {
            // if this is a castling move, move the rook
            // the king will be moved with the usual move code later
            if ((move.bits & 2) != 0)
            {
                if (InCheck(side)) return false;

                int from, to;

                switch (move.to)
                {
                    case G1:
                        if (color[F1] != EMPTY || color[G1] != EMPTY || Attacks(F1, xside) || Attacks(G1, xside))
                            return false;

                        from = H1;
                        to = F1;

                        break;
                    case C1:
                        if (color[B1] != EMPTY || color[C1] != EMPTY || color[D1] != EMPTY || Attacks(C1, xside) || Attacks(D1, xside))
                            return false;

                        from = A1;
                        to = D1;

                        break;
                    case G8:
                        if (color[F8] != EMPTY || color[G8] != EMPTY || Attacks(F8, xside) || Attacks(G8, xside))
                            return false;

                        from = H8;
                        to = F8;

                        break;
                    case C8:
                        if (color[B8] != EMPTY || color[C8] != EMPTY || color[D8] != EMPTY || Attacks(C8, xside) || Attacks(D8, xside))
                            return false;

                        from = A8;
                        to = D8;

                        break;
                    default:

                        from = -1;
                        to = -1;

                        break;
                }

                // move the rook
                color[to] = color[from];
                piece[to] = piece[from];
                color[from] = EMPTY;
                piece[from] = EMPTY;
            }

            // back up information so the move can be taken back
            history[ply].move = move;
            history[ply].capture = piece[move.to];
            history[ply].castle = castle;
            history[ply].ep = ep;
            history[ply].fifty = fifty;
            ply++;

            // update the castle, en passant, and fifty-move-draw variables
            castle &= castleMask[move.from] & castleMask[move.to];
            ep = (move.bits & 8) != 0 ? (side == LIGHT ? move.to + 8 : move.to - 8) : -1;
            fifty = (move.bits & 17) != 0 ? 0 : fifty + 1;

            // move the piece
            color[move.to] = side;
            piece[move.to] = (move.bits & 32) != 0 ? move.promote : piece[move.from];
            color[move.from] = EMPTY;
            piece[move.from] = EMPTY;

            // erase the pawn if this is an en passant move
            if ((move.bits & 4) != 0)
            {
                color[side == LIGHT ? move.to + 8 : move.to - 8] = EMPTY;
                piece[side == LIGHT ? move.to + 8 : move.to - 8] = EMPTY;
            }

            // switch sides
            side ^= 1;
            xside ^= 1;

            // test for legality
            // if we can capture the opponent's king, it's an illegal position and the move must be taken back
            if (InCheck(xside))
            {
                TakeBack();
                return false;
            }

            return true;
        }
        /// <summary>
        /// Gets the next move.
        /// </summary>
        /// <param name="fen">The board configuration.</param>
        /// <param name="repetitionMoveCandidate">
        /// The move that, if made, it will result a draw by repetition. 
        /// The engine will try to avoid the move if there is a better one.
        /// </param>
        /// <param name="depth">Search depth level.</param>
        /// <returns></returns>
        public string GetNextMove(string fen, string repetitionMoveCandidate, int depth)
        {
            // the engine is still thinking, return
            if (thinking) { return null; }

            // initialize the engine
            try
            {
                Initialize(fen);
            }
            catch
            {
                return null;
            }

               int hash;

            // look in the opening book (OBookMem.cs) in memory buffer...

            short obMove=0;
            if (moves <= Settings_Default_OpeningBookMaxMoveNo) obMove=obookmem.OBookGet(hash = GetHashCode());
            if(obMove>0)
                {
                Move move = new Move();
                move.from = (byte)(obMove>> 8);
                move.to = (byte)(obMove & 255);

                return move.ToString();
                }

            // look in the opening book

               if (book != null && moves <= Settings_Default_OpeningBookMaxMoveNo && book.ContainsKey(hash = GetHashCode()))
               {
                // get the list of available moves for this board
                List<short> list = book[hash];

                //return a random move from the list
                short shortMove = list[random.Next(list.Count)];

                Move move = new Move();
                move.from = (byte)(shortMove >> 8);
                move.to = (byte)(shortMove & 255);

                return move.ToString();
            }
            else
            {
                // set repetition move
                // a repetition move cannot be a promotion move, a castling move, a capture move or a pawn move
                // so the move bits and capture are 0
                repMove = Move.ParseRegularCAN(repetitionMoveCandidate);

                // the depth must be between 1 and ChessEngineMaxDepth
                if (depth < 1)
                    depth = 1;
                else if (depth > Settings_Default_ChessEngineMaxDepth)
                    depth = Settings_Default_ChessEngineMaxDepth;
            //                else if (depth > Settings.Default.ChessEngineMaxDepth)
            //                    depth = Settings.Default.ChessEngineMaxDepth;

            // search
                try
                {
                    thinking = true;
                    Think(depth);
                }
                catch
                {
                    // the search has ended abruptly or something went wrong
                }
                finally
                {
                    thinking = false;
                }

                // pv[0, 0] is the best move
                return pv[0, 0].ToString();
               }
        }