The wrong way

Discussion of chess software programming and technical issues.

Moderator: Ras

Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: The wrong way

Post by Henk »

By the way have you seen Skippers remaining moves generator. Very ugly and need to be optimized too.

Code: Select all

   public class PieceNonCaptureMoveIterator 
    {


        protected IField location;
        IChessPosition pos;

        int i = 0;

        int dir = 0;
        List<MoveBase> dirMoves;
        int nDirMoves = 0;
        PieceOffsets pieceOffsets = PieceOffsets.Instance;
        DirectionMoves allDirMoves = null;
         ColorSign colSign;
        ChessPiece.Sort pieceSort;

        public PieceNonCaptureMoveIterator()
        {
        }

        public void Init(IField pieceLocation, IChessPosition pos)
        {
            this.pos = pos;
            this.location = pieceLocation;
            if (pos != null) colSign = (ColorSign)pos.CurPlayer;

        }


        public void Reset()
        {
            var occupier = location.Occupier;
            pieceSort = occupier.PieceSort;
            allDirMoves = location.XRayDirectionMoves(pieceSort);

            dir = pieceOffsets[occupier.PieceKind].Length;
            i = 1000;
        }


        public bool Next()
        {
            while (dir-- > 0)
            {
                if ((pieceSort == ChessPiece.Sort.whitePawn || pieceSort == ChessPiece.Sort.blackPawn) 
                       && (dir == (int)Pawn.Direction.EP_RIGHT || dir == (int)Pawn.Direction.EP_LEFT))
                {
                    continue;
                }
                dirMoves = allDirMoves[dir];
                nDirMoves = dirMoves.Count;
                if (nDirMoves > 0)
                {
                    i = -1;
                    return true;
                }
            }
            return false;
        }

      


        public MoveBase Next2()
        {
                switch (pieceSort)
                {
                    case ChessPiece.Sort.whiteKing:
                    case ChessPiece.Sort.blackKing:                       
                            while (Next())
                            {
                                MoveBase move = dirMoves[0];
                                if (move.CanMove(colSign, pos, location))
                                {
                                    return move;
                                }
                            }
                            break;
                    case ChessPiece.Sort.whitePawn:
                        while (i < nDirMoves - 1  || Next())
                        {
                            MoveBase move = dirMoves[++i];                         
                            IField mvEnd = move.End;
                            if (mvEnd.ColNr == move.Start.ColNr)
                            {
                                if (mvEnd.Occupier == null)
                                {
                                    return move;
                                }
                                else
                                {
                                    i = 1000;
                                }
                            } 
  
                         }
                        break;
                    case ChessPiece.Sort.blackPawn:
                       
                        while (i < nDirMoves - 1  || Next())
                        {
                            MoveBase move = dirMoves[++i];                     
                            IField mvEnd = move.End;
                            if (mvEnd.ColNr == move.Start.ColNr)
                            {
                                if (mvEnd.Occupier == null)
                                {
                                    return move;
                                }
                                else
                                {
                                    i = 1000;
                                }
                            }  
                            
                        }
                        break;
                    case ChessPiece.Sort.whiteQueen:
                    case ChessPiece.Sort.whiteRook:
                    case ChessPiece.Sort.whiteBishop:
                    case ChessPiece.Sort.blackQueen:
                    case ChessPiece.Sort.blackRook:
                    case ChessPiece.Sort.blackBishop:
                        while (i < nDirMoves - 1 || Next())
                        {
                            MoveBase move = dirMoves[++i];
                            var occupier2 = move.End.Occupier;
                            if (occupier2 == null)
                            {
                                return move;
                            }
                            else
                            {
                               
                                if (!Next()) break;
                            }

                        }
                        break;

                    case ChessPiece.Sort.whiteKnight:                  
                    case ChessPiece.Sort.blackKnight:
                        while (Next())
                        {
                            if (dirMoves[0].End.Occupier == null) 
                            {
                                return dirMoves[0];
                            }
                        }
                        break;                   
                }  
                return null;
        }
    }
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: The wrong way

Post by bob »

Henk wrote:By the way have you seen Skippers remaining moves generator. Very ugly and need to be optimized too.

Code: Select all

   public class PieceNonCaptureMoveIterator 
    {


        protected IField location;
        IChessPosition pos;

        int i = 0;

        int dir = 0;
        List<MoveBase> dirMoves;
        int nDirMoves = 0;
        PieceOffsets pieceOffsets = PieceOffsets.Instance;
        DirectionMoves allDirMoves = null;
         ColorSign colSign;
        ChessPiece.Sort pieceSort;

        public PieceNonCaptureMoveIterator()
        {
        }

        public void Init(IField pieceLocation, IChessPosition pos)
        {
            this.pos = pos;
            this.location = pieceLocation;
            if (pos != null) colSign = (ColorSign)pos.CurPlayer;

        }


        public void Reset()
        {
            var occupier = location.Occupier;
            pieceSort = occupier.PieceSort;
            allDirMoves = location.XRayDirectionMoves(pieceSort);

            dir = pieceOffsets[occupier.PieceKind].Length;
            i = 1000;
        }


        public bool Next()
        {
            while (dir-- > 0)
            {
                if ((pieceSort == ChessPiece.Sort.whitePawn || pieceSort == ChessPiece.Sort.blackPawn) 
                       && (dir == (int)Pawn.Direction.EP_RIGHT || dir == (int)Pawn.Direction.EP_LEFT))
                {
                    continue;
                }
                dirMoves = allDirMoves[dir];
                nDirMoves = dirMoves.Count;
                if (nDirMoves > 0)
                {
                    i = -1;
                    return true;
                }
            }
            return false;
        }

      


        public MoveBase Next2()
        {
                switch (pieceSort)
                {
                    case ChessPiece.Sort.whiteKing:
                    case ChessPiece.Sort.blackKing:                       
                            while (Next())
                            {
                                MoveBase move = dirMoves[0];
                                if (move.CanMove(colSign, pos, location))
                                {
                                    return move;
                                }
                            }
                            break;
                    case ChessPiece.Sort.whitePawn:
                        while (i < nDirMoves - 1  || Next())
                        {
                            MoveBase move = dirMoves[++i];                         
                            IField mvEnd = move.End;
                            if (mvEnd.ColNr == move.Start.ColNr)
                            {
                                if (mvEnd.Occupier == null)
                                {
                                    return move;
                                }
                                else
                                {
                                    i = 1000;
                                }
                            } 
  
                         }
                        break;
                    case ChessPiece.Sort.blackPawn:
                       
                        while (i < nDirMoves - 1  || Next())
                        {
                            MoveBase move = dirMoves[++i];                     
                            IField mvEnd = move.End;
                            if (mvEnd.ColNr == move.Start.ColNr)
                            {
                                if (mvEnd.Occupier == null)
                                {
                                    return move;
                                }
                                else
                                {
                                    i = 1000;
                                }
                            }  
                            
                        }
                        break;
                    case ChessPiece.Sort.whiteQueen:
                    case ChessPiece.Sort.whiteRook:
                    case ChessPiece.Sort.whiteBishop:
                    case ChessPiece.Sort.blackQueen:
                    case ChessPiece.Sort.blackRook:
                    case ChessPiece.Sort.blackBishop:
                        while (i < nDirMoves - 1 || Next())
                        {
                            MoveBase move = dirMoves[++i];
                            var occupier2 = move.End.Occupier;
                            if (occupier2 == null)
                            {
                                return move;
                            }
                            else
                            {
                               
                                if (!Next()) break;
                            }

                        }
                        break;

                    case ChessPiece.Sort.whiteKnight:                  
                    case ChessPiece.Sort.blackKnight:
                        while (Next())
                        {
                            if (dirMoves[0].End.Occupier == null) 
                            {
                                return dirMoves[0];
                            }
                        }
                        break;                   
                }  
                return null;
        }
    }
You are using the wrong term. You optimize code to make it faster, sometimes hurting readability/understandability. You clean up code that is unreadable or overly complex.

A good rule of thumb is that "less is more". You can go too far in that direction of course, but the code you have is far larger. My entire move generator, including GenerateCaptures, GenerateNonCaptures, and GenerateEvasions is under 1000 lines of code with half of that total in comments.

This code doesn't need to be big, or complicated. Above all else it must be correct, first.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: The wrong way

Post by Sven »

Henk wrote:By the way have you seen Skippers remaining moves generator. Very ugly and need to be optimized too.
No. I suggest not to optimize any part of that but instead to rewrite it from scratch. But think about an appropriate algorithm first. The current implementation is really too complex and almost unmanageable.

For instance, my non-captures move generator for a bitboard engine works like this, in principle (omitting details like parameters etc.):

Code: Select all

void generateQuietMoves()
{
    generateCastles();
    generateQuietKnightMoves();
    generateQuietSlidingMoves();
    generateQuietKingMoves();
    generateQuietPawnMoves();
}
And for completeness, my capture move generator for the same bitboard engine works like this:

Code: Select all

void generateTacticalMoves()
{
    generatePromotions();
    generatePawnCaptures();
    generateEp();
    generateKnightCaptures();
    generateSlidingCaptures();
    generateKingCaptures();
}
The order can be discussed, of course. Also there are many other ways to structure the code. A good strategy may be to write small functions that have a well-defined purpose.

I cannot judge about the remaining parts of your program. However, if the other code resembles your move generator code then I suggest to rethink it completely as well.
Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: The wrong way

Post by Henk »

I had already started. Result no speed improvement and perhaps 1% slower. Maybe better leave it and never change it. For I don't expect any speed gains.

Code: Select all

     public void CollectNonCaptureMoves(List<MoveBase> moves)
        {
            PieceOffsets pieceOffsets = PieceOffsets.Instance;
            var colSign = (ColorSign)CurPlayer;


            BitBoardIndex bbIndex = BitBoardIndex.Instance;
            UInt64 bits = CurPlayer == 1 ? Board.WhitePieces : Board.BlackPieces;

            List<MoveBase> dirMoves = null;
            int nDirMoves = 0;
            int i;

            ulong emptySquares = ~Board.Occupiers;
            while (bits != 0)
            {
                var bit = bits & (~bits + 1);
                bits &= bits - 1;
                var location = ChessBoard.GetField(bbIndex, bit);
                var occupier = location.Occupier;
                var pieceSort = occupier.PieceSort;
                var allDirMoves = location.XRayDirectionMoves(occupier.PieceSort);
                var pieceKind = occupier.PieceKind;
                var dir = pieceOffsets[occupier.PieceKind].Length;
 
                switch (pieceKind)
                {
                       

                        case ChessPiece.Kind.King:
                        {
                            var xrayCapturesK = location.XRayMoves(pieceSort) & emptySquares;
                            var mvDictK = ((Field)location).AllMovesDict(pieceSort);
                            while (xrayCapturesK != 0)
                            {
                                var moveBit = xrayCapturesK & (~xrayCapturesK + 1);
                                xrayCapturesK &= xrayCapturesK - 1;
                                var move = mvDictK.Get(moveBit);
                                move.Value = (int)(HistoryTable.GetHistoryValue(move));
                                moves.Add(move);
                            }
                            for (int k = 8; k <= 9; k++)
                            {
                                dirMoves = allDirMoves[k];
                                nDirMoves = dirMoves.Count;
                                if (nDirMoves > 0)
                                {
                                    MoveBase move = dirMoves[0];
                                    if (move.CanMove(colSign, this, location))
                                    {
                                        move.Value = (int)(HistoryTable.GetHistoryValue(move));
                                        moves.Add(move);
                                    }
                                }
                            }

                        }
                        break;
                    case ChessPiece.Kind.Pawn:
                        i = 1000;
                        while (i < nDirMoves - 1 || dir-- > 0)
                        {                           
                            if (i < nDirMoves - 1)
                            {
                            }
                            else 
                            {                      
                                    if ((pieceKind == ChessPiece.Kind.Pawn) 
                                         && (dir == (int)Pawn.Direction.EP_RIGHT || dir == (int)Pawn.Direction.EP_LEFT))
                                    {
                                        continue;
                                    }
                                    dirMoves = allDirMoves[dir];
                                    nDirMoves = dirMoves.Count;
                                    if (nDirMoves > 0)
                                    {
                                        i = -1;
                                     }
                                    else continue;                          
                            }
                           
                            MoveBase move = dirMoves[++i];
                            IField mvEnd = move.End;
                            if (mvEnd.ColNr == move.Start.ColNr)
                            {
                                if (mvEnd.Occupier == null)
                                {
                                    move.Value = (int)(HistoryTable.GetHistoryValue(move));
                                    moves.Add(move);
                                }
                                else
                                {
                                    i = 1000;
                                }
                            }                         
                        }
                        break;
                    case ChessPiece.Kind.Queen:
                    case ChessPiece.Kind.Rook:
                    case ChessPiece.Kind.Bishop:
                        i = 1000;
                        bool next;
                        while ((next = i < nDirMoves - 1) || dir-- > 0)
                        {
                            if (next)
                            {                              
                            }
                            else
                            {
                                dirMoves = allDirMoves[dir];
                                nDirMoves = dirMoves.Count;
                                if (nDirMoves > 0)
                                {
                                    i = -1;
                                   
                                }
                                else continue;
                            }
                            MoveBase move = dirMoves[++i];
                            if (move.End.Occupier == null)
                            {
                                move.Value = (int)(HistoryTable.GetHistoryValue(move));
                                moves.Add(move);
                            }
                            else
                            {
                                i = 1000;
                            }


                        }
                           
                        break;

                    case ChessPiece.Kind.Knight:
                       
                        var xrayCaptures = location.XRayMoves(pieceSort) & emptySquares;
                        var mvDict = ((Field)location).AllMovesDict(pieceSort);
                        while (xrayCaptures != 0)
                        {
                            var moveBit = xrayCaptures & (~xrayCaptures + 1);
                            xrayCaptures &= xrayCaptures - 1;
                            var move = mvDict.Get(moveBit);
                            move.Value = (int)(HistoryTable.GetHistoryValue(move));
                            moves.Add(move);
                        }
                        break;                      
                }
               
            }
            moves.Sort(OneLevelMoveSelector.descMoveValueComparer);
        }
Dann Corbit
Posts: 12792
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: The wrong way

Post by Dann Corbit »

Henk wrote:I had already started. Result no speed improvement and perhaps 1% slower. Maybe better leave it and never change it. For I don't expect any speed gains.
1% faster or slower will not matter.
Make it clear.
Make it understandable.
Make it simple.
Make it neat.
Make it so you could show it to your next door neighbor and she could tell you want it is doing.

Did you notice that Sven's code was instantly transparent? In other words, one glance showed exactly what it is doing. I can tell you just by glancing at it that it was correct. Can you do that with your code? If not, why not?

{Edit: I originally put Steve's because Sven is a translation of Steve or vice-versa, IIRC and my brain transmongrified it to English version}

Organization.
Clarity.
Simplicity.

Make it right, make it clear, make it understandable.

Trying to make it 5% faster NOW is a terrible, terrible, awful, shameful, harmful, distasteful, heart-wrenching path that leads to never making it to the finish line.

IMO-YMMV.
Taking ideas is not a vice, it is a virtue. We have another word for this. It is called learning.
But sharing ideas is an even greater virtue. We have another word for this. It is called teaching.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: The wrong way

Post by Sven »

Henk wrote:I had already started. Result no speed improvement and perhaps 1% slower. Maybe better leave it and never change it. For I don't expect any speed gains.
Main goal of rewriting should not be speed improvement but proper structuring of code.

Code: Select all

void generateSlidingMovesTo(Board const & b, Color side, uint64_t targets, MoveList & moveList)
{
    // generate all bishop-type moves to any square in 'targets'
    uint64_t bbMyDiagonalPieces = b.bbBishops(side) | b.bbQueens(side);
    while (bbMyDiagonalPieces != 0) {
        SqrId from = BitUtil::popAndGetPositionOfLSB(bbMyDiagonalPieces);

        // table lookup
        uint64_t bbResult = BoardModel::diagonalAttacksFrom(from, b.bbEmpty()) & targets;

        // unfold into move list
        while (bbResult != 0) {
            SqrId to(BitUtil::popAndGetPositionOfLSB(bbResult));
            generateOneMove(moveList, from, to);
        }
    }

    // generate all rook-type moves to any square in 'targets'
    uint64_t bbMyStraightPieces = b.bbRooks  (side) | b.bbQueens(side);
    while (bbMyStraightPieces != 0) {
        SqrId from = BitUtil::popAndGetPositionOfLSB(bbMyStraightPieces);

        // table lookup
        uint64_t bbResult = BoardModel::straightAttacksFrom(from, b.bbEmpty()) & targets;

        // unfold into move list
        while (bbResult != 0) {
            SqrId to(BitUtil::popAndGetPositionOfLSB(bbResult));
            generateOneMove(moveList, from, to);
        }
    }
}
Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: The wrong way

Post by Henk »

I saw there at least was a wrong variable name. Maybe these UInt64 or operations are not making it faster. Also after you have extracted a bit of a move you still have to look up the corresponding move in a dictionary.

Code: Select all

      public void CollectNonCaptureMoves(List<MoveBase> moves)
        {
            PieceOffsets pieceOffsets = PieceOffsets.Instance;
            var colSign = (ColorSign)CurPlayer;
            BitBoardIndex bbIndex = BitBoardIndex.Instance;
            UInt64 curPiecesBB = CurPlayer == 1 ? Board.WhitePieces : Board.BlackPieces;
            List<MoveBase> dirMoves = null;
            int nDirMoves = 0;
            int i;
            ulong emptySquares = ~Board.Occupiers;
            while (curPiecesBB != 0)
            {
                var bit = curPiecesBB & (~curPiecesBB + 1);
                curPiecesBB &= curPiecesBB - 1;
                var location = ChessBoard.GetField(bbIndex, bit);
                var occupier = location.Occupier;
                var pieceSort = occupier.PieceSort;
                var allDirMoves = location.XRayDirectionMoves(occupier.PieceSort);
                var pieceKind = occupier.PieceKind;
                var dir = pieceOffsets[occupier.PieceKind].Length;
 
                switch (pieceKind)
                {
                        case ChessPiece.Kind.King:
                        {
                            var xrayNonCapturesK = location.XRayMoves(pieceSort) & emptySquares;
                            var mvDictK = ((Field)location).AllMovesDict(pieceSort);
                            while (xrayNonCapturesK != 0)
                            {
                                var moveBit = xrayNonCapturesK & (~xrayNonCapturesK + 1);
                                xrayNonCapturesK &= xrayNonCapturesK - 1;
                                var move = mvDictK.Get(moveBit);
                                move.Value = (int)(HistoryTable.GetHistoryValue(move));
                                moves.Add(move);
                            }

                            // castling
                            for (int k = 8; k <= 9; k++)
                            {
                                dirMoves = allDirMoves[k];
                                nDirMoves = dirMoves.Count;
                                if (nDirMoves > 0)
                                {
                                    MoveBase move = dirMoves[0];
                                    if (move.CanMove(colSign, this, location))
                                    {
                                        move.Value = (int)(HistoryTable.GetHistoryValue(move));
                                        moves.Add(move);
                                    }
                                }
                            }

                        }
                        break;
                    case ChessPiece.Kind.Pawn:
                        i = 1000;
                        while (i < nDirMoves - 1 || dir > 0)
                        {                           
                            if (i < nDirMoves - 1)
                            {
                            }
                            else 
                            {
                                    dir--;               
                                    if ((pieceKind == ChessPiece.Kind.Pawn) 
                                         && (dir == (int)Pawn.Direction.EP_RIGHT || dir == (int)Pawn.Direction.EP_LEFT))
                                    {
                                        continue;
                                    }
                                    dirMoves = allDirMoves[dir];
                                    nDirMoves = dirMoves.Count;
                                    if (nDirMoves > 0)
                                    {
                                        i = -1;
                                     }
                                    else continue;                          
                            }
                           
                            MoveBase move = dirMoves[++i];
                            IField mvEnd = move.End;
                            if (mvEnd.ColNr == move.Start.ColNr)
                            {
                                if (mvEnd.Occupier == null)
                                {
                                    move.Value = (int)(HistoryTable.GetHistoryValue(move));
                                    moves.Add(move);
                                }
                                else
                                {
                                    i = 1000;
                                }
                            }                         
                        }
                        break;
                    case ChessPiece.Kind.Queen:
                    case ChessPiece.Kind.Rook:
                    case ChessPiece.Kind.Bishop:
                        i = 1000;
                        bool next;
                        while ((next = i < nDirMoves - 1) || dir > 0)
                        {
                            if (next)
                            {                              
                            }
                            else
                            {
                                dir--;
                                dirMoves = allDirMoves[dir];
                                nDirMoves = dirMoves.Count;
                                if (nDirMoves > 0)
                                {
                                    i = -1;
                                   
                                }
                                else continue;
                            }
                            MoveBase move = dirMoves[++i];
                            if (move.End.Occupier == null)
                            {
                                move.Value = (int)(HistoryTable.GetHistoryValue(move));
                                moves.Add(move);
                            }
                            else
                            {
                                i = 1000;
                            }
                        }                           
                        break;

                    case ChessPiece.Kind.Knight:                      
                        var xrayNonCaptures = location.XRayMoves(pieceSort) & emptySquares;
                        var mvDict = ((Field)location).AllMovesDict(pieceSort);
                        while (xrayNonCaptures != 0)
                        {
                            var moveBit = xrayNonCaptures & (~xrayNonCaptures + 1);
                            xrayNonCaptures &= xrayNonCaptures - 1;
                            var move = mvDict.Get(moveBit);
                            move.Value = (int)(HistoryTable.GetHistoryValue(move));
                            moves.Add(move);
                        }
                        break;                      
                }
               
            }
            moves.Sort(OneLevelMoveSelector.descMoveValueComparer);
        }
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: The wrong way

Post by Sven »

Henk wrote:Also after you have extracted a bit of a move you still have to look up the corresponding move in a dictionary.
Look up what?

You have the "from" square where you started to generated moves for, and you have found a bit position which is exactly the "to" square. What else do you need to look up? All moves, except for the few special move types, only need the "from" and "to" squares to be fully defined.

How does your move representation look like?
Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: The wrong way

Post by Henk »

Sven Schüle wrote:
Henk wrote:Also after you have extracted a bit of a move you still have to look up the corresponding move in a dictionary.
Look up what?

You have the "from" square where you started to generated moves for, and you have found a bit position which is exactly the "to" square. What else do you need to look up? All moves, except for the few special move types, only need the "from" and "to" squares to be fully defined.

How does your move representation look like?
My engine only generates moves once and moves are pre-calculated so I have to look them up. Also I assigned a unique number to each move for storing it into a database.
Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: The wrong way

Post by Henk »

Code for pawns could be much simpler. Also code for sliders looks more normal now.

Code: Select all

  public void CollectNonCaptureMoves(List<MoveBase> moves)
        {
            PieceOffsets pieceOffsets = PieceOffsets.Instance;
            var colSign = (ColorSign)CurPlayer;
            BitBoardIndex bbIndex = BitBoardIndex.Instance;
            UInt64 curPiecesBB = CurPlayer == 1 ? Board.WhitePieces : Board.BlackPieces;
            List<MoveBase> dirMoves = null;
            int nDirMoves = 0;
            ulong emptySquares = ~Board.Occupiers;
            DirectionMoves allDirMoves = null;
 
            while (curPiecesBB != 0)
            {
                var bit = curPiecesBB & (~curPiecesBB + 1);
                curPiecesBB &= curPiecesBB - 1;
                var location = ChessBoard.GetField(bbIndex, bit);
                var occupier = location.Occupier;
                var pieceSort = occupier.PieceSort;
  
                switch (occupier.PieceKind)
                {
                        case ChessPiece.Kind.King:
                        {
                            var xrayNonCapturesK = location.XRayMoves(pieceSort) & emptySquares;
                            var mvDictK = ((Field)location).AllMovesDict(pieceSort);
                            while (xrayNonCapturesK != 0)
                            {
                                var moveBit = xrayNonCapturesK & (~xrayNonCapturesK + 1);
                                xrayNonCapturesK &= xrayNonCapturesK - 1;
                                var move = mvDictK.Get(moveBit);
                                move.Value = (int)(HistoryTable.GetHistoryValue(move));
                                moves.Add(move);
                            }

                            allDirMoves = location.XRayDirectionMoves(occupier.PieceSort);
                            for (int k = 8; k <= 9; k++)
                            {
                                dirMoves = allDirMoves[k];
                                nDirMoves = dirMoves.Count;
                                if (nDirMoves > 0)
                                {
                                    MoveBase move = dirMoves[0];
                                    if (move.CanMove(colSign, this, location))
                                    {
                                        move.Value = (int)(HistoryTable.GetHistoryValue(move));
                                        moves.Add(move);
                                    }
                                }
                            }

                        }
                        break;
                    case ChessPiece.Kind.Pawn:

                        allDirMoves = location.XRayDirectionMoves(occupier.PieceSort);
                        dirMoves = allDirMoves[(int)Pawn.Direction.FRONT];
                        nDirMoves = dirMoves.Count;
                        for (int j = 0; j < dirMoves.Count; j++)
                        {
                            MoveBase move = dirMoves[j];
                            if (move.End.Occupier == null)
                            {
                                move.Value = (int)(HistoryTable.GetHistoryValue(move));
                                moves.Add(move);
                            }
                            else
                            {
                                break;
                            }
                        }
                      
                        break;
                    case ChessPiece.Kind.Queen:
                    case ChessPiece.Kind.Rook:
                    case ChessPiece.Kind.Bishop:

                        allDirMoves = location.XRayDirectionMoves(occupier.PieceSort);
                        for (int dir = 0; dir < pieceOffsets[occupier.PieceKind].Length; dir++)
                        {
                            dirMoves = allDirMoves[dir];
                            for (int j = 0; j < dirMoves.Count; j++)
                            {
                                MoveBase move = dirMoves[j];
                                if (move.End.Occupier == null)
                                {
                                    move.Value = (int)(HistoryTable.GetHistoryValue(move));
                                    moves.Add(move);
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }                       
                        break;

                    case ChessPiece.Kind.Knight:
                        var xrayNonCaptures = location.XRayMoves(pieceSort) & emptySquares;
                        var mvDict = ((Field)location).AllMovesDict(pieceSort);
                        while (xrayNonCaptures != 0)
                        {
                            var moveBit = xrayNonCaptures & (~xrayNonCaptures + 1);
                            xrayNonCaptures &= xrayNonCaptures - 1;
                            var move = mvDict.Get(moveBit);
                            move.Value = (int)(HistoryTable.GetHistoryValue(move));
                            moves.Add(move);
                        }
                        break;                      
                }
               
            }
            moves.Sort(OneLevelMoveSelector.descMoveValueComparer);
        }