PieceList in older versions of Glaurung Chess Engine.

Discussion of anything and everything relating to chess playing software and machines.

Moderators: hgm, Rebel, chrisw

shahil4242
Posts: 30
Joined: Thu Sep 28, 2017 5:20 pm

PieceList in older versions of Glaurung Chess Engine.

Post by shahil4242 »

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.
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

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.

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);
  }
}
Please Explain init_piece_lists(void),PL,PL_START,PL_NEXT,PL_PREV,PL_INSERT,PL_REMOVE,PL_MOVE

I want to know how piece lists is working in Glaurung Chess Engine.

Thank you very much.
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: PieceList in older versions of Glaurung Chess Engine.

Post by mar »

this looks like a doubly-linked list through square indices as you've guessed
where there is each list per piece type (per color), with head(or tail) starting at index 128 in piece_list.

masking with 0x88 hints at a specific board implementation

EDIT: I think you're asking in a wrong subforum, you should try the programming subforum
Martin Sedlak
Tord
Posts: 31
Joined: Tue Feb 27, 2018 11:29 am

Re: PieceList in older versions of Glaurung Chess Engine.

Post by Tord »

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.
shahil4242
Posts: 30
Joined: Thu Sep 28, 2017 5:20 pm

Re: PieceList in older versions of Glaurung Chess Engine.

Post by shahil4242 »

Thanks your your beautiful explanation...
You're looking at a very old Glaurung version. Any particular reason you are interested in it?
As Chess programming is my hobby.I had made a very simple and weak chess engine with 0x88 board representation.For MoveGen and other evaluations i used to loop squares 0 to 128.But it takes more time.So I want to introduce piece list in my program.I found the source code Glaurung 1.0.2 i think so.And trying to understand to working of piecelist.I had been trying to develop chess engine since 2016,but i had many many time On last week i manage to make simple weak chess engine..During 2018 I had tried to made a chess engine with simple piecelist like

Code: Select all

//To Insert WR of square sq
piece_square[WR][ piece_count[WR]++] = sq

//To Loop
int piece_count[MAX_PIECE];
int piece_square[MAX_PIECE][20];
//To Loop WR i used
for(int count=0; count < piece_count[WR];count++) {
    int square = piece[WR][count];
    do_something(square);
}
Using this piece list the main trade off is moving a piece and undoing the move.I have to iterate the piece_square and find the square and replace it by new square by looping.
I find it embarrassing to look at that old code now. I was so stupid and inexperienced back then.
Really you are a great experienced programmer at that time.

Code: Select all

#define PL_INSERT(piece,square) do {\
  PL_NEXT(square) = PL_START(piece); \ 1
  PL_PREV(PL_NEXT(square)) = square;\ 2
  PL_PREV(square) = piece+128; \ 3
  PL_START(piece) = square;\ 4
} while(0)
1. Pos.piece_list[square].n = Pos.piece_list[piece+128] // Updating the next field of square
2. Please Explain
3. Pos.piece_list[square].p = piece+128 // Setting prev at starting square of the piece
4.Pos.piece_list[piece+128].n = square // Updating the next field of starting square of piece

Is Gothmog is open source?

Is Glaurung is derived from Gothmog?



Have a great day ahead.