static void decide_move(void) { mtx_lock(&game_mutex); if (game_started && !is_end() && !is_force_mode) { if (game_started && has_single_response()) { move m = get_single_response(); print_computer_move(m); add_move(m); engine_move_count_inc(); } else { move m = book_get_move(book, current_position()); if (m != none_move) { print_computer_move(m); add_move(m); engine_move_count_inc(); } else { set_thinking_done_cb(computer_move, ++callback_key); start_thinking(); } } } else { game_started = false; } mtx_unlock(&game_mutex); }
/* * Add all pseudo-legal non-capturing moves that the given piece (N/B/Q/K) * can make, with the exception of castles. */ static void generate_piece_noncaptures(const position_t* pos, square_t from, piece_t piece, move_t** moves_head) { move_t* moves = *moves_head; square_t to; if (piece_slide_type(piece) == NONE) { // not a sliding piece, just iterate over dest. squares for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) { to = from + *delta; if (pos->board[to] != EMPTY) continue; moves = add_move(pos, create_move(from, to, piece, NONE), moves); } } else { // a sliding piece, keep going until we hit something for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) { to = from + *delta; while (pos->board[to] == EMPTY) { moves = add_move(pos, create_move(from, to, piece, NONE), moves); to += *delta; } } } *moves_head = moves; }
void get_king_moves(char board[BOARD_SIZE][BOARD_SIZE], COLOR player, Pos piece){ Move* res = NULL; Move* res_head = res; Pos pos[4] = { { piece.col - 1, piece.row - 1 }, { piece.col + 1, piece.row - 1 }, { piece.col - 1, piece.row + 1 }, { piece.col + 1, piece.row + 1 } }; Pos curr; int found_ahead; for (int p = 0; p < 4; p++){ curr = pos[p]; while (is_valid_pos(curr) && board[curr.col][curr.row] == EMPTY){ add_move(piece, &curr, 1); curr = get_next_diag(piece, curr); // BUG - once dests_num == 1 and |dest-start| != 1 add_moves thinks its 1 capture and not a simple move.. } if (is_valid_pos(curr) && is_opposite(player, board[curr.col][curr.row])){ char tmp = board[curr.row][curr.col]; board[curr.row][curr.col] = EMPTY; Pos new_piece = get_next_diag(piece, curr); if (is_valid_pos(new_piece) && board[new_piece.row][new_piece.col] == EMPTY){ found_ahead = get_capture_moves(piece, new_piece, board, player, 1, &new_piece); if (found_ahead == 0) add_move(piece, &new_piece, 1); } board[curr.row][curr.col] = tmp; } } }
// finds all moves of a single king piece void get_king_moves(char board[BOARD_SIZE][BOARD_SIZE], COLOR player, Pos piece){ Pos pos[4] = { { piece.col - 1, piece.row - 1 }, { piece.col + 1, piece.row - 1 }, { piece.col - 1, piece.row + 1 }, { piece.col + 1, piece.row + 1 } }; Pos curr, new_piece; int found_ahead = -1; for (int p = 0; p < 4; p++){ curr = pos[p]; while (is_valid_pos(curr) && board[curr.col][curr.row] == EMPTY){ add_move(piece, &curr, 0); curr = get_next_diag(piece, curr); } if (is_valid_pos(curr) && is_opposite(player, board[curr.col][curr.row])){ char tmp = board[curr.col][curr.row]; board[curr.col][curr.row] = EMPTY; board[piece.col][piece.row] = EMPTY; new_piece = get_next_diag(piece, curr); if (is_valid_pos(new_piece) && board[new_piece.col][new_piece.row] == EMPTY){ found_ahead = get_capture_moves(piece, new_piece, board, player, 1, &new_piece); if (found_ahead == 0) add_move(piece, &new_piece, 1); } board[curr.col][curr.row] = tmp; board[piece.col][piece.row] = curr_piece; } } }
int get_capture_moves(Pos start, Pos piece, char board[BOARD_SIZE][BOARD_SIZE], COLOR player, int count, Pos* dests){ Pos pos[4] = { { piece.col - 1, piece.row - 1 }, { piece.col + 1, piece.row - 1 }, { piece.col - 1, piece.row + 1 }, { piece.col + 1, piece.row + 1 } }; int found_now = 0, found_ahead; for (int p = 0; p < 4; p++) if (is_valid_pos(pos[p]) && is_opposite(player, board[pos[p].col][pos[p].row])){ Pos new_piece = get_next_diag(piece, pos[p]); if (is_valid_pos(new_piece) && board[new_piece.col][new_piece.row] == EMPTY){ found_now++; char tmp = board[pos[p].col][pos[p].row]; board[pos[p].col][pos[p].row] = EMPTY; Pos* new_dests = malloc(sizeof(Pos) * (count + 1)); for (int i = 0; i < count; i++){ new_dests[i].row = dests[i].row; new_dests[i].col = dests[i].col; } new_dests[count].row = new_piece.row; new_dests[count].col = new_piece.col; found_ahead = get_capture_moves(start, new_piece, board, player, count + 1, new_dests); if (found_ahead == 0){ add_move(start, new_dests, count + 1); free(new_dests); } board[pos[p].row][pos[p].col] = tmp; } } return found_now; }
static int computer_move(uintmax_t key) { if (key != callback_key) return -1; move m; mtx_lock(&game_mutex); if (engine_get_best_move(&m) != 0) { puts("-"); } else { print_computer_move(m); if (exit_on_done) exit(EXIT_SUCCESS); add_move(m); engine_move_count_inc(); } mtx_unlock(&game_mutex); return 0; }
inline void bishop_move(struct position *pos, struct move_array *m, unsigned char bishops) { uint64_t bishop_pos = pos->pieces[bishops]; uint64_t moves; unsigned char index_from, index_to; for (int i = 0; i < 10; i++) { // up to 10 bishops of same color on the board, (for loop for compiler loop unrolling) if ((index_from = ffsll(bishop_pos)) != 0) { index_from--; moves = BishopMoves[index_from][magictransform((pos->allpieces & BishopMasks[index_from]), BishopMagic[index_from], BishopMagicSize [index_from])] & ~pos-> sumpieces[bishops & COLOR]; for (int i = 0; i < 14; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_move(m, index_from, index_to, bishops, find_piece(pos, index_to)); moves &= notlinboard[index_to]; } else { break; } } bishop_pos &= notlinboard[index_from]; } else { break; } } }
void move_rotate_both(t_env *e) { int c; c = 0; c += move_rotate_a(e, BOTH); c += move_rotate_b(e, BOTH); c != 0 ? add_move(e, "rr") : 0; }
/* * Generate all non-capturing, non-promoting pawn moves. */ static void generate_pawn_quiet_moves(const position_t* pos, square_t from, piece_t piece, move_t** moves_head) { color_t side = pos->side_to_move; square_t to; rank_t r_rank = relative_rank[side][square_rank(from)]; move_t* moves = *moves_head; to = from + pawn_push[side]; if (r_rank == RANK_7 || pos->board[to] != EMPTY) return; moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); to += pawn_push[side]; if (r_rank == RANK_2 && pos->board[to] == EMPTY) { // initial two-square push moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); } *moves_head = moves; }
void swap_b(t_e *env) { int tmp; if (env->b_s != NULL && env->b_s->next != NULL) { tmp = env->b_s->nbr; env->b_s->nbr = env->b_s->next->nbr; env->b_s->next->nbr = tmp; env->nb_op++; add_move(env, "sb"); } }
static void operator_move(move m) { stop_thinking(); mtx_lock(&game_mutex); if (!is_force_mode) game_started = true; add_move(m); decide_move(); mtx_unlock(&game_mutex); }
void move_push_b(t_env *e) { t_stack *temp; if (e->stack_a != NULL) { temp = e->stack_a; e->stack_a = e->stack_a->next; temp->next = e->stack_b; e->stack_b = temp; e->stack_b->next == NULL ? e->stack_end_b = e->stack_b : 0; e->stack_a == NULL ? e->stack_end_a = NULL : 0; add_move(e, "pb"); } }
int move_rotate_b(t_env *e, int move) { t_stack *tmp; if (e->stack_b != NULL && e->stack_a->next != NULL) { tmp = e->stack_b; e->stack_b = e->stack_b->next; tmp->next = NULL; e->stack_end_b->next = tmp; e->stack_end_b = tmp; move == ONE ? add_move(e, "rb") : 0; return (1); } return (0); }
inline void king_move(struct position *pos, struct move_array *m, unsigned char king) { unsigned char from = ffsll(pos->pieces[king]) - 1; uint64_t moves = kingmoves[from] & ~pos->sumpieces[king & COLOR]; unsigned char index; for (int i = 0; i < 8; i++) { if ((index = ffsll(moves)) != 0) { index--; add_move(m, from, index, king, find_piece(pos, index)); moves &= notlinboard[index]; } else { break; } } }
int move_rotate_a(t_env *e, int move) { t_stack *tmp; if (e->stack_a != NULL && e->stack_a->next != NULL) { tmp = e->stack_a; e->stack_a = e->stack_a->next; tmp->next = NULL; e->stack_end_a->next = tmp; e->stack_end_a = tmp; move == ONE ? add_move(e, "ra") : 0; return (1); } return (0); }
/* Choose a digit for the given square. * The starting digit is passed as a parameter. * Returns -1 if no choice possible. */ static int choose( int idx, int digit ) { rb->yield(); for( ; digit <= 9 ; ++digit ) if( !DISALLOWED( idx, digit ) ) { board[ idx ] = SET_DIGIT( digit ); update( idx ); add_move( idx, digit, CHOICE ); return digit; } return -1; }
/* Fill square with given digit, and update state. * Returns 0 on success, else -1 on error (i.e. invalid fill) */ static int fill( int idx, int digit ) { assert( 0 != digit ); if( !IS_EMPTY( idx ) ) return ( DIGIT( idx ) == digit ) ? 0 : -1; if( DISALLOWED( idx, digit ) ) return -1; board[ idx ] = SET_DIGIT( digit ); update( idx ); add_move( idx, digit, 0 ); return 0; }
/* * Add all pseudo-legal non-capturing promotions. */ static int generate_promotions(const position_t* pos, move_t* moves) { move_t* moves_head = moves; color_t side = pos->side_to_move; piece_t piece = create_piece(side, PAWN); for (int i = 0; i < pos->num_pawns[side]; ++i) { square_t from = pos->pawns[side][i]; rank_t r_rank = relative_rank[side][square_rank(from)]; if (r_rank < RANK_7) continue; square_t to = from + pawn_push[side]; if (pos->board[to]) continue; for (piece_type_t type=KNIGHT; type<=QUEEN; ++type) { moves = add_move(pos, create_move_promote(from, to, piece, EMPTY, type), moves); } } *moves = 0; return (moves-moves_head); }
/* * Add all pseudo-legal captures that the given pawn can make. */ static void generate_pawn_captures(const position_t* pos, square_t from, piece_t piece, move_t** moves_head) { color_t side = pos->side_to_move; int cap_left = side == WHITE ? 15 : -15; int cap_right = side == WHITE ? 17 : -17; square_t to; rank_t r_rank = relative_rank[side][square_rank(from)]; move_t* moves = *moves_head; if (r_rank < RANK_7) { // non-promote captures to = from + cap_left; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } else if (to == pos->ep_square && pos->board[to] == EMPTY) { moves = add_move(pos, create_move_enpassant(from, to, piece, pos->board[to + pawn_push[side^1]]), moves); } to = from + cap_right; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } else if (to == pos->ep_square && pos->board[to] == EMPTY) { moves = add_move(pos, create_move_enpassant(from, to, piece, pos->board[to + pawn_push[side^1]]), moves); } } else { // capture/promotes to = from + cap_left; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { for (piece_t promoted=QUEEN; promoted > PAWN; --promoted) { moves = add_move(pos, create_move_promote(from, to, piece, pos->board[to], promoted), moves); } } to = from + cap_right; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { for (piece_t promoted=QUEEN; promoted > PAWN; --promoted) { moves = add_move(pos, create_move_promote(from, to, piece, pos->board[to], promoted), moves); } } } *moves_head = moves; }
void get_man_moves(char board[BOARD_SIZE][BOARD_SIZE], COLOR player, Pos piece){ Move* res = NULL; Move* res_head = res; Pos pos[4] = { { piece.col - 1, piece.row - 1 }, { piece.col + 1, piece.row - 1 }, { piece.col - 1, piece.row + 1 }, { piece.col + 1, piece.row + 1 } }; int direction = 1, found_ahead; if (player == BLACK) direction = -1; for (int p = 0; p < 4; p++){ if (is_valid_pos(pos[p]) && pos[p].row == piece.row + direction && board[pos[p].col][pos[p].row] == EMPTY) add_move(piece, &pos[p], 1); else if (is_valid_pos(pos[p]) && is_opposite(player, board[pos[p].col][pos[p].row])){ char tmp = board[pos[p].row][pos[p].col]; board[pos[p].row][pos[p].col] = EMPTY; Pos new_piece = get_next_diag(piece, pos[p]); if (is_valid_pos(new_piece) && board[new_piece.row][new_piece.col] == EMPTY){ found_ahead = get_capture_moves(piece, new_piece, board, player, 1, &new_piece); if (found_ahead == 0) add_move(piece, &new_piece, 1); } board[pos[p].row][pos[p].col] = tmp; } } }
void get_moves_by_piece(char board[BOARD_SIZE][BOARD_SIZE], COLOR player, Pos piece){ Pos* tmp_dests; switch (board[piece.col][piece.row]){ case WHITE_B: case BLACK_B: get_bishop_moves(board, player, piece); return; case WHITE_R: case BLACK_R: get_rook_moves(board, player, piece); return; case WHITE_Q: case BLACK_Q: get_bishop_moves(board, player, piece); get_rook_moves(board, player, piece); return; case BLACK_P: case WHITE_P: get_pawn_moves(board, player, piece); return; case WHITE_K: case BLACK_K: tmp_dests = (Pos[8]) { { piece.col - 1, piece.row - 1 }, { piece.col - 1, piece.row }, { piece.col - 1, piece.row + 1 }, { piece.col + 1, piece.row - 1 }, { piece.col + 1, piece.row }, { piece.col + 1, piece.row + 1 }, { piece.col, piece.row - 1 }, { piece.col, piece.row + 1 } }; break; case WHITE_N: case BLACK_N: tmp_dests = (Pos[8]) { { piece.col - 2, piece.row - 1 }, { piece.col - 2, piece.row + 1 }, { piece.col + 2, piece.row - 1 }, { piece.col + 2, piece.row + 1 }, { piece.col - 1, piece.row - 2 }, { piece.col + 1, piece.row - 2 }, { piece.col - 1, piece.row + 2 }, { piece.col + 1, piece.row + 2 }}; break; default: return; } for (int i = 0; i < 8; i++){ if (is_valid_pos(tmp_dests[i])){ if (board[tmp_dests[i].col][tmp_dests[i].row] == EMPTY || is_opposite(player, board[tmp_dests[i].col][tmp_dests[i].row])){ add_move(piece, tmp_dests[i], 0); } } } return; }
inline void knight_move(struct position *pos, struct move_array *m, unsigned char knights) { uint64_t knight_pos = pos->pieces[knights]; uint64_t moves; unsigned char index_from, index_to; for (int i = 0; i < 10; i++) { // can have up to 10 knights of same color on the board, (for loop for compiler loop unrolling) if ((index_from = ffsll(knight_pos)) != 0) { index_from--; moves = knightmoves[index_from] & ~pos->sumpieces[knights & COLOR]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_move(m, index_from, index_to, knights, find_piece(pos, index_to)); moves &= notlinboard[index_to]; } else { break; } } knight_pos &= notlinboard[index_from]; } else { break; } } }
void get_pawn_moves(char board[BOARD_SIZE][BOARD_SIZE], COLOR player, Pos piece){ int direction = board[piece.col][piece.row] == BLACK_P ? -1 : 1; int pawn_row = board[piece.col][piece.row] == BLACK_P ? 6 : 1; Pos dest; dest.col = piece.col; dest.row = piece.row + direction; if (is_valid_pos(dest)){ if (board[dest.col][dest.row] == EMPTY){ add_move(piece, dest, 0); if (is_EOB(dest, player)) for (int i = 1; i < 5; i++) add_move(piece, dest, get_piece_by_type(i, player)); } } if (piece.row == pawn_row){ dest.row = piece.row + (2 * direction); if (is_valid_pos(dest)){ if (board[dest.col][dest.row] == EMPTY && board[piece.col][piece.row + direction] == EMPTY) add_move(piece, dest, 0); } } dest.col = piece.col + 1; dest.row = piece.row + direction; if (is_valid_pos(dest)){ if (is_opposite(player, board[dest.col][dest.row])){ add_move(piece, dest, 0); if (is_EOB(dest, player)) for (int i = 1; i < 5; i++) add_move(piece, dest, get_piece_by_type(i, player)); } } dest.col = piece.col - 1; if (is_valid_pos(dest)){ if (is_opposite(player, board[dest.col][dest.row])){ add_move(piece, dest, 0); if (is_EOB(dest, player)) for (int i = 1; i < 5; i++) add_move(piece, dest, get_piece_by_type(i, player)); } } }
inline void pawn_move(struct position *pos, struct move_array *m, unsigned char pawns) { uint64_t pawn_pos = pos->pieces[pawns]; uint64_t moves; unsigned char index_to; switch (pawns & COLOR) { case WHITE: // nonpromotion forward moves moves = moveN(pawn_pos) & ~pos->allpieces & ~rank[7]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_move(m, index_to + S, index_to, pawns, nopiece_n); moves &= notlinboard[index_to]; } else { break; } } // forward 2 moves pawn_pos = pos->pieces[pawns]; moves = moveN(moveN(pawn_pos) & ~pos->allpieces) & ~pos->allpieces & rank[3]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_move_forward2(m, index_to + S + S, index_to, pawns, nopiece_n); moves &= notlinboard[index_to]; } else { break; } } // nonpromotion attack west moves pawn_pos = pos->pieces[pawns]; moves = moveNW(pawn_pos) & (pos->bpieces | ep_squares[1][pos->ep]) & ~file[7] & ~rank[7]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_move(m, index_to + SE, index_to, pawns, find_piece_ep(pos, index_to)); moves &= notlinboard[index_to]; } else { break; } } // nonpromotion attack east moves pawn_pos = pos->pieces[pawns]; moves = moveNE(pawn_pos) & (pos->bpieces | ep_squares[1][pos->ep]) & ~file[0] & ~rank[7]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_move(m, index_to + SW, index_to, pawns, find_piece_ep(pos, index_to)); moves &= notlinboard[index_to]; } else { break; } } pawn_pos = pos->pieces[pawns]; if ((pawn_pos & rank[6]) == 0) { // no promotion possibilities return; } else { // promotion forward moves moves = moveN(pawn_pos) & ~pos->allpieces & rank[7]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_promotion_move(m, index_to + S, index_to, pawns, nopiece_n); moves &= notlinboard[index_to]; } else { break; } } // promotion attack west moves pawn_pos = pos->pieces[pawns]; moves = moveNW(pawn_pos) & pos->bpieces & ~file[7] & rank[7]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_promotion_move(m, index_to + SE, index_to, pawns, find_piece(pos, index_to)); moves &= notlinboard[index_to]; } else { break; } } // promotion attack east moves pawn_pos = pos->pieces[pawns]; moves = moveNE(pawn_pos) & pos->bpieces & ~file[0] & rank[7]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_promotion_move(m, index_to + SW, index_to, pawns, find_piece(pos, index_to)); moves &= notlinboard[index_to]; } else { break; } } } break; default: // black // nonpromotion forward moves moves = moveS(pawn_pos) & ~pos->allpieces & ~rank[0]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_move(m, index_to + N, index_to, pawns, nopiece_n); moves &= notlinboard[index_to]; } else { break; } } // forward 2 moves pawn_pos = pos->pieces[pawns]; moves = moveS(moveS(pawn_pos) & ~pos->allpieces) & ~pos->allpieces & rank[4]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_move_forward2(m, index_to + N + N, index_to, pawns, nopiece_n); moves &= notlinboard[index_to]; } else { break; } } // nonpromotion attack west moves pawn_pos = pos->pieces[pawns]; moves = moveSW(pawn_pos) & (pos->wpieces | ep_squares[0][pos->ep]) & ~file[7] & ~rank[0]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_move(m, index_to + NE, index_to, pawns, find_piece_ep(pos, index_to)); moves &= notlinboard[index_to]; } else { break; } } // nonpromotion attack east moves pawn_pos = pos->pieces[pawns]; moves = moveSE(pawn_pos) & (pos->wpieces | ep_squares[0][pos->ep]) & ~file[0] & ~rank[0]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_move(m, index_to + NW, index_to, pawns, find_piece_ep(pos, index_to)); moves &= notlinboard[index_to]; } else { break; } } pawn_pos = pos->pieces[pawns]; if ((pawn_pos & rank[1]) == 0) { // no promotion possibilities return; } else { // promotion forward moves moves = moveS(pawn_pos) & ~pos->allpieces & rank[0]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_promotion_move(m, index_to + N, index_to, pawns, nopiece_n); moves &= notlinboard[index_to]; } else { break; } } // promotion attack west moves pawn_pos = pos->pieces[pawns]; moves = moveSW(pawn_pos) & pos->wpieces & ~file[7] & rank[0]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_promotion_move(m, index_to + NE, index_to, pawns, find_piece(pos, index_to)); moves &= notlinboard[index_to]; } else { break; } } // promotion attack east moves pawn_pos = pos->pieces[pawns]; moves = moveSE(pawn_pos) & pos->wpieces & ~file[0] & rank[0]; for (int i = 0; i < 8; i++) { if ((index_to = ffsll(moves)) != 0) { index_to--; add_promotion_move(m, index_to + NW, index_to, pawns, find_piece(pos, index_to)); moves &= notlinboard[index_to]; } else { break; } } } break; } }
Board::Board(int m):root_story(-1, -1, 0) { #ifdef CKM_STORED // pIgs = NULL; #endif size = 19; // UI = new FlBoard(); // time_color = UI->black_time->text_background(); //time_color2 = UI->black_time->text_color(); //UI->b = this; set_size(size); cur_player = BLACK; for (int i=0; i<19; i++) for (int j=0; j<19; j++) { b[i][j] = EMPTY; root_story.b[i][j] = EMPTY; } s = &root_story; pos = 0; root_story.score[0] = score[0] = 0; root_story.score[1] = score[1] = 0.5; mode = 0; set_mode(m); // owner = 0; //< pointer on the possibly associated IGS game memset(inib, EMPTY, 19*19); memset(dead, EMPTY, 19*19); memset(territory, EMPTY, 19*19); memset(b, EMPTY, 19*19); // memset(old_c, 0, sizeof(old_c)); //time color next = first; first = this; if (!stn) { stn = new Stone(); stn->set_size(20); // stn->init_image(); } // UI->black_box->image(stn->img[0]); // UI->white_box->image(stn->img[1]); // UI->black_name->hide(); // UI->white_name->hide(); // UI->black_time->hide(); //UI->white_time->hide(); // UI->moves_browser->board = this; // UI->observer_browser->callback(observer_cb, this); // UI->moves_browser->type(Fl_Browser::VERTICAL | Fl_Browser::MULTI_BROWSER); strcpy(blackname, ""); strcpy(blackrank, ""); strcpy(whitename, ""); strcpy(whiterank, ""); filename = 0; title = 0; PA_ResetBgSys(); PA_ResetSpriteSys(); PA_Init3D(); PA_Reset3DSprites(); PA_LoadTiledBg(0, 3, board19); PA_LoadTiledBg(1, 1, bgscoreigs); PA_Init16cBg(1, 0); PA_16cText(1, 120, 10, 255, 192, "chris28ttttt [17k]", 1, 2, 100); // PA_LoadSpritePal(0, 1, (void*)pass_Pal); PA_3DProcess(); // Update sprites PA_WaitForVBL(); if (!ptn) { ptn = new Pointer(); } u16 gfx[6]; gfx[PASSBUTTON] = PA_3DCreateTex((void*)pass_Texture, 64, 32, TEX_256COL); PA_3DCreateSpriteFromTex(PASSBUTTON, gfx[PASSBUTTON], 64, 32, 2, 33, 164); PA_3DProcess(); // Update sprites PA_WaitForVBL(); // while (COND_PLAY_MOVE) { while(!(mode&BOARD_OBSERVE)) { ptn->move(); //add_move(ptn->xpointer, ptn->ypointer); if (mode&BOARD_SCORING) { // if (s->nbvariants) return 1; if (mode&BOARD_PLAYING) { if (!dead[ptn->xpointer][ptn->ypointer]) { char c = 'a'+ptn->xpointer; if (c>='i') c++; char s[10]; // sprintf(s, "%c%d", c, this->size-my); // owner->igs->send(s); } } else { if (0)//(mk == 1) event button remove(ptn->xpointer,ptn->ypointer, cur_board->b[ptn->xpointer][ptn->ypointer], !dead[ptn->xpointer][ptn->ypointer]); else { if (b[ptn->xpointer][ptn->ypointer] == EMPTY) dead[ptn->xpointer][ptn->ypointer] = dead[ptn->xpointer][ptn->ypointer] == 2? 0:2; } // cur_board->dead[mx][my] = !cur_board->dead[mx][my]; // refresh(); // redraw(); update_territory(); } } else if (b[ptn->xpointer][ptn->ypointer] == EMPTY) { if (mode&BOARD_PLAYING) { //IGS char s[10]; char c = 'a'+ptn->xpointer; if (c>='i') c++; //sprintf(s, "%c%d", c, this->size-my); //owner->igs->send(s); } else { // edit mode add_move(ptn->xpointer, ptn->ypointer); // refresh(); update_pos(); } } // sprintf(debug,"player : %d",cur_player); // PA_16cText(1, 10, 30, 255, 192, debug, 1, 2, 100); // refresh(); // update_pos(); } // PA_CreateSprite(0, 1, (void*)pass_Sprite, OBJ_SIZE_64X32, 1, 1, 1, 60); }
/* * Generate all non-capturing, non-promoting, pseudo-legal checks. Used for * quiescent move generation. */ int generate_pseudo_checks(const position_t* pos, move_t* moves) { move_t* moves_head = moves; color_t side = pos->side_to_move, other_side = side^1; square_t king_sq = pos->pieces[other_side][0]; for (int i = 0; i < pos->num_pawns[side]; ++i) { square_t from = pos->pawns[side][i]; square_t to = INVALID_SQUARE; piece_t piece = pos->board[from]; // Figure out whether or not we can discover check by moving. direction_t discover_check_dir = 0; bool will_discover_check; const attack_data_t* king_atk = &get_attack_data(from, king_sq); if ((king_atk->possible_attackers & Q_FLAG) == 0) { discover_check_dir = 0; } else { direction_t king_dir = king_atk->relative_direction; square_t sq; for (sq = from+king_dir; pos->board[sq] == EMPTY; sq+=king_dir) {} if (sq == king_sq) { // Nothing between us and the king. Is there anything // behind us to do the check when we move? for (sq = from-king_dir; pos->board[sq] == EMPTY; sq -= king_dir) {} if (side == piece_color(pos->board[sq]) && (king_atk->possible_attackers & get_piece_flag(pos->board[sq]))) { discover_check_dir = king_dir; } } } // Generate checking moves. will_discover_check = discover_check_dir && abs(discover_check_dir)!=N; to = from + pawn_push[side]; if (pos->board[to] != EMPTY) continue; rank_t r_rank = relative_rank[side][square_rank(from)]; if (r_rank == RANK_7) continue; // non-promotes only for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) { if (will_discover_check || to + *delta == king_sq) { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); break; } } to += pawn_push[side]; if (r_rank == RANK_2 && pos->board[to] == EMPTY) { for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) { if (will_discover_check || to + *delta == king_sq) { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); break; } } } } for (int i = 0; i < pos->num_pieces[side]; ++i) { square_t from = pos->pieces[side][i]; square_t to = INVALID_SQUARE; piece_t piece = pos->board[from]; // Figure out whether or not we can discover check by moving. direction_t discover_check_dir = 0; bool will_discover_check; const attack_data_t* king_atk = &get_attack_data(from, king_sq); if ((king_atk->possible_attackers & Q_FLAG) == 0) { discover_check_dir = 0; } else { direction_t king_dir = king_atk->relative_direction; square_t sq; for (sq = from+king_dir; pos->board[sq] == EMPTY; sq+=king_dir) {} if (sq == king_sq) { // Nothing between us and the king. Is there anything // behind us to do the check when we move? for (sq = from - king_dir; pos->board[sq] == EMPTY; sq -= king_dir) {} if (side == piece_color(pos->board[sq]) && (king_atk->possible_attackers & get_piece_flag(pos->board[sq]))) { discover_check_dir = king_dir; } } } // Generate checking moves. if (piece_is_type(piece, KNIGHT)) { for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) { to = from + *delta; if (pos->board[to] != EMPTY) continue; if (discover_check_dir || possible_attack(to, king_sq, WN)) { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); } } } else { for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) { for (to = from+*delta; pos->board[to] == EMPTY; to+=*delta) { will_discover_check = discover_check_dir && abs(discover_check_dir) != abs(*delta); if (will_discover_check) { moves = add_move(pos, create_move(from, to, piece, NONE), moves); continue; } if (possible_attack(to, king_sq, piece)) { const direction_t to_king = direction(to, king_sq); square_t x = to + to_king; for (; pos->board[x] == EMPTY; x+=to_king) {} if (x == king_sq) { moves = add_move(pos, create_move(from, to, piece, NONE), moves); } } } } } } *moves = 0; return moves-moves_head; }
void get_bishop_moves(char board[BOARD_SIZE][BOARD_SIZE], COLOR player, Pos piece){ Pos curr; curr.col = piece.col + 1; curr.row = piece.row + 1; while (is_valid_pos(curr)){ if (is_valid_dest(board, player, curr) == 1 || is_valid_dest(board, player, curr) == 2) add_move(piece, curr, 0); if (is_valid_dest(board, player, curr) == 0 || is_valid_dest(board, player, curr) == 2) break; curr.col++, curr.row++; } curr.col = piece.col - 1; curr.row = piece.row - 1; while (is_valid_pos(curr)){ if (is_valid_dest(board, player, curr) == 1 || is_valid_dest(board, player, curr) == 2) add_move(piece, curr, 0); if (is_valid_dest(board, player, curr) == 0 || is_valid_dest(board, player, curr) == 2) break; curr.col--, curr.row--; } curr.col = piece.col - 1; curr.row = piece.row + 1; while (is_valid_pos(curr)){ if (is_valid_dest(board, player, curr) == 1 || is_valid_dest(board, player, curr) == 2) add_move(piece, curr, 0); if (is_valid_dest(board, player, curr) == 0 || is_valid_dest(board, player, curr) == 2) break; curr.col--, curr.row++; } curr.col = piece.col + 1; curr.row = piece.row - 1; while (is_valid_pos(curr)){ if (is_valid_dest(board, player, curr) == 1 || is_valid_dest(board, player, curr) == 2) add_move(piece, curr, 0); if (is_valid_dest(board, player, curr) == 0 || is_valid_dest(board, player, curr) == 2) break; curr.col++, curr.row--; } }
/* * Add all pseudo-legal captures that the given piece (N/B/Q/K) can make. */ static void generate_piece_captures(const position_t* pos, square_t from, piece_t piece, move_t** moves_head) { move_t* moves = *moves_head; square_t to; // Note: I unrolled all these loops to handle each direction explicitly. // The idea was to increase performance, but it's only about 1% faster // for much more code, so it's possible I'll change this back later. switch (piece_type(piece)) { case KING: to = from - 17; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from - 16; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from - 15; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from - 1; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 1; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 15; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 16; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 17; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } break; case KNIGHT: to = from - 33; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from - 31; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from - 18; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from - 14; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 14; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 18; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 31; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 33; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } break; case BISHOP: for (to=from-17; pos->board[to]==EMPTY; to-=17) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from-15; pos->board[to]==EMPTY; to-=15) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+15; pos->board[to]==EMPTY; to+=15) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+17; pos->board[to]==EMPTY; to+=17) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } break; case ROOK: for (to=from-16; pos->board[to]==EMPTY; to-=16) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from-1; pos->board[to]==EMPTY; to-=1) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+1; pos->board[to]==EMPTY; to+=1) {} if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+16; pos->board[to]==EMPTY; to+=16) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } break; case QUEEN: for (to=from-17; pos->board[to]==EMPTY; to-=17) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from-16; pos->board[to]==EMPTY; to-=16) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from-15; pos->board[to]==EMPTY; to-=15) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from-1; pos->board[to]==EMPTY; to-=1) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+1; pos->board[to]==EMPTY; to+=1) {} if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+15; pos->board[to]==EMPTY; to+=15) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+16; pos->board[to]==EMPTY; to+=16) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+17; pos->board[to]==EMPTY; to+=17) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } break; default: assert(false); } *moves_head = moves; }
T Hex<T>::getNextBestMove(player_t player) { //First list out all the possible legal moves. //For each move: // Simulate N times to calculate the wins if this move gets selected. std::vector<T> vec_legal_move; populate_legal_move_list(player,vec_legal_move); //dummy initializations T best_move = vec_legal_move[0]; T best_win_count = 0; for (T best_move_i = 0; best_move_i != vec_legal_move.size(); ++best_move_i) { { T row = (vec_legal_move[best_move_i]/size_)+1; //Hex board row is 1-indexed col_t col = vec_legal_move[best_move_i]%size_ + 'A'; MoveType moveType = add_move(row,col,player); assert((moveType == MoveType::Valid) && "move tagged as non valid. check"); } //Now we will run Monte-Carlo assuming we have selected vec_legal_move[best_move_i] for the current player. std::vector<T> vecShuffledMove; vecShuffledMove.reserve(vec_legal_move.size()-1); for (T move_i = 0; move_i != vec_legal_move.size(); ++move_i) { if (move_i != best_move_i) { vecShuffledMove.push_back(vec_legal_move[move_i]); } } //After every simulation we also need to reset the board. //Also reset the vec_legal_move[best_move_i] after completion of monte-carlo simulation for this move. T winCount = 0; player_t otherPlayer = (player == 1) ? 2 : 1; for (T simulation_i = 0; simulation_i != NSimulation; ++simulation_i) { std::random_shuffle(vecShuffledMove.begin(),vecShuffledMove.end()); //iterate over vecShuffledMove and keep assigning the position to the two players alternatively. for (std::vector<T>::iterator it = vecShuffledMove.begin(); it != vecShuffledMove.end(); ++it) { T pos = (*it); T row = (pos/size_)+1; //Hex board row is 1-indexed col_t col = pos%size_ + 'A'; player_t curMovePlayer = (std::distance(vecShuffledMove.begin(),it)%2 == 0) ? otherPlayer : player; MoveType moveType = add_move(row,col,curMovePlayer); assert((moveType == MoveType::Valid) && "move tagged as non valid. check"); } //Now board has been filled up. //check the winner of this simulation. bool flagSuccessCurPlayer = is_winning_move(player); if (flagSuccessCurPlayer) { ++winCount; } //checking individually for both players is for debugging only bool flagSuccessOtherPlayer = is_winning_move(otherPlayer); assert((flagSuccessCurPlayer != flagSuccessOtherPlayer) && "One and only one must win"); //Now empty all the positions of the hex board that were filled up in this simulation. for (std::vector<T>::iterator it = vecShuffledMove.begin(); it != vecShuffledMove.end(); ++it) { T pos = (*it); T row = (pos/size_)+1; //Hex board row is 1-indexed col_t col = pos%size_ + 'A'; delete_move(row,col); } } if (best_win_count < winCount) { best_win_count = winCount; best_move = vec_legal_move[best_move_i]; } //Now remove the move which we considered as possible best move in this iteration. { T row = vec_legal_move[best_move_i]/size_ + 1; col_t col = vec_legal_move[best_move_i]%size_ + 'A'; delete_move(row,col); } } return best_move; }
/* * Generate all moves that evade check in the given position. This is purely * legal move generation; no pseudo-legal moves. */ int generate_evasions(const position_t* pos, move_t* moves) { assert(pos->is_check && pos->board[pos->check_square]); move_t* moves_head = moves; color_t side = pos->side_to_move, other_side = side^1; square_t king_sq = pos->pieces[side][0]; square_t check_sq = pos->check_square; piece_t king = create_piece(side, KING); piece_t checker = pos->board[check_sq]; // Generate king moves. // Don't let the king mask its possible destination squares in calls // to is_square_attacked. square_t from = king_sq, to = INVALID_SQUARE; ((position_t*)pos)->board[king_sq] = EMPTY; for (const direction_t* delta = piece_deltas[king]; *delta; ++delta) { to = from + *delta; piece_t capture = pos->board[to]; if (capture != EMPTY && !can_capture(king, capture)) continue; if (is_square_attacked((position_t*)pos,to,other_side)) continue; ((position_t*)pos)->board[king_sq] = king; moves = add_move(pos, create_move(from, to, king, capture), moves); ((position_t*)pos)->board[king_sq] = EMPTY; } ((position_t*)pos)->board[king_sq] = king; // If there are multiple checkers, only king moves are possible. if (pos->is_check > 1) { *moves = 0; return moves-moves_head; } // First, the most common case: a check that can be evaded via an // en passant capture. Note that if we're in check and an en passant // capture is available, the only way the en passant capture would evade // the check is if it's the newly moved pawn that's checking us. direction_t pin_dir; if (pos->ep_square != EMPTY && check_sq+pawn_push[side] == pos->ep_square && pos->board[pos->ep_square] == EMPTY) { piece_t our_pawn = create_piece(side, PAWN); to = pos->ep_square; for (int i=0; i<2; ++i) { from = to-piece_deltas[our_pawn][i]; if (pos->board[from] && pos->board[from] == our_pawn) { pin_dir = pin_direction(pos, from, king_sq); if (pin_dir) continue; moves = add_move(pos, create_move_enpassant(from, to, our_pawn, checker), moves); } } } // Generate captures of the checker. for (int i = 0; i < pos->num_pawns[side]; ++i) { from = pos->pawns[side][i]; piece_t piece = create_piece(side, PAWN); pin_dir = pin_direction(pos, from, king_sq); if (pin_dir) continue; if (!possible_attack(from, check_sq, piece)) continue; if (relative_rank[side][square_rank(from)] == RANK_7) { // Capture and promote. for (piece_t promoted=QUEEN; promoted > PAWN; --promoted) { moves = add_move(pos, create_move_promote(from, check_sq, piece, checker, promoted), moves); } } else { moves = add_move(pos, create_move(from, check_sq, piece, checker), moves); } } for (int i = 1; i < pos->num_pieces[side]; ++i) { from = pos->pieces[side][i]; piece_t piece = pos->board[from]; pin_dir = pin_direction(pos, from, king_sq); if (pin_dir) continue; if (!possible_attack(from, check_sq, piece)) continue; if (piece_slide_type(piece) == NONE) { moves = add_move(pos, create_move(from, check_sq, piece, checker), moves); } else { // A sliding piece, keep going until we hit something. direction_t check_dir = direction(from, check_sq); for (to=from+check_dir; pos->board[to] == EMPTY; to+=check_dir) {} if (to == check_sq) { moves = add_move(pos, create_move(from, to, piece, checker), moves); continue; } } } if (piece_slide_type(checker) == NONE) { *moves = 0; return moves-moves_head; } // A slider is doing the checking; generate blocking moves. direction_t block_dir = direction(check_sq, king_sq); for (int i = 0; i < pos->num_pawns[side]; ++i) { from = pos->pawns[side][i]; piece_t piece = create_piece(side, PAWN); direction_t k_dir; pin_dir = pin_direction(pos, from, king_sq); if (pin_dir) continue; to = from + pawn_push[side]; if (pos->board[to] != EMPTY) continue; rank_t rank = relative_rank[side][square_rank(from)]; k_dir = direction(to, king_sq); if (k_dir == block_dir && ((king_sq < to && check_sq > to) || (king_sq > to && check_sq < to))) { if (rank == RANK_7) { // Block and promote. for (piece_t promoted=QUEEN; promoted > PAWN; --promoted) { moves = add_move(pos, create_move_promote(from, to, piece, EMPTY, promoted), moves); } } else { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); } } if (rank != RANK_2) continue; to += pawn_push[side]; if (pos->board[to]) continue; k_dir = direction(to, king_sq); if (k_dir == block_dir && ((king_sq < to && check_sq > to) || (king_sq > to && check_sq < to))) { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); } } for (int i=1; i<pos->num_pieces[side]; ++i) { from = pos->pieces[side][i]; piece_t piece = pos->board[from]; direction_t k_dir; pin_dir = pin_direction(pos, from, king_sq); if (pin_dir) continue; if (piece_is_type(piece, KNIGHT)) { for (const direction_t* delta=piece_deltas[piece]; *delta; ++delta) { to = from + *delta; if (pos->board[to] != EMPTY) continue; k_dir = direction(to, king_sq); if (k_dir == block_dir && ((king_sq < to && check_sq > to) || (king_sq > to && check_sq < to))) { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); } } } else { for (const direction_t* delta=piece_deltas[piece]; *delta; ++delta) { for (to = from+*delta; pos->board[to] == EMPTY; to+=*delta) { k_dir = direction(to, king_sq); if (k_dir == block_dir && ((king_sq < to && check_sq > to) || (king_sq > to && check_sq < to))) { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); break; } } } } } *moves = 0; return moves-moves_head; }