Simplifying code

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

odomobo
Posts: 96
Joined: Fri Jul 06, 2018 1:09 am
Location: Chicago, IL
Full name: Josh Odom

Re: Simplifying code

Post by odomobo »

Henk wrote: Fri Jul 31, 2020 2:25 pm - Tried to write it functional. So recursion instead of loops.
Recursion instead of iteration is pretty bad in languages without tail-call recursion. And, honestly, tail-call recursion is a hack to allow functional languages to have better performance than they should.
Henk wrote: Fri Jul 31, 2020 2:25 pm - yes for debugging nested expressions is terrible. Although there will be more temporary variables with silly names.
Not just for debugging, but also for reasoning about the work that's being done. For example, in the return statement, if the conditionals were separated into their own variables, I might be able to understand was it was doing.

I know that some people advocate for functions with a single return statement, but I think multiple returns can greatly simplify certain functions. I think the better way to think about it is: try to structure your code such that functions will only require a single return statement.
Henk wrote: Fri Jul 31, 2020 2:25 pm Looks like Initial stupid code was best. Rewrite only makes it less natural or divergent from initial idea.
Its like gumming in a drawing. I remember teacher said use gum sparingly.
In my experience, sometimes you need to make a change in order to see that it's bad, and then revert all of your work. Even though it feels like a waste, it's necessary for forward progress, because it taught you something about the code base or about the problem you're solving.

There are a lot of different opinions on functional, but from my perspective, functional-style code can be good only for bits of your code where performance isn't the primary concern. This is because the declarative style can limit the control you have over implementation. However, I think you can benefit from the functional concepts even when you aren't writing true functional code.

For example, simply making most of your functions have no or very limited side effects will make it much easier to reason about your code.
Pio
Posts: 334
Joined: Sat Feb 25, 2012 10:42 pm
Location: Stockholm

Re: Simplifying code

Post by Pio »

odomobo wrote: Thu Jul 30, 2020 9:07 pm Instead of calling .Aggregate(), you can call .Sum() to simplify. Even though the performance for perft isn't the biggest concern, there are 2 issues with using LinQ IMO:
  1. It creates additional objects, which need to be GCd.
  2. You lose some control over the sequence in which the code is executed.
It can be really convenient for things that aren't in a tight loop, though.
I agree, linq can be very slow, but when used correctly in non performance critical parts it can be very beautiful. I use the yield return in C# for my iterative search function so I could separate the XBoard/winboard printing from the chess/search logic. My search function returns a lazy evaluated array that is automatically printed for each new depth so the search can be completely decoupled from the GUI-interface 😁
OliverBr
Posts: 725
Joined: Tue Dec 18, 2007 9:38 pm
Location: Munich, Germany
Full name: Dr. Oliver Brausch

Re: Simplifying code

Post by OliverBr »

Henk wrote: Fri Apr 24, 2020 9:11 pm
Henk wrote: Fri Apr 24, 2020 2:54 pm Can't copy position efficiently. Too many bytes.
Maybe only 32 bytes needed. So maybe not that inefficient.
But too late I already implemented my snapshot solution.
Undoing a move takes typically less data than 32bytes. I really would like to see your solution.
Chess Engine OliThink: http://brausch.org/home/chess
OliThink GitHub:https://github.com/olithink
smcracraft
Posts: 737
Joined: Wed Mar 08, 2006 8:08 pm
Location: Orange County California
Full name: Stuart Cracraft

Re: Simplifying code

Post by smcracraft »

Exactly why I converted my program to 64-bit bitmaps for both move generation and position evaluation years ago.

It has made the entirety simple.

I love engineering simplicity!!!
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Simplifying code

Post by Henk »

OliverBr wrote: Sun Aug 02, 2020 2:06 am
Henk wrote: Fri Apr 24, 2020 9:11 pm
Henk wrote: Fri Apr 24, 2020 2:54 pm Can't copy position efficiently. Too many bytes.
Maybe only 32 bytes needed. So maybe not that inefficient.
But too late I already implemented my snapshot solution.
Undoing a move takes typically less data than 32bytes. I really would like to see your solution.

Code: Select all

public enum Sort { whitePawn, whiteKnight, whiteBishop, whiteRook,  whiteQueen, whiteKing, blackPawn, blackKnight, blackBishop, blackRook, blackQueen, blackKing, none }

UInt64[] pieces;
public UInt64 Other { get; set; }

 public ChessBoardBits()
        {
            pieces = new UInt64[(int)none];
            Init();
        }

        public void Init()
        {
            for(int i = 0; i < (int)none; i++)
            {
                pieces[i] = 0;
            }
            Other = 0;
        }
        
        private ChessBoardBits Copy()
        { 

            var piecesCopy = new UInt64[(int)none];
            for (int i = 0; i < (int)none; i++)
            {
                piecesCopy[i] = pieces[i];
            }
            return new ChessBoardBits(piecesCopy, Other);
        }

So copy-ing these bits would mean (12 + 1) x 8 = 13 * 8 = 104 bytes.
Can reduce this to (6 + 1 + 1) x 8 = 64 bytes by storing bitboard of white or black pieces.

Making a move including copy-ing a position is expensive operation in my program.

Also getting white/blackpieces very slow:

Code: Select all

  public UInt64 WhitePieces
        {
            get
            {
                return pieces[0] | pieces[1] | pieces[2] | pieces[3] | pieces[4] | pieces[5];
                
            }        
        }
        public UInt64 BlackPieces
        {
            get
            {
                return pieces[6] | pieces[7] | pieces[8] | pieces[9] | pieces[10] | pieces[11];
               
            }
        }
  
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Simplifying code

Post by Sven »

The copy&make approach is not necessarily "too expensive". You could certainly optimize your implementation by using 8 bitboards instead of 13, and also by using a slightly more efficient copying technique than a loop (e.g. memcpy() in C). But in general that approach can work equally well compared to the incremental make&unmake approach which needs additional logic for unmaking a move and also at least a small amount of additional data like the type of the captured piece. Most important from my view would be that you provide enough abstraction at the interface of your board class to be able to switch easily from one implementation to another.
Sven Schüle (engine author: Jumbo, KnockOut, Surprise)
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Simplifying code

Post by Henk »

Yes c# also has a Clone and a CopyTo operation.
So I better use: private ChessBoardBits Copy() => new ChessBoardBits((UInt64[])pieces.Clone(), Other);


Advantage of the 13 bitboards is that you don't need to update whitepieces bitboard.

pieces[(int)pieceSort] ^= move.BitBoardValue;

You can make number of bytes much smaller by bitpacking or using encoder/decoder techniques .

Easiest is about 64* 3 bits.
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Simplifying code

Post by Henk »

Looks like C# CopyTo is faster than Clone

Code: Select all

 
   private ChessBoardBits Copy()
        { 
            var piecesCopy = new UInt64[(int)none];
            pieces.CopyTo(piecesCopy, 0);        
            return new ChessBoardBits(piecesCopy, Other);
        }
Pio
Posts: 334
Joined: Sat Feb 25, 2012 10:42 pm
Location: Stockholm

Re: Simplifying code

Post by Pio »

Henk wrote: Sun Aug 02, 2020 12:40 pm Looks like C# CopyTo is faster than Clone

Code: Select all

 
   private ChessBoardBits Copy()
        { 
            var piecesCopy = new UInt64[(int)none];
            pieces.CopyTo(piecesCopy, 0);        
            return new ChessBoardBits(piecesCopy, Other);
        }
Why not use structs?
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Simplifying code

Post by Henk »

Pio wrote: Sun Aug 02, 2020 1:41 pm
Henk wrote: Sun Aug 02, 2020 12:40 pm Looks like C# CopyTo is faster than Clone

Code: Select all

 
   private ChessBoardBits Copy()
        { 
            var piecesCopy = new UInt64[(int)none];
            pieces.CopyTo(piecesCopy, 0);        
            return new ChessBoardBits(piecesCopy, Other);
        }
Why not use structs?
Yes that's an idea. I should try that. Hardly ever used structs by the way in C#. Already forgot they existed.