- // board.cpp 
-   
- #include "common.h" 
-   
-   
- // initial position of a chess game : 
- // 
- //  +-----------------+ 
- // 8| R K B Q K B K R | - black 
- // 7| P P P P P P P P | 
- // 6|                 | 
- // 5|                 | 
- // 4|                 | 
- // 3|                 | 
- // 2| P P P P P P P P | 
- // 1| R K B Q K B K R | - white 
- //  +-----------------+ 
- //    a b c d e f g h 
-   
-   
- bool Board_Init (board_t *board, int white_playertype, int black_playertype, wchar_t *fen_string) 
- { 
-    // this function initializes a new chess game 
-   
-    bool is_success; 
-   
-    // initialize the moves array and blank out the first move's structure 
-    board->moves = (boardmove_t *) SAFE_malloc (1, sizeof (boardmove_t), false); 
-    memset (&board->moves[0], 0, sizeof (boardmove_t)); 
-   
-    board->viewed_move = 0; 
-    board->move_count = 1; 
-    board->game_state = STATE_UNKNOWN; // game has not started yet 
-    board->lastmove_time = 0.0f; 
-   
-    // initialize this board's players 
-    Player_Init (&board->players[COLOR_WHITE], COLOR_WHITE, white_playertype); 
-    Player_Init (&board->players[COLOR_BLACK], COLOR_BLACK, black_playertype); 
-   
-    // can we NOT successfully initialize from the given FEN string ? 
-    is_success = Move_SetupFromFEN (&board->moves[0], fen_string); 
-    if (!is_success) 
-       Move_SetupFromFEN (&board->moves[0], FENSTARTUP_STANDARDCHESS); // if so, fallback to standard chess table 
-   
-    // reset all selection and hovering information 
-    Board_SetSelectedAndHovered (board, -1, -1, -1, -1); 
-   
-    // notify that board was just set up 
-    board->was_setup = true; 
-    board->has_playerchanged = true; 
-   
-    return (is_success); // finished 
- } 
-   
-   
- void Board_Shutdown (board_t *board) 
- { 
-    // this function ends a chess game 
-   
-    boardmove_t *move; 
-    int move_index; 
-   
-    // reset the moves array 
-    for (move_index = 0; move_index < board->move_count; move_index++) 
-    { 
-       move = &board->moves[move_index]; // quick access to move 
-       SAFE_free ((void **) &move->sides[COLOR_WHITE].takenparts); // free white's taken parts 
-       SAFE_free ((void **) &move->sides[COLOR_BLACK].takenparts); // free black's taken parts 
-       SAFE_free ((void **) &move->comment); // free each move comment 
-    } 
-    SAFE_free ((void **) &board->moves); // and the moves array itself 
-    board->viewed_move = -1; 
-    board->move_count = 0; 
-   
-    // release players 
-    Player_Shutdown (&board->players[COLOR_WHITE]); 
-    Player_Shutdown (&board->players[COLOR_BLACK]); 
-   
-    // game has not started yet 
-    board->game_state = STATE_UNKNOWN; 
-   
-    return; // that's all there is 
- } 
-   
-   
- bool Board_Reset (board_t *board, wchar_t *fen_string) 
- { 
-    // this function initializes a chess game according to a FEN string, WITHOUT changing the players 
-   
-    boardmove_t *move; 
-    int move_index; 
-    bool is_success; 
-   
-    // reset the moves array 
-    for (move_index = 0; move_index < board->move_count; move_index++) 
-    { 
-       move = &board->moves[move_index]; // quick access to move 
-       SAFE_free ((void **) &move->sides[COLOR_WHITE].takenparts); // free white's taken parts 
-       SAFE_free ((void **) &move->sides[COLOR_BLACK].takenparts); // free black's taken parts 
-       SAFE_free ((void **) &move->comment); // free each move comment 
-    } 
-   
-    // resize the moves array and blank out the first move's structure 
-    board->moves = (boardmove_t *) SAFE_realloc (board->moves, board->move_count, 1, sizeof (boardmove_t), false); 
-    memset (&board->moves[0], 0, sizeof (boardmove_t)); 
-   
-    board->viewed_move = 0; 
-    board->move_count = 1; 
-    board->game_state = STATE_UNKNOWN; // game has not started yet 
-    board->lastmove_time = 0.0f; 
-   
-    // reset the players' view angles 
-    Player_ResetView (&board->players[COLOR_BLACK]); 
-    Player_ResetView (&board->players[COLOR_WHITE]); 
-   
-    // can we NOT successfully initialize from the given FEN string ? 
-    is_success = Move_SetupFromFEN (&board->moves[0], fen_string); 
-    if (!is_success) 
-       Move_SetupFromFEN (&board->moves[0], FENSTARTUP_STANDARDCHESS); // if so, fallback to standard chess table 
-   
-    // reset all selection and hovering information 
-    Board_SetSelectedAndHovered (board, -1, -1, -1, -1); 
-   
-    // notify that board was just set up 
-    board->was_setup = true; 
-    board->has_playerchanged = true; 
-   
-    return (is_success); // finished 
- } 
-   
-   
- bool Board_Think (board_t *board) 
- { 
-    // helper function to make both a board's players think 
-   
-    bool do_update; 
-   
-    do_update = false; // don't update scene until told otherwise 
-   
-    do_update |= Player_Think (&board->players[COLOR_WHITE]); // make white player think 
-    do_update |= Player_Think (&board->players[COLOR_BLACK]); // make black player think 
-   
-    // do the board sides need to be swapped ? 
-    if (board->want_playerswap) 
-    { 
-       Board_SwapSides (board); // if so, swap board sides 
-       board->want_playerswap = false; // don't do this all day long 
-       do_update |= true; // and update the scene 
-    } 
-   
-    // clear board notifications (they should have been processed in Player_Think()) 
-    board->was_setup = false; 
-    board->has_playerchanged = false; 
-   
-    return (do_update); // finished, return whether we update the scene or not 
- } 
-   
-   
- void Board_SwapSides (board_t *board) 
- { 
-    // helper function to swap a board's sides 
-   
-    player_t player_to_swap; 
-   
-    // THREAD-SAFE: wait until all buffers are unlocked 
-    while (board->players[COLOR_BLACK].sendbuffer_locked 
-           || board->players[COLOR_WHITE].sendbuffer_locked) 
-       Sleep (10); // test again in 10 milliseconds 
-   
-    // lock all the buffers at once 
-    board->players[COLOR_BLACK].sendbuffer_locked = true; 
-    board->players[COLOR_WHITE].sendbuffer_locked = true; 
-   
-    // swap players structures 
-    memcpy (&player_to_swap, &board->players[COLOR_BLACK], sizeof (player_t)); 
-    memcpy (&board->players[COLOR_BLACK], &board->players[COLOR_WHITE], sizeof (player_t)); 
-    memcpy (&board->players[COLOR_WHITE], &player_to_swap, sizeof (player_t)); 
-   
-    // restore correct colors 
-    board->players[COLOR_BLACK].color = COLOR_BLACK; 
-    board->players[COLOR_WHITE].color = COLOR_WHITE; 
-   
-    // turn their point of view 180 degrees 
-    board->players[COLOR_BLACK].view_yaw = WrapAngle (board->players[COLOR_BLACK].view_yaw + 180.0f); 
-    board->players[COLOR_WHITE].view_yaw = WrapAngle (board->players[COLOR_WHITE].view_yaw + 180.0f); 
-   
-    // now unlock all the players' buffers 
-    board->players[COLOR_BLACK].sendbuffer_locked = false; 
-    board->players[COLOR_WHITE].sendbuffer_locked = false; 
-   
-    board->reevaluate = true; // remember to reevaluate this board 
-   
-    return; // finished 
- } 
-   
-   
- void Board_SetSelectedAndHovered (board_t *board, int selected_line, int selected_column, int hovered_line, int hovered_column) 
- { 
-    // helper function to forcibly set a board's selected and hovered slots (respectively move source and destination) 
-   
-    board->selected_position[0] = selected_line; 
-    board->selected_position[1] = selected_column; 
-    board->hovered_position[0] = hovered_line; 
-    board->hovered_position[1] = hovered_column; 
-   
-    return; // finished 
- } 
-   
-   
- char Board_ColorToMove (board_t *board) 
- { 
-    // helper function that returns the current color to move for the given board 
-    // NOTE: since the return value may be used to address an array, DO NOT return an invalid value ! 
-   
-    if ((board->moves == NULL) || (board->move_count < 1)) 
-       return (COLOR_WHITE); // consistency check 
-   
-    return (1 - board->moves[the_board.move_count - 1].color); // return the opposite color of the last move's color 
- } 
-   
-   
- void Board_AppendMove (board_t *board, int from_line, int from_column, int to_line, int to_column, char promotion_type, wchar_t *comment) 
- { 
-    // this function processes a part movement on the specified board. 
-   
-    boardmove_t *last_move; 
-    boardmove_t new_move; 
-    int side_index; 
-    boardside_t *playing_side; 
-    boardside_t *opposing_side; 
-   
-    // get a quick access to board's last move 
-    last_move = &board->moves[board->move_count - 1]; 
-   
-    // prepare the new move 
-    new_move.color = 1 - last_move->color; // switch colors 
-    new_move.part = last_move->slots[from_line][from_column].part; // save the move part type 
-    new_move.promotion_type = promotion_type; // save the promotion type 
-    new_move.has_captured = false; // assume there's no capture until told otherwise 
-    new_move.is_enpassant = false; // assume no en passant coup is played until told otherwise 
-    new_move.is_check = false; // assume no check until told otherwise 
-    new_move.is_stalemate = false; // assume no stalemate until told otherwise 
-    new_move.source[0] = from_line; // save the move source line and column 
-    new_move.source[1] = from_column; 
-    new_move.target[0] = to_line; // save the move target line and column 
-    new_move.target[1] = to_column; 
-    new_move.pgntext[0] = 0; // will be evaluated at the end of this function 
-    new_move.comment = NULL; // assume no comment until told otherwise 
-    new_move.comment_size = 0; 
-    for (side_index = 0; side_index < 2; side_index++) 
-    { 
-       new_move.sides[side_index].takenparts = (unsigned char *) SAFE_malloc (last_move->sides[side_index].takenpart_count, sizeof (unsigned char), false); 
-       memcpy (new_move.sides[side_index].takenparts, last_move->sides[side_index].takenparts, last_move->sides[side_index].takenpart_count * sizeof (unsigned char)); 
-       new_move.sides[side_index].takenpart_count = last_move->sides[side_index].takenpart_count; // copy side's taken parts 
-       new_move.sides[side_index].shortcastle_allowed = last_move->sides[side_index].shortcastle_allowed; // copy whether side can castle short 
-       new_move.sides[side_index].longcastle_allowed = last_move->sides[side_index].longcastle_allowed; // copy whether side can castle long 
-    } 
-    memcpy (&new_move.slots, last_move->slots, sizeof (last_move->slots)); // copy table disposition 
-    new_move.fen_string[0] = 0; // will be evaluated at the end of this function 
-   
-    // get a quick access to current and opposing sides 
-    playing_side = &new_move.sides[new_move.color]; 
-    opposing_side = &new_move.sides[1 - new_move.color]; 
-   
-    // is a piece being taken ? 
-    if (new_move.slots[to_line][to_column].part != PART_NONE) 
-    { 
-       // was the piece being taken a rook ? 
-       if (new_move.slots[to_line][to_column].part == PART_ROOK) 
-       { 
-          // was it a white tower in A1, a white tower in A7, a black tower in H1 or a black tower in H7 ? 
-          if ((new_move.slots[to_line][to_column].color == COLOR_WHITE) && (to_line == 0) && (to_column == 0)) 
-             new_move.sides[COLOR_WHITE].longcastle_allowed = false; // our opponent can no longer castle queenside 
-          else if ((new_move.slots[to_line][to_column].color == COLOR_WHITE) && (to_line == 0) && (to_column == 7)) 
-             new_move.sides[COLOR_WHITE].shortcastle_allowed = false; // our opponent can no longer castle bishopside 
-          else if ((new_move.slots[to_line][to_column].color == COLOR_BLACK) && (to_line == 7) && (to_column == 0)) 
-             new_move.sides[COLOR_BLACK].longcastle_allowed = false; // our opponent can no longer castle queenside 
-          else if ((new_move.slots[to_line][to_column].color == COLOR_BLACK) && (to_line == 7) && (to_column == 7)) 
-             new_move.sides[COLOR_BLACK].shortcastle_allowed = false; // our opponent can no longer castle bishopside 
-       } 
-   
-       // resize this players' taken parts array and move the taken piece in it 
-       playing_side->takenparts = (unsigned char *) SAFE_realloc (playing_side->takenparts, playing_side->takenpart_count, playing_side->takenpart_count + 1, sizeof (unsigned char), true); 
-       playing_side->takenparts[playing_side->takenpart_count] = new_move.slots[to_line][to_column].part; 
-       playing_side->takenpart_count++; // player has now taken one piece more 
-       new_move.has_captured = true; // remember a part has just been captured 
-    } 
-   
-    // else is it an "en passant" coup ? 
-    else if ((new_move.slots[from_line][from_column].part == PART_PAWN) // we're a pawn 
-             && (abs (to_column - from_column) == 1) // we moved diagonally 
-             && (new_move.slots[to_line][to_column].part == PART_NONE) // no part on destination 
-             && (new_move.slots[from_line][to_column].part == PART_PAWN)) // but a pawn next to us 
-    { 
-       // resize this players' taken parts array and move the taken piece in it 
-       playing_side->takenparts = (unsigned char *) SAFE_realloc (playing_side->takenparts, playing_side->takenpart_count, playing_side->takenpart_count + 1, sizeof (unsigned char), true); 
-       playing_side->takenparts[playing_side->takenpart_count] = new_move.slots[from_line][to_column].part; 
-       memset (&new_move.slots[from_line][to_column], 0, sizeof (boardslot_t)); // "en passant" coup 
-       playing_side->takenpart_count++; // player has now taken one piece more 
-       new_move.has_captured = true; // remember a part has just been captured 
-       new_move.is_enpassant = true; // and that it's an en passant coup 
-    } 
-   
-    // has a promotion been specified ? 
-    if (promotion_type != PART_NONE) 
-       Move_SetSlot (&new_move, from_line, from_column, new_move.color, promotion_type); // promote the pawn to the desired type 
-   
-    // was the moved part the king ? if so, player can't castle anymore 
-    if (new_move.slots[from_line][from_column].part == PART_KING) 
-    { 
-       // did the king castle queenside ? or did it castle bishopside ? 
-       if ((from_column == 4) && (to_column == 2)) 
-       { 
-          // move the rook from A to D (0 -> 3) and wipe its previous location 
-          memcpy (&new_move.slots[to_line][3], &new_move.slots[from_line][0], sizeof (boardslot_t)); 
-          memset (&new_move.slots[from_line][0], 0, sizeof (boardslot_t)); 
-       } 
-       else if ((from_column == 4) && (to_column == 6)) 
-       { 
-          // move the rook from H to F (7 -> 5) and wipe its previous location 
-          memcpy (&new_move.slots[to_line][5], &new_move.slots[from_line][7], sizeof (boardslot_t)); 
-          memset (&new_move.slots[from_line][7], 0, sizeof (boardslot_t)); 
-       } 
-   
-       // no matter whether it castled or not, remember this king cannot castle anymore 
-       playing_side->shortcastle_allowed = false; 
-       playing_side->longcastle_allowed = false; 
-    } 
-   
-    // else was it the rook ? 
-    else if (new_move.slots[from_line][from_column].part == PART_ROOK) 
-    { 
-       // was the tower in A ? or was it in H ? 
-       if (from_column == 0) 
-          playing_side->longcastle_allowed = false; // player can no longer castle queenside 
-       else if (from_column == 7) 
-          playing_side->shortcastle_allowed = false; // player can no longer castle bishopside 
-    } 
-   
-    // move the part and erase the starting slot 
-    memcpy (&new_move.slots[to_line][to_column], &new_move.slots[from_line][from_column], sizeof (boardslot_t)); 
-    memset (&new_move.slots[from_line][from_column], 0, sizeof (boardslot_t)); 
-   
-    // does the new move have a comment ? if so, save it 
-    if ((comment != NULL) && (comment[0] != 0)) 
-    { 
-       new_move.comment_size = wcslen (comment) + 1; // save this move's comment and the size of the mallocated space 
-       new_move.comment = (wchar_t *) SAFE_malloc (new_move.comment_size, sizeof (wchar_t), false); 
-       wcscpy_s (new_move.comment, new_move.comment_size, comment); // copy comment 
-    } 
-   
-    // evaluate check and stalemate status 
-    new_move.is_check = Move_IsCheck (&new_move, 1 - new_move.color); // save whether opponent is in check or not 
-    new_move.is_stalemate = Move_IsStaleMate (&new_move, 1 - new_move.color); // save whether opponent is stalemate 
-   
-    // describe our move in Standard Abbreviated Notation and describe the resulting table in Forsyth-Edwards Notation 
-    Move_DescribeInSAN (&new_move); 
-    Move_DescribeInFEN (&new_move); 
-   
-    // resize the previous moves array and insert our new move at the end of it 
-    board->moves = (boardmove_t *) SAFE_realloc (board->moves, board->move_count, board->move_count + 1, sizeof (boardmove_t), false); 
-    memcpy (&board->moves[board->move_count], &new_move, sizeof (boardmove_t)); 
-    board->move_count++; // we know now one previous move more 
-   
-    board->viewed_move = board->move_count - 1; // set the move to be viewed to be the last move 
-   
-    // if the game hadn't started yet, remember it has now 
-    if (board->game_state == STATE_UNKNOWN) 
-       board->game_state = STATE_PLAYING; 
-   
-    // remember the last move time 
-    board->lastmove_time = current_time; 
-   
-    // reset stoppage time 
-    stoppage_time = 0; 
-   
-    // remember the game state should be reevaluated 
-    board->reevaluate = true; 
-   
-    return; // finished 
- } 
-