]> git.sesse.net Git - pgn-extract/commitdiff
Add support for outputting positions in my own bit-packed FEN format.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 10 Dec 2014 23:19:24 +0000 (00:19 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Fri, 12 Dec 2014 21:56:56 +0000 (22:56 +0100)
apply.c
apply.h
grammar.c
output.c
typedef.h

diff --git a/apply.c b/apply.c
index 53118d28fa601b0642df9a42d72db60dab383b3d..bd7b4721e2467974ad26db29c97a05f2e0d31d9b 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -714,6 +714,9 @@ apply_move(Colour colour,Move *move_details, Board *board)
             move_details->epd = (char *) MallocOrDie(FEN_SPACE);
             build_basic_EPD_string(board,move_details->epd);
         }
+        else if(GlobalState.output_format == SESSE_BIN){
+            build_BPFEN_string(board, &move_details->bpfen, &move_details->bpfen_len);
+        }
 
        if(move_details->class != NULL_MOVE) {
            make_move(move_details->class, move_details->from_col,move_details->from_rank,
@@ -1792,6 +1795,104 @@ build_FEN_string(const Board *board,char *fen)
     sprintf(&fen[ix],"%u", full_move_number);
 }
 
+void
+build_BPFEN_string(const Board *board,char **bpfen, int* bpfen_len)
+{   static int bits[256];   /* Max six bits per piece, 32 blanks, and then some. */
+    int bit_pos = 0;
+    Rank rank;
+    int ix = 0;
+    for(rank = LASTRANK; rank >= FIRSTRANK; rank--){
+        Col col;
+        for(col = FIRSTCOL; col <= LASTCOL; col++){
+            int coloured_piece = board->board[RankConvert(rank)]
+                                             [ColConvert(col)];
+            if(coloured_piece == EMPTY){
+                bits[bit_pos++] = 0;
+                continue;
+            }
+            bits[bit_pos++] = 1;
+            bits[bit_pos++] = (EXTRACT_COLOUR(coloured_piece) == WHITE) ? 1 : 0;
+            switch(EXTRACT_PIECE(coloured_piece)) {
+                case PAWN:
+                    bits[bit_pos++] = 0;
+                    break;
+                case KNIGHT:
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 0;
+                    bits[bit_pos++] = 0;
+                    break;
+                case BISHOP:
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 0;
+                    bits[bit_pos++] = 1;
+                    break;
+                case ROOK:
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 0;
+                    break;
+                case QUEEN:
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 0;
+                    break;
+                case KING:
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 1;
+                    bits[bit_pos++] = 1;
+                    break;
+            }
+        }
+    }
+    /* Pad board. */
+    while ((bit_pos % 8) != 0) {
+        bits[bit_pos++] = 0;
+    }
+
+    /* Non-board information. */
+    bits[bit_pos++] = (board->to_move == WHITE) ? 0 : 1;
+    bits[bit_pos++] = board->WKingCastle ? 1 : 0;
+    bits[bit_pos++] = board->WQueenCastle ? 1 : 0;
+    bits[bit_pos++] = board->BKingCastle ? 1 : 0;
+    bits[bit_pos++] = board->BQueenCastle ? 1 : 0;
+
+    if(board->EnPassant){
+        int col_index = board->ep_col - COLBASE;
+        bits[bit_pos++] = 1;
+        bits[bit_pos++] = (col_index >> 2) & 1;
+        bits[bit_pos++] = (col_index >> 1) & 1;
+        bits[bit_pos++] = col_index & 1;
+    }
+    else{
+        bits[bit_pos++] = 0;
+    }
+
+    /* Pad non-board. */
+    while ((bit_pos % 8) != 0) {
+        bits[bit_pos++] = 0;
+    }
+
+    /* Convert from bits to binary form. */
+    *bpfen = (char *)malloc(bit_pos / 8);
+    *bpfen_len = bit_pos / 8;
+
+    for (ix = 0; ix < bit_pos / 8; ++ix) {
+        unsigned char ch = 0;
+        int jx;
+
+        for (jx = 0; jx < 8; ++jx) {
+            ch |= (bits[ix * 8 + jx] << jx);
+        }
+
+        (*bpfen)[ix] = ch;
+    }
+}
+
     /* Append to move_details a FEN comment of the board.
      * The board state is immediately following application of the
      * given move.
diff --git a/apply.h b/apply.h
index 5c6d3bae5762d86daaed248a0c48569b980ba77d..455a8375a7191a8a71268be724cc7a4d28efabbc 100644 (file)
--- a/apply.h
+++ b/apply.h
@@ -30,6 +30,7 @@ Board *new_fen_board(const char *fen);
 void set_output_piece_characters(const char *letters);
 char coloured_piece_to_SAN_letter(Piece coloured_piece);
 void build_basic_EPD_string(const Board *board,char *fen);
+void build_BPFEN_string(const Board *board,char **bpfen, int* bpfen_len);
 char SAN_piece_letter(Piece piece);
 const char *piece_str(Piece piece);
 void build_FEN_string(const Board *board,char *fen);
index 0d708de6735b41872aaf85974868b271327c01be..1d792a4a645f68a0897a1f5289826dcb2584a6dc 100644 (file)
--- a/grammar.c
+++ b/grammar.c
@@ -734,6 +734,9 @@ free_move_list(Move *move_list)
         if(next->epd != NULL){
             (void) free((void *)next->epd);
         }
+        if(next->bpfen != NULL){
+            (void) free((void *)next->bpfen);
+        }
         if(next->terminating_result != NULL){
             (void) free((void *)next->terminating_result);
         }
index 2878b00a3b195165c2ef6c38f51246d5f6e4a55a..6e47275ca8842e32106a35d3b0117d95230c6975 100644 (file)
--- a/output.c
+++ b/output.c
@@ -62,6 +62,8 @@ static char promoted_piece_letter(Piece piece);
 static void print_algebraic_game(Game current_game,FILE *outputfile,
                            unsigned move_number,Boolean white_to_move,
                            Board *final_board);
+static void output_sesse_bin_game(Game current_game,FILE *outputfile,
+                                  unsigned move_number,Boolean white_to_move);
 static void print_epd_game(Game current_game,FILE *outputfile,
                            unsigned move_number,Boolean white_to_move,
                            Board *final_board);
@@ -149,6 +151,7 @@ which_output_format(const char *arg)
         { "elalg", ELALG },
         { "uci", UCI },
         { "cm", CM },
+        { "sessebin", SESSE_BIN },
         { "", SOURCE },
         /* Add others before the terminating NULL. */
         { (const char *) NULL, SAN }
@@ -188,6 +191,7 @@ output_file_suffix(OutputFormat format)
     static const char PGN_suffix[] = ".pgn";
     static const char EPD_suffix[] = ".epd";
     static const char CM_suffix[] = ".cm";
+    static const char BIN_suffix[] = ".bin";
 
     switch(format){
         case SOURCE:
@@ -200,6 +204,8 @@ output_file_suffix(OutputFormat format)
             return EPD_suffix;
         case CM:
             return CM_suffix;
+        case SESSE_BIN:
+            return BIN_suffix;
         default:
             return PGN_suffix;
     }
@@ -996,6 +1002,9 @@ output_game(Game current_game,FILE *outputfile)
            case CM:
                output_cm_game(outputfile,move_number,white_to_move,current_game);
                break;
+           case SESSE_BIN:
+               output_sesse_bin_game(current_game,outputfile,move_number,white_to_move);
+               break;
            default:
                fprintf(GlobalState.logfile,
                            "Internal error: unknown output type %d in output_game().\n",
@@ -1156,6 +1165,61 @@ print_algebraic_game(Game current_game,FILE *outputfile,
     putc('\n',outputfile);
 }
 
+static void
+output_sesse_bin_game(Game current_game,FILE *outputfile,
+                      unsigned move_number,Boolean white_to_move)
+{
+    const char *result = NULL;
+    Move *move;
+
+    // Find the result. Skip games with no result.
+    for (move = current_game.moves; move != NULL; move = move->next) {
+        if (move->terminating_result) {
+            result = move->terminating_result;
+        }
+    }
+    if (result == NULL || strcmp(result, "*") == 0) {
+        return;
+    }
+
+    int result_int = -1;
+    if (strcmp(result, "1-0") == 0) {
+        result_int = 0;
+    } else if (strcmp(result, "1/2-1/2") == 0) {
+        result_int = 1;
+    } else if (strcmp(result, "0-1") == 0) {
+        result_int = 2;
+    } else {
+        fprintf(stderr, "Unknown result '%s'\n", result);
+        return;
+    }
+
+    // Find Black and White Elos. Skip games with no Elo.
+    const char *white_elo_tag = current_game.tags[WHITE_ELO_TAG];
+    const char *black_elo_tag = current_game.tags[BLACK_ELO_TAG];
+    if (white_elo_tag == NULL || black_elo_tag == NULL) {
+        return;
+    }
+
+    int white_elo = atoi(white_elo_tag);
+    int black_elo = atoi(black_elo_tag);
+
+    for (move = current_game.moves; move != NULL; move = move->next) {
+        unsigned int opening = 0;  // TODO
+
+        // key
+        putc(move->bpfen_len + strlen((char *)move->move), outputfile);
+        fwrite(move->bpfen, move->bpfen_len, 1, outputfile);
+        fwrite(move->move, strlen((char *)move->move), 1, outputfile);
+
+        // value
+        putc(result_int, outputfile);
+        fwrite(&white_elo, sizeof(white_elo), 1, outputfile);
+        fwrite(&black_elo, sizeof(black_elo), 1, outputfile);
+        fwrite(&opening, sizeof(opening), 1, outputfile);
+    }
+}
+
 static void
 print_epd_move_list(Game current_game,FILE *outputfile,
                     unsigned move_number, Boolean white_to_move,
index 9f7f270e416fbecc5f3cc2b914366a98935365b1..f405a63f2c04d9736004f2ebcd583af85b3bf499 100644 (file)
--- a/typedef.h
+++ b/typedef.h
@@ -33,7 +33,7 @@
      *            and en-passant notation.
      *     UCI: UCI-compatible format - actually LALG.
      */
-typedef enum { SOURCE, SAN, EPD, CM, LALG, HALG, ELALG, UCI } OutputFormat;
+typedef enum { SOURCE, SAN, EPD, CM, LALG, HALG, ELALG, UCI, SESSE_BIN } OutputFormat;
 
     /* Define a type to specify whether a move gives check, checkmate,
      * or nocheck.
@@ -96,6 +96,11 @@ typedef struct move{
      * has been played.
      */
     char *epd;
+    /* Same as epd, but in our special binary packed format.
+     * Not zero-terminated, since it is binary.
+     */
+    char *bpfen;
+    int bpfen_len;
     StringList *Nags;
     CommentList *Comment;
     /* terminating_result hold the result of the current list of moves. */