Author: Wylie Garvin
Date: 19:54:36 12/08/01
Go up one level in this thread
On December 08, 2001 at 08:57:41, Sune Fischer wrote: >On December 08, 2001 at 08:10:42, Wylie Garvin wrote: > >>On December 06, 2001 at 17:31:55, Sune Fischer wrote: >> >>>.... >>> >>>I have special move functions for the pawns and kings, then I have one >>>makemove() for the rest. When the kings are done with the castling I switch so >>>the kings also uses the standard makemove(). It is only one "if" and a few local >>>variables I save, but I have a feeling that it is a bit faster to call the same >>>function often rather than dispersing the calls to many functions. >>>It is just a feeling, but why not make the switch when I already have the faster >>>function running. >>> >> >>Do you mind if I ask what representation you use for your generated moves? >>I use the bottom 13 bits of an int, with 6 bits of source and 6 bits of dest and >>1 "special" bit. The first think my makemove does is test this special bit, and >>if clear it skips the checks for enpassant captures, castling moves and >>promotions. This seems a lot simpler than having separate functions. >>? >> >>wylie > >Sorry Wylie, didn't catch your post until now. > >I know people say 1 integer is faster than a 4 chars, but this compact notation >with AND'ing and shifting is a bit over the top for me right now. I have enough >stuff to optimize and debug so I'm trying to keep the basic stuff simple. >One day I will of cause do an implementation to see if it is faster. > >About my design for checking the castle and en-passent, then I put information >into the move struct about what kind of piece is doing the move, I use this for >calling the right move function. This way I don't have to check for EP or castle >if it is a rook, night, bishop or queen moving. > >It is a complete pseudo-object orientated code, I never need to check for the >type of piece when finding its moves or when moving it. >In principle I could extend this so that every special move (like castle) had >its own move rutine, I would not need to check a thing. > >I don't know exactly what the top programs' "move design" are. >But I hear most are written in C so I think they are doing similar stuff. > >How are you doing it? > >-S. Well, first of all I'm writing the interesting parts of my program in 80x86 assembly, so my method may not be general enough for everybody. ;) However, my observation is that at the time you GENERATE moves you know what kind of move you are generating; so I differentiate them into two categories. There are the "normal" moves, which simply means "if dest is non-empty, remove captured piece. Then move source to dest." Notice that the vast majority of moves fit into this category. I use the bottom 12 bits (0-11) for the source and dest squares, and bit 12 to indicate that a move is a "special" move. In the category of "special" moves we have: castling, enpassant capture, and promotion (oh, and null moves!). In all cases, my "source" bits accurately indicate the source square, so I can look up the type of the piece moving in a 64-byte array my makemove maintains in addition to the bitboards. For a castling move the "destination" is two squares to the left or right of the king. I can test for both possible castling moves of a side with two comparison instructions (since my move representation starts out as a 13-bit number in one register). The numbers are then split into two registers, and the enpassant square is compared to the "destination" square, and if they match I branch off and do that special case. Lastly, if the piece type moving is a pawn and the source square is the rank from which the pawn promotes, then the destination *file* is correct but the destination *rank* encodes the promotion type. So I copy those bits elsewhere and smash them to be 0's/1's. The only purpose for my "special" flag is to avoid testing for all these special cases in the common case. For most of the moves generated, my move generators can assert that the move is not any of these special cases. The reason I have an explicit representation of null moves is so enpassant, half-move counter, etc. are saved and restored correctly across a null move. It's just like a normal move except it doesn't move any pieces around; I use src==dest==0 to indicate this. And why did I decide to write it all in assembly?? Well, (more than any other reason) because it's fun. Also I can do some things that no C compiler can, like take full advantage of Intel's bit-scan and bit-manipulation instructions which have been fast since the Pentium II. My code will be A LOT smaller, and hopefully a lot faster, than that generated by any C compiler, because I know exactly what's going on in there and carefully juggle registers, etc. for maximum effect. Of course there are some optimizations that I probably can't do as well as a strong compiler, such as instruction scheduling, especially since P2/P3/P4 have some different requirements. A major worry is that sometimes you forget one single optimization principle (such as alignment of certain labels) and the whole thing runs 15% slower. But I have VTune and someday when I have a whole working engine, I'll go back and work harder on the parts where my code gets punished the most. =) cheers, wylie
This page took 0 seconds to execute
Last modified: Thu, 15 Apr 21 08:11:13 -0700
Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.