bool abstract_piece::can_i_move(const board &m_board) const { int8_t pieces_in_between = 0; bool found_one_g = false; bool am_i_in_between = false; for (int8_t irank = 0; irank < board::RANK_NUM; irank++) { auto piece = m_board.at(pos.file, irank); if (piece) { if (found_one_g) { if (piece->is_king()) { break; } pieces_in_between++; if (*piece == *this) { am_i_in_between = true; } } else if (piece->is_king()) { found_one_g = true; } } } return !am_i_in_between || pieces_in_between != 1; }
string game::generate_fen(const board &bd) { std::string fen; int8_t space = 0; for (int8_t rank = board::RANK_NUM - 1; rank >= 0; --rank) { for (int8_t file = 0; file < board::FILE_NUM; ++file) { auto p = bd.at(file, rank); if (p) { if (space != 0) { fen.push_back(static_cast<char>(space) + '0'); space = 0; } fen.push_back(p->abbr_name()); } else { space++; } } if (space != 0) { fen.push_back(static_cast<char>(space) + '0'); space = 0; } fen.push_back('/'); } fen.pop_back();//remove last '/' return fen; }
//If this move will close any of the surrounding cells point will_close_any(const board & board, point idx, border_names border) { auto orig_idx = idx; auto orig_idx2 = idx; switch (border) { case top: orig_idx2 += point(0, -1); break; case left: orig_idx2 += point(-1, 0); break; case right: orig_idx2 += point(1, 0); break; case bottom: orig_idx2 += point(0, 1); break; } class board copy(board); fix_move(idx, border); if ((board.at(idx).owner & player_owned) != empty) return false; copy.place(idx, border); point idx2; if (border == top) idx2 = idx + point(0, -1); if (border == left) idx2 = idx + point(-1, 0); if (border_change(board, copy, orig_idx, 3, 4)) return orig_idx; if (border_change(board, copy, orig_idx2, 3, 4)) return orig_idx2; return point(-1, -1); }
//Fill this move leaves the given cell to be closed on 2 turns bool will_remain_with_2lines(const board & board, point idx, border_names border) { auto orig_idx = idx; class board copy(board); fix_move(idx, border); if ((board.at(idx).owner & player_owned) != empty) return false; copy.place(idx, border); return border_change(board, copy, orig_idx, 1, 2); }
bool king::is_flying_king(const position &proposed, const board &m_board) const { int8_t king_rank = -1; for (int8_t irank = 0; irank < board::RANK_NUM; irank++) { auto p = m_board.at(proposed.file, irank); if (p) { if (p->is_king()) { king_rank = irank; break; } } } if (king_rank == -1) {//there is no king, don't bother the flying king rule return false; } bool triggered = true; if (red_side) { for (int8_t irank = proposed.rank + 1; irank < king_rank; irank++) {//proposed.rank is equal to current position's rank if (m_board.at(proposed.file, irank)) { triggered = false; break; } } } else { for (int8_t irank = proposed.rank - 1; irank > king_rank; irank--) { if (m_board.at(proposed.file, irank)) { triggered = false; break; } } } return triggered; }
void abstract_piece::remove_invalid_moves(const board &m_board, int8_t min_file, int8_t max_file, int8_t min_rank, int8_t max_rank) { for (auto it = avail_pos.begin(); it != avail_pos.end();) { bool invalid = false; if (it->not_in_range(min_file, max_file, min_rank, max_rank)) { invalid = true; } else { auto target_piece = m_board.at(*it); if (target_piece) { //can't capture same-side pieces if (target_piece->red_side == this->red_side) { invalid = true; } } } if (invalid) { it = avail_pos.erase(it); } else { ++it; } } }
//for checking if they won, we can simplify because if we check every turn //then we *know* that a winning sequence must include that cell bool check_win(board& b, unsigned x, char id, unsigned to_win) { //x == bin of last move unsigned h = b.height(); unsigned w = b.num_bins(); unsigned y = 0; for (; y < h; ++y) { if (b[x][y] == 0) { break; } } --y; //last move was at x,y //check row if (check_win(range<adapters::horiz_it>(b.at(0, y), b.at(w, y)), id, to_win)) { return true; } //check column if (check_win(range<adapters::vert_it>(b.at(x, 0), b.at(x, h)), id, to_win)) { return true; } //check diagonals int intercept; int hs = h; //h signed int ws = w; //w signed unsigned xi; unsigned xf; unsigned yi; unsigned yf; //up slope: intercept = y - x; //all of these magic numbers are based off geometry. I'm not going //to prove it, as this is a program, not a proof, but if you want to //see it, it's not hard. My copy is on a receipt somewhere in the //trash :/ if (intercept < 0) { xi = (unsigned) -intercept; yi = 0; } else { xi = 0; yi = (unsigned) intercept; } if (intercept < hs - ws) { xf = w; yf = (unsigned)(ws + intercept); } else { xf = (unsigned)(hs - intercept); yf = h; } if (check_win(range<adapters::pos_diag_it>(b.at(xi, yi), b.at(xf, yf)), id, to_win)) { return true; } //down slope //there are some unsigned -1s because i need an invalid index that is //= to --0, so the underflow is OK. It will never be dereferenced. intercept = x + y; if (intercept < hs) { xi = 0; yi = (unsigned) intercept; } else { xi = (unsigned)(intercept - hs) + 1; yi = h - 1; } if (intercept < ws) { xf = (unsigned) intercept + 1; yf = (unsigned) -1; } else { xf = w; yf = (unsigned)(intercept - ws); } if (check_win(range<adapters::neg_diag_it>(b.at(xi, yi), b.at(xf, yf)), id, to_win)) { return true; } return false; }