Simplifying code

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

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

Re: Simplifying code

Post by Henk »

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: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Simplifying code

Post by Henk »

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: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Simplifying code

Post by Henk »

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: 334
Joined: Sat Feb 25, 2012 10:42 pm
Location: Stockholm

Re: Simplifying code

Post by Pio »

Henk wrote: Wed Aug 26, 2020 4: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: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Simplifying code

Post by Henk »

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: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Simplifying code

Post by Henk »

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).

[pgn]
[Event "Computer Chess Game"]
[Site "LAPTOP-1FK7MTIP"]
[Date "2020.08.28"]
[Round "-"]
[White "Skipper_5"]
[Black "Fairy-Max 4.8V"]
[Result "1-0"]
[TimeControl "120"]
[Annotator "1. +0.11 2... +0.18"]

1. Nc3 {+0.11/8} d5 2. Nf3 {+0.26/7 2.4} c6 {+0.18/8 3} 3. d3 {+1.03/6 2.3}
g6 {+0.17/9 13} 4. Bf4 {+0.74/7 2.3} f5 {+0.10/8 7} 5. e4 {+1.26/7 2.2}
dxe4 {+0.18/8 1.4} 6. dxe4 {+1.16/7 2.2} Qxd1+ {+0.18/9 1.5} 7. Rxd1
{+1.13/7 2.1} Nf6 {+0.13/8 2.3} 8. e5 {+1.30/7 2.1} Nh5 {+0.01/9 1.5} 9.
Be3 {+1.30/6 2.1} Bg7 {-0.02/9 3} 10. Bc4 {+1.36/6 2.0} f4 {-0.12/9 2.4}
11. Bd4 {+1.44/6 2.0} a5 {-0.12/8 1.6} 12. Ng5 {+1.88/5 1.9} Bf5
{-0.17/8 1.7} 13. Ne6 {+1.84/6 1.9} Bxe6 {-0.28/10 1.7} 14. Bxe6
{+1.55/6 1.9} Na6 {-0.19/9 1.1} 15. Ne4 {+1.93/5 1.8} Nc7 {-0.28/9 2.4} 16.
Nc5 {+1.80/5 1.8} Rd8 {-0.27/9 1.5} 17. Bb3 {+0.86/6 1.7} b6 {-0.23/10 1.9}
18. Ne6 {+0.95/7 1.7} Nxe6 {-0.27/12 1.7} 19. Bxe6 {+1.27/7 1.7} c5
{-0.29/11 1.2} 20. Bc3 {+1.33/8 1.6} Rxd1+ {-0.33/12 1.6} 21. Kxd1
{+1.07/7 1.6} b5 {-0.60/12 1.2} 22. Re1 {+1.02/6 1.6} b4 {-0.65/12 3} 23.
Bd2 {+1.41/6 1.6} Rf8 {-0.66/10 2.1} 24. Kc1 {+1.21/6 1.5} a4
{-0.59/10 1.2} 25. a3 {+1.80/6 1.5} bxa3 {-0.57/12 1.8} 26. bxa3
{+1.74/6 1.5} f3 {-1.30/12 5} 27. g3 {+1.48/6 1.4} Bh8 {-1.33/11 0.8} 28.
Re4 {+2.26/6 1.4} Ng7 {-1.32/11 0.7} 29. Bd5 {+2.42/6 1.4} e6
{-1.57/11 1.3} 30. Bc6+ {+2.19/6 1.3} Kf7 {-1.68/10 2.5} 31. Rf4+
{+2.83/7 1.3} Kg8 {-1.44/11 0.9} 32. Rxf8+ {+2.64/7 1.3} Kxf8
{-0.89/13 1.5} 33. Bxf3 {+1.36/7 1.3} Nf5 {-0.89/12 0.9} 34. Bc6
{+1.38/7 1.2} Bxe5 {-0.87/11 1.0} 35. f4 {+1.39/6 1.2} Bd4 {-0.88/12 1.1}
36. Bxa4 {+1.20/7 1.2} h5 {-0.61/11 0.6} 37. Bb3 {+1.14/6 1.2} Kf7
{-0.94/12 2.1} 38. a4 {+1.44/7 1.2} Nd6 {-1.20/12 1.9} 39. c4 {+1.52/7 1.1}
Bg1 {-1.18/12 0.5} 40. a5 {+1.93/8 1.1} Bxh2 {-0.99/12 1.0} 41. a6
{+1.95/8 1.1} Nc8 {-0.96/13 0.6} 42. Be1 {+1.97/7 1.1} h4 {-0.95/12 1.4}
43. gxh4 {+2.08/7 1.0} Bxf4+ {-0.96/12 0.5} 44. Kd1 {+1.45/7 1.0} Be5
{-1.08/10 0.5} 45. Ba4 {+1.61/7 1.0} Bd4 {-1.12/10 0.5} 46. Bc6
{+1.43/7 1.0} Na7 {-1.51/12 0.9} 47. Be4 {+1.53/7 1.0} Kf6 {-1.38/11 0.7}
48. Ba5 {+1.69/7 0.9} Ke7 {-1.74/11 0.5} 49. Bxg6 {+2.58/7 0.9} Nc8
{-1.88/10 0.5} 50. h5 {+3.31/7 0.9} Be3 {-2.51/12 0.7} 51. Bc7
{+4.05/7 0.9} Kd7 {-2.27/13 0.7} 52. Bb8 {+4.22/7 0.9} Kc6 {-2.56/13 0.4}
53. Ke2 {+4.09/8 0.9} Bd4 {-2.52/14 0.5} 54. Bf7 {+4.34/7 0.8} Kb6
{-2.57/15 0.9} 55. Bxe6 {+4.48/8 0.8} Na7 {-2.47/15 0.6} 56. Bxa7+
{+4.42/8 0.8} Kxa7 {-2.22/14 0.5} 57. Bc8 {+4.31/8 0.8} Bg7 {-3.11/14 0.4}
58. Kd3 {+4.38/8 0.8} Ka8 {-3.11/14 0.5} 59. Bb7+ {+4.47/9 0.8} Kb8
{-3.06/15 0.4} 60. Bc6 {+4.46/8 0.7} Ka7 {-3.09/14 0.6} 61. Bb7
{+4.52/8 0.7} Kb8 {-0.01/17 0.3} 62. Ke4 {+4.44/8 0.7} Kc7 {-3.88/14 0.9}
63. Kf4 {+4.54/7 0.7} Bh6+ {-3.69/13 0.3} 64. Kf5 {+5.99/8 0.7} Bc1
{-3.92/14 0.5} 65. Kg6 {+6.09/8 0.7} Bd2 {-4.19/14 0.4} 66. h6
{+6.11/8 0.7} Kb6 {-4.33/14 0.4} 67. Kg7 {+6.24/8 0.6} Ka7 {-4.48/15 0.5}
68. h7 {+6.26/8 0.6} Bc3+ {-5.07/17 0.6} 69. Kg8 {+6.36/9 0.6} Kb6
{-5.33/18 0.8} 70. h8=Q {+6.30/9 0.6} Bxh8 {-5.57/17 0.3} 71. Kxh8
{+6.40/10 0.6} Kc7 {-11.38/19 0.4} 72. Kg7 {+7.43/10 0.6} Kb6
{-12.83/18 2.9} 73. Kf6 {+7.44/9 0.6} Ka5 {-12.77/17 1.2} 74. a7
{+15.06/7 0.6} Kb4 {-12.90/14 0.5} 75. Ba6 {+16.02/6 0.5} Kc3
{-12.81/13 0.3} 76. a8=Q {+16.01/5 0.5} Kd3 {-13.65/12 0.3} 77. Qd5+
{+15.97/5 0.5} Kc2 {-13.72/11 0.4} 78. Bb5 {+16.01/4 0.5} Kc3
{-13.66/10 0.2} 79. Qxc5 {+16.06/4 0.5} Kb3 {-19.52/10 0.4} 80. Be8
{+16.56/4 0.5} Kc3 {-20.05/11 0.6} 81. Qd5 {+16.82/4 0.5} Kb3
{-20.95/11 1.0} 82. c5+ {+17.44/4 0.5} Kb4 {-21.02/10 0.2} 83. c6
{+18.33/3 0.5} Kc3 {-79.96/12 0.2} 84. c7 {+26.25/3 0.5} Kb2
{-79.97/14 0.1} 85. c8=Q {+327.61/2 0.4} Kb1 {-79.98/28 0.1} 86. Qb3+
{+327.63/2 0.4} Ka1 {-79.99/28 0.1} 87. Qcc3# {+327.65/3 0.4}
{Xboard adjudication: Checkmate} 1-0
[/pgn]
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Simplifying code

Post by Henk »

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: 70
Joined: Tue Dec 31, 2019 2:52 am
Full name: Kieren Pearson

Re: Simplifying code

Post by Kieren Pearson »

Henk wrote: Fri Aug 28, 2020 12:13 pm 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: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Simplifying code

Post by Henk »

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

Food for rewrite:

JohnWoe
Posts: 491
Joined: Sat Mar 02, 2013 11:31 pm

Re: Simplifying code

Post by JohnWoe »

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

Food for rewrite:

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.