If someone is interested in doing the same thing with toga then
I think that it may be interesting if (s)he can send me his commented code of toga and I will send him(her) my commented code of glaurung.
I post an example to code that I commented to explain what I mean by heavily commented code.
- Code: Select all
move_stack_t *generate_moves(const position_t *pos, move_stack_t *ms) {
int from, to, piece, type, tmp, step, rank, prom;
int side = pos->side, xside = side^1;
/*we get side to move and side of the opponent*/
const int *ptr;
for(from = KingSquare(pos, side); from != PieceListEnd;
from = NextPiece(pos, from)) {
/*loop on the pieces from the king to the pawns*/
if(from > H8) continue;
/*we skip markers to the next type of the piece list or the end of the list
it seems a waste of time to skip a lot of markers in the endgame when
there are not many types of pieces and I think that it may be better to have shorter list
when after the last piece you have only marker to the next piece type*/
piece = pos->board[from]; type = TypeOfPiece(piece);
tmp = (from<<7)|(type<<17);
/*
0<=from<=127 0<=type<=7
tmp is initialized to be 2^7*(<2^7)+2^17*(<2^3)
tmp is part of move.
bits of move:
1)bits 0-7:to square(<2^7)
2)bits 8-14:2^7*the from square inside tmp bits(<2^14)
3)bits 15-17:2^14*promoted piece(promoted piece can be 0-4 when 0 is for no promotion)
4)bits 18-20:2^17*type of piece
5)bits 21-23:2^20*type of captured piece(only needed for captures)
6)bit 24:enpassent capture move(1 for enpassent capture 0 for other moves)
7)bit 25:castling move(1 for castling move 0 for other moves)
*/
if(type == PAWN) {
step = PawnPush[side];
/*PawnPush[2] = {16, -16}
the pawn may advance to from+step in case that from+step empty*/
rank = PawnRank[side][from];
if(rank < RANK_7) {
/*not promotion case*/
if(pos->board[from+step] == EMPTY) {
/*advancing the pawn is pseudolegal and we put it in the move list*/
(ms++)->move = tmp|(from+step);
if(rank == RANK_2 && pos->board[from+2*step] == EMPTY)
/*if advancing the pawn 2 steps is pseudo legal we also put it in the move list*/
(ms++)->move = tmp|(from+2*step);
}
for(ptr = Directions[piece]; *ptr; ptr++) {
/*generating captures
note that cheking it for every pawn seem to be not efficient
when only in rare cases there are captures and
it may be better to update capture list incrementally*/
to = from + (*ptr);
if(ColourOfPiece(pos->board[to]) == xside)
/*if the capture is pseudo legal we generate it*/
(ms++)->move = tmp|to|(TypeOfPiece(pos->board[to])<<20);
}
}
else {
/*generating promotions*/
if(pos->board[from+step] == EMPTY)
for(prom = QUEEN; prom >= KNIGHT; prom--)
/*if promotion that is not capture is pseudo legal generate it*/
(ms++)->move = tmp|(from+step)|(prom<<14);
for(ptr = Directions[piece]; *ptr; ptr++) {
to = from + (*ptr);
if(ColourOfPiece(pos->board[to]) == xside) {
/*PawnRank[side[[to]==RANK_8 always when the square is not out of the board
and when the square is out of the board pos->board[to]==OUTSIDE so
the condition is not needed*/
if(PawnRank[side][to] == RANK_8) {
for(prom = QUEEN; prom >= KNIGHT; prom--)
/*promtion with capture is pseudolegal so we generate it*/
(ms++)->move =
tmp|to|(TypeOfPiece(pos->board[to])<<20)|(prom<<14);
}
/*never happen so you can delete it and the case of not promotion was done earlier*/
else (ms++)->move = tmp|to|(TypeOfPiece(pos->board[to])<<20);
}
}
}
}
else {
/*dealing with pieces that are not pawns*/
for(ptr = Directions[piece]; *ptr; ptr++) {
/*
if(SLIDER(piece)) {
to = from;
do {
to += (*ptr);
if(pos->board[to]==EMPTY || ColourOfPiece(pos->board[to])==xside)
(ms++)->move = tmp|to|(TypeOfPiece(pos->board[to])<<20);
} while(pos->board[to]==EMPTY);
}
else {
to = from + (*ptr);
if(pos->board[to]==EMPTY || ColourOfPiece(pos->board[to])==xside)
(ms++)->move = tmp|to|(TypeOfPiece(pos->board[to])<<20);
}
*/
/*
not very important but it seems better
and shorter to add this code and get read of the code that is commented out
in order not to have the same lines repeat twice
I did not check speed but the code is simpler so I am not talkin about speed
optimization that make the code harder to understand
*/
to = from;
do {
/*Knight and king are not sliders so the do is done once for them*/
to += (*ptr);
/*loop on every possible direction*/
if(pos->board[to]==EMPTY || ColourOfPiece(pos->board[to])==xside)
/*TypeOfPiece[EMPTY]=EMPTY&7=16&7=0 so the data
for the move is correct also for captures and we can pseudo do it*/
(ms++)->move = tmp|to|(TypeOfPiece(pos->board[to])<<20);
} while ((pos->board[to]==EMPTY)&&(SLIDER(piece)));
}
}
}
// Finally, we have the ugly special cases of en passant captures and
// castling moves:
if(pos->ep_square)
for(ptr = Directions[PawnOfColour(xside)]; *ptr; ptr++) {
/*calculating the from square from the ep square when use the fact that
the opponent pawn can capture the from square from the enpassent square*/
from = pos->ep_square + (*ptr);
if(pos->board[from] == PawnOfColour(side))
/*in case that enpassent capture is pseudolegal generate it*/
(ms++)->move =
(pos->ep_square)|(from<<7)|(PAWN<<17)|(PAWN<<20)|EP_FLAG;
}
/*alternative code that I did not check
int legalcastle(const position_t *pos,int fromking,int toking,int fromrook,int torook)
{
for (sq=Min(fromking,toking);sq<=Max(fromking,toking);sq++)
if ((sq!=fromking&&sq!=toking&&pos->board[sq]!=EMPTY)||is_attacked(pos, sq, xside))
return 0;
for (sq=Min(fromrook,torook);sq<=Max(fromrook,torook);sq++)
if (sq!=fromrook&&sq!=torook&&pos->board[sq]!=EMPTY)
return 0;
return 1;
}
if (CanCastle(pos,side))
{
int fromking = InitialKSQ+side*A8;
if (canCastleKingside(pos.side))
{
fromrook=InitialKRSQ+side*A8;
torook=F1+side*A8;
toking=G1+side*A8;
if legalcastle(pos,fromking,toking,fromrook,torook)
(ms++)-> move = (KING<<17)|(fromking<<7)|toking|CASTLE_FLAG;
}
if(CanCastleQueenside(pos, side))
{
fromrook=InitialQRSQ+side*A8;
torook=D1+side*A8;
toking=C1+side*A8;
if legalcastle(pos,fromking,toking,fromrook,torook)
(ms++)-> move = (KING<<17)|(fromking<<7)|toking|CASTLE_FLAG;
}
}
*/
if(!pos->check) {
/*castling allowed only if the king is not in check
it is probably faster to start from if (CanCastle(pos,side)) because the condition
if (!pos->check) usually happens and practically you can even delete that
condition because the loop already check that the king path including the from square
is not under threat
note also that using the same letters
for different variables is confusing and I thought for a moment that
the initial value of InitialKRSQ is changed*/
if(CanCastleKingside(pos, side)) {
int initialKSQ = InitialKSQ+side*A8, initialKRSQ = InitialKRSQ+side*A8;
int g1 = G1 + side*A8, f1 = F1 + side*A8;
int illegal = 0, sq;
/*checking that the path of the king is empty and not under threat*/
for(sq = Min(initialKSQ, g1); sq <= Max(initialKSQ, g1); sq++)
if((sq != initialKSQ && sq != initialKRSQ && pos->board[sq] != EMPTY)
|| is_attacked(pos, sq, xside))
illegal = 1;
for(sq = Min(initialKRSQ, f1); sq <= Max(initialKRSQ, f1); sq++)
if(sq != initialKSQ && sq != initialKRSQ && pos->board[sq] != EMPTY)
illegal = 1;
if(!illegal) (ms++)-> move = (KING<<17)|(initialKSQ<<7)|g1|CASTLE_FLAG;
}
if(CanCastleQueenside(pos, side)) {
int initialKSQ = InitialKSQ+side*A8, initialQRSQ = InitialQRSQ+side*A8;
int c1 = C1 + side*A8, d1 = D1 + side*A8;
int illegal = 0, sq;
for(sq = Min(initialKSQ, c1); sq <= Max(initialKSQ, c1); sq++)
if((sq != initialKSQ && sq != initialQRSQ && pos->board[sq] != EMPTY)
|| is_attacked(pos, sq, xside))
illegal = 1;
for(sq = Min(initialQRSQ, d1); sq <= Max(initialQRSQ, d1); sq++)
if(sq != initialKSQ && sq != initialQRSQ && pos->board[sq] != EMPTY)
illegal = 1;
if(InitialQRSQ == B1 && (pos->board[A1+side*A8] == RookOfColour(xside) ||
pos->board[A1+side*A8] == QueenOfColour(xside)))
illegal = 1;
if(!illegal) (ms++)-> move = (KING<<17)|(initialKSQ<<7)|c1|CASTLE_FLAG;
}
}
return ms;
}