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?
design choices
Moderator: Ras
-
- Posts: 40
- Joined: Mon Mar 01, 2021 7:51 pm
- Location: İstanbul, Turkey
- Full name: Ömer Faruk Tutkun
Re: design choices
collecting PV from TT
using make/unmake instead of copy make
using make/unmake instead of copy make
-
- Posts: 28353
- Joined: Fri Mar 10, 2006 10:06 am
- Location: Amsterdam
- Full name: H G Muller
Re: design choices
My two most-frequent regrets: too few piece types and too small a board.
-
- Posts: 93
- Joined: Sun Aug 08, 2021 9:14 pm
- Full name: Kurt Peters
Re: design choices
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.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?
-
- Posts: 3233
- Joined: Wed Mar 10, 2010 10:18 pm
- Location: Hamburg, Germany
- Full name: Srdja Matovic
Re: design choices
My regrets, not reading the C/OpenCL specifications carefully, not reading the architecture white papers carefully.
--
Srdja
--
Srdja
-
- Posts: 28353
- Joined: Fri Mar 10, 2006 10:06 am
- Location: Amsterdam
- Full name: H G Muller
Re: design choices
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.
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.
-
- Posts: 23
- Joined: Wed Nov 17, 2021 1:19 am
- Full name: Laurie Tunnicliffe
Re: design choices
I suppose that is why you write more than one chess program
-
- Posts: 325
- Joined: Tue Aug 31, 2021 10:32 pm
- Full name: tcusr
Re: design choices
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.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.
-
- Posts: 28353
- Joined: Fri Mar 10, 2006 10:06 am
- Location: Amsterdam
- Full name: H G Muller
Re: design choices
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.
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.
-
- Posts: 325
- Joined: Tue Aug 31, 2021 10:32 pm
- Full name: tcusr
Re: design choices
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.