Optimised Algebraic Notation

Discussion of chess software programming and technical issues.

Moderator: Ras

Fulvio
Posts: 396
Joined: Fri Aug 12, 2016 8:43 pm

Re: Optimised Algebraic Notation

Post by Fulvio »

leanchess wrote: Thu Dec 02, 2021 4:41 am

Code: Select all

struct rmove {
    int fromSquare:    6;
    int toSquare:      6;    
    int fromPiece:     3; // MovedKing = 0, MovedRook = 7
    int toPiece:       3; // None = 0, MovedRook = 7
    int flags:         2; // CastleQueen = 1, CastleKing = 2
                          // PromoQueen = 0, PromoKnight = 1
                          // PromoRook = 2, PromoBishop = 3
    int isEnPassant:   1;
    int enPassantFile: 3;
};
I guess it's a typo, but just to be precise

Code: Select all

int fromPiece: 3;
has a range of -4 .. 3.

The fromPiece is not necessary to undo a move:

Code: Select all

struct rmove {
    // bits  0- 5: destination square (from 0 to 63)
    // bits  6-11: origin square (from 0 to 63)
    // bits 12-13: promotion piece type -2 (from QUEEN-2 to KNIGHT-2)
    // bits 14-15: special move flag: promotion (1), en passant (2), castling (3)
    uint16_t usual_move; 
    uint8_t castling_flags_of_the_moving_side : 2;
    uint8_t enPassantFile : 3;
    uint8_t capturedPiece : 3; // Use KING when capturing the enemy rook with castle rights.
};
encoding castle as king takes rook would also handle chess960.
User avatar
leanchess
Posts: 181
Joined: Sun Dec 08, 2019 8:16 pm
Full name: Dmitry Shechtman

Re: Optimised Algebraic Notation

Post by leanchess »

Fulvio wrote: Fri Dec 03, 2021 6:41 am
leanchess wrote: Thu Dec 02, 2021 4:41 am

Code: Select all

struct rmove {
    int fromSquare:    6;
    int toSquare:      6;    
    int fromPiece:     3; // MovedKing = 0, MovedRook = 7
    int toPiece:       3; // None = 0, MovedRook = 7
    int flags:         2; // CastleQueen = 1, CastleKing = 2
                          // PromoQueen = 0, PromoKnight = 1
                          // PromoRook = 2, PromoBishop = 3
    int isEnPassant:   1;
    int enPassantFile: 3;
};
I guess it's a typo, but just to be precise

Code: Select all

int fromPiece: 3;
has a range of -4 .. 3.
Feel free to replace with int8_t.
Fulvio wrote: The fromPiece is not necessary to undo a move:
I suppose so, but it makes the code prettier (and you'd still need at least one bit to tell if the rook/king had been moved).
Fulvio wrote:

Code: Select all

struct rmove {
    // bits  0- 5: destination square (from 0 to 63)
    // bits  6-11: origin square (from 0 to 63)
    // bits 12-13: promotion piece type -2 (from QUEEN-2 to KNIGHT-2)
    // bits 14-15: special move flag: promotion (1), en passant (2), castling (3)
    uint16_t usual_move; 
    uint8_t castling_flags_of_the_moving_side : 2;
    uint8_t enPassantFile : 3;
    uint8_t capturedPiece : 3; // Use KING when capturing the enemy rook with castle rights.
};
encoding castle as king takes rook would also handle chess960.
  1. Bits 14-15 are redundant.
  2. isEnPassant is missing.
Sopel
Posts: 391
Joined: Tue Oct 08, 2019 11:39 pm
Full name: Tomasz Sobczyk

Re: Optimised Algebraic Notation

Post by Sopel »

leanchess wrote: Fri Dec 03, 2021 2:37 am
Sopel wrote: Thu Dec 02, 2021 9:20 pm

Code: Select all

void make(struct rmove m, int color) {
    int piece = m.fromPiece;
    switch (piece) {
        case MovedRook: piece = Rook;
                        break;
        case MovedKing: piece = King;
                        break; // See what I did here?
        case King:      if (m.flags) {
                            //...
                        }
                        break;
        case Pawn:      //...
                        break;
    }
    board[m.fromSquare] = 0;
    board[m.toSquare] = piece | Moved | color;
    //...
}

void unmake(struct rmove m, int color) {
    int toPiece = m.toPiece != MovedRook
        ? m.toPiece
        : (Rook | Moved);
    board[m.toSquare] = toPiece | (color ^ Color);
    //...
}
I see what you mean now, but this doesn't help. Previous castling rights cannot be inferred just from the pieces involved in the move, as demonstrated in my first PGN.

Fulvio's way sounds okay, if it had the 1 ep bit.
dangi12012 wrote:No one wants to touch anything you have posted. That proves you now have negative reputations since everyone knows already you are a forum troll.

Maybe you copied your stockfish commits from someone else too?
I will look into that.
User avatar
leanchess
Posts: 181
Joined: Sun Dec 08, 2019 8:16 pm
Full name: Dmitry Shechtman

Re: Optimised Algebraic Notation

Post by leanchess »

Sopel wrote: Fri Dec 03, 2021 12:23 pm
leanchess wrote: Fri Dec 03, 2021 2:37 am
Sopel wrote: Thu Dec 02, 2021 9:20 pm

Code: Select all

void make(struct rmove m, int color) {
    int piece = m.fromPiece;
    switch (piece) {
        case MovedRook: piece = Rook;
                        break;
        case MovedKing: piece = King;
                        break; // See what I did here?
        case King:      if (m.flags) {
                            //...
                        }
                        break;
        case Pawn:      //...
                        break;
    }
    board[m.fromSquare] = 0;
    board[m.toSquare] = piece | Moved | color;
    //...
}

void unmake(struct rmove m, int color) {
    int toPiece = m.toPiece != MovedRook
        ? m.toPiece
        : (Rook | Moved);
    board[m.toSquare] = toPiece | (color ^ Color);
    //...
}
I see what you mean now, but this doesn't help. Previous castling rights cannot be inferred just from the pieces involved in the move, as demonstrated in my first PGN.
Note the Moved bit.

Code: Select all

int canCastlePseudo(int king, int rook, int color) {
    return board[king] == (King | color) && board[rook] == (Rook | color);
}
Sopel
Posts: 391
Joined: Tue Oct 08, 2019 11:39 pm
Full name: Tomasz Sobczyk

Re: Optimised Algebraic Notation

Post by Sopel »

leanchess wrote: Fri Dec 03, 2021 12:57 pm
Sopel wrote: Fri Dec 03, 2021 12:23 pm
leanchess wrote: Fri Dec 03, 2021 2:37 am
Sopel wrote: Thu Dec 02, 2021 9:20 pm

Code: Select all

void make(struct rmove m, int color) {
    int piece = m.fromPiece;
    switch (piece) {
        case MovedRook: piece = Rook;
                        break;
        case MovedKing: piece = King;
                        break; // See what I did here?
        case King:      if (m.flags) {
                            //...
                        }
                        break;
        case Pawn:      //...
                        break;
    }
    board[m.fromSquare] = 0;
    board[m.toSquare] = piece | Moved | color;
    //...
}

void unmake(struct rmove m, int color) {
    int toPiece = m.toPiece != MovedRook
        ? m.toPiece
        : (Rook | Moved);
    board[m.toSquare] = toPiece | (color ^ Color);
    //...
}
I see what you mean now, but this doesn't help. Previous castling rights cannot be inferred just from the pieces involved in the move, as demonstrated in my first PGN.
Note the Moved bit.

Code: Select all

int canCastlePseudo(int king, int rook, int color) {
    return board[king] == (King | color) && board[rook] == (Rook | color);
}
What are the "Moved" bits in this fen? [fen]rn2k1nr/p3bp2/2pqb1p1/1p2p2p/4P3/NQPP1N2/P2BBPPP/2KR3R b kq - 3 12[/fen]
dangi12012 wrote:No one wants to touch anything you have posted. That proves you now have negative reputations since everyone knows already you are a forum troll.

Maybe you copied your stockfish commits from someone else too?
I will look into that.
User avatar
leanchess
Posts: 181
Joined: Sun Dec 08, 2019 8:16 pm
Full name: Dmitry Shechtman

Re: Optimised Algebraic Notation

Post by leanchess »

Sopel wrote: Fri Dec 03, 2021 2:04 pm What are the "Moved" bits in this fen? [fen]rn2k1nr/p3bp2/2pqb1p1/1p2p2p/4P3/NQPP1N2/P2BBPPP/2KR3R b kq - 3 12[/fen]
All Moved bits are cleared by default. When a castling right is missing in FEN, the respective rook's Moved bit is set.
Sopel
Posts: 391
Joined: Tue Oct 08, 2019 11:39 pm
Full name: Tomasz Sobczyk

Re: Optimised Algebraic Notation

Post by Sopel »

leanchess wrote: Fri Dec 03, 2021 2:15 pm
Sopel wrote: Fri Dec 03, 2021 2:04 pm What are the "Moved" bits in this fen? [fen]rn2k1nr/p3bp2/2pqb1p1/1p2p2p/4P3/NQPP1N2/P2BBPPP/2KR3R b kq - 3 12[/fen]
All Moved bits are cleared by default. When a castling right is missing in FEN, the respective rook's Moved bit is set.
So it doesn't work until you encode positions with the "Moved" bit. Which is what what you cannot do in general.
dangi12012 wrote:No one wants to touch anything you have posted. That proves you now have negative reputations since everyone knows already you are a forum troll.

Maybe you copied your stockfish commits from someone else too?
I will look into that.
Fulvio
Posts: 396
Joined: Fri Aug 12, 2016 8:43 pm

Re: Optimised Algebraic Notation

Post by Fulvio »

leanchess wrote: Fri Dec 03, 2021 11:51 am Feel free to replace with int8_t.
Maybe it wasn't a typo: uint8_t
leanchess wrote: Fri Dec 03, 2021 11:51 am
  1. Bits 14-15 are redundant.
  2. isEnPassant is missing.
:?: :?: :?:

Code: Select all

bool rmove::isEnPassant() {
	return (usual_move >> 14) == 2;
}
You can also check how Stockfish use it:
https://github.com/official-stockfish/S ... pes.h#L112
Fulvio
Posts: 396
Joined: Fri Aug 12, 2016 8:43 pm

Re: Optimised Algebraic Notation

Post by Fulvio »

Sopel wrote: Fri Dec 03, 2021 12:23 pm
leanchess wrote: Fri Dec 03, 2021 2:37 am
Sopel wrote: Thu Dec 02, 2021 9:20 pm

Code: Select all

void make(struct rmove m, int color) {
    int piece = m.fromPiece;
    switch (piece) {
        case MovedRook: piece = Rook;
                        break;
        case MovedKing: piece = King;
                        break; // See what I did here?
        case King:      if (m.flags) {
                            //...
                        }
                        break;
        case Pawn:      //...
                        break;
    }
    board[m.fromSquare] = 0;
    board[m.toSquare] = piece | Moved | color;
    //...
}

void unmake(struct rmove m, int color) {
    int toPiece = m.toPiece != MovedRook
        ? m.toPiece
        : (Rook | Moved);
    board[m.toSquare] = toPiece | (color ^ Color);
    //...
}
I see what you mean now, but this doesn't help. Previous castling rights cannot be inferred just from the pieces involved in the move, as demonstrated in my first PGN.
He is using 2 MovedRook: 1 in the fromPiece and the other in toPiece.
In your example with the move Rh1h8, fromPiece is set to MovedRook and toPiece is set to MovedRook only if black can castle king side.
Sopel
Posts: 391
Joined: Tue Oct 08, 2019 11:39 pm
Full name: Tomasz Sobczyk

Re: Optimised Algebraic Notation

Post by Sopel »

Fulvio wrote: Fri Dec 03, 2021 2:40 pm
Sopel wrote: Fri Dec 03, 2021 12:23 pm
leanchess wrote: Fri Dec 03, 2021 2:37 am
Sopel wrote: Thu Dec 02, 2021 9:20 pm

Code: Select all

void make(struct rmove m, int color) {
    int piece = m.fromPiece;
    switch (piece) {
        case MovedRook: piece = Rook;
                        break;
        case MovedKing: piece = King;
                        break; // See what I did here?
        case King:      if (m.flags) {
                            //...
                        }
                        break;
        case Pawn:      //...
                        break;
    }
    board[m.fromSquare] = 0;
    board[m.toSquare] = piece | Moved | color;
    //...
}

void unmake(struct rmove m, int color) {
    int toPiece = m.toPiece != MovedRook
        ? m.toPiece
        : (Rook | Moved);
    board[m.toSquare] = toPiece | (color ^ Color);
    //...
}
I see what you mean now, but this doesn't help. Previous castling rights cannot be inferred just from the pieces involved in the move, as demonstrated in my first PGN.
He is using 2 MovedRook: 1 in the fromPiece and the other in toPiece.
In your example with the move Rh1h8, fromPiece is set to MovedRook and toPiece is set to MovedRook only if black can castle king side.
Yes, I understood that, that's why I'm only posting the other pgn now, because there I don't see a way without encoding more into the position.
dangi12012 wrote:No one wants to touch anything you have posted. That proves you now have negative reputations since everyone knows already you are a forum troll.

Maybe you copied your stockfish commits from someone else too?
I will look into that.