Chess engine performance/blunder issue after implementing transposition table in C#

101 views Asked by At

I have been working on developing a chess engine using C#. It was working quite well until I added the transposition table feature. My engine's strength decreased with the transposition table, which is strange since it should be stronger or at least the same.

For example, in this position below:

8/6K1/4k3/5r2/8/8/8/8 w - - 28 15 8/6K1/4k3/5r2/8/8/8/8 w - - 28 15

My engine without the transposition table doesn't see the mate at first, so it tries to move my king to the corner of the board and finally sees a checkmate.

but when I turn on the transposition table, it sees checkmate at first, but instead, it shuffles around its king just before the three-fold repetition and moves the king backward.

also, there was a situation where it blundered its queen when it was completely winning when the transposition table was turned on. I know it's because of the transposition table because it played a logical move when I reset the transposition table.

----these are the key codes of my chess engine.

(sorry for the dirty codes- I'm not that good at programming)

minimax code- maximizing player.

(int, Move, bool) AlphaBetaMax(int depth, int[] CB, List<int> HashList, bool WKC, bool WQC, bool BKC, bool BQC, Move lMove, int alpha, int beta, UInt64 h, Dictionary<UInt64, int> ThreeFold, ref PVLine pline)
    {
        PVLine line = new PVLine(0, new Move[20]);
        int[] Board;
        List<int> HL;
        List<Move> MoveList = new();
        bool Check;
        bool isCheckingMove;
        int Col = Piece.White;
        Move BestMove = new Move(0, 0, 0);
        UInt64 Hash = h;

        (MoveList, Check, isCheckingMove) = GenerateLegalMoves(WKC, WQC, BKC, BQC, CB, HashList, Col, false, true);
        
        Dictionary<UInt64, int> ThreeFoldRepCopy = new Dictionary<UInt64, int>(ThreeFold);
        //List<Move> nodeLineCopy = new List<Move>(NodeLine);
        if (MoveList.Count == 0)
        {
            if (Check)
            {
                Hash ^= side_Keys;
                TranspositionTable[GetTranspositionIndex(Hash, hashSize)] = new TranspositionValue(h, -100000000, 9999, null, 0);
                //pline.Cmove = 0;
                return (-100000000, lMove, true);

            }
            else
            {
                Hash ^= side_Keys;
                TranspositionTable[GetTranspositionIndex(Hash, hashSize)] = new TranspositionValue(h, 0, 9999, null, 0);
                //pline.Cmove = 0;
                return (0, lMove, true);
            }

        }
        if (depth == 0)
        {
            if ((lMove.Type | MoveType.capture) != 0)//capture move
            {
                int Eval = EvaluateBoard(CB, HashList, WKC, WQC, BKC, BQC);

                UpdateTranspositionTable(h, Eval, pline, 0, 0);

                int Val;
                bool isComplete;
                (Val, isComplete) = quiescenceMax(Q_DEPTH, CB, HashList, WKC, WQC, BKC, BQC, lMove, alpha, beta, Hash);
                
                return (Val, lMove, isComplete);
            }
            else
            {
                int Eval = EvaluateBoard(CB, HashList, WKC, WQC, BKC, BQC);
                UpdateTranspositionTable(h, Eval, pline, 0, 0);

                return (Eval, lMove, true);
            }


        }
        if (HashList.Count == 2)
        {
            return (0, lMove, true);
        }
        if (IsThreeFold(ThreeFoldRepCopy, Hash, 3))
        {
            return (0, new Move(0, 0, 0), true);
        }

        if (depth != 1)
        {
            MoveList.Sort(CompareMoves);
        }


        bool WhiteKingCastle = WKC;
        bool WhiteQueenCastle = WQC;
        bool BlackKingCastle = BKC;
        bool BlackQueenCastle = BQC;
        
        int Score= 0;
      
        for (int i = 0; i < MoveList.Count; i++)
        {
            ThreeFoldRepCopy = ThreeFoldRep.ToDictionary(entry => entry.Key,
                                               entry => entry.Value);
            if (TimeControl.ElapsedMilliseconds >= TIME_LIMIT)
            {
                return (0, new Move(0, 0, 0), false);
            }
            (Board, HL) = MakeMove(MoveList[i], CB, HashList, ref Hash);
            if (lMove.Type == MoveType.Special00)//hash enpassent
            {
                Hash ^= en_Keys[lMove.From + 8];
            }
            moveCount++;
            Hash ^= castle_Keys[CastlingIndex(WKC, WQC, BKC, BQC)];
            if (WKC && ((Board[60] != (Piece.White | Piece.King)) || (Board[63] != (Piece.White | Piece.Rook))))
            {
                WhiteKingCastle = false;
            }
            if (WQC && ((Board[60] != (Piece.White | Piece.King)) || (Board[56] != (Piece.White | Piece.Rook))))
            {
                WhiteQueenCastle = false;
            }
            Hash ^= castle_Keys[CastlingIndex(WhiteKingCastle, WhiteQueenCastle, BlackKingCastle, BlackQueenCastle)];

            Hash ^= side_Keys;
            
            
            if (((MoveList[i].Type & MoveType.capture) != 0) || (ValueToPiece(CB[MoveList[i].To]) == Piece.Pawn) || ((MoveList[i].Type == MoveType.Special01) || (MoveList[i].Type == (MoveType.Special01 | MoveType.Special00))))//resetMoveCount
            {
                ThreeFoldRepCopy.Clear();
            }
            if (ThreeFoldRepCopy.ContainsKey(Hash))
            {
                ThreeFoldRepCopy[Hash] += 1;
            }
            else
            {
                ThreeFoldRepCopy.Add(Hash, 1);
            }
            bool isTransposition = false;
            
            if (IsThreeFold(ThreeFoldRepCopy, Hash, 3))
            {
                Score = 0;
                isTransposition = true;
                //Debug.Log(true);
                //return (0, new Move(0, 0, 0), true);
                
            }
            else
            {
                
                
                TranspositionValue transValue = TranspositionTable[GetTranspositionIndex(Hash, hashSize)];
                if (transValue != null && transValue.Zobrish == Hash && transValue.Depth >= depth - 1 && (((transValue.Depth) % 2 == (depth - 1) % 2) || transValue.Depth == 9999))//prevent collision problem
                {
                    if (transValue.State == 0)//fully searched node
                    {
                        isTransposition = true;
                        Score = transValue.Eval;

                        Array.Copy(transValue.EngineLine.ArgMove, line.ArgMove, line.Cmove);
                        line.Cmove = transValue.EngineLine.Cmove;
                        
                    }
                    else if (transValue.State == 2)
                    {
                        if (beta <= transValue.Eval)
                        {
                            isTransposition = true;
                            Score = beta;

                            Array.Copy(transValue.EngineLine.ArgMove, line.ArgMove, line.Cmove);
                            line.Cmove = transValue.EngineLine.Cmove;
                            
                        }

                    }
                }
            }
            if(!isTransposition)
            {
                (Score, _, _) = AlphaBetaMin(depth - 1, Board, HL, WhiteKingCastle, WhiteQueenCastle, BlackKingCastle, BlackQueenCastle, MoveList[i], alpha, beta, Hash, ThreeFoldRepCopy, ref line);
            }
            else
            {
                SavedByTransposition++;
            }
            

            if (Score >= beta)
            {
                if (!isTransposition)
                {
                    UpdateTranspositionTable(Hash, beta, line, 1, 2);
                }
                return (beta, MoveList[i], true);
            }
            if (!isTransposition)
            {
                UpdateTranspositionTable(Hash, Score, line, depth - 1, 0);
            }
            if (Score > alpha)
            {
                alpha = Score;
                BestMove = MoveList[i];

                pline.ArgMove[0] = BestMove;
                Array.Copy(line.ArgMove, 0, pline.ArgMove, 1, line.Cmove);
                pline.Cmove = line.Cmove + 1;
                
            }
            
            Hash = h;
        }

        return (alpha, BestMove, true);
        int CompareMoves(Move move1, Move move2)
        {

            if (move1.To == lMove.To)
            {
                if (move2.To == lMove.To)
                    return 0; // Both moves capture the lastly moved piece.
                else
                    return -1; // move1 captures the lastly moved piece.
            }
            else if (move2.To == lMove.To)
            {
                return 1; // move2 captures the lastly moved piece.
            }
            if (IsCapture(move1) && IsCapture(move2))
            {

                int value1 = Get_MVVLVA_Value(move1, CB);
                int value2 = Get_MVVLVA_Value(move2, CB);
                return value2.CompareTo(value1); // Sort in descending order
            }
            else if (IsCapture(move1))
            {
                return -1; // move1 is a capture, move2 is not
            }
            else if (IsCapture(move2))
            {
                return 1; // move2 is a capture, move1 is not
            }
            else
            {
                return 0; // Both moves are non-captures; maintain their order
            }
        }
    }

minimax code minimizing player

(int, Move, bool) AlphaBetaMin(int depth, int[] CB, List<int> HashList, bool WKC, bool WQC, bool BKC, bool BQC, Move lMove, int alpha, int beta, UInt64 h, Dictionary<UInt64, int> ThreeFold, ref PVLine pline)
    {
        PVLine line = new PVLine(0, new Move[20]); 
        int[] Board;
        List<int> HL;
        List<Move> MoveList = new();
        bool Check;
        bool isCheckingMove;
        int Col = Piece.Black;
        UInt64 Hash = h;
        (MoveList, Check, isCheckingMove) = GenerateLegalMoves(WKC, WQC, BKC, BQC, CB, HashList, Col, false, true);
        //move ordering

        Dictionary<UInt64, int> ThreeFoldRepCopy = new Dictionary<UInt64, int>(ThreeFold);
        //List<Move> nodeLineCopy = new List<Move>(NodeLine);
        if (MoveList.Count == 0)
        {
            if (Check)
            {
                Hash ^= side_Keys;
                TranspositionTable[GetTranspositionIndex(Hash, hashSize)] = new TranspositionValue(h, 100000000, 9999, null, 0);
                
                return (100000000, lMove, true);
            }
            else
            {
                Hash ^= side_Keys;
                TranspositionTable[GetTranspositionIndex(Hash, hashSize)] = new TranspositionValue(h, 0, 9999, null, 0);
                
                return (0, lMove, true);
            }

        }
        if (depth == 0)
        {
            //pline.Cmove = 0;

            if ((lMove.Type | MoveType.capture) != 0)//capture move
            {
                int Eval = EvaluateBoard(CB, HashList, WKC, WQC, BKC, BQC);

                UpdateTranspositionTable(h, Eval, pline, 0, 0);
                
                

                int Val;
                bool isComplete;
                (Val, isComplete) = quiescenceMin(Q_DEPTH, CB, HashList, WKC, WQC, BKC, BQC, lMove, alpha, beta, Hash);

                return (Val, lMove, isComplete);
               

            }
            else
            {
                int Eval = EvaluateBoard(CB, HashList, WKC, WQC, BKC, BQC);

                UpdateTranspositionTable(h, Eval, pline, 0, 0);
                return (Eval, lMove, true);
            }
            



        }
        if (HashList.Count == 2)
        {
            return (0, lMove, true);
        }
        if (IsThreeFold(ThreeFoldRepCopy, Hash, 3))
        {
            return (0, new Move(0, 0, 0), true);

        }
        if (depth != 1)
        {
            MoveList.Sort(CompareMoves);
        }



        bool WhiteKingCastle = WKC;
        bool WhiteQueenCastle = WQC;
        bool BlackKingCastle = BKC;
        bool BlackQueenCastle = BQC;

        Move BestMove = new Move(0, 0, 0);
        
        int Score = 0;
        
        for (int i = 0; i < MoveList.Count; i++)
        {
            ThreeFoldRepCopy = ThreeFoldRep.ToDictionary(entry => entry.Key,
                                      entry => entry.Value);

            if (TimeControl.ElapsedMilliseconds >= TIME_LIMIT)
            {
                return (0, new Move(0, 0, 0), false);
            }
            
            (Board, HL) = MakeMove(MoveList[i], CB, HashList, ref Hash);
            if (lMove.Type == MoveType.Special00)//hash enpassent
            {
                Hash ^= en_Keys[lMove.From - 8];
            }
            moveCount++;
            Hash ^= castle_Keys[CastlingIndex(WKC, WQC, BKC, BQC)];
            if (BKC && (Board[4] != (Piece.White | Piece.King)) || (Board[7] != (Piece.White | Piece.Rook)))
            {
                BlackKingCastle = false;

            }

            if (BQC && (Board[4] != (Piece.White | Piece.King)) || (Board[0] != (Piece.White | Piece.Rook)))
            {
                BlackQueenCastle = false;
            }
            Hash ^= castle_Keys[CastlingIndex(WhiteKingCastle, WhiteQueenCastle, BlackKingCastle, BlackQueenCastle)];

            Hash ^= side_Keys;
            //nodeLineCopy.Add(MoveList[i]);

            
            if (((MoveList[i].Type & MoveType.capture) != 0) || (ValueToPiece(CB[MoveList[i].To]) == Piece.Pawn) || ((MoveList[i].Type == MoveType.Special01) || (MoveList[i].Type == (MoveType.Special01 | MoveType.Special00))))//resetMoveCount
            {
                ThreeFoldRepCopy.Clear();
            }
            if (ThreeFoldRepCopy.ContainsKey(Hash))
            {
                ThreeFoldRepCopy[Hash] += 1;
            }
            else
            {
                ThreeFoldRepCopy.Add(Hash, 1);
            }
            bool isTransposition = false;
            //Debug.Log(IsThreeFold(ThreeFoldRepCopy, Hash));
            if (IsThreeFold(ThreeFoldRepCopy, Hash, 3))
            {
                Score = 0;
                isTransposition = true;
                //Debug.Log(true);
                //return (0, new Move(0, 0, 0), true);
            }
            else
            {
                TranspositionValue transValue = TranspositionTable[GetTranspositionIndex(Hash, hashSize)];
                if (transValue != null && transValue.Zobrish == Hash && transValue.Depth >= depth - 1 && (((transValue.Depth) % 2 == (depth - 1) % 2) || transValue.Depth == 9999))//prevent collision problem
                {
                    if (transValue.State == 0)//fully searched node
                    {
                        isTransposition = true;
                        Score = transValue.Eval;
                        //line.ArgMove = transValue.EngineLine.ArgMove;
                        Array.Copy(transValue.EngineLine.ArgMove, line.ArgMove, line.Cmove);
                        line.Cmove = transValue.EngineLine.Cmove;
                    }
                    else if (transValue.State == 1)
                    {
                        if (alpha >= transValue.Eval)
                        {
                            isTransposition = true;
                            Score = alpha;
                            Array.Copy(transValue.EngineLine.ArgMove, line.ArgMove, line.Cmove);
                            line.Cmove = transValue.EngineLine.Cmove;
                            //line = transValue.EngineLine;
                        }

                    }
                }
            }
            
            
            if (!isTransposition)
            {

                (Score, _, _) = AlphaBetaMax(depth - 1, Board, HL, WhiteKingCastle, WhiteQueenCastle, BlackKingCastle, BlackQueenCastle, MoveList[i], alpha, beta, Hash, ThreeFoldRepCopy, ref line);
                
            }
            else
            {
                SavedByTransposition++;
            }



            if (Score <= alpha)
            {
                if(!isTransposition)
                {
                    UpdateTranspositionTable(Hash, alpha, line, 1, 1);
                }
                
                return (alpha, MoveList[i], true);
            }
            if(!isTransposition)
            {
                UpdateTranspositionTable(Hash, Score, line, depth - 1, 0);
            }
            
            if (Score < beta)
            {
                
                beta = Score;
                BestMove = MoveList[i];

                pline.ArgMove[0] = BestMove;
                Array.Copy(line.ArgMove, 0, pline.ArgMove, 1, line.Cmove);
                pline.Cmove = line.Cmove + 1;
                
               
            }
            
            Hash = h;
        }
        

        return (beta, BestMove, true);

        int CompareMoves(Move move1, Move move2)
        {
            //changecomparemoves

            if (move1.To == lMove.To)
            {
                if (move2.To == lMove.To)
                    return 0; // Both moves capture the lastly moved piece.
                else
                    return -1; // move1 captures the lastly moved piece.
            }
            else if (move2.To == lMove.To)
            {
                return 1; // move2 captures the lastly moved piece.
            }
            if (IsCapture(move1) && IsCapture(move2))
            {

                int value1 = Get_MVVLVA_Value(move1, CB);
                int value2 = Get_MVVLVA_Value(move2, CB);
                return value2.CompareTo(value1); // Sort in descending order
            }
            else if (IsCapture(move1))
            {
                return -1; // move1 is a capture, move2 is not
            }
            else if (IsCapture(move2))
            {
                return 1; // move2 is a capture, move1 is not
            }
            else
            {
                return 0; // Both moves are non-captures; maintain their order
            }
        }
    }

Transposition update function

void UpdateTranspositionTable(UInt64 Zobrish, int eval, PVLine MoveLine, int depth, int State)
    {
        int index = GetTranspositionIndex(Zobrish, hashSize);
        TranspositionValue Transposition = TranspositionTable[index];
        if (Transposition == null || depth > Transposition.Depth)
        {
            TranspositionTable[index] = new TranspositionValue(Zobrish, eval, depth, MoveLine, State);
        }
    }

Other functions used in minimax code

 bool IsCapture(Move move)
    {
        if ((move.Type & MoveType.capture) != 0)
        {
            return true;
        }
        return false;
    }
    int GetValueOfPiece(int piece)
    {
        int shape = ValueToPiece(piece);
        if (shape == Piece.Pawn)
        {
            return 1;
        }
        else if ((shape == Piece.Knight) || (shape == Piece.Bishop))
        {
            return 2;
        }
        else if (shape == Piece.Rook)
        {
            return 3;
        }
        else if (shape == Piece.Queen)
        {
            return 4;
        }
        else//king
        {
            return 5;
        }
    }
 (int[] Board, List<int> Hash) MakeMove(Move move, int[] cb, List<int> hs, ref UInt64 Hash)
    {

        int[] AppliedBoard = (int[])cb.Clone();
        List<int> AppliedHash = new List<int>(hs);

        int from = move.From;

        int to = move.To;
        int moveType = move.Type;

        int whatPiece = cb[from];
        int WhatColor = ValueToCol(whatPiece);

        //Debug.Log(from + "to" + to+ "movetype" + moveType);
        //for(int i= 0; i < AppliedHash.Count; i++)
        //{
        //    Debug.Log("hash" + AppliedHash[i]);
        //}
        //Debug.Log("moveType" + moveType);
        //Debug.Log("from" + from + "to" + to);
        if (moveType == 0 || moveType == MoveType.Special00) // quiet move & double pawn push
        {
            AppliedBoard[from] = 0;
            Hash ^= piece_Keys[Get_HashIndex(whatPiece), from];

            AppliedBoard[to] = whatPiece;
            Hash ^= piece_Keys[Get_HashIndex(whatPiece), to];

            AppliedHash[AppliedHash.IndexOf(from)] = to;
            

        }
        else if ((moveType & MoveType.promotion) != 0) // promotion
        {

            //Debug.Log("moveType" + moveType);
            AppliedBoard[from] = 0;
            Hash ^= piece_Keys[Get_HashIndex(whatPiece), from];
            if ((moveType & MoveType.capture) != 0)//capturePromo
            {
                //Debug.Log("capturepromom");
                AppliedHash.RemoveAt(AppliedHash.IndexOf(from));
                Hash ^= piece_Keys[Get_HashIndex(cb[to]), to];


            }
            else
            {
                AppliedHash[AppliedHash.IndexOf(from)] = to;
                
            }


            if ((moveType & QueenPromo) == QueenPromo)
            {
                AppliedBoard[to] = WhatColor | Piece.Queen;
                Hash ^= piece_Keys[Get_HashIndex(WhatColor | Piece.Queen), to];
                //Debug.Log(ValueToPiece(AppliedBoard[to]));
            }
            else if ((moveType & RookPromo) == RookPromo)
            {
                AppliedBoard[to] = WhatColor | Piece.Rook;
                Hash ^= piece_Keys[Get_HashIndex(WhatColor | Piece.Rook), to];
            }
            else if ((moveType & BishopPromo) == BishopPromo)
            {
                AppliedBoard[to] = WhatColor | Piece.Bishop;
                Hash ^= piece_Keys[Get_HashIndex(WhatColor | Piece.Bishop), to];
            }
            else if ((moveType & knightPromo) == knightPromo)
            {
                AppliedBoard[to] = WhatColor | Piece.Knight;
                Hash ^= piece_Keys[Get_HashIndex(WhatColor | Piece.Knight), to];
            }


        }
        else if (moveType == MoveType.capture)
        {
            AppliedBoard[from] = 0;
            Hash ^= piece_Keys[Get_HashIndex(whatPiece), from];
            AppliedBoard[to] = whatPiece;
            Hash ^= piece_Keys[Get_HashIndex(whatPiece), to];

            AppliedHash.RemoveAt(AppliedHash.IndexOf(from));
            //Debug.Log("deleted" + AppliedHash.IndexOf(from));
        }
        else if (moveType == (MoveType.capture | MoveType.Special00))
        {
            int Forward;
            if (WhatColor == Piece.White)
            {
                Forward = 8;
            }
            else
            {
                Forward = -8;
            }

            AppliedBoard[from] = 0;
            Hash ^= piece_Keys[Get_HashIndex(whatPiece), from];
            AppliedBoard[to + Forward] = 0;
            Hash ^= piece_Keys[Get_HashIndex(WhatColor | Piece.Pawn), to + Forward];
            AppliedBoard[to] = whatPiece;
            Hash ^= piece_Keys[Get_HashIndex(whatPiece), to];

            AppliedHash.RemoveAt(AppliedHash.IndexOf(from));
            //Debug.Log(to - Forward);
            AppliedHash.RemoveAt(AppliedHash.IndexOf(to + Forward));
            AppliedHash.Add(to);
        }
        else if (moveType == MoveType.Special01) // Kingside Castling
        {
            AppliedBoard[from] = 0;
            Hash ^= piece_Keys[Get_HashIndex(whatPiece), from];

            AppliedBoard[to] = whatPiece;
            Hash ^= piece_Keys[Get_HashIndex(whatPiece), to];

            AppliedHash[AppliedHash.IndexOf(from)] = to;


            AppliedBoard[from + 3] = 0;
            Hash ^= piece_Keys[Get_HashIndex(WhatColor | Piece.Rook), from + 3];

            AppliedBoard[from + 1] = WhatColor | Piece.Rook;
            Hash ^= piece_Keys[Get_HashIndex(WhatColor | Piece.Rook), from + 1];
            AppliedHash[AppliedHash.IndexOf(from + 3)] = from + 1;
        }
        else if (moveType == (MoveType.Special00 | MoveType.Special01))
        {
            AppliedBoard[from] = 0;
            Hash ^= piece_Keys[Get_HashIndex(whatPiece), from];

            AppliedBoard[to] = whatPiece;
            Hash ^= piece_Keys[Get_HashIndex(whatPiece), to];

            AppliedHash[AppliedHash.IndexOf(from)] = to;

            AppliedBoard[from - 4] = 0;
            Hash ^= piece_Keys[Get_HashIndex(WhatColor | Piece.Rook), from - 4];
            AppliedBoard[from - 1] = WhatColor | Piece.Rook;
            Hash ^= piece_Keys[Get_HashIndex(WhatColor | Piece.Rook), from - 1];

            AppliedHash[AppliedHash.IndexOf(from - 4)] = from - 1;
        }


        //lastMove = move;
        
        return (AppliedBoard, AppliedHash);
    }
    int GetTranspositionIndex(UInt64 Zobrish, int HashSize)
    {
        //Debug.Log(TranspositionTable.Length + "," + (int)(Zobrish % (UInt64)HashSize));

        //if (((int)Zobrish % HashSize )< 0 || ((int)Zobrish % HashSize) >= TranspositionTable.Length)
        //{
        //    // Log or handle the out-of-range index here
        //    Console.WriteLine("Index out of range: " + (int)Zobrish % HashSize + "length" + TranspositionTable.Length);
        //}
        return ((int)(Zobrish % (UInt64)HashSize));
    }
    UInt64 Generate_HashKey()
    {
        UInt64 final_key = 0;

        for(int i = 0; i < chessBoardHash.Count; i++)
        {
            
            final_key ^= piece_Keys[Get_HashIndex(chessBoard[chessBoardHash[i]]), chessBoardHash[i]];
        }

        final_key ^= castle_Keys[CastlingIndex(WhiteKingCastle, WhiteQueenCastle, BlackKingCastle, BlackQueenCastle)];
        return final_key;
    }

    int CastlingIndex(bool WKC, bool WQC, bool BKC, bool BQC)
    {
        int caseNumber = 0;
        caseNumber |= (WKC ? 1 : 0) << 0;
        caseNumber |= (WQC ? 1 : 0) << 1;
        caseNumber |= (BKC ? 1 : 0) << 2;
        caseNumber |= (BQC ? 1 : 0) << 3;
        return caseNumber;
    }
    int ValueToPiece(int num)
    {
        return num & 7;
    }
    int ValueToCol(int num)
    {
        return num & 24;
    }
    int OppColor(int col)
    {
        return 24 - col;
    }
    public static class Piece
    {
        public const int None = 0;
        public const int King = 1;
        public const int Pawn = 2;
        public const int Knight = 3;
        public const int Bishop = 4;
        public const int Rook = 5;
        public const int Queen = 6;

        public const int White = 8;
        public const int Black = 16;


    }
    public static class MoveType
    {
        public const int promotion = 8;
        public const int capture = 4;
        public const int Special01 = 2;
        public const int Special00 = 1;

    }
    class Move
    {

        public int From { get; set; }
        public int To { get; set; }
        public int Type { get; set; }
        

        public Move(int from, int to, int type)
        {
            From = from;
            To = to;
            Type = type;

        }
    }

    class TranspositionValue
    {
        public UInt64 Zobrish { get; set; }
        public int Eval { get; set; }
        public int Depth { get; set; }
        public int State { get; set; }

        public PVLine EngineLine;
        public TranspositionValue (UInt64 zobrish, int eval, int depth, PVLine engineLine, int state    )
        {
            Zobrish = zobrish;
            Eval = eval;
            Depth = depth;
            EngineLine = engineLine;
            State = state;
        }
    }
    class PVLine
    {

        public int Cmove { get; set; }
        public Move[] ArgMove { get; set; }
        


        public PVLine(int cmove, Move[] argmove)
        {
            Cmove = cmove;
            ArgMove = argmove;

        }
    }

I tried only using Exact flag (which is 0 in this code. 1 is alpha, 2 is beta.), but the issue didn't disappear. So it's not a bug about upperbound and lowerbound problem. or at least there are other bugs.

I'm new to chess programming and I don't know what to try to solve this problem.

I also tried using same depth for transposition version and non-transposition version, and the issue was not solved. It's also not about iterative deepening.

Also, I can tell you move generation doesn't have a problem. It passed all the test positions on chessprogrammingwiki. and also if it has a problem, it should appear without transposition table.

Thank you.

you can ask any questions you want to know, and I will try to answer as detailed as possible.

0

There are 0 answers