#include <stdlib.h> #include <string.h> #include <stdbool.h> #include <assert.h> #include "pony.h" #include "u64.h" #include "bitgeo.h" #include "board.h" #include "utils.h" #include "pawn.h" #ifndef RELEASE //#define PAWN_DETAILS #endif enum { castle_own_3th = 10, castle_own_4th = 20, castle_own_nopawn = 25, castle_opp_5th = 5, castle_opp_4th = 10, castle_opp_3th = 15, castle_opp_nopawn = 20, castle_front_semi = 10, castle_front_open = 15, info_count = _32Mb / sizeof(pawn_info_t) }; int opn_pawn_pst[2][64] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 16, 16, 6, 4, 2, 4, 6, 8, 18, 18, 8, 6, 4, 6, 8, 10, 20, 20, 10, 8, 6, 4, 6, 8, 10, 10, 8, 6, 4, 2, 4, 6, 8, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0 } }; static int opn_promo[2][64] = { { 0, 0, 0, 0, 0, 0, 0, 0, 55, 60, 60, 60, 60, 60, 60, 55, 45, 50, 50, 50, 50, 50, 50, 45, 35, 40, 40, 40, 40, 40, 40, 35, 25, 30, 30, 30, 30, 30, 30, 25, 15, 20, 20, 20, 20, 20, 20, 15, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0 } }; static int end_promo[2][64] = { { 0, 0, 0, 0, 0, 0, 0, 0, 110, 120, 120, 120, 120, 120, 120, 110, 90, 100, 100, 100, 100, 100, 100, 90, 70, 80, 80, 80, 80, 80, 80, 70, 50, 60, 60, 60, 60, 60, 60, 50, 30, 40, 40, 40, 40, 40, 40, 30, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0 } }; static int opn_doubled[8] = { 8, 10, 10, 10, 10, 10, 10, 8 }; // by file static int end_doubled[8] = { 10, 12, 12, 12, 12, 12, 12, 10 }; static int opn_isolated[8] = { 8, 10, 12, 12, 12, 12, 10, 8 }; static int end_isolated[8] = { 8, 10, 10, 10, 10, 10, 10, 8 }; static int opn_backward[8] = { 8, 10, 12, 12, 12, 12, 10, 8 }; static int end_backward[8] = { 10, 12, 12, 12, 12, 12, 12, 10 }; static int opn_chain[8] = { 6, 8, 8, 10, 10, 8, 8, 6 }; static int opn_candidate[8] = { 0, 5, 5, 10, 15, 20, 0, 0 }; // by rank static int end_candidate[8] = { 0, 10, 10, 20, 30, 40, 0, 0 }; static pawn_info_t pawn_info[info_count] = { 0 }; u32 hash_pawn[2][64] = { 0 }; bool is_pawn_init = false; //------------------------------------------------------------------------- void pawn_init(void) { assert(is_u64_init); assert(is_bitgeo_init); if (is_pawn_init) return; memset(&pawn_info, 0, sizeof(pawn_info)); pawn_info[0].uid = -1; // hack init int i; u32 *p = (u32*)hash_pawn; for (i = 0; i < (sizeof(hash_pawn) / sizeof(u32)); ++i) *p++ = rand32(); for (i = 0; i < 64; ++i) opn_pawn_pst[white][idx2sq(i)] = opn_pawn_pst[black][i]; for (i = 0; i < 64; ++i) opn_pawn_pst[black][sq_flip_horz(i)] = opn_pawn_pst[white][i]; for (i = 0; i < 64; ++i) opn_promo[white][idx2sq(i)] = opn_promo[black][i]; for (i = 0; i < 64; ++i) opn_promo[black][sq_flip_horz(i)] = opn_promo[white][i]; for (i = 0; i < 64; ++i) end_promo[white][idx2sq(i)] = end_promo[black][i]; for (i = 0; i < 64; ++i) end_promo[black][sq_flip_horz(i)] = end_promo[white][i]; is_pawn_init = true; } void pawn_info_clear(void) { assert(is_pawn_init); memset(&pawn_info, 0, sizeof(pawn_info)); pawn_info[0].uid = -1; } //------------------------------------------------------------------------- #ifdef PAWN_DETAILS static int save_opn[2] = { 0, 0 }, save_end[2] = { 0, 0 }; static void save_vars(int opn[2], int end[2]) { save_opn[white] = opn[white]; save_end[white] = end[white]; save_opn[black] = opn[black]; save_end[black] = end[black]; } static void show_diff(int sq, int opn[2], int end[2]) { outf( "%s\n" "diff after %s %s:\n\n" "opn_score[white]: %+d\n" "end_score[white]: %+d\n" "opn_score[black]: %+d\n" "end_score[black]: %+d\n\n" "result:\n\n" "opn_score[white]: %d\n" "end_score[white]: %d\n" "opn_score[black]: %d\n" "end_score[black]: %d\n\n", brd_deskdump(), piece_is_white(board.desk[sq]) ? "white" : "black", sq_dump(sq), opn[white] - save_opn[white], end[white] - save_end[white], opn[black] - save_opn[black], end[black] - save_end[black], opn[white], end[white], opn[black], end[black] ); save_vars(opn, end); } #endif pawn_info_t *pawn_get_info(void) { assert(is_board_init); assert(is_pawn_init); pawn_info_t *p = &pawn_info[board.props.pawn_key % info_count]; if (p->uid == board.props.pawn_key) return p; memset(p, 0, sizeof(*p)); // zeroinit p->uid = board.props.pawn_key; // let's go int sq, file, rank, weight, opn_score[2] = { 0, 0 }, end_score[2] = { 0, 0 }; bool is_semiopen[2][8]; // beg init memset(&p->is_openfile, true, sizeof(p->is_openfile)); memset(&is_semiopen, true, sizeof(is_semiopen)); memset(&p->barrier_opp[white][0], rank_8, sizeof(p->barrier_opp[white])); // absence memset(&p->barrier_own[black][0], rank_8, sizeof(p->barrier_own[black])); // barrier_own[white] == rank_1 && barrier_opp[black] == rank_1, owing to zeroinit #ifdef PAWN_DETAILS outf("-= start log =-\n\n"), save_vars(opn_score, end_score); #endif // main cycle for (int a_color = white, b_color = black; a_color >= black; --a_color, ++b_color) { u64 set, a_pawns, b_pawns; if (set = a_pawns = board.items[pawn | a_color]) { b_pawns = board.items[pawn | b_color]; p->on_start[a_color] = (set & (a_color ? u64_rank_2 : u64_rank_7)) != 0; p->captures[a_color] = a_color ? geo_shift_lup(a_pawns) | geo_shift_rup(a_pawns) : geo_shift_ldown(a_pawns) | geo_shift_rdown(a_pawns); } while (set) { sq = rbit_cut_sq(&set); file = sq_file(sq), rank = sq_rank(sq); opn_score[a_color] += opn_pawn_pst[a_color][sq]; // mid set p->is_openfile[file] = is_semiopen[a_color][file] = false; if (a_color == white) { if (rank > p->barrier_own[white][file]) p->barrier_own[white][file] = rank; if (rank > p->barrier_opp[black][file]) p->barrier_opp[black][file] = rank; } else { if (rank < p->barrier_own[black][file]) p->barrier_own[black][file] = rank; if (rank < p->barrier_opp[white][file]) p->barrier_opp[white][file] = rank; } // pawn props bool is_front_dbl = (geo_ray[sq][a_color ? dir_down : dir_up] & a_pawns) != 0; bool is_back_dbl = (geo_ray[sq][a_color ? dir_up : dir_down] & a_pawns) != 0; bool is_promo = !is_back_dbl && (geo_pawn_road[a_color][sq] & b_pawns) == 0; bool is_isolated = !is_promo && (geo_neighbour_files[file] & a_pawns) == 0; bool in_chain = !is_isolated && (geo_pawn_support[a_color][sq] & a_pawns) != 0; bool on_free_dir = (geo_ray[sq][a_color ? dir_up : dir_down] & b_pawns) == 0; bool is_backward = false; if (!is_promo && !is_isolated && !in_chain) if ((atk_fork[a_color][sq] & b_pawns) == 0) if ((geo_pawn_scratch[b_color][sq] & a_pawns) == 0) { u64 hold = geo_pawn_scratch[a_color][sq] & (a_pawns | b_pawns); int horz = sq_rank(a_color ? rbit2sq(hold) : lbit2sq(hold)); hold = geo_rank[horz] | geo_rank[horz + (a_color ? 1 : -1)]; is_backward = (hold & b_pawns) != 0; } bool is_candidate = false; if (!is_back_dbl && !is_promo && !is_isolated && !is_backward && on_free_dir) { int hold = bit_count(geo_pawn_scratch[a_color][sq] & b_pawns); if (hold > 0) hold -= bit_count(geo_pawn_scratch[b_color][sq + (a_color ? 8 : -8)] & a_pawns); is_candidate = hold <= 0; } // pawn bonus and penalty if (is_promo) { opn_score[a_color] += opn_promo[a_color][sq]; end_score[a_color] += end_promo[a_color][sq]; } if (is_candidate) { opn_score[a_color] += opn_candidate[rank]; end_score[a_color] += end_candidate[rank]; } if (in_chain) opn_score[a_color] += opn_chain[file]; if (is_back_dbl) { opn_score[a_color] -= opn_doubled[file]; end_score[a_color] -= end_doubled[file]; } if (is_isolated) { opn_score[a_color] -= opn_isolated[file]; end_score[a_color] -= end_isolated[file]; if (on_free_dir) { opn_score[a_color] -= opn_isolated[file] / 2; end_score[a_color] -= end_isolated[file] / 2; } } if (is_backward) { opn_score[a_color] -= opn_backward[file]; end_score[a_color] -= end_backward[file]; if (on_free_dir) { opn_score[a_color] -= opn_backward[file] / 2; end_score[a_color] -= end_backward[file] / 2; } } // safety of own castling if (!is_front_dbl) if (a_color ? rank == rank_3 : rank == rank_6) { if (file < file_d) p->qside_castle[a_color] -= castle_own_3th; else if (file == file_f) { p->kfront_castle[a_color] -= castle_front_open; p->kside_castle[a_color] -= castle_own_4th; } else if (file > file_f) p->kside_castle[a_color] -= castle_own_3th; } else if (a_color ? rank != rank_2 : rank != rank_7) { if (file < file_d) p->qside_castle[a_color] -= castle_own_4th; else if (file == file_f) { p->kfront_castle[a_color] -= castle_front_open; p->kside_castle[a_color] -= castle_own_4th; } else if (file > file_f) p->kside_castle[a_color] -= castle_own_4th; } // danger for opp castling if (!is_back_dbl) if (a_color ? rank == rank_4 : rank == rank_5) { if (file < file_d) p->qside_castle[b_color] -= castle_opp_5th; else if (file > file_e) p->kside_castle[b_color] -= castle_opp_5th; } else if (a_color ? rank == rank_5 : rank == rank_4) { if (file < file_d) p->qside_castle[b_color] -= castle_opp_4th; else if (file > file_e) p->kside_castle[b_color] -= castle_opp_4th; } else if (a_color ? rank >= rank_6 : rank <= rank_3) { if (file < file_d) p->qside_castle[b_color] -= castle_opp_3th; else if (file > file_e) p->kside_castle[b_color] -= castle_opp_3th; } #ifdef PAWN_DETAILS show_diff(sq, opn_score, end_score); #endif } } #ifdef PAWN_DETAILS outf("-= stop log =-\n\n"); #endif // fin fix for (file = file_a; file <= file_h; ++file) { if (p->is_openfile[file]) is_semiopen[white][file] = is_semiopen[black][file] = false; if (!is_semiopen[white][file]) p->barrier_opp[white][file] = rank_1; // double sense if (!is_semiopen[black][file]) p->barrier_opp[black][file] = rank_8; // fix safety of castling for (int a_color = white, b_color = black; a_color >= black; --a_color, ++b_color) { if (file == file_c || file == file_d || file == file_e) // qfront { if (p->is_openfile[file]) p->qfront_castle[a_color] -= castle_front_open; else if (is_semiopen[a_color][file]) p->qfront_castle[a_color] -= castle_front_semi; } if (file == file_d || file == file_e || file == file_f) // kfront { if (p->is_openfile[file]) p->kfront_castle[a_color] -= castle_front_open; else if (is_semiopen[a_color][file]) p->kfront_castle[a_color] -= castle_front_semi; } if (file < file_d) // qside { if (p->is_openfile[file] || is_semiopen[a_color][file]) { p->qside_castle[a_color] -= castle_own_nopawn; p->qside_castle[b_color] -= castle_opp_nopawn; } } else if (file > file_e) // kside { if (p->is_openfile[file] || is_semiopen[a_color][file]) { p->kside_castle[a_color] -= castle_own_nopawn; p->kside_castle[b_color] -= castle_opp_nopawn; } } } } // result p->opn_score = opn_score[white] - opn_score[black]; p->end_score = end_score[white] - end_score[black]; return p; } //------------------------------------------------------------------------- #ifndef RELEASE static void show_info(void) { pawn_info_t *p = pawn_get_info(); dbg_show_board(); outf( "pawns for white:\n" "opn_score: %d\n" "end_score: %d\n\n", p->opn_score, p->end_score ); outf("on_start[white]: %s\n", p->on_start[white] ? "true" : "false"); outf("on_start[black]: %s\n\n", p->on_start[black] ? "true" : "false"); int i; outf("is_openfile:\n"); for (i = 0; i < 8; ++i) if (p->is_openfile[i]) outf("%c ", 'a' + i); outf("\n\n"); outf("barrier_own[white]:\n"); for (i = 0; i < 8; ++i) if (p->barrier_own[white][i] > rank_1) outf("%c%c ", 'a' + i, '1' + p->barrier_own[white][i]); outf("\n\n"); outf("barrier_opp[white]:\n"); for (i = 0; i < 8; ++i) if (p->barrier_opp[white][i] > rank_1) outf("%c%c ", 'a' + i, '1' + p->barrier_opp[white][i]); outf("\n\n"); outf("barrier_own[black]:\n"); for (i = 0; i < 8; ++i) if (p->barrier_own[black][i] < rank_8) outf("%c%c ", 'a' + i, '1' + p->barrier_own[black][i]); outf("\n\n"); outf("barrier_opp[black]:\n"); for (i = 0; i < 8; ++i) if (p->barrier_opp[black][i] < rank_8) outf("%c%c ", 'a' + i, '1' + p->barrier_opp[black][i]); outf("\n\n"); outf( "qside_castle[white]: %d\n" "qside_castle[black]: %d\n" "kside_castle[white]: %d\n" "kside_castle[black]: %d\n" "qfront_castle[white]: %d\n" "qfront_castle[black]: %d\n" "kfront_castle[white]: %d\n" "kfront_castle[black]: %d\n\n", p->qside_castle[white], p->qside_castle[black], p->kside_castle[white], p->kside_castle[black], p->qfront_castle[white], p->qfront_castle[black], p->kfront_castle[white], p->kfront_castle[black] ); outf("bpawns\n%s\n", dbg_bitdump(board.items[bpawn])); outf("captures[black]\n%s\n", dbg_bitdump(p->captures[black])); outf("wpawns\n%s\n", dbg_bitdump(board.items[wpawn])); outf("captures[white]\n%s\n", dbg_bitdump(p->captures[white])); } void dbg_pawn_main(void) { assert(is_pawn_init); assert(is_board_init); // char *fen = "rnbqkb1r/5ppp/p3pn2/1p6/3P4/3B1N2/PP2QPPP/RNB2RK1 b kq - 0 9"; // isolator // char *fen = "r1r3k1/pp2ppbp/3pbnp1/q7/3BP3/1BN2P2/PPPQ2PP/2KR3R w - - 5 12"; // gragon // char *fen = "r2qrnk1/pp1b1ppp/3b1n2/3pp3/8/1P1P1NP1/PBRNPPBP/3Q1RK1 w - - 2 2"; // Q+B // char *fen = "7k/3Q4/8/8/4K3/8/8/8 w - - 0 1"; // KQk // char *fen = "rnb1k1nr/pp3ppp/8/3Q4/5q2/5N2/PP2PKPP/RN3B1R b kq - 1 9"; // char *fen = "7k/P7/8/8/4K3/8/8/8 w - - 0 1"; // KPk // char *fen = "rnbqkbnr/pp3ppp/4p3/2ppP3/3P4/2P5/PP3PPP/RNBQKBNR b KQkq - 0 4"; char *fen = "6k1/4n1p1/1p1qb2p/p4p2/2P1p3/1P2Q3/PN3PPP/1B4K1 w - - 1 33"; brd_fen_setup(fen); show_info(); exit(0); } #endif
|