void test_board_san() { puts("test_board_san"); board_t pos; char san[LEN_SAN]; // Double pawn move. board_reset(&pos); board_san(&pos, move_make(SQ_H2, SQ_H4, kNone), san); assert(strcmp(san, "h4") == 0); // Promotion. assert(board_set_fen(&pos, "4k3/8/8/8/8/8/6p1/4K3 b - - 0 1")); board_san(&pos, move_make(SQ_G2, SQ_G1, kRook), san); assert(strcmp(san, "g1=R+") == 0); // Not ambiguous because of pin. assert(board_set_fen(&pos, "4k3/8/8/b7/8/2N3N1/8/4K3 w - - 0 1")); board_san(&pos, move_make(SQ_G3, SQ_E4, 0), san); puts(san); assert(strcmp(san, "Ne4") == 0); // Ambiguous. board_remove_piece_at(&pos, SQ_A5); board_san(&pos, move_make(SQ_G3, SQ_E4, 0), san); assert(strcmp(san, "Nge4") == 0); }
void test_pawn_divide(int depth) { int i,move_count; move_t ms[MOVE_STACK]; uint64 nodes = 0; uint64 total_nodes = 0; int legal_moves = 0; if(!depth) return; pawnhits = 0; pawncollisions = 0; pht_init(); depth -= 1; timer_start(); move_count = move_gen(&ms[0]); for(i = 0; i < move_count; i++) { if(!move_make(ms[i])) continue; nodes = perft(depth); print_move(ms[i].p); legal_moves++; printf("%I64u",nodes); printf("\n"); move_undo(); total_nodes += nodes; } printf("\nNodes: %I64u",total_nodes); printf("\nMoves: %d",legal_moves); printf("\nPawnHits: %d",pawnhits); printf("\nPawnCollisions: %d",pawncollisions); printf("\n\n"); timer_stop(); pht_free(); }
MOVE ConvertTextInputToMove (STRING input) { int theInput = atoi(input); int from = theInput/10; int to = theInput%10; return ((MOVE) move_make(from, to)); }
void test_board_parse_san() { puts("test_board_parse_san"); board_t pos; move_t move; board_reset(&pos); assert(board_parse_san(&pos, "e4", &move)); assert(move == move_make(SQ_E2, SQ_E4, 0)); assert(board_set_fen(&pos, "r1bqkb1r/pppp1ppp/2n2n2/4p3/2B1P3/2N2N2/PPPP1PPP/R1BQK2R b KQkq - 5 4")); assert(board_parse_san(&pos, "Nxe4", &move)); assert(move == move_make(SQ_F6, SQ_E4, 0)); assert(board_set_fen(&pos, "r3r2R/pppb1kP1/n2p4/3Pp3/2P1P3/2N1K3/PP3P2/6R1 w - - 3 23")); assert(board_parse_san(&pos, "g8=Q+", &move)); assert(move == move_make(SQ_G7, SQ_G8, kQueen)); }
void test_board_evasive_capture() { puts("test_board_evasive_capture"); board_t pos; assert(board_set_fen(&pos, "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P1RPP/R2Q2K1 b af - 1 1")); board_move(&pos, move_make(SQ_B6, SQ_F2, 0)); move_t moves[255]; move_t *end = board_legal_moves(&pos, moves, BB_ALL, BB_ALL); assert(end - moves == 3); }
void test_divide(int depth) { int i,move_count; move_t ms[MOVE_STACK]; uint64 nodes; uint64 total_nodes; int legal_moves; #ifdef EVASIONS char strbuff[256]; move_t ms_test[MOVE_STACK]; #endif if(!depth) return; nodes = 0; total_nodes = 0; legal_moves = 0; pht_init(); depth -= 1; timer_start(); #ifdef EVASIONS if(is_in_check(board->side)) { move_count = move_gen_evasions(&ms[0]); if(move_count != move_gen_legal(&ms_test[0])) { board_to_fen(&strbuff[0]); printf("error: \n %s \n",strbuff); } } else { move_count = move_gen(&ms[0]); } #else move_count = move_gen(&ms[0]); #endif for(i = 0; i < move_count; i++) { if(!move_make(ms[i])) continue; nodes = perft(depth); print_move(ms[i].p); legal_moves++; printf("%I64u",nodes); printf("\n"); move_undo(); total_nodes += nodes; } printf("\nNodes: %I64u",total_nodes); printf("\nMoves: %d",legal_moves); printf("\n\n"); timer_stop(); pht_free(); }
void test_board_pin() { puts("test_board_pin"); board_t pos; assert(board_set_fen(&pos, "4k3/8/8/b7/8/2N3N1/8/4K3 w - - 0 1")); move_t moves[255]; move_t *end = board_legal_moves(&pos, moves, BB_ALL, BB_ALL); bool found_Nge4 = false, found_Nce4 = false; for (move_t *current = moves; current < end; current++) { char san[LEN_SAN], uci[LEN_UCI]; move_uci(*current, uci); board_san(&pos, *current, san); printf("- %s %s\n", uci, san); if (*current == move_make(SQ_C3, SQ_E4, kNone)) found_Nce4 = true; if (*current == move_make(SQ_G3, SQ_E4, kNone)) found_Nge4 = true; } assert(found_Nge4); assert(!found_Nce4); }
void test_board_pseudo_legal_ep() { puts("test_board_pseudo_legal_ep"); struct board pos; assert(board_set_fen(&pos, "4k3/8/8/8/4Pp2/8/8/4K3 b - e3 0 1")); move_t ep = move_make(SQ_F4, SQ_E3, 0); move_t moves[255]; move_t *end = board_pseudo_legal_moves(&pos, moves, BB_ALL, BB_ALL); bool found = false; for (move_t *current = moves; current < end; current++) { if (*current == ep) found = true; char uci[6]; move_uci(*current, uci); puts(uci); } assert(found); }
void test_legal_promotion() { puts("test_legal_promotion"); board_t pos; assert(board_set_fen(&pos, "4k3/1P6/8/8/8/8/8/4K3 w - - 0 1")); move_t moves[255]; move_t *end = board_legal_moves(&pos, moves, BB_ALL, BB_ALL); move_t needle = move_make(SQ_B7, SQ_B8, kQueen); bool found = false; bool found_uci = false; for (move_t *current = moves; current < end; current++) { if (*current == needle) found = true; char uci[6]; move_uci(*current, uci); if (strcmp(uci, "b7b8q") == 0) found_uci = true; puts(uci); } assert(found); assert(found_uci); }
static int move_from_lan(const char string[], const board_t * board) { int len; int move; int promote; char s[256]; int from, to; int colour; int inc; int piece_char; int n; const uint8 * ptr; int piece; int side; ASSERT(string!=NULL); ASSERT(board_is_ok(board)); // init len = strlen(string); if (len != 7) return MoveNone; move = MoveNone; colour = board->turn; // promote promote = 0; switch (string[6]) { case '?': // not a promotion break; case 'N': promote = MovePromoteKnight; break; case 'B': promote = MovePromoteBishop; break; case 'R': promote = MovePromoteRook; break; case 'Q': promote = MovePromoteQueen; break; default: return MoveNone; break; } // to square s[0] = string[4]; s[1] = string[5]; s[2] = '\0'; to = square_from_string(s); if (to == SquareNone) return MoveNone; // known from square? if (string[1] != '?' && string[2] != '?') { // from square s[0] = string[1]; s[1] = string[2]; s[2] = '\0'; from = square_from_string(s); if (from == SquareNone) return MoveNone; // convert "king slide" castling to KxR if (piece_is_king(board->square[from]) && square_rank(to) == square_rank(from) && abs(to-from) > 1) { side = (to > from) ? SideH : SideA; to = board->castle[colour][side]; if (to == SquareNone) return MoveNone; } // move move = move_make(from,to) | promote; return move; } // pawn non-capture? if (string[0] == '?' && string[1] == '?') { if (board->square[to] != Empty) return MoveNone; // useful? inc = (colour_is_white(colour)) ? +16 : -16; from = to - inc; if (board->square[from] == Empty && square_side_rank(to,colour) == Rank4) { from -= inc; } if (board->square[from] != piece_make_pawn(colour)) { // useful? return MoveNone; } // move move = move_make(from,to) | promote; return move; } // pawn capture? piece_char = string[0]; if (piece_char == '?' && string[1] != '?') { piece_char = 'P'; } // attack loop n = 0; for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) { piece = board->square[from]; if (toupper(piece_to_char(piece)) == piece_char) { if (piece_attack(board,piece,from,to)) { if (true && (string[1] == '?' || file_to_char(square_file(from)) == string[1]) && (string[2] == '?' || rank_to_char(square_rank(from)) == string[2])) { if (!is_pinned(board,from,to,colour)) { move = move_make(from,to) | promote; n++; } } } } } if (n != 1) move = MoveNone; return move; }
int qsearch(s_search_info *info, s_stack *stack, s_board *board, int alpha, int beta) { assert(info != NULL); assert(stack != NULL); assert(board != NULL); assert(alpha < beta); int stand_pat = evaluate(board); if(stack->ply > info->seldepth) { info->seldepth = stack->ply-1; } if(stand_pat >= beta) { return beta; } #ifdef DELTA_PRUNING const int safety = 900; // The value of a queen if(stand_pat < alpha - safety && !is_endgame(board)) { return alpha; } #endif if(stand_pat > alpha) { alpha = stand_pat; } if(stack->ply >= MAX_DEPTH) { return stand_pat; } // Set old permissions s_irreversible permissions; store_irreversible(&permissions, board); s_move moves[MAX_MOVES]; int num_moves = find_moves_captures(board, moves, board->turn); #ifdef SORT_MOVES moves_sort_see(board, moves, num_moves); #endif for(int m = 0; m < num_moves; ++m) { int val = see_capture(board, moves[m]); if(val < -50) { break; } move_make(board, &moves[m]); if(square_attacked(board, board->pieces[KINGS]&board->colour[!board->turn], board->turn)) { // Restore old permissions restore_irreversible(&permissions, board); move_undo(board, &moves[m]); continue; } info->nodes++; int score = -qsearch(info, stack+1, board, -beta, -alpha); // Restore old permissions restore_irreversible(&permissions, board); move_undo(board, &moves[m]); if(score >= beta) { #ifndef NDEBUG info->num_cutoffs[m]++; #endif return beta; } if(score > alpha) { alpha = score; } } return alpha; }
uint64 perft(int depth) { int i,move_count; move_t ms[MOVE_STACK]; uint64 nodes; uint64 val; #ifdef EVASIONS char strbuff[256]; move_t ms_test[MOVE_STACK]; #endif #ifdef BITS bitboard_t bb; #endif if(depth == 0) return 1; if((val = probe_hash(depth)) != 0) return val; nodes = 0; val = 0; #ifdef BITS bb = 0; for(i = PLS(WP); i <= H8; i = PLN(i)) bitset(&bb, rsz[i]); if(bb != board->bb_pawns[W]) printf("pawn_error\n"); bb = 0; for(i = PLS(BP); i <= H8; i = PLN(i)) bitset(&bb, rsz[i]); if(bb != board->bb_pawns[B]) printf("pawn_error\n"); #endif #ifdef EVASIONS if(is_in_check(board->side)) { move_count = move_gen_evasions(&ms[0]); if(move_count != move_gen_legal(&ms_test[0])) { board_to_fen(&strbuff[0]); printf("error: \n %s \n",strbuff); } } else { move_count = move_gen(&ms[0]); } #else move_count = move_gen(&ms[0]); #endif for(i = 0; i < move_count; i++) { if(!move_make(ms[i])) continue; if(depth == 1) nodes++; else nodes += perft(depth - 1); move_undo(); } record_hash(depth,nodes); return (nodes); }