void set_cell_state(board_t* board, pos_t pos, cell_t new_state) { assert(NULL != board); assert(is_valid_board(board)); assert(is_valid_pos(pos)); /* // this assertion is tentative, it may prove too strict */ /* // it relies on the caller checking the state of this cell */ /* // before trying to change it */ /* const cell_t old_state = get_cell(board, pos); */ /* assert(new_state != old_state); */ row* white_col = &board->b[W][pos.y]; row* black_col = &board->b[B][pos.y]; switch (new_state) { case WHITE: *black_col = unset(*black_col, trans_x(pos.x)); *white_col = set(*white_col, trans_x(pos.x)); break; case BLACK: *white_col = unset(*white_col, trans_x(pos.x)); *black_col = set(*black_col, trans_x(pos.x)); break; case EMPTY: // deactivate the bit representing the cell at _pos_ // we apply the macro to both columns because we don't // know to which player it belongs *white_col = unset(*white_col, trans_x(pos.x)); *black_col = unset(*black_col, trans_x(pos.x)); } // make sure we didn't corrupt the board in the process of // updating the cell assert(is_valid_board(board)); }
void set_cell(board_t* board, player_t player, pos_t pos) { assert(NULL != board); assert(is_valid_pos(pos)); assert(is_valid_board(board)); // make sure the given cell is empty assert(EMPTY == get_cell(board, pos)); board->b[player][pos.y] = set(board->b[player][pos.y], trans_x(pos.x)); }
cell_t get_cell(const board_t* board, pos_t pos) { assert(NULL != board); assert(is_valid_board(board)); if (is_set(board->b[W][pos.y], trans_x(pos.x))) { return WHITE; } else if (is_set(board->b[B][pos.y], trans_x(pos.x))) { return BLACK; } return EMPTY; }
int cells_count(const board_t* board, player_t player) { assert(NULL != board); assert(is_valid_board(board)); assert(W == player || B == player); int cells = 0; for (size_t y = 0; y < ROWS; y++) for (row crnt_row = board->b[player][y]; crnt_row; crnt_row >>= 1) cells += crnt_row & 1; assert(0 <= cells && cells <= COLUMNS * ROWS); return cells; }
/** * For a given game state and player, returns an integer which\ * tells how favourable the given state is for this player. * @returns A positive integer means max_player wins, zero means a tie, * and when a negative integer is returned, max_player loses. * @param board the game state which is to be evaluated * @param max_player the player (either Black or White) which seeks\ * to maximize the rating. */ int get_rating(const board_t* board, player_t max_player) { // definition of symmetry within the context of adversarial search ratings? const int steps = 500; assert(NULL != board); assert(is_valid_board(board)); assert(max_player == W || max_player == B); const player_t min_player = max_player == W ? B : W; board_t board1, board2; memset(&board2, 0, sizeof(board_t)); memcpy(&board1, board, sizeof(board_t)); board_t *p1, *p2; p1 = &board1; p2 = &board2; for (int i = 0; i < steps; i++) { step(p2, p1); // halt the simulation if two consecutive states don't differ if (0 == memcmp(p1, p2, sizeof(board_t))) break; board_t *tmp; tmp = p1; p1 = p2; p2 = tmp; } const int max_player_cells = cells_count(p1, max_player); const int min_player_cells = cells_count(p1, min_player); return max_player_cells - min_player_cells; }
/** * Advances the state of the board (cellular automaton) by a single step. */ void step(board_t* board, const board_t* old_board) { assert(NULL != board); assert(NULL != old_board); assert(is_valid_board(board)); // create a copy of the old state // the board pointed to by _board_ will //board_t old_board = *board; // iterate over the living cells // TODO decide whether a linked list is worth the added complexity for (pos_t pos = {0, 0}; pos.y < ROWS; pos.y++) { for (pos.x = 0; pos.x < COLUMNS; pos.x++) { const cell_t old_state = get_cell(old_board, pos); // determine the number of living cells bordering this one const int black_neighbors = n_neighbors(old_board, pos, BLACK); const int white_neighbors = n_neighbors(old_board, pos, WHITE); const cell_t new_state = successor_cell_state(old_state, white_neighbors, black_neighbors); //if (new_state != old_state) set_cell_state(board, pos, new_state); /* if (new_state != EMPTY) */ /* printf("(%d,%d) b: %d, w: %d\n", */ /* pos.x, pos.y, black_neighbors, white_neighbors); */ } } }
void print_board(const board_t* board) { assert(NULL != board); assert(is_valid_board(board)); char column[COLUMNS+1]; memset(column, 0, sizeof(column)); for (pos_t pos = {0, 0}; pos.y < ROWS; pos.y++) { for (pos.x = 0; pos.x < COLUMNS; pos.x++) { const cell_t content = get_cell(board, pos); switch (content) { case WHITE: column[pos.x] = 'w'; break; case BLACK: column[pos.x] = 'b'; break; case EMPTY: column[pos.x] = '-'; } } // make sure the column string terminates assert(0 == column[COLUMNS]); printf("%s\n", column); } }
int main(void) { char board[BOARD_SIZE][BOARD_SIZE]; init_board(board); printf(WELCOME_TO_DRAUGHTS); printf(ENTER_SETTINGS); char *command = input2str(stdin); int win_pos = 0; while (strcmp(command, "quit") != 0){ if (strcmp(command, "start") == 0){ if (is_valid_board(board)) break; else{ printf(WROND_BOARD_INITIALIZATION); free(command); command = input2str(stdin); continue; } } exc(command,board); free(command); command = input2str(stdin); } if (strcmp(command, "start") == 0){ // initially we printed the board at the start of the game, commented out in order to match the running examples. //if (user_color == WHITE) print_board(board); while (1){ if (user_color == WHITE){ int ret_val = user_turn(board, WHITE); if (ret_val == QUIT) break; if (ret_val == WIN_POS){ printf(BLACK_WIN); win_pos = 1; break; } if (computer_turn(board, BLACK) == WIN_POS){ printf(WHITE_WIN); win_pos = 1; break; } } else{ if (computer_turn(board, WHITE) == WIN_POS){ printf(BLACK_WIN); win_pos = 1; break; } int ret_val = user_turn(board, BLACK); if (ret_val == QUIT) break; if (ret_val == WIN_POS){ printf(WHITE_WIN); win_pos = 1; break; } } } } if (win_pos == 1){ free(command); command = input2str(stdin); } free(command); }