in dipcc/dipcc/cc/game_state.cc [127:264]
void GameState::load_all_possible_orders_m() {
JCHECK(phase_.phase_type == 'M', "load_all_possible_orders_m non-m phase");
clear_all_possible_orders();
vector<vector<Order>> move_orders_by_dest;
std::set<Loc> global_fleets_visited;
all_possible_orders_.reserve(LOCS.size() + 1);
move_orders_by_dest.resize(LOCS.size() + 1);
unordered_map<Power, set<Loc>> orderable_locations;
// Determine all orders except support-moves
for (const auto &it : units_) {
Unit unit = it.second.unowned();
JCHECK(unit.type != UnitType::NONE, "load_all_possible_orders_m NONE unit");
orderable_locations[it.second.power].insert(unit.loc);
auto &adj = unit.type == UnitType::ARMY ? ADJ_A : ADJ_F;
auto &adj_coasts =
unit.type == UnitType::ARMY ? ADJ_A_ALL_COASTS : ADJ_F_ALL_COASTS;
set<Order> &unit_orders = all_possible_orders_[unit.loc];
// Hold
unit_orders.insert(Order(unit, OrderType::H));
// Non-via moves
for (auto adj_loc : adj[static_cast<size_t>(unit.loc)]) {
move_orders_by_dest[static_cast<int>(adj_loc)].push_back(
Order(unit, OrderType::M, adj_loc));
}
// Support-holds
for (auto adj_loc : adj_coasts[static_cast<size_t>(unit.loc)]) {
const Unit &adj_unit = get_unit(adj_loc).unowned();
if (adj_unit.type != UnitType::NONE) {
unit_orders.insert(Order(unit, OrderType::SH, adj_unit));
// Accept e.g. "F BLA S F BUL" instead of "F BUL/SC"
Loc adj_root = root_loc(adj_unit.loc);
if (adj_root != adj_unit.loc) {
unit_orders.insert(
Order(unit, OrderType::SH, {adj_unit.type, adj_root}));
}
}
}
// Convoys + moves via
if (unit.type == UnitType::FLEET && is_water(unit.loc)) {
std::set<Unit> adj_armies;
std::set<Unit> adj_fleets_todo{unit};
std::set<Unit> local_fleets_visited;
std::set<Loc> adj_coast_locs;
while (adj_fleets_todo.size() > 0) {
// Pop fleet to consider
auto fleet_it = adj_fleets_todo.begin();
Unit fleet = *fleet_it;
adj_fleets_todo.erase(fleet_it);
local_fleets_visited.insert(fleet);
global_fleets_visited.insert(fleet.loc);
for (Loc adj_loc : ADJ_F_ALL_COASTS[static_cast<size_t>(fleet.loc)]) {
if (!is_water(adj_loc)) {
// Possible destination loc
adj_coast_locs.insert(root_loc(adj_loc));
}
Unit adj_unit = this->get_unit(adj_loc).unowned();
if (adj_unit.type == UnitType::FLEET && is_water(adj_loc) &&
global_fleets_visited.find(adj_loc) ==
global_fleets_visited.end()) {
// Adjacent fleet that can chain convoy
adj_fleets_todo.insert(adj_unit);
} else if (adj_unit.type == UnitType::ARMY) {
// Possible source army to convoy
adj_armies.insert(adj_unit);
}
}
}
// Each adj_army can be convoyed to each adj_coast_loc via each
// local_fleets_visited
for (const Unit &army : adj_armies) {
for (Loc dest : adj_coast_locs) {
if (dest == army.loc) {
continue;
}
move_orders_by_dest[static_cast<int>(dest)].push_back(
Order(army, OrderType::M, dest, true));
for (const Unit &convoy_fleet : local_fleets_visited) {
all_possible_orders_[convoy_fleet.loc].insert(
Order(convoy_fleet, OrderType::C, army, dest));
}
}
}
}
}
// Move move_orders to all_possible_orders_
for (const auto &move_orders : move_orders_by_dest) {
for (const Order &order : move_orders) {
all_possible_orders_[order.get_unit().loc].insert(order);
}
}
// Determine support moves
for (const auto &it : units_) {
auto &unit = it.second;
auto &adj_coasts =
unit.type == UnitType::ARMY ? ADJ_A_ALL_COASTS : ADJ_F_ALL_COASTS;
set<Order> &unit_orders = all_possible_orders_[unit.loc];
for (Loc dest : adj_coasts[static_cast<size_t>(unit.loc)]) {
if (dest == unit.loc) {
continue; // can't support self-dislodge
}
for (const Order &move_order :
move_orders_by_dest[static_cast<int>(dest)]) {
if (move_order.get_unit().loc == unit.loc) {
continue; // can't support own move
}
unit_orders.insert(
Order(unit, OrderType::SM, move_order.get_unit(), dest));
// Accept e.g. "F BLA S F CON - BUL" instead of "BUL/SC"
Loc dest_root = root_loc(dest);
if (dest_root != dest) {
unit_orders.insert(
Order(unit, OrderType::SM, move_order.get_unit(), dest_root));
}
}
}
}
copy_sorted_root_locs(orderable_locations, orderable_locations_);
}