I wrote a long reply to this, but unfortunately, the board ate it. I don't have time to retype everything, but I hope a shorter version will be comprehensible.
You're looking at a
very old Glaurung version. Any particular reason you are interested in it? I find it embarrassing to look at that old code now. I was so stupid and inexperienced back then.
shahil4242 wrote: ↑Sat Jun 19, 2021 5:28 am
Some of the definations are
1.list_t
Code: Select all
typedef struct {
uint8 p, n;
} list_t;
Here p and n are previous and next square I think so.
Correct.
2.position_t
Code: Select all
typedef struct {
uint8 board_[256];
uint8 *board;
list_t piece_list[256];
int ep_square;
int castle_flags;
int rule50;
int side, xside;
} position_t;
extern position_t Pos//Global pointer to the position_t
Question: why *board is used and it is offset by 64 Pos.board = Pos.board_ + 64
I use a mailbox board with a frame of squares containing the constant OUTSIDE around the "real" board, but at the same time I want the square indexes to start from 0. The pointer hack is just an ugly way to make this possible.
Some of the Maccros are realated to piece list are
Code: Select all
#define PL(x) (Pos.piece_list[(x)])
#define PL_START(x) (Pos.piece_list[(x)+128].n)
#define PL_NEXT(x) (Pos.piece_list[(x)].n)
#define PL_PREV(x) (Pos.piece_list[(x)].p)
#define PL_REMOVE(x) do {\
PL_NEXT(PL_PREV(x)) = PL_NEXT(x); PL_PREV(PL_NEXT(x)) = PL_PREV(x);\
} while(0)
#define PL_INSERT(x,y) do {\
PL_NEXT(y) = PL_START(x); PL_PREV(PL_NEXT(y)) = y;\
PL_PREV(y) = x+128; PL_START(x) = y;\
printf("pl_insert(x,y) : (%3d,%3d) PL_START(x): %3d\n",x,y,PL_START(x));\
} while(0)
#define PL_MOVE(x,y) do {\
PL(y)=PL(x); PL_PREV(PL_NEXT(y)) = PL_NEXT(PL_PREV(y)) = y;\
} while(0)
#define PL_END (BK+128+1)
Please explain all the macros.
For a piece p, Pos.piece_list[p + 128].n (or, equivalently, PL_START(P)) will contain the first square containing a piece of type p, assuming that there is such a piece on the board. If there is no such piece, PL_START(p) will equal p - 1 (the next smaller valued piece of the same color), or PL_END if p is a pawn (white or black).
For a non-empty square s containing a piece of type p, Pos.piece_list[s].n (or, equivalently, PL_NEXT(s)) will contain the next square containing a piece of the same type p, or p - 1 + 128 if there is no next square with a piece of type p.
The point of this is that it makes it quite straightforward both to loop through just the pieces of a particular type, or all pieces of a given color. Looping through the squares of a single type could be done like this:
Code: Select all
int sq = PL_START(WR); // Let's use white rooks as an example
while (sq <= H8) {
do_something(sq);
sq = PL_NEXT(sq);
}
At the end of the loop, sq will equal WR - 1 + 128, which equals WB + 128. This means that if we do sq = PL_NEXT(sq) again, we'll get the first square containing a white bishop (assuming that there is a white bishop on the board). This means that iterating through all white pieces can be done like this (in the order king, queens, rooks, bishops, knights, pawns):
Code: Select all
int sq = PL_START(WK);
while (sq != PL_END) {
if (sq <= H8) {
do_something(sq);
}
sq = PL_NEXT(sq);
}
In the above discussion, I only talked about PL_NEXT (and the corresponding slot "n" in list_t), not about PL_PREV (and the corresponding slot "p" in list_t). The only purpose of PL_PREV is to enable efficient deletion and insertion of piece list entries. Consider what we need to do when we want to delete a piece from the list. We need to modify the "next piece" information for the
previous piece; it can no longer point to the piece that gets deleted, but needs to point to the piece
after the deleted piece instead. This is why PL_REMOVE looks the way it does:
Code: Select all
#define PL_REMOVE(x) do {\
PL_NEXT(PL_PREV(x)) = PL_NEXT(x);\
PL_PREV(PL_NEXT(x)) = PL_PREV(x);\
} while(0)
If you understand this one, PL_INSERT should also be straightforward.
If this still is confusing, try to draw a list of squares connected by forward/backward arrows, and consider what needs to be changed when you delete or add a square to the list.
Some of the code in board.c are
Code: Select all
void init_board(void) {
int i;
for(i=0; i<256; i++) Pos.board_[i] = ((i-64)&0x88)? OUTSIDE : EMPTY;
Pos.board = Pos.board_ + 64;
}
void init_piece_lists(void) {
int sq, piece;
for(piece=KING; piece>=KNIGHT; piece--) {
PL_START(piece) = piece-1+128; PL_START(piece+8) = piece+7+128;
PL_PREV(piece-1+128) = piece+128; PL_PREV(piece+7+128) = piece+8+128;
}
PL_START(WP) = PL_START(BP) = PL_END;
for(sq=A1; sq<=H8; sq++) {
if(Board[sq]==OUTSIDE || Board[sq]==EMPTY) continue;
PL_INSERT(Board[sq], sq);
}
}
I guess the only non-obvious thing here is the first loop in init_piece_lists. That one simply initializes the piece list to an empty state.