From 99b227ec8c7dd8bb4116b643cc13ce39189195a0 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Thu, 11 Dec 2014 00:19:24 +0100 Subject: [PATCH] Add support for outputting positions in my own bit-packed FEN format. --- apply.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ apply.h | 1 + grammar.c | 3 ++ output.c | 64 ++++++++++++++++++++++++++++++++++ typedef.h | 7 +++- 5 files changed, 175 insertions(+), 1 deletion(-) diff --git a/apply.c b/apply.c index 53118d2..bd7b472 100644 --- 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 5c6d3ba..455a837 100644 --- 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); diff --git a/grammar.c b/grammar.c index 0d708de..1d792a4 100644 --- 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); } diff --git a/output.c b/output.c index 2878b00..6e47275 100644 --- 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, diff --git a/typedef.h b/typedef.h index 9f7f270..f405a63 100644 --- 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. */ -- 2.39.2