Simplifying code

Discussion of chess software programming and technical issues.

Moderators: Harvey Williamson, bob, hgm

Forum rules
This textbox is used to restore diagrams posted with the [d] tag before the upgrade.
Henk
Posts: 6556
Joined: Mon May 27, 2013 8:31 am

Re: Simplifying code

Post by Henk » Tue Aug 11, 2020 11:28 am

Huh why don't I use this ??

Code: Select all

class ABState2<S>
    {
        public S State
        {
            get;
            private set;
        }

        public ABState2(S state)
        {
            State = state;
        }
        public void Update (S state)
        {
            State = state;
        }
    }
   
O wait I don't need to use this class at all. Talking about stupidity.

Henk
Posts: 6556
Joined: Mon May 27, 2013 8:31 am

Re: Simplifying code

Post by Henk » Mon Aug 17, 2020 10:30 am

Not so happy with this code. It's short but not that easy to understand. Also CollectCaptures is one of most expensive operations.
So maybe better not use LINQ here. Although might be that performance can not be improved because
sq.Moves(sort, Board.Occupiers) is bottleneck and these magic bitboard operations can hardly be improved.

Code: Select all

     public void CollectCaptures(Builder builder, ulong source, ulong target,
            bool excludePromotions)
        {
            var iter = new BitBoardIterator(0);
            builder.AddRange(
                new BitBoardIterator(source).Select(b =>
                 {
                     var sq = BoardSquares[b];
                     var sort = Board.PieceSort(sq);
                     var capturesBB = sq.Moves(sort, Board.Occupiers) & target;
                     iter.Init(capturesBB);
                     return CollectCaptures(iter, sq.MovesDict[(int)sort], excludePromotions);
                 }
               ).Aggregate((x, y) => x.AddRange(y))
           );
        }

        private IImmutableList<IMoveBase> CollectCaptures(BitBoardIterator iter,  BitCoordMoveDict mvDict, 
                                                            bool excludePromotions)
                        => iter
                          .Where(bit=>!(excludePromotions && mvDict[bit] is Promotion))
                          .Select(bit=>mvDict[bit])
                          .ToImmutableList();
  

Henk
Posts: 6556
Joined: Mon May 27, 2013 8:31 am

Re: Simplifying code

Post by Henk » Wed Aug 26, 2020 2:29 pm

Looks like MD5 giving best performance. That is key of 128 bits.
If I would use Sha512 I might as well store all bitboards in the key giving 8 x 64 = 512 bits.
Maybe that would be best for now I have to verify if move from hashtable is invalid because of collisions.

Code: Select all

class ChessBoardBits  
   ....
   public byte[] ComputeHashKey(HashAlgorithm hashAlgorithm)
        {
            const int ByteCountBB = sizeof(ulong);
            const int nBitBooards = (int)None_Kind + 2;

            var arr = new byte[ByteCountBB * nBitBooards];
            int k = 0;

            for (var j = Pawn_Kind; j <= King_Kind; j++)
            {
                foreach (var b in GetBytes(GetBits(j)))
                {
                    arr[k++] = b;
                }
            }

            foreach (var b in GetBytes(GetBits(White)))
            {
                arr[k++] = b;
            }

            foreach (var b in GetBytes(Other))
            {
                arr[k++] = b;
            }

            return hashAlgorithm.ComputeHash(arr);
        }

Pio
Posts: 196
Joined: Sat Feb 25, 2012 9:42 pm
Location: Stockholm
Contact:

Re: Simplifying code

Post by Pio » Wed Aug 26, 2020 6:23 pm

Henk wrote:
Wed Aug 26, 2020 2:29 pm
Looks like MD5 giving best performance. That is key of 128 bits.
If I would use Sha512 I might as well store all bitboards in the key giving 8 x 64 = 512 bits.
Maybe that would be best for now I have to verify if move from hashtable is invalid because of collisions.

Code: Select all

[url][/url]
class ChessBoardBits  
   ....
   public byte[] ComputeHashKey(HashAlgorithm hashAlgorithm)
        {
            const int ByteCountBB = sizeof(ulong);
            const int nBitBooards = (int)None_Kind + 2;

            var arr = new byte[ByteCountBB * nBitBooards];
            int k = 0;

            for (var j = Pawn_Kind; j <= King_Kind; j++)
            {
                foreach (var b in GetBytes(GetBits(j)))
                {
                    arr[k++] = b;
                }
            }

            foreach (var b in GetBytes(GetBits(White)))
            {
                arr[k++] = b;
            }

            foreach (var b in GetBytes(Other))
            {
                arr[k++] = b;
            }

            return hashAlgorithm.ComputeHash(arr);
        }
Hi Henk, you could easily compress your bitboard representation to 256 bit using quad bit boards https://www.chessprogramming.org/Quad-Bitboards. You could also represent enpassant pawn and rooks that can castle in that representation.

Henk
Posts: 6556
Joined: Mon May 27, 2013 8:31 am

Re: Simplifying code

Post by Henk » Thu Aug 27, 2020 7:49 am

Don't know. Looks bit slower when making a move for you have to access 4 bitboards instead of 3.
But may be comparable. I don't know.

By the way maybe I go back and use Zobrist key. If I use MD5 I might as well use Zobrist key. Although more code because MD5 is a hash algorithm available in .NET .

Henk
Posts: 6556
Joined: Mon May 27, 2013 8:31 am

Re: Simplifying code

Post by Henk » Fri Aug 28, 2020 8:15 am

After all these rewrites. This is first time in months Skipper winning from Fairy-max in a normal way.
Hmm appears to be lucky win. Fairy-max almost playing with a knight less (Nh5).


Henk
Posts: 6556
Joined: Mon May 27, 2013 8:31 am

Re: Simplifying code

Post by Henk » Fri Aug 28, 2020 10:13 am

O wait just won for second time. So this version is one of the better ones. Maybe I should save it before I ruin it (again).

Kieren Pearson
Posts: 35
Joined: Tue Dec 31, 2019 1:52 am
Full name: Kieren Pearson

Re: Simplifying code

Post by Kieren Pearson » Sun Aug 30, 2020 10:45 am

Henk wrote:
Fri Aug 28, 2020 10:13 am
O wait just won for second time. So this version is one of the better ones. Maybe I should save it before I ruin it (again).
One of the biggest things (imho) for making a strong engine is proper version control and standardised testing. I’d highly recommend using GitHub or something similar in order to be able to “go back” to a previous version in future.

As for testing, it pays to be able to test each change you make by playing the “new” version against the “previous” version. Some people disagree with this and think gauntlet testing is better but self play testing is what the top engines do (stockfish etc)

Henk
Posts: 6556
Joined: Mon May 27, 2013 8:31 am

Re: Simplifying code

Post by Henk » Thu Sep 17, 2020 11:41 am

Functions no longer than twenty lines of code.
No more than three arguments.

Food for rewrite:

https://www.youtube.com/watch?v=QvrNwfuWbCQ

JohnWoe
Posts: 228
Joined: Sat Mar 02, 2013 10:31 pm

Re: Simplifying code

Post by JohnWoe » Tue Sep 29, 2020 6:24 pm

Henk wrote:
Thu Sep 17, 2020 11:41 am
Functions no longer than twenty lines of code.
No more than three arguments.

Food for rewrite:

https://www.youtube.com/watch?v=QvrNwfuWbCQ
Exactly!
Functions that take 4 or less arguments fit into register and that is processed really fast.
Functions should do just one thing. And _ONE_ thing only.

Somehow in chess programming it's ok to have a search function that's 1000+ lines long.
Quiescence check -> Tablebase probe -> Razoring -> Futility -> Null Move ...

I have 9 small search functions. You could fit them into one single function.

Post Reply