// MOBILITY heuristic: safe squares around king of color color. int mobility(position_t *p, color_t color) { char* laser_map; if (color == WHITE) { laser_map = laser_map_black; } else { laser_map = laser_map_white; } int mobility = 0; square_t king_sq = p->kloc[color]; tbassert(ptype_of(p->board[king_sq]) == KING, "ptype: %d\n", ptype_of(p->board[king_sq])); tbassert(color_of(p->board[king_sq]) == color, "color: %d\n", color_of(p->board[king_sq])); if (laser_map[king_sq] == 0) { mobility++; } for (int d = 0; d < 8; ++d) { square_t sq = king_sq + dir_of(d); if (laser_map[sq] == 0) { mobility++; } } return mobility; }
// KFACE heuristic: bonus (or penalty) for King facing toward the other King ev_score_t kface(position_t *p, fil_t f, rnk_t r) { square_t sq = square_of(f, r); piece_t x = p->board[sq]; color_t c = color_of(x); square_t opp_sq = p->kloc[opp_color(c)]; int delta_fil = fil_of(opp_sq) - f; int delta_rnk = rnk_of(opp_sq) - r; int bonus; switch (ori_of(x)) { case NN: bonus = delta_rnk; break; case EE: bonus = delta_fil; break; case SS: bonus = -delta_rnk; break; case WW: bonus = -delta_fil; break; default: bonus = 0; tbassert(false, "Illegal King orientation.\n"); } return (bonus * KFACE) / (abs(delta_rnk) + abs(delta_fil)); }
// KAGGRESSIVE heuristic: bonus for King with more space to back ev_score_t kaggressive(position_t *p, rnk_t r, fil_t f, full_board_t* board) { piece_t x = get_piece(p, r, f, board); color_t c = color_of(x); tbassert(ptype_of(x) == KING, "ptype_of(x) = %d\n", ptype_of(x)); square_t opp_sq = board->pieces[opp_color(c)][0]; fil_t of = fil_of(opp_sq); rnk_t _or = (rnk_t) rnk_of(opp_sq); int delta_fil = of - f; int delta_rnk = _or - r; int bonus = 0; if (delta_fil >= 0 && delta_rnk >= 0) { bonus = (f + 1) * (r + 1); } else if (delta_fil <= 0 && delta_rnk >= 0) { bonus = (BOARD_WIDTH - f) * (r + 1); } else if (delta_fil <= 0 && delta_rnk <= 0) { bonus = (BOARD_WIDTH - f) * (BOARD_WIDTH - r); } else if (delta_fil >= 0 && delta_rnk <= 0) { bonus = (f + 1) * (BOARD_WIDTH - r); } return (KAGGRESSIVE * bonus) / (BOARD_WIDTH * BOARD_WIDTH); }
// KFACE heuristic: bonus (or penalty) for King facing toward the other King ev_score_t kface(position_t *p, rnk_t r, fil_t f, full_board_t* board) { piece_t x = get_piece(p, r, f, board); color_t c = color_of(x); square_t opp_sq = board->pieces[opp_color(c)][0]; int delta_fil = fil_of(opp_sq) - f; int delta_rnk = rnk_of(opp_sq) - r; int bonus; switch (ori_of(x)) { case NN: bonus = delta_rnk; break; case EE: bonus = delta_fil; break; case SS: bonus = -delta_rnk; break; case WW: bonus = -delta_fil; break; default: bonus = 0; tbassert(false, "Illegal King orientation.\n"); } return (bonus * KFACE) / (abs(delta_rnk) + abs(delta_fil)); }
// KAGGRESSIVE heuristic: bonus for King with more space to back ev_score_t kaggressive_old(position_t *p, fil_t f, rnk_t r) { square_t sq = square_of(f, r); piece_t x = p->board[sq]; color_t c = color_of(x); tbassert(ptype_of(x) == KING, "ptype_of(x) = %d\n", ptype_of(x)); square_t opp_sq = p->kloc[opp_color(c)]; fil_t of = fil_of(opp_sq); rnk_t _or = (rnk_t) rnk_of(opp_sq); int delta_fil = of - f; int delta_rnk = _or - r; int bonus = 0; if (delta_fil >= 0 && delta_rnk >= 0) { bonus = (f + 1) * (r + 1); } else if (delta_fil <= 0 && delta_rnk >= 0) { bonus = (BOARD_WIDTH - f) * (r + 1); } else if (delta_fil <= 0 && delta_rnk <= 0) { bonus = (BOARD_WIDTH - f) * (BOARD_WIDTH - r); } else if (delta_fil >= 0 && delta_rnk <= 0) { bonus = (f + 1) * (BOARD_WIDTH - r); } return (KAGGRESSIVE * bonus) / (BOARD_WIDTH * BOARD_WIDTH); }
static Key polyglot_key(const Pos *pos) { Key key = 0; Bitboard b = pieces(); while (b) { Square s = pop_lsb(&b); Piece p = piece_on(s); // PolyGlot pieces are: BP = 0, WP = 1, BN = 2, ... BK = 10, WK = 11 key ^= PG.Zobrist.psq[2 * (type_of_p(p) - 1) + (color_of(p) == WHITE)][s]; } b = can_castle_any(); while (b) key ^= PG.Zobrist.castle[pop_lsb(&b)]; if (ep_square()) key ^= PG.Zobrist.enpassant[file_of(ep_square())]; if (pos_stm() == WHITE) key ^= PG.Zobrist.turn; return key; }
void signal_printer_message_public_highlight(gpointer *params) { session *sess = params[0]; gchar *from = params[1]; gchar *message = params[2]; gchar *nickchar = params[3]; gchar *idtext = params[4]; gint nickcolor = color_of(from); gchar *temp = g_strdup_printf("\x03%d%s\x03", nickcolor, from); gchar *nick; if (prefs.coloredhnicks) { nick = g_strdup(temp); g_free(temp); } else { nick = g_strdup(from); } session_print_format(sess, "channel msg hilight", nick, nickchar, idtext, message); g_free(nick); }
void signal_printer_message_private(gpointer *params) { session *sess = params[0]; gchar *from = params[1]; gchar *message = params[2]; gchar *idtext = params[3]; gint nickcolor = color_of(from); gchar *temp = g_strdup_printf("\x03%d%s\x03", nickcolor, from); gchar *nick; if (prefs.colorednicks) { nick = g_strdup(temp); g_free(temp); } else { nick = g_strdup(from); } if (sess->type == SESS_DIALOG) { session_print_format(sess, "private message to dialog", nick, message, idtext); } else { session_print_format(sess, "private message", nick, message, idtext); } g_free(nick); }
// Marks the path of the laser until it hits a piece or goes off the board. // Returns the number of unpinned pawns. // // p : current board state // laser_map : end result will be stored here. Every square on the // path of the laser is marked with mark_mask // c : color of king shooting laser // mark_mask: what each square is marked with int mark_laser_path(position_t *p, char *laser_map, color_t c, char mark_mask) { int pinned_pawns = 0; uint8_t total_pawns; color_t color = opp_color(c); square_t o_king_sq = p->kloc[color]; if (c == WHITE) { // opposing king pins our pawns total_pawns = p->pawn_count[BLACK]; } else { total_pawns = p->pawn_count[WHITE]; } // Fire laser, recording in laser_map square_t sq = p->kloc[c]; int bdir = ori_of(p->board[sq]); int beam = beam_of(bdir); tbassert(ptype_of(p->board[sq]) == KING, "ptype: %d\n", ptype_of(p->board[sq])); laser_map[sq] |= mark_mask; // we update h_attackable here h_attackable = h_dist(sq, o_king_sq); while (true) { sq += beam; laser_map[sq] |= mark_mask; tbassert(sq < ARR_SIZE && sq >= 0, "sq: %d\n", sq); switch (ptype_of(p->board[sq])) { case EMPTY: // empty square h_attackable += h_dist(sq, o_king_sq); break; case PAWN: // Pawn h_attackable += h_dist(sq, o_king_sq); if (color_of(p->board[sq]) == color) { pinned_pawns += 1; } bdir = reflect_of(bdir, ori_of(p->board[sq])); if (bdir < 0) { // Hit back of Pawn return total_pawns - pinned_pawns; } beam = beam_of(bdir); break; case KING: // King h_attackable += h_dist(sq, o_king_sq); return total_pawns - pinned_pawns; break; case INVALID: // Ran off edge of board return total_pawns - pinned_pawns; break; default: // Shouldna happen, man! tbassert(false, "Not cool, man. Not cool.\n"); break; } } }
MoveStack* generate<EVASIONS>(const Position& pos, MoveStack* mlist) { assert(pos.checkers()); Square from, checksq; int checkersCnt = 0; Color us = pos.side_to_move(); Square ksq = pos.king_square(us); Bitboard sliderAttacks = 0; Bitboard b = pos.checkers(); assert(pos.checkers()); // Find squares attacked by slider checkers, we will remove them from the king // evasions so to skip known illegal moves avoiding useless legality check later. do { checkersCnt++; checksq = pop_lsb(&b); assert(color_of(pos.piece_on(checksq)) == ~us); switch (type_of(pos.piece_on(checksq))) { case BISHOP: sliderAttacks |= PseudoAttacks[BISHOP][checksq]; break; case ROOK: sliderAttacks |= PseudoAttacks[ROOK][checksq]; break; case QUEEN: // If queen and king are far or not on a diagonal line we can safely // remove all the squares attacked in the other direction becuase are // not reachable by the king anyway. if (between_bb(ksq, checksq) || !(PseudoAttacks[BISHOP][checksq] & ksq)) sliderAttacks |= PseudoAttacks[QUEEN][checksq]; // Otherwise we need to use real rook attacks to check if king is safe // to move in the other direction. For example: king in B2, queen in A1 // a knight in B1, and we can safely move to C1. else sliderAttacks |= PseudoAttacks[BISHOP][checksq] | pos.attacks_from<ROOK>(checksq); default: break; } } while (b); // Generate evasions for king, capture and non capture moves b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks; from = ksq; SERIALIZE(b); if (checkersCnt > 1) return mlist; // Double check, only a king move can save the day // Generate blocking evasions or captures of the checking piece Bitboard target = between_bb(checksq, ksq) | pos.checkers(); return generate_all<EVASIONS>(pos, mlist, us, target); }
static void parse_nondirective(char *s) { char *base = s; char *t; const char *attr0 = Ident_attr; const char *attr1 = Ident2_attr; char *attr2 = Literal_attr; if (FltOptions('c')) { t = skip_ident(s = base); if (t != s) { int save = *t; /* this parses one of * "name" * "name:class" * "name:color" */ parse_keyword(s, 0); *t = 0; attr0 = actual_color(s, abbr_len(s), 0); *t = (char) save; } if (skip_eqls_ch(&t)) { s = skip_ident(t); if (s != t) { attr1 = actual_color(t, (int) (s - t), 1); } } } t = skip_ident(s = base); flt_puts(s, (int) (t - s), attr0); if (parse_eqls_ch(&t)) { s = skip_ident(t); if (s != t) { int save = *s; *s = 0; if (!FltOptions('c')) { if (*(attr1 = color_of(t, 0)) == '\0') attr1 = Action_attr; } flt_puts(t, (int) strlen(t), attr1); *s = (char) save; } if (parse_eqls_ch(&s)) { flt_puts(s, (int) strlen(s), attr2); } else if (*s) { flt_puts(s, (int) strlen(s), Error_attr); } } else if (*t) { flt_puts(t, (int) strlen(t), Error_attr); } }
// MOBILITY heuristic: safe squares around king of color color. int mobility(position_t *p, color_t color, char* laser_map, full_board_t* board) { int mobility = 0; square_t king_sq = board->pieces[color][0]; tbassert(ptype_of(board->board[king_sq]) == KING, "ptype: %d\n", ptype_of(board->board[king_sq])); tbassert(color_of(board->board[king_sq]) == color, "color: %d\n", color_of(board->board[king_sq])); if (laser_map[king_sq] == 0) { mobility++; } for (int d = 0; d < 8; ++d) { square_t sq = king_sq + dir_of(d); if (in_bounds(sq) && laser_map[sq] == 0) { mobility++; } } return mobility; }
int pawnpin(position_t *p, color_t color, square_t* laser_list, int laser_list_len, full_board_t* board) { int unpinned_pawns = board->pawn_count[color]; for(int i = 1; i < laser_list_len; i++) { if (color_of(board->board[laser_list[i]]) == color && ptype_of(board->board[laser_list[i]]) == PAWN) { unpinned_pawns--; } } return unpinned_pawns; }
// H_SQUARES_ATTACKABLE heuristic: for shooting the enemy king int h_squares_attackable(position_t *p, color_t c) { char* laser_map; if (c == WHITE) { laser_map = laser_map_white; } else { laser_map = laser_map_black; } square_t o_king_sq = p->kloc[opp_color(c)]; tbassert(ptype_of(p->board[o_king_sq]) == KING, "ptype: %d\n", ptype_of(p->board[o_king_sq])); tbassert(color_of(p->board[o_king_sq]) != c, "color: %d\n", color_of(p->board[o_king_sq])); float h_attackable_temp = 0; for (fil_t f = 0; f < BOARD_WIDTH; f++) { for (rnk_t r = 0; r < BOARD_WIDTH; r++) { square_t sq = square_of(f, r); if (laser_map[sq] != 0) { h_attackable_temp += h_dist(sq, o_king_sq); } } } return h_attackable_temp; }
static score_t get_game_over_score(victims_t victims, int pov, int ply) { tbassert(ptype_of(victims.stomped) != KING, "Stomped a king.\n"); score_t score; if (color_of(victims.zapped) == WHITE) { score = -WIN * pov; } else { score = WIN * pov; } if (score < 0) { score += ply; } else { score -= ply; } return score; }
// Translate a position struct into a fen string // NOTE: When you use the test framework in search.c, you should modify this // function to match your optimized board representation in move_gen.c // // Input: (populated) position struct // empty string where FEN characters will be written // Output: null int pos_to_fen(position_t *p, char *fen) { int pos = 0; int i; for (rnk_t r = BOARD_WIDTH - 1; r >=0 ; --r) { int empty_in_a_row = 0; for (fil_t f = 0; f < BOARD_WIDTH; ++f) { piece_t piece = get_piece(p, r, f, &base_board); if (ptype_of(piece) == INVALID) { // invalid square tbassert(false, "Bad news, yo.\n"); // This is bad! } if (ptype_of(piece) == EMPTY) { // empty square empty_in_a_row++; continue; } else { if (empty_in_a_row) fen[pos++] = '0' + empty_in_a_row; empty_in_a_row = 0; int ori = ori_of(piece); // orientation color_t c = color_of(piece); if (ptype_of(piece) == KING) { for (i = 0; i < 2; i++) fen[pos++] = king_ori_to_rep[c][ori][i]; continue; } if (ptype_of(piece) == PAWN) { for (i = 0; i < 2; i++) fen[pos++] = pawn_ori_to_rep[c][ori][i]; continue; } } } // assert: for larger boards, we need more general solns tbassert(BOARD_WIDTH <= 10, "BOARD_WIDTH = %d\n", BOARD_WIDTH); if (empty_in_a_row == 10) { fen[pos++] = '1'; fen[pos++] = '0'; } else if (empty_in_a_row) { fen[pos++] = '0' + empty_in_a_row; } if (r) fen[pos++] = '/'; } fen[pos++] = ' '; fen[pos++] = 'W'; fen[pos++] = '\0'; return pos; }
static const char * actual_color(const char *param, int len, int arg) { const char *result; char *s = strmalloc(param); if (len > 0) { /* if not null-terminated, set it now */ s[len] = '\0'; } result = color_of(s, arg); if (*result == 0) result = keyword_attr(s); if (result != 0 && *result != 0 && !is_color(result)) { result = Literal_attr; } free(s); return result; }
ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* mlist) { assert(pos.checkers()); int checkersCnt = 0; Color us = pos.side_to_move(); Square ksq = pos.king_square(us), from = ksq /* For SERIALIZE */, checksq; Bitboard sliderAttacks = 0; Bitboard b = pos.checkers(); assert(pos.checkers()); // Find all the squares attacked by slider checkers. We will remove them from // the king evasions in order to skip known illegal moves, which avoids any // useless legality checks later on. do { ++checkersCnt; checksq = pop_lsb(&b); assert(color_of(pos.piece_on(checksq)) == ~us); if (type_of(pos.piece_on(checksq)) > KNIGHT) // A slider sliderAttacks |= LineBB[checksq][ksq] ^ checksq; } while (b); // Generate evasions for king, capture and non capture moves b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks; SERIALIZE(b); if (checkersCnt > 1) return mlist; // Double check, only a king move can save the day // Generate blocking evasions or captures of the checking piece Bitboard target = between_bb(checksq, ksq) | checksq; return us == WHITE ? generate_all<WHITE, EVASIONS>(pos, mlist, target) : generate_all<BLACK, EVASIONS>(pos, mlist, target); }
static void ExecClass(char *param) { char *t = strmalloc(param); char *s; const char *attr = ""; parse_keyword(t, 1); free(t); t = flt_put_blanks(param); s = skip_ident(t); if (FltOptions('c')) { attr = actual_color(param, (int) (s - param), 1); } else { attr = Ident2_attr; } flt_puts(param, (int) (s - param), attr); if (parse_eqls_ch(&s)) { t = s; s = skip_ident(t); if (FltOptions('c')) { attr = actual_color(t, (int) (s - t), 1); } else { if (*(attr = color_of(t, 0)) == '\0') attr = Action_attr; } flt_puts(t, (int) (s - t), attr); if (parse_eqls_ch(&s)) { flt_puts(s, (int) strlen(s), Literal_attr); } else if (*s) { flt_puts(s, (int) strlen(s), Error_attr); } } else if (*s) { flt_puts(s, (int) strlen(s), Error_attr); } }
void signal_printer_action_private_hilight(gpointer *params) { session *sess = params[0]; gchar *from = params[1]; gchar *text = params[2]; gchar *nickchar = params[3]; gint nickcolor = color_of(from); gchar *temp = g_strdup_printf("\x03%d%s\x03", nickcolor, from); gchar *nick; if (prefs.coloredhnicks) { nick = g_strdup(temp); g_free(temp); } else { nick = g_strdup(from); } session_print_format(sess, "query action hilight", nick, nickchar, text); g_free(nick); }
bool move_is_legal(const Position& pos, Move move) { Move m = move; assert(is_ok(m)); Color us = pos.side_to_move(); Square from = from_sq(m); Square to = to_sq(m); assert(color_of(pos.piece_moved(m)) == us); assert(pos.piece_on(pos.king_square(us)) == make_piece(us, KING)); PieceType pfr = type_of(pos.piece_on(from)); PieceType pto= type_of(pos.piece_on(to)); Bitboard pawns = pos.pieces(~us, PAWN); Bitboard knights = pos.pieces(~us, KNIGHT); Bitboard cannons = pos.pieces(~us, CANNON); Bitboard rooks = pos.pieces(~us, ROOK); Bitboard occ = pos.pieces(); Bitboard occl90 = pos.piecesl90(); occl90 ^= square_rotate_l90_bb(from); occ ^= from; if(pto == NO_PIECE_TYPE) { occl90 ^= square_rotate_l90_bb(to); occ ^= to; } Square ksq = pos.king_square(us); if(ksq == from) ksq = to; if (pto != NO_PIECE_TYPE) { switch(pto) { case PAWN: pawns ^= to; break; case KNIGHT: knights ^= to; break; case ROOK: rooks ^= to; break; case CANNON: cannons ^= to; break; } } if((PseudoAttacks[ROOK][ksq]& cannons) &&(cannon_control_bb(ksq, occ,occl90) & cannons)) return false; if((PseudoAttacks[ROOK][ksq]& rooks) && (rook_attacks_bb(ksq,occ,occl90)& rooks) ) return false; if( knight_attackers_to_bb(ksq, knights, occ) ) return false; if( pos.attacks_from_pawn_nomask(ksq, us) & pawns ) return false; if((PseudoAttacks[ROOK][ksq]& pos.king_square(~us)) && (rook_attacks_bb(ksq,occ,occl90)& pos.king_square(~us))) return false;//╤таЁ return true; }
// Static evaluation. Returns score score_t eval(position_t *p, bool verbose) { // seed rand_r with a value of 1, as per // http://linux.die.net/man/3/rand_r static __thread unsigned int seed = 1; // verbose = true: print out components of score ev_score_t score[2] = { 0, 0 }; // int corner[2][2] = { {INF, INF}, {INF, INF} }; ev_score_t bonus; //char buf[MAX_CHARS_IN_MOVE]; color_t c; for (fil_t f = 0; f < BOARD_WIDTH; f++) { for (rnk_t r = 0; r < BOARD_WIDTH; r++) { square_t sq = square_of(f, r); piece_t x = p->board[sq]; //if (verbose) { // square_to_str(sq, buf, MAX_CHARS_IN_MOVE); //} switch (ptype_of(x)) { case EMPTY: break; case PAWN: c = color_of(x); // MATERIAL heuristic: Bonus for each Pawn bonus = PAWN_EV_VALUE; // if (verbose) { // printf("MATERIAL bonus %d for %s Pawn on %s\n", bonus, color_to_str(c), buf); // } score[c] += bonus; // PBETWEEN heuristic bonus = pbetween(p, f, r); // if (verbose) { // printf("PBETWEEN bonus %d for %s Pawn on %s\n", bonus, color_to_str(c), buf); // } score[c] += bonus; // PCENTRAL heuristic bonus = pcentral(f, r); // if (verbose) { // printf("PCENTRAL bonus %d for %s Pawn on %s\n", bonus, color_to_str(c), buf); // } score[c] += bonus; break; case KING: c = color_of(x); // KFACE heuristic bonus = kface(p, f, r); // if (verbose) { // printf("KFACE bonus %d for %s King on %s\n", bonus, // color_to_str(c), buf); // } score[c] += bonus; // KAGGRESSIVE heuristic color_t othercolor = opp_color(c); square_t otherking = p->kloc[othercolor]; fil_t otherf = fil_of(otherking); rnk_t otherr = rnk_of(otherking); bonus = kaggressive(f, r, otherf, otherr); assert(bonus == kaggressive_old(p, f, r)); // if (verbose) { // printf("KAGGRESSIVE bonus %d for %s King on %s\n", bonus, color_to_str(c), buf); // } score[c] += bonus; break; case INVALID: break; default: tbassert(false, "Jose says: no way!\n"); // No way, Jose! } laser_map_black[sq] = 0; laser_map_white[sq] = 0; } } int black_pawns_unpinned = mark_laser_path(p, laser_map_white, WHITE, 1); // 1 = path of laser with no moves ev_score_t w_hattackable = HATTACK * (int) h_attackable; score[WHITE] += w_hattackable; // if (verbose) { // printf("HATTACK bonus %d for White\n", w_hattackable); // } // PAWNPIN Heuristic --- is a pawn immobilized by the enemy laser. int b_pawnpin = PAWNPIN * black_pawns_unpinned; score[BLACK] += b_pawnpin; int b_mobility = MOBILITY * mobility(p, BLACK); score[BLACK] += b_mobility; // if (verbose) { // printf("MOBILITY bonus %d for Black\n", b_mobility); // } int white_pawns_unpinned = mark_laser_path(p, laser_map_black, BLACK, 1); // 1 = path of laser with no moves ev_score_t b_hattackable = HATTACK * (int) h_attackable; score[BLACK] += b_hattackable; // if (verbose) { // printf("HATTACK bonus %d for Black\n", b_hattackable); // } int w_mobility = MOBILITY * mobility(p, WHITE); score[WHITE] += w_mobility; // if (verbose) { // printf("MOBILITY bonus %d for White\n", w_mobility); // } int w_pawnpin = PAWNPIN * white_pawns_unpinned; score[WHITE] += w_pawnpin; // score from WHITE point of view ev_score_t tot = score[WHITE] - score[BLACK]; if (RANDOMIZE) { ev_score_t z = rand_r(&seed) % (RANDOMIZE*2+1); tot = tot + z - RANDOMIZE; } if (color_to_move_of(p) == BLACK) { tot = -tot; } return tot / EV_SCORE_RATIO; }
void inbound_chanmsg (server *serv, char *chan, char *from, char *text, char fromme) { struct User *user; session *sess; int hilight = FALSE; char nickchar[2] = "\000"; if (chan) { sess = find_channel (serv, chan); if (!sess && !is_channel (serv, chan)) sess = find_dialog (serv, chan); } else { sess = find_dialog (serv, from); } if (!sess) return; if (sess != current_tab) { sess->msg_said = TRUE; sess->new_data = FALSE; } user = find_name (sess, from); if (user) { nickchar[0] = user->prefix[0]; user->lasttalk = time (0); } if (fromme) { if (prefs.auto_unmark_away && serv->is_away) sess->server->p_set_back (sess->server); EMIT_SIGNAL (XP_TE_UCHANMSG, sess, from, text, nickchar, NULL, 0); return; } if (sess->type != SESS_DIALOG) if (prefs.beepchans || sess->beep) fe_beep (); if (is_hilight (text, sess, serv)) { hilight = TRUE; if (prefs.beephilight) fe_beep (); } if (sess->type == SESS_DIALOG) EMIT_SIGNAL (XP_TE_DPRIVMSG, sess, from, text, NULL, NULL, 0); else if (hilight) EMIT_SIGNAL (XP_TE_HCHANMSG, sess, from, text, nickchar, NULL, 0); else if (prefs.colorednicks) { char tbuf[NICKLEN + 4]; snprintf (tbuf, sizeof (tbuf), "\003%d%s", color_of (from), from); EMIT_SIGNAL (XP_TE_CHANMSG, sess, tbuf, text, nickchar, NULL, 0); } else EMIT_SIGNAL (XP_TE_CHANMSG, sess, from, text, nickchar, NULL, 0); }
static score_t get_game_over_score(victims_t* victims, int pov, int ply) { tbassert(ptype_of(victims->stomped) != KING, "Stomped a king.\n"); // score negative when victims.zapped == WHITE score_t score = -1*(1 - 2*(color_of(victims->zapped)))*WIN*pov; return score + (1 - 2*(score >= 0))*ply; }
// Translate a fen string into a board position struct // int fen_to_pos(position_t *p, char *fen) { static position_t dmy1, dmy2; // these sentinels simplify checking previous // states without stepping past null pointers. dmy1.key = 0; dmy1.victims.stomped = 1; dmy1.victims.zapped = 1; dmy1.history = NULL; dmy2.key = 0; dmy2.victims.stomped = 1; dmy2.victims.zapped = 1; dmy2.history = &dmy1; p->key = 0; // hash key p->victims.stomped = 0; // piece destroyed by stomper p->victims.zapped = 0; // piece destroyed by shooter p->history = &dmy2; // history memset(&base_board, 0, sizeof(full_board_t)); if (fen[0] == '\0') { // Empty FEN => use starting position fen = "ss3nw5/3nw2nw3/2nw7/1nw6SE1/nw9/9SE/1nw6SE1/7SE2/3SE2SE3/5SE3NN W"; } int c_count = 0; // Invariant: fen[c_count] is next char to be read for (int i = 0; i < ARR_SIZE; ++i) { base_board.board[i] = INVALID_PIECE; } c_count = parse_fen_board(p, fen); if (!c_count) { return 1; // parse error of board } // King check int Kings[2] = {0, 0}; for (fil_t f = 0; f < BOARD_WIDTH; ++f) { for (rnk_t r = 0; r < BOARD_WIDTH; ++r) { square_t sq = square_of(r, f); piece_t x = base_board.board[sq]; ptype_t typ = ptype_of(x); if (typ == KING) { Kings[color_of(x)]++; } } } if (Kings[WHITE] == 0) { fen_error(fen, c_count, "No White Kings"); return 1; } else if (Kings[WHITE] > 1) { fen_error(fen, c_count, "Too many White Kings"); return 1; } else if (Kings[BLACK] == 0) { fen_error(fen, c_count, "No Black Kings"); return 1; } else if (Kings[BLACK] > 1) { fen_error(fen, c_count, "Too many Black Kings"); return 1; } char c; bool done = false; // Look for color to move and set ply accordingly while (!done && (c = fen[c_count++]) != '\0') { switch (c) { // ignore whitespace until the end case ' ': case '\t': case '\n': case '\r': break; // White to move case 'W': case 'w': p->ply = 0; base_board.ply = 0; done = true; break; // Black to move case 'B': case 'b': p->ply = 1; base_board.ply = 1; done = true; break; default: fen_error(fen, c_count, "Must specify White (W) or Black (B) to move"); return 1; break; } } // Look for last move, if it exists int lm_from_sq, lm_to_sq, lm_rot; if (get_sq_from_str(fen, &c_count, &lm_from_sq) != 0) { // parse error return 1; } if (lm_from_sq == 0) { // from-square of last move p->last_move = 0; // no last move specified p->key = compute_zob_key(p, &base_board); return 0; } c = fen[c_count]; switch (c) { case 'R': case 'r': lm_to_sq = lm_from_sq; lm_rot = RIGHT; break; case 'U': case 'u': lm_to_sq = lm_from_sq; lm_rot = UTURN; break; case 'L': case 'l': lm_to_sq = lm_from_sq; lm_rot = LEFT; break; default: // Not a rotation lm_rot = NONE; if (get_sq_from_str(fen, &c_count, &lm_to_sq) != 0) { return 1; } break; } p->last_move = move_of(EMPTY, lm_rot, lm_from_sq, lm_to_sq); p->key = compute_zob_key(p, &base_board); return 0; // everything is okay }
// Evaluate the move by performing a search. void evaluateMove(searchNode *node, move_t mv, move_t killer_a, move_t killer_b, searchType_t type, uint64_t *node_count_serial, moveEvaluationResult* result) { int ext = 0; // extensions bool blunder = false; // shoot our own piece result->next_node.subpv[0] = 0; result->next_node.parent = node; // Make the move, and get any victim pieces. bool isko = make_move(&(node->position), &(result->next_node.position), mv); // Check whether this move changes the board state. // such moves are not legal. if (isko) { result->type = MOVE_ILLEGAL; return; } victims_t* victims = &result->next_node.position.victims; // Check whether the game is over. if (is_game_over(victims, node->pov, node->ply)) { // Compute the end-game score. result->type = MOVE_GAMEOVER; result->score = get_game_over_score(victims, node->pov, node->ply); return; } // Ignore noncapture moves when in quiescence. if (zero_victims(victims) && node->quiescence) { result->type = MOVE_IGNORE; return; } // Check whether the board state has been repeated, this results in a draw. if (is_repeated(&(result->next_node.position), node->ply)) { result->type = MOVE_GAMEOVER; result->score = get_draw_score(&(result->next_node.position), node->ply); return; } tbassert(victims->stomped == 0 || color_of(victims->stomped) != node->fake_color_to_move, "stomped = %d, color = %d, fake_color_to_move = %d\n", victims->stomped, color_of(victims->stomped), node->fake_color_to_move); // Check whether we caused our own piece to be zapped. This isn't considered // a blunder if we also managed to stomp an enemy piece in the process. if (victims->stomped == 0 && victims->zapped > 0 && color_of(victims->zapped) == node->fake_color_to_move) { blunder = true; } // Do not consider moves that are blunders while in quiescence. if (node->quiescence && blunder) { result->type = MOVE_IGNORE; return; } // Extend the search-depth by 1 if we captured a piece, since that means the // move was interesting. if (victim_exists(victims) && !blunder) { ext = 1; } // Late move reductions - or LMR. Only done in scout search. int next_reduction = 0; if (type == SEARCH_SCOUT && node->legal_move_count + 1 >= LMR_R1 && node->depth > 2 && zero_victims(victims) && mv != killer_a && mv != killer_b) { if (node->legal_move_count + 1 >= LMR_R2) { next_reduction = 2; } else { next_reduction = 1; } } result->type = MOVE_EVALUATED; int search_depth = ext + node->depth - 1; // Check if we need to perform a reduced-depth search. // // After a reduced-depth search, a full-depth search will be performed if the // reduced-depth search did not trigger a cut-off. if (next_reduction > 0) { search_depth -= next_reduction; int reduced_depth_score = -scout_search(&(result->next_node), search_depth, node_count_serial); if (reduced_depth_score < node->beta) { result->score = reduced_depth_score; return; } search_depth += next_reduction; } // Check if we should abort due to time control. if (abortf) { result->score = 0; result->type = MOVE_IGNORE; return; } if (type == SEARCH_SCOUT) { result->score = -scout_search(&(result->next_node), search_depth, node_count_serial); } else { if (node->legal_move_count == 0 || node->quiescence) { result->score = -searchPV(&(result->next_node), search_depth, node_count_serial); } else { result->score = -scout_search(&(result->next_node), search_depth, node_count_serial); if (result->score > node->alpha) { result->score = -searchPV(&(result->next_node), node->depth + ext - 1, node_count_serial); } } } }
void inbound_action (session *sess, char *chan, char *from, char *text, int fromme) { session *def = sess; server *serv = sess->server; int beep = FALSE; int hilight = FALSE; if (!fromme) { if (is_channel (serv, chan)) { sess = find_channel (serv, chan); beep = prefs.beepchans; } else { /* it's a private action! */ beep = prefs.beepmsg; /* find a dialog tab for it */ sess = find_dialog (serv, from); /* if non found, open a new one */ if (!sess && prefs.autodialog) sess = new_ircwindow (serv, from, SESS_DIALOG); } } if (!sess) sess = def; if (sess != current_tab) { if (fromme) { sess->msg_said = FALSE; sess->new_data = TRUE; } else { sess->msg_said = TRUE; sess->new_data = FALSE; } } if (!fromme) { hilight = is_hilight (text, sess, serv); if (hilight && prefs.beephilight) beep = TRUE; if (beep || sess->beep) fe_beep (); if (hilight) { EMIT_SIGNAL (XP_TE_HCHANACTION, sess, from, text, NULL, NULL, 0); return; } } if (prefs.colorednicks) { char tbuf[NICKLEN + 4]; snprintf (tbuf, sizeof (tbuf), "\003%d%s", color_of (from), from); EMIT_SIGNAL (XP_TE_CHANACTION, sess, tbuf, text, NULL, NULL, 0); } else { EMIT_SIGNAL (XP_TE_CHANACTION, sess, from, text, NULL, NULL, 0); } }