// Compute the amount of time to spend on the next move // Some parameters might be -1 if they do not apply int time_use(board *b, int time_left, int increment, int movestogo) { if (time_left <= 0) return 100; // Oops! // Algorithm for remaining move estimation based on: // http://facta.junis.ni.ac.rs/acar/acar200901/acar2009-07.pdf // Slightly more aggresive time managment because of overhead after search // Calculate the total value of material int mat_value = 0; for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { if (p_eq(b->b[i][j], no_piece)) continue; switch(b->b[i][j].type) { case 'P': mat_value += 1; break; case 'N': mat_value += 3; break; case 'B': mat_value += 3; break; case 'R': mat_value += 5; break; case 'Q': mat_value += 9; break; default: ; } } } // Assume the game is 70 moves long, but never use more than 1/10th of the remaining time int half_moves_left_guess; if (mat_value < 20) half_moves_left_guess = mat_value + 10; else if (mat_value <= 60) half_moves_left_guess = (mat_value * 3 + 176) / 8; else half_moves_left_guess = (mat_value * 5 - 120) / 4; half_moves_left_guess += 6; // Adjustment for search invocation overhead int our_moves_left_guess = max(5, (half_moves_left_guess / 2)); return time_left/our_moves_left_guess; }
/* Pair : row,column */ int lee_algo(Pair* source, Pair* target){ int i, j, v1, v2; Pair p, v, step[4] = {{1,0},{0,1},{-1,0},{0,-1}}; /* initialize all cells like unvisited */ for(i=0; i<sz.r; ++i){ for(j=0; j<sz.c; ++j){ W[i][j] = -1; } } q_clear(); p_set(W,source,0); q_push(source); while(!q_empty()){ p = q_pop(); for(i=0; i<4; ++i){ v = p_sum(step+i,&p); v1 = p_get(Z,&p); v2 = p_get(Z,&v); #ifdef DEBUG printf("try: %d,%d\n",v.r,v.c); #endif if(p_in(&v) && p_get(W,&v)==-1 && (v1-v2 <= 3) && (v1-v2 >= -1) && can_go(&v)){ #ifdef DEBUG printf("from: %d,%d go: %d,%d\n",p.r,p.c,v.r,v.c); #endif p_set(W,&v,p_get(W,&p)+1); q_push(&v); if(p_eq(&v,target)) break; } } if(p_eq(&v,target)) break; } #ifdef DEBUG printf("q: %d\n",q_empty()); #endif return p_get(W,target); }
int hadlock_algo(Pair* source, Pair* target){ int i, j, v1, v2, res; Pair p, v, step[4] = {{1,0},{0,1},{-1,0},{0,-1}}; /* initialize all cells like unvisited */ for(i=0; i<sz.r; ++i){ for(j=0; j<sz.c; ++j){ W[i][j] = -1; } } q_clear(); p_set(W,source,0); q_push(source); while(!q_empty()){ p = q_pop(); for(i=0; i<4; ++i){ v = p_sum(step+i,&p); v1 = p_get(Z,&p); v2 = p_get(Z,&v); if(p_in(&v) && (p_get(W,&v)==-1 || (p_get(W,&v)>p_get(W,&p))) && (v1-v2 <= 3) && (v1-v2 >= -1) && can_go(&v)){ if(p_mhtn_norm(&v,target) < p_mhtn_norm(&p,target)){ p_set(W,&v,p_get(W,&p)); q_push_back(&v); }else{ /* > */ /*if(!(p_get(W,&v)!=-1 || (p_get(W,&v)==p_get(W,&p)+1))){ */ p_set(W,&v,p_get(W,&p)+1); q_push_front(&v); } if(p_eq(&v,target)){ break; } } } if(p_eq(&v,target)) break; } res = p_get(W,target); if(res != -1) res = 2*res+p_mhtn_norm(source,target); return res; }
int can_go(Pair* p){ Pair *b = bts; Pair s, t, md, mv, mh, next, buf1, buf2, buf3; int v, h, ver, hor; /* coordinate steps */ double val; int vis; while(b != bts+2){ ln_init(b,p_get(Z,b)+0.5,p,p_get(Z,p)+0.5); /* go from the bottom up */ if(p_get(Z,p) < p_get(Z,b)){ s = *p; t = *b; }else{ s = *b; t = *p; } hor = (s.c > t.c) ? -1 : 1; ver = (s.r > t.r) ? -1 : 1; #ifdef DEBUG printf("v: %d, h: %d\n",ver,hor); #endif h = (hor>0) ? 0 : 1; v = (ver>0) ? 0 : 1; vis = 1; while(!p_eq(&s,&t)){ md = p_new(ver,hor); md = p_sum(&s,&md); buf1 = p_new(md.r+v,md.c+h); if(ln_rc_val(&buf1)==0){ val = ln_z_by_r(buf1.r); next = md; }else{ mv = p_new(ver,0); mv = p_sum(&s,&mv); buf2 = p_new(mv.r+v,mv.c+h); if(!ln_rc_on_same_side(&buf1,&buf2)){ val = ln_z_by_r(buf2.r); next = mv; }else{ mh = p_new(0,hor); mh = p_sum(&s,&mh); buf3 = p_new(mh.r+v,mh.c+h); val = ln_z_by_c(buf3.c); next = mh; } } #ifdef DEBUG printf("next %d,%d\n",next.r,next.c); #endif if(p_get(Z,&next) > val){ #ifdef DEBUG printf("bad p: %d,%d val: %f\n",next.r,next.c,val); #endif vis = 0; break; } s = next; } if(vis) break; ++b; /* take next bts */ } return vis; }
void unapply(board *b, move m) { // Information piece old_piece = p_eq(m.promote_to, no_piece) ? at(b, m.to) : (piece){'P', at(b, m.to).white}; // If we are unapplying a double pawn push, disable en passant if (b->en_passant_pawn_push_col_history[b->last_move_ply] != -1) { b->hash ^= zobrist_en_passant_files[b->en_passant_pawn_push_col_history[b->last_move_ply]]; } // Transform board and hash b->hash ^= tt_pieceval(b, m.to); set(b, m.from, old_piece); set(b, m.to, m.captured); b->hash ^= tt_pieceval(b, m.from); b->hash ^= tt_pieceval(b, m.to); b->hash ^= zobrist_black_to_move; b->black_to_move = !b->black_to_move; b->last_move_ply--; // If the previous move was a double pawn push, enable en passant if (b->en_passant_pawn_push_col_history[b->last_move_ply] != -1) { b->hash ^= zobrist_en_passant_files[b->en_passant_pawn_push_col_history[b->last_move_ply]]; } // If we just unapplied an en passant move, put the pawn back if (m.en_passant_capture) { uint8_t en_passant_capture_row = old_piece.white ? 4 : 3; coord en_pasant_capture_square = (coord){b->en_passant_pawn_push_col_history[b->last_move_ply], en_passant_capture_row}; piece captured_pawn = (piece) {'P', !old_piece.white}; set(b, en_pasant_capture_square, captured_pawn); } if (old_piece.type == 'K') { if (old_piece.white) b->white_king = m.from; else b->black_king = m.from; } // Manually move rook for castling if (m.c != N) { // Manually move rook uint8_t rook_to_col = ((m.c == K) ? 7 : 0); uint8_t rook_from_col = ((m.c == K) ? 5 : 3); b->hash ^= tt_pieceval(b, (coord){rook_from_col, m.from.row}); b->b[rook_to_col][m.to.row] = (piece){'R', at(b, m.from).white}; b->b[rook_from_col][m.from.row] = no_piece; b->hash ^= tt_pieceval(b, (coord){rook_to_col, m.to.row}); } // Restore castling rights if (b->castle_wq_lost_on_ply == b->last_move_ply + 1) { b->castle_rights_wq = true; b->hash ^= zobrist_castle_wq; b->castle_wq_lost_on_ply = -1; } if (b->castle_wk_lost_on_ply == b->last_move_ply + 1) { b->castle_rights_wk = true; b->hash ^= zobrist_castle_wk; b->castle_wk_lost_on_ply = -1; } if (b->castle_bq_lost_on_ply == b->last_move_ply + 1) { b->castle_rights_bq = true; b->hash ^= zobrist_castle_bq; b->castle_bq_lost_on_ply = -1; } if (b->castle_bk_lost_on_ply == b->last_move_ply + 1) { b->castle_rights_bk = true; b->hash ^= zobrist_castle_bk; b->castle_bk_lost_on_ply = -1; } }
void apply(board *b, move m) { // Disable the old en passant eligibility for a file if (b->en_passant_pawn_push_col_history[b->last_move_ply] != -1) { b->hash ^= zobrist_en_passant_files[b->en_passant_pawn_push_col_history[b->last_move_ply]]; } // Information piece moved_piece = at(b, m.from); piece new_piece = p_eq(m.promote_to, no_piece) ? moved_piece : m.promote_to; // If the move we will apply is en passant, remove the captured pawn if (m.en_passant_capture) { uint8_t en_passant_capture_row = moved_piece.white ? 4 : 3; coord en_pasant_capture_square = (coord){b->en_passant_pawn_push_col_history[b->last_move_ply], en_passant_capture_row}; set(b, en_pasant_capture_square, no_piece); } // Transform board and hash b->hash ^= tt_pieceval(b, m.from); b->hash ^= tt_pieceval(b, m.to); set(b, m.to, new_piece); set(b, m.from, no_piece); b->hash ^= tt_pieceval(b, m.to); b->hash ^= zobrist_black_to_move; b->black_to_move = !b->black_to_move; b->last_move_ply++; // For en passant b->en_passant_pawn_push_col_history[b->last_move_ply] = -1; if (at(b, m.to).type == 'P' && abs(m.to.row - m.from.row) == 2) { b->en_passant_pawn_push_col_history[b->last_move_ply] = m.to.col; // En passant capture now enabled on this file b->hash ^= zobrist_en_passant_files[b->en_passant_pawn_push_col_history[b->last_move_ply]]; } // Manually move rook for castling if (m.c != N) { // Manually move rook uint8_t rook_from_col = ((m.c == K) ? 7 : 0); uint8_t rook_to_col = ((m.c == K) ? 5 : 3); b->hash ^= tt_pieceval(b, (coord){rook_from_col, m.from.row}); b->b[rook_to_col][m.to.row] = (piece){'R', at(b, m.to).white}; // !! b->b[rook_from_col][m.from.row] = no_piece; b->hash ^= tt_pieceval(b, (coord){rook_to_col, m.to.row}); } // King moves always strip castling rights if (moved_piece.white && moved_piece.type == 'K') { if (b->castle_rights_wk) { b->hash ^= zobrist_castle_wk; b->castle_wk_lost_on_ply = b->last_move_ply; b->castle_rights_wk = false; } if (b->castle_rights_wq) { b->hash ^= zobrist_castle_wq; b->castle_wq_lost_on_ply = b->last_move_ply; b->castle_rights_wq = false; } } else if (!moved_piece.white && moved_piece.type == 'K') { if (b->castle_rights_bk) { b->hash ^= zobrist_castle_bk; b->castle_bk_lost_on_ply = b->last_move_ply; b->castle_rights_bk = false; } if (b->castle_rights_bq) { b->hash ^= zobrist_castle_bq; b->castle_bq_lost_on_ply = b->last_move_ply; b->castle_rights_bq = false; } } if (moved_piece.type == 'K') { if (moved_piece.white) b->white_king = m.to; else b->black_king = m.to; } // Moves involving rook squares always strip castling rights if ((c_eq(m.from, wqr) || c_eq(m.to, wqr)) && b->castle_rights_wq) { b->castle_rights_wq = false; b->hash ^= zobrist_castle_wq; b->castle_wq_lost_on_ply = b->last_move_ply; } if ((c_eq(m.from, wkr) || c_eq(m.to, wkr)) && b->castle_rights_wk) { b->castle_rights_wk = false; b->hash ^= zobrist_castle_wk; b->castle_wk_lost_on_ply = b->last_move_ply; } if ((c_eq(m.from, bqr) || c_eq(m.to, bqr)) && b->castle_rights_bq) { b->castle_rights_bq = false; b->hash ^= zobrist_castle_bq; b->castle_bq_lost_on_ply = b->last_move_ply; } if ((c_eq(m.from, bkr) || c_eq(m.to, bkr)) && b->castle_rights_bk) { b->castle_rights_bk = false; b->hash ^= zobrist_castle_bk; b->castle_bk_lost_on_ply = b->last_move_ply; } }