Page 10 of 14

Re: Simplifying code

Posted: Tue Aug 11, 2020 1:28 pm
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.

Re: Simplifying code

Posted: Mon Aug 17, 2020 12:30 pm
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();
  

Re: Simplifying code

Posted: Wed Aug 26, 2020 4:29 pm
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);
        }

Re: Simplifying code

Posted: Wed Aug 26, 2020 8:23 pm
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.

Re: Simplifying code

Posted: Thu Aug 27, 2020 9:49 am
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 .

Re: Simplifying code

Posted: Fri Aug 28, 2020 10:15 am
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]

Re: Simplifying code

Posted: Fri Aug 28, 2020 12:13 pm
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).

Re: Simplifying code

Posted: Sun Aug 30, 2020 12:45 pm
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)

Re: Simplifying code

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

Food for rewrite:


Re: Simplifying code

Posted: Tue Sep 29, 2020 8:24 pm
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.