void GameState::load_all_possible_orders_m()

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_);
}