design choices

Discussion of chess software programming and technical issues.

Moderator: Ras

tcusr
Posts: 325
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

design choices

Post by tcusr »

what are some decision that you've made early in the development of your engine that you've come to regret?
for example i would change my move structure to be able to store much more information. why do i need to spend time decoding my move when at the moment of creation (move generation) i know everything i need?
this can also affect the board structure itself to be able to accept different move representations instead of the canonical "from" and "to" form.

as a general coding principle i would also try to keep the code as simple as possible. this makes me consider copy-make because less code = less errors.
thoughts?
yeni_sekme
Posts: 40
Joined: Mon Mar 01, 2021 7:51 pm
Location: İstanbul, Turkey
Full name: Ömer Faruk Tutkun

Re: design choices

Post by yeni_sekme »

collecting PV from TT
using make/unmake instead of copy make
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: design choices

Post by hgm »

My two most-frequent regrets: too few piece types and too small a board.
KhepriChess
Posts: 93
Joined: Sun Aug 08, 2021 9:14 pm
Full name: Kurt Peters

Re: design choices

Post by KhepriChess »

tcusr wrote: Tue Oct 11, 2022 9:10 pm what are some decision that you've made early in the development of your engine that you've come to regret?
for example i would change my move structure to be able to store much more information. why do i need to spend time decoding my move when at the moment of creation (move generation) i know everything i need?
this can also affect the board structure itself to be able to accept different move representations instead of the canonical "from" and "to" form.

as a general coding principle i would also try to keep the code as simple as possible. this makes me consider copy-make because less code = less errors.
thoughts?
I actually just reworked by move encoding to remove some information (as some of it could be determined later as needed). The specificity of the encoded data ended up requiring more code in places to figure some stuff out about a move. More data in the encoded move is not necessarily a bad thing but what exactly is all encoded is important to consider how it affects code elsewhere.
Puffin: Github
KhepriChess: Github
smatovic
Posts: 3233
Joined: Wed Mar 10, 2010 10:18 pm
Location: Hamburg, Germany
Full name: Srdja Matovic

Re: design choices

Post by smatovic »

My regrets, not reading the C/OpenCL specifications carefully, not reading the architecture white papers carefully.

--
Srdja
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: design choices

Post by hgm »

If the move is encoded as the from- and to-square in separate bytes, there is very little decoding to do. Of course you could save things like the new hash key and new incremental evaluation in the move, but these are not automatically available during move generation. And moving tasks from MakeMove() to MoveGen() is the opposit of what one should do. To apply the move to the game state I need to know the pieces (mover and victim). But getting those from the move struct is not any cheaper than getting those from the board, when the corresponding squares are in CPU registers anyway. I guess the victim type is really only needed in UnMake(), so saving it in a local variabe during MakeMove() is an extra load and store, while in the move generator it was probably just an extra store to get it in the move struct. But wheter that is a good tradeoff depends on the number of moves you generate per node compared to the number of moves you search, and that could be so close to 50% that there is nothing to gain.

To get the best speed I was actually driven in the opposit direction: encode moves as a single bit, and decode all parameters of the move from the location of that bit.
laurietunnicliffe
Posts: 23
Joined: Wed Nov 17, 2021 1:19 am
Full name: Laurie Tunnicliffe

Re: design choices

Post by laurietunnicliffe »

I suppose that is why you write more than one chess program
tcusr
Posts: 325
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: design choices

Post by tcusr »

hgm wrote: Wed Oct 12, 2022 8:10 am If the move is encoded as the from- and to-square in separate bytes, there is very little decoding to do. Of course you could save things like the new hash key and new incremental evaluation in the move, but these are not automatically available during move generation. And moving tasks from MakeMove() to MoveGen() is the opposit of what one should do. To apply the move to the game state I need to know the pieces (mover and victim). But getting those from the move struct is not any cheaper than getting those from the board, when the corresponding squares are in CPU registers anyway. I guess the victim type is really only needed in UnMake(), so saving it in a local variabe during MakeMove() is an extra load and store, while in the move generator it was probably just an extra store to get it in the move struct. But wheter that is a good tradeoff depends on the number of moves you generate per node compared to the number of moves you search, and that could be so close to 50% that there is nothing to gain.

To get the best speed I was actually driven in the opposit direction: encode moves as a single bit, and decode all parameters of the move from the location of that bit.
this applies only if you have a very fast way to find where a piece is at. image how slow that would be in a quadboard or a pure bitboard representation.
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: design choices

Post by hgm »

I am not sure to which part of my posting your remark applies.

But perhaps the worst regret then should be that you represent the game state by quadboard or pure bitboard? The game-state representation should be designed such that it can quickly and easily provide the info you need in the rest of your engine. Pure bitboard seems flawed because it cannot easily answer the question what the piece type of the capture victim is. Which is info that is not really needed in move generation; there you only have to know the color of the piece on the target square. So you must go through the expensive procedure to figure that out. And it is usually better to postpone expensive procedures to the latest possible moment, in the hope a beta cutoff might make it unneeded.

Having a mailbox board on the side to find the victim type in a single load is of course much faster, in the move generator as well as in MakeMove(). Regret if you don't have it.

But it depends on the type of move generator as well. If you generate captures by victim in a staged way, you would automatically know what the victim type was in each stage. And from the type of 'retro-move' you would use to test for attackers, you would immediately know what attacker type to test for. But it seems better in that case to not encode the victim in the move struct, but take it directly from the victim-loop counter in MakeMove/Unmake. As several captures could share the same victim, and storing the same in each such capture just multiplies the work.
tcusr
Posts: 325
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: design choices

Post by tcusr »

hgm wrote: Wed Oct 12, 2022 7:03 pm But perhaps the worst regret then should be that you represent the game state by quadboard or pure bitboard? The game-state representation should be designed such that it can quickly and easily provide the info you need in the rest of your engine.
yep, a hybrid approach is the best but some people still use bitboards as the main representation.
i spent so much time on bitboards just to realize a mailbox is just as good.