int get_liberties_board (unsigned short pos) { if (!on_board (pos) || get_point_board (pos) == EMPTY) { return -1; } setup_marks (); int ret_val = 0; unsigned char orig_color = get_point_board (pos); empty_stack (&parse_stack); push_pos_stack (&parse_stack, pos); /* Since we only ever test for liberties in order to determine captures and the like, there's no reason to count any liberties higher than 2 (we sometimes need to know if something has 1 liberty for dealing with ko) */ while (pop_pos_stack (&parse_stack, &pos) && ret_val < 2) { ret_val += get_liberties_helper (NORTH (pos), orig_color); ret_val += get_liberties_helper (SOUTH (pos), orig_color); ret_val += get_liberties_helper (EAST (pos), orig_color); ret_val += get_liberties_helper (WEST (pos), orig_color); } /* if there's more than two liberties, the stack isn't empty, so empty it */ empty_stack (&parse_stack); return ret_val; }
void gamemap::set_terrain(const map_location& loc, const t_translation::terrain_code & terrain, const terrain_type_data::merge_mode mode, bool replace_if_failed) { if(!on_board_with_border(loc)) { DBG_G << "set_terrain: " << loc << " is not on the map.\n"; // off the map: ignore request return; } t_translation::terrain_code new_terrain = tdata_->merge_terrains(get_terrain(loc), terrain, mode, replace_if_failed); if(new_terrain == t_translation::NONE_TERRAIN) { return; } if(on_board(loc)) { const bool old_village = is_village(loc); const bool new_village = tdata_->is_village(new_terrain); if(old_village && !new_village) { villages_.erase(std::remove(villages_.begin(),villages_.end(),loc),villages_.end()); } else if(!old_village && new_village) { villages_.push_back(loc); } } (*this)[loc] = new_terrain; }
int flood_fill_board (unsigned short pos, unsigned char color) { if (!on_board (pos) || get_point_board (pos) == color) { return 0; } empty_stack (&parse_stack); int ret_val = 0; unsigned char orig_color = get_point_board (pos); set_point_board (pos, color); ++ret_val; push_pos_stack (&parse_stack, pos); while (pop_pos_stack (&parse_stack, &pos)) { ret_val += flood_fill_helper (NORTH (pos), orig_color, color); ret_val += flood_fill_helper (SOUTH (pos), orig_color, color); ret_val += flood_fill_helper (EAST (pos), orig_color, color); ret_val += flood_fill_helper (WEST (pos), orig_color, color); } return ret_val; }
unsigned short WRAP (unsigned short pos) { int x, y; if (on_board (pos)) { return pos; } else { x = I (pos); y = J (pos); if (x < 0) { x = board_width - 1; } else if ((unsigned int) x >= board_width) { x = 0; } if (y < 0) { y = board_height - 1; } else if ((unsigned int) y >= board_height) { y = 0; } return POS (x, y); } }
bool GoBoard::is_self_atari(int point, int color) // is_self_atari that is , add this point, the group of the move will be in atari(only one liberty) { std::queue<int> q; q.push(point); int lib = 0; int* visited = new int[board_size * board_size]; int cur; while (!q.empty()) { cur = q.front(); visited[cur] = 1; q.pop(); for (int k = 0; k < 4; ++k) { int ai = I(cur) + deltai[k]; int aj = J(cur) + deltaj[k]; if (on_board(ai, aj) && !visited[POS(ai, aj)]) { if (get_board(ai, aj) == color) q.push(POS(ai, aj)); else if (get_board(ai, aj) == EMPTY) { ++lib; visited[POS(ai, aj)] = 1; } } } } delete []visited; return lib == 1; }
void gamemap::set_terrain(const map_location& loc, const t_translation::t_terrain & terrain, const terrain_type_data::tmerge_mode mode, bool replace_if_failed) { if(!on_board_with_border(loc)) { // off the map: ignore request return; } t_translation::t_terrain new_terrain = tdata_->merge_terrains(get_terrain(loc), terrain, mode, replace_if_failed); if(new_terrain == t_translation::NONE_TERRAIN) { return; } if(on_board(loc)) { const bool old_village = is_village(loc); const bool new_village = tdata_->is_village(new_terrain); if(old_village && !new_village) { villages_.erase(std::remove(villages_.begin(),villages_.end(),loc),villages_.end()); } else if(!old_village && new_village) { villages_.push_back(loc); } } tiles_[loc.x + border_size_][loc.y + border_size_] = new_terrain; // Update the off-map autogenerated tiles map_location adj[6]; get_adjacent_tiles(loc,adj); for(int n = 0; n < 6; ++n) { remove_from_border_cache(adj[n]); } }
void move_display (unsigned short pos) { if (!on_board (pos)) { return; } while ((unsigned) I (pos) >= REAL_MAX_X) { cursor_pos = EAST (cursor_pos); cursor_updated (); } while ((unsigned) I (pos) < REAL_MIN_X) { cursor_pos = WEST (cursor_pos); cursor_updated (); } while ((unsigned) J (pos) >= REAL_MAX_Y) { cursor_pos = SOUTH (cursor_pos); cursor_updated (); } while ((unsigned) J (pos) < REAL_MIN_Y) { cursor_pos = NORTH (cursor_pos); cursor_updated (); } }
static void draw_hoshi (unsigned short pos) { /* color and drawmode are already set before this function (all lines and hoshi and stuff are drawn together) */ if (!on_board(pos)) { return; } if ((unsigned) I (pos) < MIN_X || (unsigned) I (pos) >= MAX_X || (unsigned) J (pos) < MIN_Y || (unsigned) J (pos) >= MAX_Y) { return; } if (intersection_size > 8) { rb->lcd_fillrect (pixel_x (pos) + LINE_OFFSET - 1, pixel_y (pos) + LINE_OFFSET - 1, 3, 3); } else { rb->lcd_drawpixel (pixel_x (pos) + LINE_OFFSET - 1, pixel_y (pos) + LINE_OFFSET - 1); rb->lcd_drawpixel (pixel_x (pos) + LINE_OFFSET + 1, pixel_y (pos) + LINE_OFFSET + 1); } }
bool legal_move_board (unsigned short pos, unsigned char color, bool allow_suicide) { /* you can always pass */ if (pos == PASS_POS) { return true; } if (!on_board (pos) || (color != BLACK && color != WHITE)) { return false; } if (pos == ko_pos && color == current_player) { return false; } if (get_point_board (pos) != EMPTY) { return false; } /* don't need to save the current state, because it's always empty since we tested for that above */ set_point_board (pos, color); /* if we have liberties, it can't be illegal */ if (get_liberties_board (pos) > 0 || /* if we can capture something, it can't be illegal */ (get_point_board (NORTH (pos)) == OTHER (color) && !get_liberties_board (NORTH (pos))) || (get_point_board (SOUTH (pos)) == OTHER (color) && !get_liberties_board (SOUTH (pos))) || (get_point_board (EAST (pos)) == OTHER (color) && !get_liberties_board (EAST (pos))) || (get_point_board (WEST (pos)) == OTHER (color) && !get_liberties_board (WEST (pos))) || /* if we're allowed to suicide, only multi-stone suicide is legal (no ruleset allows single-stone suicide that I know of) */ (allow_suicide && (get_point_board (NORTH (pos)) == color || get_point_board (SOUTH (pos)) == color || get_point_board (EAST (pos)) == color || get_point_board (WEST (pos)) == color))) { /* undo our previous set */ set_point_board (pos, EMPTY); return true; } else { /* undo our previous set */ set_point_board (pos, EMPTY); return false; } }
static void draw_stone (unsigned short pos, bool black) { if (!on_board (pos)) { return; } draw_stone_raw (pixel_x (pos), pixel_y (pos), black); }
int anything_near() { int i; for (i = 1; i < MAX_MOBS; i++) if (game->mob[i].type != MOB_NONE && on_board(&game->mob[i])) return true; return false; }
void cave_map_generator::set_terrain(map_location loc, t_translation::t_terrain t) { if (on_board(loc)) { if (t == clear_ && (rand() % 1000) < village_density_) { t = village_; } t_translation::t_terrain& c = map_[loc.x + gamemap::default_border][loc.y + gamemap::default_border]; if(c == clear_ || c == wall_ || c == village_) { c = t; } } }
static int flood_fill_helper (unsigned short pos, unsigned char orig_color, unsigned char color) { if (on_board (pos) && get_point_board (pos) == orig_color) { set_point_board (pos, color); push_pos_stack (&parse_stack, pos); return 1; } return 0; }
/* Generate a move. */ static void generate_move(int *i, int *j, int color) { int moves[MAX_BOARD * MAX_BOARD]; int num_moves = 0; int move; int ai, aj; int k; memset(moves, 0, sizeof(moves)); for (ai = 0; ai < board_size; ai++) for (aj = 0; aj < board_size; aj++) { /* Consider moving at (ai, aj) if it is legal and not suicide. */ if (legal_move(ai, aj, color) && !suicide(ai, aj, color)) { /* Further require the move not to be suicide for the opponent... */ if (!suicide(ai, aj, OTHER_COLOR(color))) moves[num_moves++] = POS(ai, aj); else { /* ...however, if the move captures at least one stone, * consider it anyway. */ for (k = 0; k < 4; k++) { int bi = ai + deltai[k]; int bj = aj + deltaj[k]; if (on_board(bi, bj) && get_board(bi, bj) == OTHER_COLOR(color)) { moves[num_moves++] = POS(ai, aj); break; } } } } } /* Choose one of the considered moves randomly with uniform * distribution. (Strictly speaking the moves with smaller 1D * coordinates tend to have a very slightly higher probability to be * chosen, but for all practical purposes we get a uniform * distribution.) */ if (num_moves > 0) { move = moves[xor_randn(num_moves)]; *i = I(move); *j = J(move); } else { /* But pass if no move was considered. */ *i = -1; *j = -1; } }
static int legal_move(int i, int j, int color) { int other = OTHER_COLOR(color); /* Pass is always legal. */ if (pass_move(i, j)) return 1; /* Already occupied. */ if (get_board(i, j) != EMPTY) return 0; /* Illegal ko recapture. It is not illegal to fill the ko so we must * check the color of at least one neighbor. */ if (i == ko_i && j == ko_j && ((on_board(i - 1, j) && get_board(i - 1, j) == other) || (on_board(i + 1, j) && get_board(i + 1, j) == other))) return 0; return 1; }
void cave_map_generator::build_chamber(map_location loc, std::set<map_location>& locs, size_t size, size_t jagged) { if(size == 0 || locs.count(loc) != 0 || !on_board(loc)) return; locs.insert(loc); map_location adj[6]; get_adjacent_tiles(loc,adj); for(size_t n = 0; n != 6; ++n) { if((rand() % 100) < (100l - static_cast<long>(jagged))) { build_chamber(adj[n],locs,size-1,jagged); } } }
/* Compute final status. This function is only valid to call in a * position where generate_move() would return pass for at least one * color. * * Due to the nature of the move generation algorithm, the final * status of stones can be determined by a very simple algorithm: * * 1. Stones with two or more liberties are alive with territory. * 2. Stones in atari are dead. * * Moreover alive stones are unconditionally alive even if the * opponent is allowed an arbitrary number of consecutive moves. * Similarly dead stones cannot be brought alive even by an arbitrary * number of consecutive moves. * * Seki is not an option. The move generation algorithm would never * leave a seki on the board. * * Comment: This algorithm doesn't work properly if the game ends with * an unfilled ko. If three passes are required for game end, * that will not happen. */ static void compute_final_status(void) { int i, j; int pos; int k; for (pos = 0; pos < board_size * board_size; pos++) final_status[pos] = UNKNOWN; for (i = 0; i < board_size; i++) for (j = 0; j < board_size; j++) if (get_board(i, j) == EMPTY) for (k = 0; k < 4; k++) { int ai = i + deltai[k]; int aj = j + deltaj[k]; if (!on_board(ai, aj)) continue; /* When the game is finished, we know for sure that (ai, aj) * contains a stone. The move generation algorithm would * never leave two adjacent empty vertices. Check the number * of liberties to decide its status, unless it's known * already. * * If we should be called in a non-final position, just make * sure we don't call set_final_status_string() on an empty * vertex. */ pos = POS(ai, aj); if (final_status[pos] == UNKNOWN) { if (get_board(ai, aj) != EMPTY) { if (has_additional_liberty(ai, aj, i, j)) set_final_status_string(pos, ALIVE); else set_final_status_string(pos, DEAD); } } /* Set the final status of the (i, j) vertex to either black * or white territory. */ if (final_status[POS(i, j)] == UNKNOWN) { if ((final_status[pos] == ALIVE) ^ (get_board(ai, aj) == WHITE)) final_status[POS(i, j)] = BLACK_TERRITORY; else final_status[POS(i, j)] = WHITE_TERRITORY; } } }
void set_mark_display (unsigned short pos, unsigned char mark_char) { if (!on_board (pos)) { return; } if ((mark_char == 'b' || mark_char == 'w') && display_marks[I (pos) + J (pos) * board_width] != ' ') { /* don't overwrite real board marks with last-move or variation marks */ return; } display_marks[I (pos) + J (pos) * board_width] = mark_char; }
std::string gamemap::write() const { // Convert the starting positions to a map std::map<int, t_translation::coordinate> starting_positions; for (int i = 0; i < MAX_PLAYERS + 1; ++i) { if (!on_board(startingPositions_[i])) continue; t_translation::coordinate position( startingPositions_[i].x + border_size_ , startingPositions_[i].y + border_size_); starting_positions[i] = position; } // Let the low level converter do the conversion std::ostringstream s; s << t_translation::write_game_map(tiles_, starting_positions) << "\n"; return s.str(); }
static void draw_cursor (unsigned short pos) { if (!on_board (pos)) { return; } #if LCD_DEPTH > 1 rb->lcd_set_foreground (CURSOR_COLOR); #else rb->lcd_set_drawmode (DRMODE_COMPLEMENT); #endif rb->lcd_drawrect (pixel_x (pos), pixel_y (pos), intersection_size, intersection_size); rb->lcd_set_drawmode (DRMODE_SOLID); }
std::string gamemap::write() const { std::map<int, t_translation::coordinate> starting_positions = std::map<int, t_translation::coordinate>(); // Convert the starting positions to a map for(int i = 0; i < MAX_PLAYERS+1; ++i) { if(on_board(startingPositions_[i])) { const struct t_translation::coordinate position = {startingPositions_[i].x + border_size_, startingPositions_[i].y + border_size_}; starting_positions.insert(std::pair<int, t_translation::coordinate>(i, position)); } } // Let the low level convertor do the conversion const std::string& data = t_translation::write_game_map(tiles_, starting_positions); const std::string& header = "border_size=" + lexical_cast<std::string>(border_size_) + "\nusage=" + (usage_ == IS_MAP ? "map" : "mask"); return header + "\n\n" + data; }
static int get_liberties_helper (unsigned short pos, unsigned char orig_color) { if (on_board (pos) && get_point_board (pos) != OTHER (orig_color) && !is_marked (pos)) { make_mark (pos); if (get_point_board (pos) == EMPTY) { return 1; } else { push_pos_stack (&parse_stack, pos); } } return 0; }
/* Does the string at (i, j) have any more liberty than the one at * (libi, libj)? */ static int has_additional_liberty(int i, int j, int libi, int libj) { int pos = POS(i, j); do { int ai = I(pos); int aj = J(pos); int k; for (k = 0; k < 4; k++) { int bi = ai + deltai[k]; int bj = aj + deltaj[k]; if (on_board(bi, bj) && get_board(bi, bj) == EMPTY && (bi != libi || bj != libj)) return 1; } pos = next_stone[pos]; } while (pos != POS(i, j)); return 0; }
/* Does (ai, aj) provide a liberty for a stone at (i, j)? */ static int provides_liberty(int ai, int aj, int i, int j, int color) { /* A vertex off the board does not provide a liberty. */ if (!on_board(ai, aj)) return 0; /* An empty vertex IS a liberty. */ if (get_board(ai, aj) == EMPTY) return 1; /* A friendly string provides a liberty to (i, j) if it currently * has more liberties than the one at (i, j). */ if (get_board(ai, aj) == color) return has_additional_liberty(ai, aj, i, j); /* An unfriendly string provides a liberty if and only if it is * captured, i.e. if it currently only has the liberty at (i, j). */ return !has_additional_liberty(ai, aj, i, j); }
bool GoBoard::is_virtual_eye(int point, int color) { if (!is_surrounded(point, color)) return false; int nopponent = 0; int ai = I(point); int aj = J(point); bool at_edge = false; for (int i = 0; i < 4; i++) { int bi = ai + diag_i[i]; int bj = aj + diag_j[i]; if (!on_board(bi,bj)) { at_edge = true; continue; } if( get_board(bi,bj) == OTHER_COLOR(color) ) { nopponent++; } } if(at_edge) ++nopponent; return nopponent < 2; }
bool is_keep(const map_location& loc) const { return on_board(loc) && is_keep(get_terrain(loc)); }
int gives_healing(const map_location& loc) const { return on_board(loc) ? gives_healing(get_terrain(loc)) : 0; }
bool gamemap::is_castle(const map_location& loc) const { return on_board(loc) && is_castle(get_terrain(loc)); }
bool is_village(const map_location& loc) const { return on_board(loc) && is_village(get_terrain(loc)); }
t_translation::t_terrain gamemap::get_terrain(const map_location& loc) const { if(on_board_with_border(loc)) { return tiles_[loc.x + border_size_][loc.y + border_size_]; } if ( loc == map_location::null_location() ) { return t_translation::NONE_TERRAIN; } const std::map<map_location, t_translation::t_terrain>::const_iterator itor = borderCache_.find(loc); if(itor != borderCache_.end()) return itor->second; // If not on the board, decide based on what surrounding terrain is t_translation::t_terrain items[6]; int number_of_items = 0; map_location adj[6]; get_adjacent_tiles(loc,adj); for(int n = 0; n != 6; ++n) { if(on_board(adj[n])) { items[number_of_items] = tiles_[adj[n].x][adj[n].y]; ++number_of_items; } else { // If the terrain is off map but already in the border cache, // this will be used to determine the terrain. // This avoids glitches // * on map with an even width in the top right corner // * on map with an odd height in the bottom left corner. // It might also change the result on other map and become random, // but the border tiles will be determined in the future, so then // this will no longer be used in the game // (The editor will use this feature to expand maps in a better way). std::map<map_location, t_translation::t_terrain>::const_iterator itor = borderCache_.find(adj[n]); // Only add if it is in the cache and a valid terrain if(itor != borderCache_.end() && itor->second != t_translation::NONE_TERRAIN) { items[number_of_items] = itor->second; ++number_of_items; } } } // Count all the terrain types found, // and see which one is the most common, and use it. t_translation::t_terrain used_terrain; int terrain_count = 0; for(int i = 0; i != number_of_items; ++i) { if(items[i] != used_terrain && !tdata_->is_village(items[i]) && !tdata_->is_keep(items[i])) { const int c = std::count(items+i+1,items+number_of_items,items[i]) + 1; if(c > terrain_count) { used_terrain = items[i]; terrain_count = c; } } } borderCache_.insert(std::pair<map_location, t_translation::t_terrain>(loc,used_terrain)); return used_terrain; }