diff --git a/r2sol.cc b/r2sol.cc index 9a08fde60fee5a7e030aa12ee7f4a10a8d4caffb..ad0a37f82df36b6ed49908b44603b7da0f46b1ed 100644 --- a/r2sol.cc +++ b/r2sol.cc @@ -33,7 +33,7 @@ using namespace std; #define TMAX 2567 #define MAX_NUM_THREADS 1//3//4 #define MAX_CTURNS 5 -#define INF 1000000000 +#define INF 10000 #define ZERO 0.000001 #define ONE 0.999999 #define USE_SPACING_TO_AVOID_DEADLOCKS 1 @@ -751,7 +751,7 @@ int tend_ongoing_move[NMAX]; bool OverlapsOngoingMove(int t1, int t2, int node, const short int covered_by[][MAXNODES], const int is_covered[][MAXNODES], int is_covered_idx, const Path tmp_path[], short int tmax_at_poz_node[]) { if (!USE_SPACING_TO_AVOID_DEADLOCKS) return false; - //***if (t1 < tend_ongoing_move[node]) return true; + ///***if (t1 < tend_ongoing_move[node]) return true; if (t2 <= tend_ongoing_move[node]) return true; //***const int min_tstart = t2;//USE_STRICT_SPACING_TO_AVOID_DEADLOCKS ? t2 : t1; @@ -2376,4 +2376,19 @@ int main() { SOLVE::GetMoves("1", true); return 0; } - +/* +0 105 77.7777777778 -54551.6666667190 3 2.2222222222 2.2222222222 +1 106 75.7142857143 -42933.5833333511 5 3.5714285714 2.8968253968 +2 55 45.4545454545 -47614.0000000257 -7 -5.7851239669 0.0028422756 +3 80 100.0000000000 -12752.6666666697 0 0.0000000000 0.0021317067 +4 104 67.0967741935 -95937.8333332090 7 4.5161290323 0.9049311718 +5 123 93.8931297710 -44463.0833333478 -3 -2.2900763359 0.3724299205 +6 130 75.1445086705 -70924.3333333715 -9 -5.2023121387 -0.4239618022 +7 93 68.3823529412 -46478.5000000219 12 8.8235294118 0.7319745995 +8 79 65.8333333333 -42068.4166666825 -3 -2.5000000000 0.3728663107 +9 64 41.8300653595 -78048.1666666569 3 1.9607843137 0.5316581110 +10 87 51.7857142857 -92886.0833332524 -1 -0.5952380952 0.4292130013 +11 90 86.5384615385 -18690.0833333352 -4 -3.8461538462 0.0729324307 +12 70 63.6363636364 -48049.9166666936 4 3.6363636364 0.3470425234 +13 112 70.4402515723 -58866.8333333958 -14 -8.8050314465 -0.3066770458 +*/ diff --git a/run.sh b/run.sh index adcbcbb8d195c84e80246eb43a107c21edd8c6a8..be73855558011e565b4424ad4fb274cab937d8ac 100755 --- a/run.sh +++ b/run.sh @@ -6,8 +6,11 @@ python setup.py build_ext cp -f build/lib.linux-x86_64-3.7/_r2sol.cpython-37m-x86_64-linux-gnu.so ./_r2sol.so rm -f -r build -python run.py -#python run_local.py +if [ "$1" == "local" ]; then + python run_local.py +else + python run.py +fi rm -f -r __pycache__ rm -f _r2sol.so diff --git a/run_local.py b/run_local.py index c784b2e4b6f2fe4ac50f1895e85901973779d0eb..8e4f303e6be7f125a42b5ac2b42db457850dc413 100644 --- a/run_local.py +++ b/run_local.py @@ -25,8 +25,8 @@ def GetTestParams(tid): return (seed, width, height, nr_trains, nr_cities, max_rails_between_cities, max_rails_in_cities, malfunction_rate, malfunction_min_duration, malfunction_max_duration) def ShouldRunTest(tid): - #return tid >= 22 - #return tid >= 6 + #return tid == 13 + return tid >= 14 return True DEFAULT_SPEED_RATIO_MAP = {1.: 0.25, diff --git a/tmp-scores.txt b/tmp-scores.txt index 0e4c8a289416e998025ba7222c05c5a80ede1d63..330b58bef48a89eb77919f561e1244451078392d 100644 --- a/tmp-scores.txt +++ b/tmp-scores.txt @@ -1,2 +1,7 @@ -0 105 77.7777777778 -54551.6666667190 3 2.2222222222 2.2222222222 -1 106 75.7142857143 -42933.5833333511 5 3.5714285714 2.8968253968 +14 91 73.9837398374 -53871.5000000432 9 7.3170731707 7.3170731707 +15 79 41.5789473684 -141963.1666665719 4 2.1052631579 4.7111681643 +16 44 39.2857142857 -79070.4999999909 -8 -7.1428571429 0.7598263953 +17 101 70.1388888889 -59876.9166667267 9 6.2500000000 2.1323697964 +18 83 45.1086956522 -65137.1666667329 0 0.0000000000 1.7058958372 +19 68 85.0000000000 -29969.6666666545 -3 -3.7500000000 0.7965798643 +20 120 91.6030534351 -42452.9166666759 1 0.7633587786 0.7918339949 diff --git a/x-r2sol.cc b/x-r2sol.cc new file mode 100644 index 0000000000000000000000000000000000000000..df84032d0b904e32d8e8e1df13aeb9c190ee906c --- /dev/null +++ b/x-r2sol.cc @@ -0,0 +1,2379 @@ +#include "r2sol.h" +#undef NDEBUG +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <algorithm> +#include <memory> +#include <mutex> +#include <thread> + +#include <algorithm> +#include <vector> + +using namespace std; + +#define DEBUG_LEVEL 0//2 + +#define DBG(debug_level, ...) \ + { \ + if (debug_level <= DEBUG_LEVEL) { \ + fprintf(stderr, __VA_ARGS__); \ + fflush(stderr); \ + } \ + } + +#define HMAX 151 +#define NMAX 201 +#define MAXNODES 3000 +#define TMAX 2567 +#define MAX_NUM_THREADS 1//3//4 +#define MAX_CTURNS 5 +#define INF 1000000000 +#define ZERO 0.000001 +#define ONE 0.999999 +#define USE_SPACING_TO_AVOID_DEADLOCKS 1 +#define USE_STRICT_SPACING_TO_AVOID_DEADLOCKS 0 +#define MIN_TINIT_FOR_SAVE_DATA_FOR_REPLAY 1000000 + +class Xor128 { + public: + void reset(unsigned int seed) { + xx = seed; + yy = 362436069; + zz = 521288629; + uu = 786232308; + } + + inline unsigned int rand() { + unsigned int t = (xx ^ (xx << 11)); + xx = yy; + yy = zz; + zz = uu; + return (uu = (uu ^ (uu >> 19)) ^ (t ^ (t >> 8))); + } + + private: + unsigned int xx, yy, zz, uu; +}; + +double GetTime() { + return 1.0 * clock() / CLOCKS_PER_SEC; +} + +const int DROW[4] = {-1, 0, +1, 0}; +const int DCOL[4] = {0, +1, 0, -1}; + +namespace SOLVE { + +FILE* fin; +char fname[128]; +int H, W, T, TEST, N, TINIT; +double TSTART; + +struct Node { + int row, col; +} node[MAXNODES]; + +int cell_to_node[HMAX][HMAX], nnodes; +int next[MAXNODES][4][4]; +int revnext[MAXNODES][4][4]; + +int target_node_agents[MAXNODES][NMAX], num_target_node_agents[MAXNODES]; + +void ReadTransitionsMap() { + int has_transition_map; + fscanf(fin, "%d", &has_transition_map); + if (!has_transition_map) return; + fscanf(fin, "%d %d", &H, &W); + DBG(2, "[ReadTransitionsMap] has_transition_map=%d H=%d W=%d\n", has_transition_map, H, W); + assert(1 <= H && H < HMAX && 1 <= W && W < HMAX); + for (int i = 0; i < H; ++i) { + for (int j = 0; j < W; ++j) { + cell_to_node[i][j] = -2; + } + } + nnodes = 0; + T = TMAX - 7; + //T = 8 * (H + W + 20); + int row, col, o1, o2, num_transitions = 0; + while (fscanf(fin, "%d %d %d %d", &row, &col, &o1, &o2) == 4) { + if (row < 0 || col < 0 || o1 < 0 || o2 < 0) break; + DBG(4, "row=%d/%d col=%d/%d o1=%d o2=%d nnodes=%d\n", row, H, col, W, o1, o2, nnodes); + assert(0 <= row && row < H); + assert(0 <= col && col < W); + assert(0 <= o1 && o1 < 4); + assert(0 <= o2 && o2 < 4); + if (cell_to_node[row][col] < 0) { + assert(nnodes < MAXNODES); + auto& new_node = node[nnodes]; + new_node.row = row; + new_node.col = col; + auto& next_nnodes = next[nnodes]; + auto& revnext_nnodes = revnext[nnodes]; + for (int tmpo1 = 0; tmpo1 <= 3; ++tmpo1) { + auto& next_nnodes_tmpo1 = next_nnodes[tmpo1]; + auto& revnext_nnodes_tmpo1 = revnext_nnodes[tmpo1]; + for (int tmpo2 = 0; tmpo2 <= 3; ++tmpo2) { + next_nnodes_tmpo1[tmpo2] = revnext_nnodes_tmpo1[tmpo2] = -1; + } + } + num_target_node_agents[nnodes] = 0; + cell_to_node[row][col] = nnodes++; + } + const auto& v1 = cell_to_node[row][col]; + const int rnext = row + DROW[o2], cnext = col + DCOL[o2]; + assert(0 <= rnext && rnext < H); + assert(0 <= cnext && cnext < W); + if (cell_to_node[rnext][cnext] < 0) { + assert(nnodes < MAXNODES); + auto& new_node = node[nnodes]; + new_node.row = rnext; + new_node.col = cnext; + auto& next_nnodes = next[nnodes]; + auto& revnext_nnodes = revnext[nnodes]; + for (int tmpo1 = 0; tmpo1 <= 3; ++tmpo1) { + auto& next_nnodes_tmpo1 = next_nnodes[tmpo1]; + auto& revnext_nnodes_tmpo1 = revnext_nnodes[tmpo1]; + for (int tmpo2 = 0; tmpo2 <= 3; ++tmpo2) { + next_nnodes_tmpo1[tmpo2] = revnext_nnodes_tmpo1[tmpo2] = -1; + } + } + num_target_node_agents[nnodes] = 0; + cell_to_node[rnext][cnext] = nnodes++; + } + const auto& v2 = cell_to_node[rnext][cnext]; + next[v1][o1][o2] = v2; + revnext[v2][o2][o1] = v1; + ++num_transitions; + } + DBG(0, "[ReadTransitionsMap] num_transitions=%d nnodes=%d/%d\n", num_transitions, nnodes, H * W); +} + +enum HowIGotHere { + INVALID = -1, + OUTSIDE_SRC = 0, + ENTERED_SRC = 1, + STARTED_MOVING = 2, + CONTINUED_MOVING = 3, + WAITED = 4, + MALFUNCTIONED = 5, +}; + +enum RailAgentStatus { + READY_TO_DEPART = 0, + ACTIVE = 1, + DONE = 2, + DONE_REMOVED = 3, +}; + +enum RailEnvActions { + DO_NOTHING = 0, + MOVE_LEFT = 1, + MOVE_FORWARD = 2, + MOVE_RIGHT = 3, + STOP_MOVING = 4, +}; + +struct PathElem { + int node, o, moving_to_node, moving_to_o, num_partial_turns; + HowIGotHere how_i_got_here; + + void PrintDebug(int t = -1) { + DBG(0, "t=%d poz=(%d %d) moving_to=(%d %d) npturns=%d how=%d\n", t, node, o, moving_to_node, moving_to_o, num_partial_turns, how_i_got_here); + } +}; + +struct Path { + struct PathElem p[TMAX]; + int tmax; +}; + +void CopyPath(const Path& src, Path* dst) { + dst->tmax = src.tmax; + if (src.tmax >= TINIT) memcpy(&dst->p[TINIT], &src.p[TINIT], (src.tmax - TINIT + 1) * sizeof(PathElem)); +} + +struct Agent { + int aid, poz_row, poz_col, poz_o, poz_node, target_row, target_col, target_node, malfunc, nr_malfunc, cturns; + double speed, poz_frac; + int inside_poz, fresh_malfunc, moving_to_node, moving_to_o; + RailAgentStatus status; +} agent[NMAX], tmp_agent; + +int cturns_agents[MAX_CTURNS][NMAX], num_cturns_agents[MAX_CTURNS]; + +int MAX_DONE_AGENTS; +double MIN_COST; +struct Path path[NMAX], ipath[NMAX]; + +int checkpoints[NMAX][TMAX], checkpoints_o[NMAX][TMAX], checkpoints_t[NMAX][TMAX], checkpoints_cnt[NMAX][TMAX], num_checkpoints[NMAX], tcheckpoints[NMAX][TMAX], next_checkpoint[NMAX]; + +vector<pair<int, int>> ipath_visiting_order[MAXNODES]; + +void RepopulateVisitingOrders() { + for (int node = 0; node < nnodes; ++node) ipath_visiting_order[node].clear(); + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + const auto& checkpoints_aid = checkpoints[aid]; + const auto& checkpoints_t_aid = checkpoints_t[aid]; + const auto& num_checkpoints_aid = num_checkpoints[aid]; + for (int idx = next_checkpoint[aid]; idx < num_checkpoints_aid; ++idx) + ipath_visiting_order[checkpoints_aid[idx]].push_back({checkpoints_t_aid[idx], aid}); + } + for (int node = 0; node < nnodes; ++node) { + auto& ipath_visiting_order_node = ipath_visiting_order[node]; + sort(ipath_visiting_order_node.begin(), ipath_visiting_order_node.end()); + } +} + +short int covered_by[MAX_NUM_THREADS][TMAX][MAXNODES]; +int is_covered[MAX_NUM_THREADS][TMAX][MAXNODES], is_covered_idx[MAX_NUM_THREADS], can_reach_idx[MAX_NUM_THREADS], can_reach[MAX_NUM_THREADS][TMAX][MAXNODES][4]; +short int can_reach_with_t1[MAX_NUM_THREADS][TMAX][MAXNODES][4]; +short int tmax_at_poz_node[MAX_NUM_THREADS][NMAX]; + +void CheckAgent(int aid) { + auto& agent_aid = agent[aid]; + const auto& path = ipath[aid]; + if (path.tmax < TINIT) { + assert(agent_aid.status == DONE_REMOVED); + return; + } + + const auto& path_elem = path.p[TINIT]; + if (path_elem.how_i_got_here == OUTSIDE_SRC) { + assert(!agent_aid.inside_poz); + assert(agent_aid.status == READY_TO_DEPART); + return; + } + + if (agent_aid.inside_poz) { + auto& next_checkpoint_aid = next_checkpoint[aid]; + assert(next_checkpoint_aid < num_checkpoints[aid]); + if (checkpoints[aid][next_checkpoint_aid] == agent_aid.poz_node) { + assert(checkpoints_o[aid][next_checkpoint_aid] == agent_aid.poz_o); + ++next_checkpoint_aid; + } + } + + const auto& is_covered_idx_0 = is_covered_idx[0]; + auto& is_covered_0 = is_covered[0]; + + if (agent_aid.fresh_malfunc) { + if (path_elem.how_i_got_here == STARTED_MOVING || path_elem.how_i_got_here == CONTINUED_MOVING) { + assert(0 <= agent_aid.moving_to_node && agent_aid.moving_to_node < nnodes); + assert(0 <= agent_aid.moving_to_o && agent_aid.moving_to_o < nnodes); + if (path_elem.num_partial_turns >= 1) { + assert(agent_aid.poz_node == path_elem.node); + assert(agent_aid.poz_o == path_elem.o); + assert(fabs(agent_aid.poz_frac - (path_elem.num_partial_turns - 1) * agent_aid.speed) < ZERO); + } else { + assert(next[agent_aid.poz_node][agent_aid.poz_o][path_elem.o] == path_elem.node); + assert(agent_aid.poz_frac >= (agent_aid.cturns - 1) * agent_aid.speed - ZERO); + } + } else { + assert(agent_aid.poz_node == path_elem.node); + assert(agent_aid.poz_o == path_elem.o); + assert(fabs(agent_aid.poz_frac - path_elem.num_partial_turns * agent_aid.speed) < ZERO); + } + } else if (is_covered_0[TINIT][path_elem.node] == is_covered_idx_0) { + assert((path_elem.how_i_got_here == STARTED_MOVING || path_elem.how_i_got_here == CONTINUED_MOVING || path_elem.how_i_got_here == ENTERED_SRC) && path_elem.num_partial_turns == 0); + if (path_elem.how_i_got_here == ENTERED_SRC) assert(!agent_aid.inside_poz); + else { + assert(agent_aid.inside_poz); + assert(agent_aid.poz_frac >= ONE); + assert(agent_aid.moving_to_node == path_elem.node); + assert(agent_aid.moving_to_o == path_elem.o); + } + } else if (path.tmax == TINIT) { + assert(!agent_aid.inside_poz); + assert(agent_aid.status == DONE_REMOVED); + assert(agent_aid.moving_to_node == path_elem.node); + agent_aid.moving_to_node = agent_aid.moving_to_o = -1; + } else { + assert(agent_aid.inside_poz); + assert(agent_aid.poz_node == path_elem.node); + assert(agent_aid.poz_o == path_elem.o); + assert(fabs(agent_aid.poz_frac - path_elem.num_partial_turns * agent_aid.speed) < ZERO); + if (0 <= agent_aid.moving_to_node && agent_aid.moving_to_node < nnodes && path_elem.num_partial_turns == 0 && + (path_elem.how_i_got_here == STARTED_MOVING || path_elem.how_i_got_here == CONTINUED_MOVING)) { + assert(agent_aid.moving_to_node == path_elem.node); + assert(agent_aid.moving_to_o == path_elem.o); + agent_aid.moving_to_node = agent_aid.moving_to_o = -1; + } + if (path_elem.num_partial_turns == 0 && (path_elem.how_i_got_here == STARTED_MOVING || path_elem.how_i_got_here == CONTINUED_MOVING)) + assert(agent_aid.moving_to_node < 0); + } + + if (agent_aid.inside_poz) is_covered_0[TINIT][agent_aid.poz_node] = is_covered_idx_0; +} + +bool reschedule; +int num_done_agents, num_planned, num_reschedules, num_adjust_ipaths; +int num_adjust_ipaths_without_full_plan_regeneration; + +int important_row[2 * NMAX], important_col[2 * NMAX]; +char visited[2 * NMAX]; + +void DFSMarkCities(int aid) { + visited[aid] = 1; + static const int kMaxDiff = 2; + for (int aid2 = 0; aid2 < 2 * N; ++aid2) { + if (visited[aid2]) continue; + if (abs(important_row[aid] - important_row[aid2]) <= kMaxDiff && abs(important_col[aid] - important_col[aid2]) <= kMaxDiff) + DFSMarkCities(aid2); + } +} + +void EstimateT() { + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + important_row[2 * aid] = agent_aid.poz_row; + important_col[2 * aid] = agent_aid.poz_col; + important_row[2 * aid + 1] = agent_aid.target_row; + important_col[2 * aid + 1] = agent_aid.target_col; + visited[2 * aid] = visited[2 * aid + 1] = 0; + } + int num_cities = 0; + for (int aid = 0; aid < 2 * N; ++aid) { + if (visited[aid]) continue; + DFSMarkCities(aid); + ++num_cities; + } + if (1.0 * N / num_cities < 20.0 - 1e-6) + TEST = (int)(8.0 * (H + W + 1.0 * N / num_cities)); + else + TEST = 8 * (H + W + 20); + DBG(0, "(estimated) num_cities=%d TEST=%d\n", num_cities, TEST); +} + +void ReadAgentsData(bool replay_mode = false) { + fscanf(fin, "%d %d", &N, &TINIT); + DBG(2, "[ReadAgentsData] N=%d TINIT=%d/%d\n", N, TINIT, T); + assert(1 <= N && N < NMAX); + if (replay_mode) { + fscanf(fin, "%d %d %d", &num_reschedules, &num_planned, &num_adjust_ipaths_without_full_plan_regeneration); + reschedule = TINIT == 0; + } else if (TINIT == 0) { + reschedule = true; + num_reschedules = 0; + num_adjust_ipaths = 0; + num_adjust_ipaths_without_full_plan_regeneration = 0; + num_planned = N; + } else reschedule = false; + if (num_planned == 0) return; + for (int cturns = 0; cturns < MAX_CTURNS; ++cturns) num_cturns_agents[cturns] = 0; + num_done_agents = 0; + num_planned = TINIT == 0 ? N : 0; + ++is_covered_idx[0]; + for (int aid = 0; aid < N; ++aid) { + int has_path_data = 0, has_moving_to_data = 0, status = -1; + fscanf(fin, "%d %d %d %d %d %d %lf %lf %d %d %d %d %d %d", &tmp_agent.aid, &tmp_agent.poz_row, &tmp_agent.poz_col, &tmp_agent.poz_o, &tmp_agent.target_row, &tmp_agent.target_col, &tmp_agent.speed, &tmp_agent.poz_frac, &tmp_agent.malfunc, &tmp_agent.nr_malfunc, &status, &tmp_agent.fresh_malfunc, &has_moving_to_data, &has_path_data); + assert(aid == tmp_agent.aid); + assert(status == READY_TO_DEPART || status == ACTIVE || status == DONE || status == DONE_REMOVED); + tmp_agent.status = (RailAgentStatus) status; + tmp_agent.poz_node = cell_to_node[tmp_agent.poz_row][tmp_agent.poz_col]; + tmp_agent.target_node = cell_to_node[tmp_agent.target_row][tmp_agent.target_col]; + tmp_agent.cturns = 0; + while (tmp_agent.cturns * tmp_agent.speed < ONE) ++tmp_agent.cturns; + tmp_agent.inside_poz = tmp_agent.status != READY_TO_DEPART && tmp_agent.status != DONE_REMOVED; + + auto& agent_aid = agent[aid]; + if (has_moving_to_data) { + int row, col; + fscanf(fin, "%d %d %d", &row, &col, &tmp_agent.moving_to_o); + if (row < 0 && col < 0) { + tmp_agent.moving_to_node = -1; + assert(tmp_agent.moving_to_o < 0); + } else { + tmp_agent.moving_to_node = cell_to_node[row][col]; + assert(0 <= tmp_agent.moving_to_node && tmp_agent.moving_to_node < nnodes); + assert(0 <= tmp_agent.moving_to_o && tmp_agent.moving_to_o <= 3); + } + } else if (TINIT == 0) tmp_agent.moving_to_node = tmp_agent.moving_to_o = -1; + else { + tmp_agent.moving_to_node = agent_aid.moving_to_node; + tmp_agent.moving_to_o = agent_aid.moving_to_o; + } + + if (TINIT >= 1) { + if (!replay_mode) tmp_agent.fresh_malfunc |= (tmp_agent.nr_malfunc > agent_aid.nr_malfunc); + reschedule |= tmp_agent.fresh_malfunc; + if (tmp_agent.status == DONE_REMOVED) ++num_done_agents; + } + memcpy(&agent_aid, &tmp_agent, sizeof(Agent)); + + if (replay_mode || TINIT == 0) target_node_agents[agent_aid.target_node][num_target_node_agents[agent_aid.target_node]++] = aid; + + auto& ipath_aid = ipath[aid]; + if (has_path_data) { + fscanf(fin, "%d", &ipath_aid.tmax); + for (int t = TINIT; t <= ipath_aid.tmax; ++t) { + auto& new_path_elem = ipath_aid.p[t]; + int poz_row, poz_col, moving_to_row, moving_to_col, how_i_got_here = -1; + fscanf(fin, "%d %d %d %d %d %d %d %d", &poz_row, &poz_col, &new_path_elem.o, &moving_to_row, &moving_to_col, &new_path_elem.moving_to_o, &new_path_elem.num_partial_turns, &how_i_got_here); + assert(0 <= poz_row && poz_row < H && 0 <= poz_col && poz_col < W); + new_path_elem.node = cell_to_node[poz_row][poz_col]; + assert(0 <= new_path_elem.node && new_path_elem.node < nnodes); + if (moving_to_row >= 0 && moving_to_col >= 0) + new_path_elem.moving_to_node = cell_to_node[moving_to_row][moving_to_col]; + else new_path_elem.moving_to_node = -1; + assert(how_i_got_here == OUTSIDE_SRC || how_i_got_here == ENTERED_SRC || how_i_got_here == STARTED_MOVING || how_i_got_here == CONTINUED_MOVING || how_i_got_here == WAITED || how_i_got_here == MALFUNCTIONED); + new_path_elem.how_i_got_here = (HowIGotHere) how_i_got_here; + } + auto& num_checkpoints_aid = num_checkpoints[aid]; + fscanf(fin, "%d", &num_checkpoints_aid); + ++num_checkpoints_aid; + auto& checkpoints_aid = checkpoints[aid]; + auto& checkpoints_o_aid = checkpoints_o[aid]; + auto& checkpoints_t_aid = checkpoints_t[aid]; + next_checkpoint[aid] = 1; + for (int cid = 1; cid < num_checkpoints_aid; ++cid) { + int row, col; + fscanf(fin, "%d %d %d %d", &row, &col, &checkpoints_o_aid[cid], &checkpoints_t_aid[cid]); + checkpoints_aid[cid] = cell_to_node[row][col]; + assert(0 <= checkpoints_aid[cid] && checkpoints_aid[cid] < nnodes); + } + if (agent_aid.inside_poz) { + checkpoints_aid[0] = agent_aid.poz_node; + checkpoints_o_aid[0] = agent_aid.poz_o; + } else { + checkpoints_aid[0] = checkpoints_o_aid[0] = -1; + } + checkpoints_t_aid[0] = TINIT; + } else if (TINIT == 0) { + // Initialize the path with fully waiting outside. + ipath_aid.tmax = T; + for (int t = 0; t <= T; ++t) { + auto& new_path_elem = ipath_aid.p[t]; + new_path_elem.node = agent_aid.poz_node; + new_path_elem.o = agent_aid.poz_o; + new_path_elem.moving_to_node = new_path_elem.moving_to_o = -1; + new_path_elem.num_partial_turns = 0; + new_path_elem.how_i_got_here = OUTSIDE_SRC; + } + num_checkpoints[aid] = next_checkpoint[aid] = 1; + checkpoints[aid][0] = checkpoints_o[aid][0] = -1; + } + + if (ipath_aid.tmax >= TINIT && ipath_aid.p[ipath_aid.tmax].node == agent_aid.target_node && agent_aid.status != DONE_REMOVED) + ++num_planned; + + DBG(2, "\nTINIT=%d aid=%d: poz=(%d %d %d):%d inside_poz=%d target=(%d %d):%d moving_to_node=%d:(%d %d) moving_to_o=%d cturns=%d speed=%.6lf poz_frac=%.6lf malf=%d nr_malf=%d status=%d fresh_malf=%d\n", TINIT, agent_aid.aid, agent_aid.poz_row, agent_aid.poz_col, agent_aid.poz_o, agent_aid.poz_node, agent_aid.inside_poz, agent_aid.target_row, agent_aid.target_col, agent_aid.target_node, agent_aid.moving_to_node, node[agent_aid.moving_to_node].row, node[agent_aid.moving_to_node].col, agent_aid.moving_to_o, agent_aid.cturns, agent_aid.speed, agent_aid.poz_frac, agent_aid.malfunc, agent_aid.nr_malfunc, agent_aid.status, agent_aid.fresh_malfunc); + + assert(0 <= agent_aid.poz_row && agent_aid.poz_row < H); + assert(0 <= agent_aid.poz_col && agent_aid.poz_col < W); + assert(0 <= agent_aid.poz_node && agent_aid.poz_node < nnodes); + assert(0 <= agent_aid.poz_o && agent_aid.poz_o <= 3); + assert(0 <= agent_aid.target_row && agent_aid.target_row < H); + assert(0 <= agent_aid.target_col && agent_aid.target_col < W); + assert(0 <= agent_aid.target_node && agent_aid.target_node < nnodes); + assert(agent_aid.cturns < MAX_CTURNS); + cturns_agents[agent_aid.cturns][num_cturns_agents[agent_aid.cturns]++] = aid; + + if (TINIT >= 1) { + CheckAgent(aid); + DBG(2, " still moving_to_node=%d:(%d %d) moving_to_o=%d\n", agent_aid.moving_to_node, node[agent_aid.moving_to_node].row, node[agent_aid.moving_to_node].col, agent_aid.moving_to_o); + } + } + + if (TINIT == 0 || replay_mode) { + if (TINIT == 0) EstimateT(); + else fscanf(fin, "%d", &T); + } + + //exit(1); +} + +struct ShortestPathQueueElement { + int node, o; +} qshpath[MAXNODES * 4]; + +int dmin[NMAX][MAXNODES][4], prev_node[NMAX][MAXNODES][4], prev_o[NMAX][MAXNODES][4]; + +void ComputeShortestPaths(int aid) { + auto& dmin_aid = dmin[aid]; + auto& prev_node_aid = prev_node[aid]; + auto& prev_o_aid = prev_o[aid]; + for (int node = 0; node < nnodes; ++node) { + auto& dmin_aid_node = dmin_aid[node]; + for (int o = 0; o <= 3; ++o) dmin_aid_node[o] = INF; + } + int qli = 0, qls = -1; + const auto& agent_aid = agent[aid]; + for (int o = 0; o <= 3; ++o) { + auto& new_queue_elem = qshpath[++qls]; + new_queue_elem.node = agent_aid.target_node; + new_queue_elem.o = o; + dmin_aid[agent_aid.target_node][o] = 0; + } + while (qli <= qls) { + const auto& qelem = qshpath[qli++]; + const auto& node1 = qelem.node; + const auto& o1 = qelem.o; + const int dnew = dmin_aid[node1][o1] + agent_aid.cturns; + const auto& revnext_node1_o1 = revnext[node1][o1]; + for (int o2 = 0; o2 <= 3; ++o2) { + const auto& node2 = revnext_node1_o1[o2]; + if (node2 < 0) continue; + if (dnew < dmin_aid[node2][o2]) { + dmin_aid[node2][o2] = dnew; + auto& new_queue_elem = qshpath[++qls]; + new_queue_elem.node = node2; + new_queue_elem.o = o2; + prev_node_aid[node2][o2] = node1; + prev_o_aid[node2][o2] = o1; + } + } + } +} + +void ComputeShortestPaths() { + for (int aid = 0; aid < N; ++aid) ComputeShortestPaths(aid); +} + +Xor128 xor128[MAX_NUM_THREADS]; +short int perm[MAX_NUM_THREADS][NMAX]; +char pused[MAX_NUM_THREADS][NMAX]; + +#define MAX_HEAP_SIZE 100000 + +struct HeapElement { + short int t, node, t1, est_tmin; + char o; + + bool IsSmaller(const HeapElement& other) const { + return est_tmin < other.est_tmin || (est_tmin == other.est_tmin && t1 > other.t1); + } +} heap[MAX_NUM_THREADS][/*TMAX * MAXNODES * 4*/MAX_HEAP_SIZE]; + +int heap_size[MAX_NUM_THREADS]; + +inline void Swap(HeapElement h[], int poza, int pozb) { + auto& a = h[poza]; + auto& b = h[pozb]; + const HeapElement tmp = a; + a = b; + b = tmp; +} + +inline void PushUp(HeapElement h[], int poz) { + while (poz > 1) { + const int parent = poz >> 1; + auto& h_poz = h[poz]; + auto& h_parent = h[parent]; + if (h_poz.IsSmaller(h_parent)) { + Swap(h, poz, parent); + poz = parent; + } else + break; + } +} + +inline void PushDown(HeapElement h[], int& hsize, int poz) { + while (1) { + const int lchild = poz << 1; + if (lchild > hsize) break; + auto& h_lchild = h[lchild]; + auto& h_poz = h[poz]; + const int rchild = lchild + 1; + if (rchild <= hsize) { + auto& h_rchild = h[rchild]; + if (h_lchild.IsSmaller(h_rchild)) { + if (h_lchild.IsSmaller(h_poz)) { + Swap(h, lchild, poz); + poz = lchild; + } else + break; + } else { + if (h_rchild.IsSmaller(h_poz)) { + Swap(h, rchild, poz); + poz = rchild; + } else + break; + } + } else { + if (h_lchild.IsSmaller(h_poz)) { + Swap(h, lchild, poz); + poz = lchild; + } else + break; + } + } +} + +inline void InsertIntoHeap(HeapElement h[], int& hsize, int t, int node, int o, int t1, int est_tmin) { + assert(hsize< MAX_HEAP_SIZE); + auto& new_element = h[++hsize]; + new_element.t = t; + new_element.node = node; + new_element.o = o; + new_element.t1 = t1; + new_element.est_tmin = est_tmin; + PushUp(h, hsize); +} + +inline void ExtractMinFromHeap(HeapElement h[], int& hsize, int& t, int& node, int& o, int& t1) { + assert(hsize >= 1); + auto& min_element = h[1]; + t = min_element.t; + node = min_element.node; + o = min_element.o; + t1 = min_element.t1; + min_element = h[--hsize]; + if (hsize >= 1) PushDown(h, hsize, 1); +} + +struct Path tmp_path[MAX_NUM_THREADS][NMAX], tmp_path2[MAX_NUM_THREADS][NMAX]; +mutex m; + +struct PrevState { + short int node, t; + char o; + HowIGotHere type; +} prev[MAX_NUM_THREADS][TMAX][MAXNODES][4]; + + +void CopyTmpPathToPath(int tid) { + // The mutex must be held before calling this function. + const auto& tmp_path_tid = tmp_path[tid]; + for (int aid = 0; aid < N; ++aid) { + auto& path_aid = path[aid]; + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) { + path_aid.tmax = -1; + continue; + } + const auto& tmp_path_tid_aid = tmp_path_tid[aid]; + CopyPath(tmp_path_tid_aid, &path_aid); + } +} + +void RecomputeCheckpoints() { + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + auto& num_checkpoints_aid = num_checkpoints[aid]; + + if (agent_aid.status == DONE_REMOVED) { + num_checkpoints_aid = next_checkpoint[aid] = 0; + continue; + } + + const auto& ipath_aid = ipath[aid]; + assert(ipath_aid.tmax > TINIT); + if (ipath_aid.p[ipath_aid.tmax].node != agent_aid.target_node) { + // This path hasn't been updated. We should keep the previously computed checkpoints. + continue; + } + + num_checkpoints_aid = next_checkpoint[aid] = 1; + + auto& checkpoints_aid = checkpoints[aid]; + auto& checkpoints_o_aid = checkpoints_o[aid]; + auto& checkpoints_t_aid = checkpoints_t[aid]; + + if (agent_aid.inside_poz) { + checkpoints_aid[0] = agent_aid.poz_node; + checkpoints_o_aid[0] = agent_aid.poz_o; + } else { + checkpoints_aid[0] = checkpoints_o_aid[0] = -1; + } + + for (int t = TINIT + 1; t <= ipath_aid.tmax; ++t) { + const auto& path_elem = ipath_aid.p[t]; + if (path_elem.how_i_got_here == OUTSIDE_SRC) continue; + if (path_elem.how_i_got_here == ENTERED_SRC || path_elem.node != checkpoints_aid[num_checkpoints_aid - 1]) { + checkpoints_aid[num_checkpoints_aid] = path_elem.node; + checkpoints_o_aid[num_checkpoints_aid] = path_elem.o; + checkpoints_t_aid[num_checkpoints_aid] = t; + ++num_checkpoints_aid; + } + } + } +} + +bool CanEnterCell(int aid, int t, int from, int to, const short int covered_by[][MAXNODES], const int is_covered[][MAXNODES], int is_covered_idx, const Path tmp_path[]) { + assert(t > TINIT); + assert(0 <= to && to < nnodes); + const auto& agent_aid = agent[aid]; + const auto& is_covered1 = is_covered[t][to]; + const auto& is_covered2 = is_covered[t - 1][to]; + const auto& aid1 = covered_by[t][to]; + const auto& aid2 = covered_by[t - 1][to]; + + if (agent_aid.target_node == to) { + if (is_covered1 == is_covered_idx && aid1 < aid) return false; + if (is_covered2 == is_covered_idx && aid2 > aid) return false; + //if (USE_SPACING_TO_AVOID_DEADLOCKS && is_covered1 == is_covered_idx && (agent_aid.cturns >= 2 || agent[aid2].cturns >= 2)) return false; + } else { + if (is_covered1 == is_covered_idx) return false; + if (is_covered2 == is_covered_idx && aid2 > aid) return false; + if (from >= 0) { + const auto& is_covered3 = is_covered[t][from]; + const auto& aid3 = covered_by[t][from]; + if (is_covered2 == is_covered_idx && is_covered3 == is_covered_idx && aid2 == aid3) return false; + if (is_covered3 == is_covered_idx && aid3 < aid) return false; + } + if (t + 1 < T) { + const auto& is_covered4 = is_covered[t + 1][to]; + const auto& aid4 = covered_by[t + 1][to]; + if (is_covered4 == is_covered_idx && aid4 < aid) return false; + } + const auto& target_node_agents_to = target_node_agents[to]; + const auto& num_target_node_agents_to = num_target_node_agents[to]; + for (int idx = num_target_node_agents_to - 1; idx >= 0; --idx) { + const auto& aid5 = target_node_agents_to[idx]; + const auto& agent_aid5 = agent[aid5]; + if (agent_aid5.status == DONE_REMOVED) continue; + const auto& tmp_path_aid5 = tmp_path[aid5]; + assert(tmp_path_aid5.tmax > TINIT); + if (aid5 > aid && tmp_path_aid5.tmax == t && tmp_path_aid5.p[t].node == to) return false; + //if (USE_SPACING_TO_AVOID_DEADLOCKS && tmp_path_aid5.tmax == t && tmp_path_aid5.p[t].node == to && (agent_aid.cturns >= 2 || agent_aid5.cturns >= 2)) return false; + if (aid5 < aid && tmp_path_aid5.tmax == t + 1 && tmp_path_aid5.p[t + 1].node == to) return false; + } + } + + return true; +} + +inline bool IsFreeTimeWindow(int aid, int t1, int t2, int node, const short int covered_by[][MAXNODES], const int is_covered[][MAXNODES], int is_covered_idx, const Path tmp_path[]) { + for (int t = t1; t <= t2; ++t) if (!CanEnterCell(aid, t, node, node, covered_by, is_covered, is_covered_idx, tmp_path)) return false; + return true; +} + +int tend_ongoing_move[NMAX]; + +bool OverlapsOngoingMove(int t1, int t2, int node, const short int covered_by[][MAXNODES], const int is_covered[][MAXNODES], int is_covered_idx, const Path tmp_path[], short int tmax_at_poz_node[]) { + if (!USE_SPACING_TO_AVOID_DEADLOCKS) return false; + + if (t1 < tend_ongoing_move[node]) return true; + //if (t2 <= tend_ongoing_move[node]) return true; + + const int min_tstart = t2;//USE_STRICT_SPACING_TO_AVOID_DEADLOCKS ? t2 : t1; + //const int min_tstart = t1;//USE_STRICT_SPACING_TO_AVOID_DEADLOCKS ? t2 : t1; + + const int aid_t1 = is_covered[t1][node] == is_covered_idx ? covered_by[t1][node] : -1; + + for (int tend = t2 + 1; tend <= t2 + 3 && tend <= T; ++tend) { + if (is_covered[tend][node] == is_covered_idx) { + const auto& aid = covered_by[tend][node]; + const auto& agent_aid = agent[aid]; + if (tend - agent_aid.cturns < min_tstart && (aid != aid_t1 || is_covered[tend - 1][node] != is_covered_idx)) return true; + } + } + + if (USE_STRICT_SPACING_TO_AVOID_DEADLOCKS) { + for (int tend = t1 + 1; tend <= t2; ++tend) { + if (is_covered[tend][node] == is_covered_idx) { + const auto& aid_tend = covered_by[tend][node]; + if (aid_tend != aid_t1 || is_covered[tend - 1][node] != is_covered_idx) return true; + } + } + } + + /*for (int tend = t2 + 1; tend <= t2 + 3 && tend <= T; ++tend) { + if (is_covered[tend][node] == is_covered_idx) { + const auto& aid = covered_by[tend][node]; + const auto& agent_aid = agent[aid]; + if (tend - agent_aid.cturns < t2) return true; + } + } + for (int tend = t1 + 1; tend <= t2; ++tend) { + if (is_covered[tend][node] == is_covered_idx) { + const auto& aid_tend = covered_by[tend][node]; + const auto& curr_node_aid_tend = agent[aid_tend].poz_node; + if (curr_node_aid_tend != node || tmax_at_poz_node[aid_tend] < tend) return true; + } + }*/ + + + /*const auto& target_node_agents_node = target_node_agents[node]; + const auto& num_target_node_agents_node = num_target_node_agents[node]; + for (int idx = num_target_node_agents_node - 1; idx >= 0; --idx) { + const auto& aid5 = target_node_agents_node[idx]; + const auto& agent_aid5 = agent[aid5]; + if (agent_aid5.status == DONE_REMOVED) continue; + const auto& tmp_path_aid5 = tmp_path[aid5]; + assert(tmp_path_aid5.tmax > TINIT); + if (tmp_path_aid5.p[tmp_path_aid5.tmax].node == agent_aid5.target_node && t1 < tmp_path_aid5.tmax && tmp_path_aid5.tmax <= t2) { + return true; + } + }*/ + + return false; +} + +bool FindBestPath(int aid, const short int covered_by[][MAXNODES], const int is_covered[][MAXNODES], int is_covered_idx, int can_reach[][MAXNODES][4], int& can_reach_idx, short int can_reach_with_t1[][MAXNODES][4], HeapElement h[], int& hsize, PrevState prev[][MAXNODES][4], Path tmp_path[], Path* tmp_path2, short int tmax_at_poz_node[]) { + const auto& agent_aid = agent[aid]; + auto& tmp_path_aid = tmp_path[aid]; + + hsize = 0; + + ++can_reach_idx; + const auto& target_node = agent_aid.target_node; + const auto& cturns = agent_aid.cturns; + const auto& dmin_aid = dmin[aid]; + + int t1 = TINIT, t2 = TINIT, rnode = -1, ro = -1; + + if (!agent_aid.inside_poz) { + rnode = agent_aid.poz_node; + ro = agent_aid.poz_o; + t1 = TINIT + max(agent_aid.malfunc - 1, 0); + for (int tstart = t1; tstart < T; ++tstart) { + if (!CanEnterCell(aid, tstart + 1, -1, rnode, covered_by, is_covered, is_covered_idx, tmp_path)) continue; + int t2 = tstart + 1; + const int est_tmin = t2 + dmin_aid[rnode][ro]; + if (est_tmin > T) break; + can_reach[t2][rnode][ro] = can_reach_idx; + can_reach_with_t1[t2][rnode][ro] = tstart + 1; + auto& new_prev = prev[t2][rnode][ro]; + new_prev.t = new_prev.node = new_prev.o = -1; + InsertIntoHeap(h, hsize, t2, rnode, ro, tstart + 1, est_tmin); + } + } else { + t1 = TINIT; + rnode = agent_aid.poz_node; + ro = agent_aid.poz_o; + int moving_to_node = agent_aid.moving_to_node, moving_to_o = agent_aid.moving_to_o; + while (t1 + 1 <= tmp_path_aid.tmax && tmp_path_aid.p[t1 + 1].how_i_got_here == MALFUNCTIONED) { + ++t1; + if (!CanEnterCell(aid, t1, rnode, rnode, covered_by, is_covered, is_covered_idx, tmp_path)) return false; + } + if (t1 >= T) return false; + if (t1 != TINIT + agent_aid.malfunc) { + DBG(0, "!!! [FindBestPath] aid=%d TINIT=%d malfunc=%d t1=%d/%d/%d\n", aid, TINIT, agent_aid.malfunc, t1, TINIT + agent_aid.malfunc, T); + exit(1); + } + memcpy(&tmp_path2->p[TINIT], &tmp_path_aid.p[TINIT], (t1 - TINIT + 1) * sizeof(PathElem)); + t2 = t1; + if (moving_to_node >= 0) { + bool finished_moving = false; + while (t2 < T && rnode == agent_aid.poz_node) { + const auto& prev_path_elem = tmp_path2->p[t2]; + auto& next_path_elem = tmp_path2->p[t2 + 1]; + if (prev_path_elem.num_partial_turns + 1 < agent_aid.cturns || !CanEnterCell(aid, t2 + 1, rnode, moving_to_node, covered_by, is_covered, is_covered_idx, tmp_path)) { + memcpy(&next_path_elem, &prev_path_elem, sizeof(PathElem)); + ++next_path_elem.num_partial_turns; + next_path_elem.how_i_got_here = CONTINUED_MOVING; + } else { + next_path_elem.node = moving_to_node; + next_path_elem.o = moving_to_o; + next_path_elem.moving_to_node = next_path_elem.moving_to_o = -1; + next_path_elem.num_partial_turns = 0; + next_path_elem.how_i_got_here = CONTINUED_MOVING; + finished_moving = true; + } + ++t2; + } + if (finished_moving) { + rnode = moving_to_node; + ro = moving_to_o; + } + if (OverlapsOngoingMove(TINIT, t2, moving_to_node, covered_by, is_covered, is_covered_idx, tmp_path, tmax_at_poz_node)) + return false; + } + const int est_tmin = t2 + dmin_aid[rnode][ro]; + if (est_tmin <= T) { + can_reach[t2][rnode][ro] = can_reach_idx; + can_reach_with_t1[t2][rnode][ro] = t1; + auto& new_prev = prev[t2][rnode][ro]; + new_prev.t = new_prev.node = new_prev.o = -1; + InsertIntoHeap(h, hsize, t2, rnode, ro, t1, est_tmin); + } + } + + int TMIN = T + 1, best_o = -1, best_node = -1, best_t1 = -1; + + if (tmp_path_aid.tmax < TINIT || tmp_path_aid.p[tmp_path_aid.tmax].node == agent_aid.target_node) TMIN = tmp_path_aid.tmax; + + while (hsize >= 1) { + int t, node, o, ct1; + ExtractMinFromHeap(h, hsize, t, node, o, ct1); + assert(0 <= t && t <= T); + assert(can_reach[t][node][o] == can_reach_idx); + if (ct1 != can_reach_with_t1[t][node][o]) continue; + const auto& curr_dmin_aid = dmin_aid[node][o]; + if (t + curr_dmin_aid > TMIN) break; + + // Case 1: Wait. + if (t + 1 <= TMIN && t + 1 <= T && CanEnterCell(aid, t + 1, node, node, covered_by, is_covered, is_covered_idx, tmp_path) && + (can_reach[t + 1][node][o] != can_reach_idx || can_reach_with_t1[t + 1][node][o] < ct1) && + (agent_aid.inside_poz || t > ct1)) { + can_reach[t + 1][node][o] = can_reach_idx; + can_reach_with_t1[t + 1][node][o] = ct1; + auto& new_prev = prev[t + 1][node][o]; + new_prev.t = t; + new_prev.node = node; + new_prev.o = o; + new_prev.type = WAITED; + const int est_tmin = t + 1 + dmin_aid[node][o]; + if (best_node != target_node || est_tmin <= TMIN) InsertIntoHeap(h, hsize, t + 1, node, o, ct1, est_tmin); + } + + const int tarrive_node2 = t + cturns; + if (tarrive_node2 > TMIN || tarrive_node2 > T) continue; + if (!IsFreeTimeWindow(aid, t + 1, tarrive_node2 - 1, node, covered_by, is_covered, is_covered_idx, tmp_path)) continue; + + // Case 2: Move. + const auto& next_node_o = next[node][o]; + for (int onext = 0; onext <= 3; ++onext) { + const auto& node2 = next_node_o[onext]; + if (node2 >= 0 && node2 < nnodes && CanEnterCell(aid, tarrive_node2, node, node2, covered_by, is_covered, is_covered_idx, tmp_path) && + (can_reach[tarrive_node2][node2][onext] != can_reach_idx || can_reach_with_t1[tarrive_node2][node2][onext] < ct1)) { + if (OverlapsOngoingMove(t, tarrive_node2, node2, covered_by, is_covered, is_covered_idx, tmp_path, tmax_at_poz_node)) + continue; + if (node2 != target_node) { + can_reach[tarrive_node2][node2][onext] = can_reach_idx; + can_reach_with_t1[tarrive_node2][node2][onext] = ct1; + auto& new_prev = prev[tarrive_node2][node2][onext]; + new_prev.t = t; + new_prev.node = node; + new_prev.o = o; + new_prev.type = STARTED_MOVING; + const int est_tmin = tarrive_node2 + dmin_aid[node2][onext]; + if (best_node != target_node || est_tmin <= TMIN) InsertIntoHeap(h, hsize, tarrive_node2, node2, onext, ct1, est_tmin); + } else { + can_reach[tarrive_node2][node2][onext] = can_reach_idx; + can_reach_with_t1[tarrive_node2][node2][onext] = ct1; + auto& new_prev = prev[tarrive_node2][node2][onext]; + new_prev.t = t; + new_prev.node = node; + new_prev.o = o; + new_prev.type = STARTED_MOVING; + if (best_node != target_node || tarrive_node2 < TMIN || (tarrive_node2 == TMIN && best_t1 < ct1)) { + TMIN = tarrive_node2; + best_node = target_node; + best_o = onext; + best_t1 = ct1; + } + } + } + } + } + + //if (agent_aid.inside_poz) assert(best_o >= 0); + if (best_o < 0) return false; + if (best_node != target_node && !agent_aid.inside_poz) { + tmp_path_aid.tmax = T; + for (int t = TINIT; t <= T; ++t) { + auto& new_path_elem = tmp_path_aid.p[t]; + new_path_elem.node = agent_aid.poz_node; + new_path_elem.o = agent_aid.poz_o; + new_path_elem.moving_to_node = new_path_elem.moving_to_o = -1; + new_path_elem.num_partial_turns = 0; + new_path_elem.how_i_got_here = OUTSIDE_SRC; + } + return true; + } + + //assert(best_node == target_node); + + tmp_path_aid.tmax = TMIN; + int ct = TMIN, cnode = best_node, co = best_o; + while (1) { + assert(can_reach[ct][cnode][co] == can_reach_idx); + assert(ct >= can_reach_with_t1[ct][cnode][co]); + const auto& cprev = prev[ct][cnode][co]; + if (cprev.t < 0) break; + if (cprev.type == WAITED || cprev.type == MALFUNCTIONED) { + // Wait 1 unit. + auto& new_path_elem = tmp_path_aid.p[ct]; + new_path_elem.node = cnode; + new_path_elem.o = co; + new_path_elem.moving_to_node = new_path_elem.moving_to_o = -1; + new_path_elem.num_partial_turns = 0; + new_path_elem.how_i_got_here = cprev.type; + } else { + assert(cprev.type == STARTED_MOVING); + // Move cturns units. + int num_partial_turns = 0; + + for (int tmove = cprev.t; tmove < ct; ++tmove) { + auto& new_path_elem = tmp_path_aid.p[tmove + 1]; + ++num_partial_turns; + if (num_partial_turns < agent_aid.cturns) { + new_path_elem.node = cprev.node; + new_path_elem.o = cprev.o; + new_path_elem.moving_to_node = cnode; + new_path_elem.moving_to_o = co; + new_path_elem.num_partial_turns = num_partial_turns; + new_path_elem.how_i_got_here = num_partial_turns == 1 ? STARTED_MOVING : CONTINUED_MOVING; + } else { + new_path_elem.node = cnode; + new_path_elem.o = co; + new_path_elem.moving_to_node = new_path_elem.moving_to_o = -1; + new_path_elem.num_partial_turns = 0; + new_path_elem.how_i_got_here = num_partial_turns == 1 ? STARTED_MOVING : CONTINUED_MOVING; + } + } + } + ct = cprev.t; + cnode = cprev.node; + co = cprev.o; + } + + if (!agent_aid.inside_poz) { + for (int t = TINIT + 1; t < ct; ++t) { + auto& new_path_elem = tmp_path_aid.p[t]; + new_path_elem.node = rnode; + new_path_elem.o = ro; + new_path_elem.moving_to_node = new_path_elem.moving_to_o = -1; + new_path_elem.num_partial_turns = 0; + new_path_elem.how_i_got_here = OUTSIDE_SRC; + } + auto& new_path_elem = tmp_path_aid.p[ct]; + new_path_elem.node = rnode; + new_path_elem.o = ro; + new_path_elem.moving_to_node = new_path_elem.moving_to_o = -1; + new_path_elem.num_partial_turns = 0; + new_path_elem.how_i_got_here = ENTERED_SRC; + } else { + memcpy(&tmp_path_aid.p[TINIT], &tmp_path2->p[TINIT], (t2 - TINIT + 1) * sizeof(PathElem)); + } + + return true; +} + +bool updated_best_solution; +int rerun; + +vector<pair<int, int>> shpaths_sorted; + +void CoverPath(int aid, const Path& path, short int covered_by[][MAXNODES], int is_covered[][MAXNODES], int is_covered_idx) { + const auto& agent_aid = agent[aid]; + for (int t = TINIT; t <= path.tmax; ++t) { + const auto& path_elem = path.p[t]; + if (path_elem.how_i_got_here != OUTSIDE_SRC && path_elem.node != agent_aid.target_node) { + assert(is_covered[t][path_elem.node] != is_covered_idx); + is_covered[t][path_elem.node] = is_covered_idx; + covered_by[t][path_elem.node] = aid; + } + } +} + +void UncoverPath(int aid, const Path& path, short int covered_by[][MAXNODES], int is_covered[][MAXNODES], int is_covered_idx) { + const auto& agent_aid = agent[aid]; + for (int t = TINIT; t <= path.tmax; ++t) { + const auto& path_elem = path.p[t]; + if (path_elem.how_i_got_here != OUTSIDE_SRC && path_elem.node != agent_aid.target_node) { + assert(is_covered[t][path_elem.node] == is_covered_idx && covered_by[t][path_elem.node] == aid); + is_covered[t][path_elem.node] = 0; + } + } +} + +void CoverPath1(int aid, const Path& path, short int covered_by[][MAXNODES], int is_covered[][MAXNODES], int is_covered_idx) { + const auto& agent_aid = agent[aid]; + if (!agent_aid.inside_poz) return; + for (int t = TINIT; t <= T; ++t) { + assert(is_covered[t][agent_aid.poz_node] != is_covered_idx); + is_covered[t][agent_aid.poz_node] = is_covered_idx; + covered_by[t][agent_aid.poz_node] = aid; + } +} + +void UncoverPath1(int aid, const Path& path, short int covered_by[][MAXNODES], int is_covered[][MAXNODES], int is_covered_idx) { + const auto& agent_aid = agent[aid]; + if (!agent_aid.inside_poz) return; + for (int t = TINIT; t <= T; ++t) { + assert(is_covered[t][agent_aid.poz_node] == is_covered_idx && covered_by[t][agent_aid.poz_node] == aid); + is_covered[t][agent_aid.poz_node] = 0; + } +} + +bool RunConsistencyChecks(Path path[], const short int covered_by[][MAXNODES], const int is_covered[][MAXNODES], int is_covered_idx, bool crash_on_error = true) { + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + const auto& path_aid = path[aid]; + for (int t = TINIT + 1; t <= path_aid.tmax; ++t) { + const auto& path_elem = path_aid.p[t]; + if (path_elem.how_i_got_here == OUTSIDE_SRC) continue; + const auto& is_covered1 = is_covered[t][path_elem.node]; + const auto& is_covered2 = is_covered[t - 1][path_elem.node]; + const auto& aid1 = covered_by[t][path_elem.node]; + const auto& aid2 = covered_by[t - 1][path_elem.node]; + if (path_elem.node == agent_aid.target_node) { + if (is_covered1 == is_covered_idx) { + const bool ok = aid1 > aid; + if (!ok) { + if (crash_on_error) assert(ok); + return false; + } + } + if (is_covered2 == is_covered_idx) { + const bool ok = aid2 < aid; + if (!ok) { + if (crash_on_error) assert(ok); + return false; + } + } + } else { + Agent* agent_aid1 = is_covered1 != is_covered_idx ? nullptr : &agent[aid1]; + if (is_covered1 == is_covered_idx && aid1 != aid && agent_aid1->target_node != path_elem.node) { + DBG(0, "!!! [RunConsistencyChecks] aid=%d t=%d node=%d cov=%d how=%d\n", aid, t, path_elem.node, covered_by[t][path_elem.node], path_elem.how_i_got_here); + if (crash_on_error) exit(1); + return false; + } + + const auto& target_node_agents_node = target_node_agents[path_elem.node]; + const auto& num_target_node_agents_node = num_target_node_agents[path_elem.node]; + for (int idx = num_target_node_agents_node - 1; idx >= 0; --idx) { + const auto& aid3 = target_node_agents_node[idx]; + const auto& agent_aid3 = agent[aid3]; + if (agent_aid3.status == DONE_REMOVED) continue; + const auto& path_aid3 = path[aid3]; + bool ok = path_aid3.tmax > TINIT; + if (!ok) { + if (crash_on_error) assert(ok); + return false; + } + if (path_aid3.tmax == t && path_aid3.p[t].node == path_elem.node) { + ok = aid3 < aid; + if (!ok) { + if (crash_on_error) assert(ok); + return false; + } + } + if (path_aid3.tmax == t + 1 && path_aid3.p[t].node == path_elem.node) { + ok = aid3 > aid; + if (!ok) { + if (crash_on_error) assert(ok); + return false; + } + } + } + + Agent* agent_aid2 = is_covered2 != is_covered_idx ? nullptr : &agent[aid2]; + if (t > TINIT && is_covered2 == is_covered_idx && aid2 > aid && agent_aid2->target_node != path_elem.node) { + DBG(0, "!!! [RunConsistencyChecks] aid=%d t=%d node=%d cov_t-1=%d(target=%d)\n", aid, t, path_elem.node, aid2, agent_aid2->target_node); + if (crash_on_error) exit(1); + return false; + } + } + + if (path_elem.num_partial_turns >= agent_aid.cturns && (path_elem.how_i_got_here == STARTED_MOVING || path_elem.how_i_got_here == CONTINUED_MOVING)) { + bool ok = path_elem.moving_to_node >= 0; + if (!ok) { + if (crash_on_error) assert(ok); + return false; + } + if ((is_covered[t][path_elem.moving_to_node] != is_covered_idx && + (is_covered[t - 1][path_elem.moving_to_node] != is_covered_idx || + covered_by[t - 1][path_elem.moving_to_node] <= aid)) || + (is_covered[t][path_elem.moving_to_node] == is_covered_idx && + covered_by[t][path_elem.moving_to_node] >= aid && + (is_covered[t - 1][path_elem.moving_to_node] != is_covered_idx || + covered_by[t - 1][path_elem.moving_to_node] != covered_by[t][path_elem.moving_to_node]))) { + DBG(0, "!!! [RunConsistencyChecks] Agent in motion can enter next cell, but doesn't: aid=%d t=%d node=%d->%d npt=%d/%d cov_t=%d cov_t-1=%d\n", aid, t, path_elem.node, path_elem.moving_to_node, path_elem.num_partial_turns, agent_aid.cturns, is_covered[t][path_elem.moving_to_node] != is_covered_idx ? -1 : covered_by[t][path_elem.moving_to_node], is_covered[t - 1][path_elem.moving_to_node] != is_covered_idx ? -1 : covered_by[t - 1][path_elem.moving_to_node]); + if (crash_on_error) exit(1); + return false; + } + } + } + } + return true; +} + +vector<pair<pair<int, int>, int>> tmoves[MAXNODES]; + +void CheckNonDeadlockPaths() { + return; + if (!USE_SPACING_TO_AVOID_DEADLOCKS) return; + for (int node = 0; node < nnodes; ++node) tmoves[node].clear(); + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + const auto& ipath_aid = ipath[aid]; + + int curr_node = agent_aid.poz_node; + int next_node = agent_aid.moving_to_node; + int tdeparture = TINIT, tarrival = -1; + + for (int t = TINIT + 1; t <= ipath_aid.tmax; ++t) { + const auto& path_elem = ipath_aid.p[t]; + if (next_node < 0) { + if (path_elem.node != curr_node) { + next_node = path_elem.node; + tdeparture = t - 1; + } else if (path_elem.moving_to_node >= 0) { + next_node = path_elem.moving_to_node; + tdeparture = t - 1; + } + } + if (path_elem.node == next_node) { + tarrival = t; + if (next_node != agent_aid.target_node) { + tmoves[next_node].push_back({{tarrival, tdeparture}, aid}); + } + curr_node = next_node; + next_node = -1; + } + } + } + for (int node = 0; node < nnodes; ++node) { + auto& tmoves_node = tmoves[node]; + if (tmoves_node.empty()) continue; + sort(tmoves_node.begin(), tmoves_node.end()); + int prev_tarrival = -1, prev_tdeparture = -1, prev_aid = -1; + for (const auto& tuple : tmoves_node) { + const auto& tarrival = tuple.first.first; + const auto& tdeparture = tuple.first.second; + const auto& aid = tuple.second; + if (prev_tarrival > tdeparture) { + DBG(0, "!!! [CheckNonDeadlockPaths] node=%d: aid=%d ct=%d tdep=%d tarr=%d target=%d | aid2=%d ct2=%d tdep2=%d tarr2=%d target2=%d\n", node, aid, agent[aid].cturns, tdeparture, tarrival, agent[aid].target_node, prev_aid, agent[prev_aid].cturns, prev_tdeparture, prev_tarrival, agent[prev_aid].target_node); + DBG(0, " tend_ongoing_move[node]=%d\n", tend_ongoing_move[node]); + exit(1); + } + prev_tarrival = tarrival; + prev_tdeparture = tdeparture; + prev_aid = aid; + } + } +} + +double SCORE_EXPONENT1, SCORE_EXPONENT2; +double MAX_TMAX_WEIGHT; + +#define GetScore(t) (t <= TEST ? pow(1.0 * t / TEST, SCORE_EXPONENT1) : pow(1.0 * t / TEST, SCORE_EXPONENT2)) + +/*void RandomPermutations(int tid, int ntries) { + auto& pused_tid = pused[tid]; + auto& perm_tid = perm[tid]; + auto& xor128_tid = xor128[tid]; + auto& covered_by_tid = covered_by[tid]; + auto& is_covered_tid = is_covered[tid]; + auto& is_covered_idx_tid = is_covered_idx[tid]; + auto& can_reach_tid = can_reach[tid]; + auto& can_reach_idx_tid = can_reach_idx[tid]; + auto& can_reach_with_t1_tid = can_reach_with_t1[tid]; + auto& heap_tid = heap[tid]; + auto& heap_size_tid = heap_size[tid]; + auto& prev_tid = prev[tid]; + auto& tmp_path_tid = tmp_path[tid]; + auto& tmp_path2_tid = tmp_path2[tid]; + auto& tmax_at_poz_node_tid = tmax_at_poz_node[tid]; + + if (tid == 0) { + shpaths_sorted.clear(); + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + shpaths_sorted.push_back({agent_aid.malfunc + dmin[aid][agent_aid.poz_node][agent_aid.poz_o], aid}); + } + sort(shpaths_sorted.begin(), shpaths_sorted.end()); + } + + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + CopyPath(ipath[aid], &tmp_path_tid[aid]); + } + + int last_trial_update = -1, last_idx_update = -1; + + for (int trial = 1; trial <= ntries; ++trial) { + if (tid == 0 && trial <= 1) { + if (trial == 2) reverse(shpaths_sorted.begin(), shpaths_sorted.end()); + for (int i = 0; i < N; ++i) perm_tid[i] = shpaths_sorted[i].second; + } else { + for (int i = 0; i < N; ++i) pused_tid[i] = 0; + int idx = 0; + if ((0&&trial & 3) >= 2) { + for (int i = 0; i < N; ++i) { + do { + perm_tid[idx] = xor128_tid.rand() % N; + } while (pused_tid[perm_tid[idx]]); + pused_tid[perm_tid[idx++]] = 1; + } + } else if (0&&(trial & 3) == 1) { + for (int cturns = MAX_CTURNS - 1; cturns >= 0; --cturns) { + const auto& cturns_agents_cturns = cturns_agents[cturns]; + const auto& num_cturns_agents_cturns = num_cturns_agents[cturns]; + for (int i = 0; i < num_cturns_agents_cturns; ++i) { + do { + perm_tid[idx] = cturns_agents_cturns[xor128_tid.rand() % num_cturns_agents_cturns]; + } while (pused_tid[perm_tid[idx]]); + pused_tid[perm_tid[idx++]] = 1; + } + } + } else { + for (int cturns = 0; cturns < MAX_CTURNS; ++cturns) { + const auto& cturns_agents_cturns = cturns_agents[cturns]; + const auto& num_cturns_agents_cturns = num_cturns_agents[cturns]; + for (int i = 0; i < num_cturns_agents_cturns; ++i) { + do { + perm_tid[idx] = cturns_agents_cturns[xor128_tid.rand() % num_cturns_agents_cturns]; + } while (pused_tid[perm_tid[idx]]); + pused_tid[perm_tid[idx++]] = 1; + } + } + } + } + ++is_covered_idx_tid; + for (int aid = 0; aid < N; ++aid) { + auto& tmax_at_poz_node_tid_aid = tmax_at_poz_node_tid[aid]; + tmax_at_poz_node_tid_aid = -1; + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + const auto& tmp_path_tid_aid = tmp_path_tid[aid]; + CoverPath(aid, tmp_path_tid_aid, covered_by_tid, is_covered_tid, is_covered_idx_tid); + if (agent_aid.inside_poz) { + tmax_at_poz_node_tid_aid = TINIT; + for (int t = TINIT + 1; t <= tmp_path_tid_aid.tmax; ++t) { + const auto& path_elem = tmp_path_tid_aid.p[t]; + if (path_elem.node != agent_aid.poz_node) break; + tmax_at_poz_node_tid_aid = t; + } + } + } + for (int idx = 0; idx < N; ++idx) { + const auto& aid = perm_tid[idx]; + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + const auto& ipath_aid = ipath[aid]; + auto& tmp_path_tid_aid = tmp_path_tid[aid]; + UncoverPath(aid, tmp_path_tid_aid, covered_by_tid, is_covered_tid, is_covered_idx_tid); + const int curr_tmax = tmp_path_tid_aid.tmax; + FindBestPath(aid, covered_by_tid, is_covered_tid, is_covered_idx_tid, can_reach_tid, can_reach_idx_tid, can_reach_with_t1_tid, heap_tid, heap_size_tid, prev_tid, tmp_path_tid, &tmp_path2_tid[aid], tmax_at_poz_node_tid); + if (tmp_path_tid_aid.tmax < curr_tmax) { + last_trial_update = trial; + last_idx_update = idx; + } + CoverPath(aid, tmp_path_tid_aid, covered_by_tid, is_covered_tid, is_covered_idx_tid); + auto& tmax_at_poz_node_tid_aid = tmax_at_poz_node_tid[aid]; + tmax_at_poz_node_tid_aid = -1; + if (agent_aid.inside_poz) { + tmax_at_poz_node_tid_aid = TINIT; + for (int t = TINIT + 1; t <= tmp_path_tid_aid.tmax; ++t) { + const auto& path_elem = tmp_path_tid_aid.p[t]; + if (path_elem.node != agent_aid.poz_node) break; + tmax_at_poz_node_tid_aid = t; + } + } + } + } + + if (RunConsistencyChecks(tmp_path_tid, covered_by_tid, is_covered_tid, is_covered_idx_tid, false)) { + int num_done_agents = 0; + double cost = 0.0, max_tmax = 0.0; + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + const auto& tmp_path_tid_aid = tmp_path_tid[aid]; + assert(tmp_path_tid_aid.tmax > TINIT); + if (tmp_path_tid_aid.tmax > TINIT && tmp_path_tid_aid.tmax <= T && tmp_path_tid_aid.p[tmp_path_tid_aid.tmax].node == agent_aid.target_node) { + ++num_done_agents; + cost += pow(tmp_path_tid_aid.tmax, kScoreExponent); + if (tmp_path_tid_aid.tmax > max_tmax) max_tmax = tmp_path_tid_aid.tmax; + } + } + cost += max_tmax * kMaxTmaxWeight; + { + lock_guard<mutex> guard(m); + DBG(3, "[RandomPermutations] rerun=%d tid=%d ltu=%d/%d liu=%d/%d nda=%d/%d cost=%.6lf: maxda=%d/%d minc=%.6lf time=%.3lf\n", rerun, tid, last_trial_update, ntries, last_idx_update, N - 1, num_done_agents, num_planned, cost, MAX_DONE_AGENTS, num_planned, MIN_COST, GetTime() - TSTART); + if (num_done_agents > MAX_DONE_AGENTS || (num_done_agents == MAX_DONE_AGENTS && cost < MIN_COST - 1e-6)) { + MAX_DONE_AGENTS = num_done_agents; + MIN_COST = cost; + updated_best_solution = true; + CopyTmpPathToPath(tid); + DBG(0, "[RandomPermutations] rerun=%d tid=%d ltu=%d/%d liu=%d/%d nda=%d/%d cost=%.6lf: maxda=%d/%d minc=%.6lf time=%.3lf\n", rerun, tid, last_trial_update, ntries, last_idx_update, N - 1, num_done_agents, num_planned, cost, MAX_DONE_AGENTS, num_planned, MIN_COST, GetTime() - TSTART); + CheckNonDeadlockPaths(); + } + } + } +} +*/ + +void RandomPermutations(int tid, int ntries) { + auto& pused_tid = pused[tid]; + auto& perm_tid = perm[tid]; + auto& xor128_tid = xor128[tid]; + auto& covered_by_tid = covered_by[tid]; + auto& is_covered_tid = is_covered[tid]; + auto& is_covered_idx_tid = is_covered_idx[tid]; + auto& can_reach_tid = can_reach[tid]; + auto& can_reach_idx_tid = can_reach_idx[tid]; + auto& can_reach_with_t1_tid = can_reach_with_t1[tid]; + auto& heap_tid = heap[tid]; + auto& heap_size_tid = heap_size[tid]; + auto& prev_tid = prev[tid]; + auto& tmp_path_tid = tmp_path[tid]; + auto& tmp_path2_tid = tmp_path2[tid]; + auto& tmax_at_poz_node_tid = tmax_at_poz_node[tid]; + + if (tid == 0) { + shpaths_sorted.resize(N); + for (int aid = 0; aid < N; ++aid) { + shpaths_sorted[aid].second = aid; + const auto& agent_aid = agent[aid]; + shpaths_sorted[aid].first = agent_aid.malfunc + dmin[aid][agent_aid.poz_node][agent_aid.poz_o]; + } + sort(shpaths_sorted.begin(), shpaths_sorted.end()); + } + + for (int trial = 1; trial <= ntries; ++trial) { + if (tid == 0 && trial <= 1) { + for (int i = 0; i < N; ++i) perm_tid[i] = shpaths_sorted[i].second; + reverse(shpaths_sorted.begin(), shpaths_sorted.end()); + } else { + for (int i = 0; i < N; ++i) pused_tid[i] = 0; + int idx = 0; + if (0&&(trial & 1) == 1) { + for (int cturns = MAX_CTURNS - 1; cturns >= 0; --cturns) { + const auto& cturns_agents_cturns = cturns_agents[cturns]; + const auto& num_cturns_agents_cturns = num_cturns_agents[cturns]; + for (int i = 0; i < num_cturns_agents_cturns; ++i) { + do { + perm_tid[idx] = cturns_agents_cturns[xor128_tid.rand() % num_cturns_agents_cturns]; + } while (pused_tid[perm_tid[idx]]); + pused_tid[perm_tid[idx++]] = 1; + } + } + } else { + for (int cturns = 0; cturns < MAX_CTURNS; ++cturns) { + const auto& cturns_agents_cturns = cturns_agents[cturns]; + const auto& num_cturns_agents_cturns = num_cturns_agents[cturns]; + for (int i = 0; i < num_cturns_agents_cturns; ++i) { + do { + perm_tid[idx] = cturns_agents_cturns[xor128_tid.rand() % num_cturns_agents_cturns]; + } while (pused_tid[perm_tid[idx]]); + pused_tid[perm_tid[idx++]] = 1; + } + } + } + } + ++is_covered_idx_tid; + for (int aid = 0; aid < N; ++aid) { + auto& tmax_at_poz_node_tid_aid = tmax_at_poz_node_tid[aid]; + tmax_at_poz_node_tid_aid = -1; + auto& tmp_path_tid_aid = tmp_path_tid[aid]; + CopyPath(ipath[aid], &tmp_path_tid_aid); + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + CoverPath(aid, tmp_path_tid_aid, covered_by_tid, is_covered_tid, is_covered_idx_tid); + if (agent_aid.inside_poz) { + tmax_at_poz_node_tid_aid = TINIT; + for (int t = TINIT + 1; t <= tmp_path_tid_aid.tmax; ++t) { + const auto& path_elem = tmp_path_tid_aid.p[t]; + if (path_elem.node != agent_aid.poz_node) break; + tmax_at_poz_node_tid_aid = t; + } + } + } + bool inconsistent = false; + for (int idx = 0; idx < N; ++idx) { + const auto& aid = perm_tid[idx]; + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + auto& tmp_path_tid_aid = tmp_path_tid[aid]; + UncoverPath(aid, tmp_path_tid_aid, covered_by_tid, is_covered_tid, is_covered_idx_tid); + if (!FindBestPath(aid, covered_by_tid, is_covered_tid, is_covered_idx_tid, can_reach_tid, can_reach_idx_tid, can_reach_with_t1_tid, heap_tid, heap_size_tid, prev_tid, tmp_path_tid, &tmp_path2_tid[aid], tmax_at_poz_node_tid)) { + //inconsistent = true; + //break; + } + CoverPath(aid, tmp_path_tid_aid, covered_by_tid, is_covered_tid, is_covered_idx_tid); + } + if (!inconsistent && RunConsistencyChecks(tmp_path_tid, covered_by_tid, is_covered_tid, is_covered_idx_tid, false)) { + int num_done_agents = 0; + double cost = 0.0; + int max_tmax = 0; + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + const auto& tmp_path_tid_aid = tmp_path_tid[aid]; + assert(tmp_path_tid_aid.tmax > TINIT); + if (tmp_path_tid_aid.tmax > TINIT && tmp_path_tid_aid.tmax <= T && tmp_path_tid_aid.p[tmp_path_tid_aid.tmax].node == agent_aid.target_node) { + ++num_done_agents; + cost += GetScore(tmp_path_tid_aid.tmax); + if (tmp_path_tid_aid.tmax > max_tmax) max_tmax = tmp_path_tid_aid.tmax; + } + } + if (num_done_agents >= 1) cost /= num_done_agents; + + { + lock_guard<mutex> guard(m); + if (num_done_agents > MAX_DONE_AGENTS || (num_done_agents == MAX_DONE_AGENTS && cost < MIN_COST - 1e-6)) { + MAX_DONE_AGENTS = num_done_agents; + MIN_COST = cost; + updated_best_solution = true; + CopyTmpPathToPath(tid); + DBG(0, "[RandomPermutations] rerun=%d tid=%d trial=%d/%d maxda=%d/%d minc=%.6lf time=%.3lf\n", rerun, tid, trial, ntries, MAX_DONE_AGENTS, num_planned, MIN_COST, GetTime() - TSTART); + } + } + } + } +} + +bool any_best_solution_updates; + +void RegenerateFullPlan() { + ++num_reschedules; + any_best_solution_updates = false; + updated_best_solution = true; + rerun = 0; + + const int kMaxReruns = 4;//2; + + while (updated_best_solution && rerun < kMaxReruns) { + updated_best_solution = false; + ++rerun; + + for (int node = 0; node < nnodes; ++node) tend_ongoing_move[node] = TINIT; + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + if (!agent_aid.inside_poz || agent_aid.status == DONE_REMOVED) continue; + if (agent_aid.moving_to_node >= 0) { + const auto& ipath_aid = ipath[aid]; + const auto& first_path_elem = ipath_aid.p[TINIT]; + assert(ipath_aid.tmax >= TINIT); + tend_ongoing_move[agent_aid.moving_to_node] = TINIT + agent_aid.malfunc + max(0, agent_aid.cturns - first_path_elem.num_partial_turns); + } + } + + int max_threads = thread::hardware_concurrency(); + if (max_threads > MAX_NUM_THREADS) max_threads = MAX_NUM_THREADS; + DBG(2, "max_threads=%d\n", max_threads); + + if (N >= 2) { + thread** th = nullptr; + if (max_threads >= 2) th = new thread*[max_threads - 1]; + + // Random Permutations. + const int kNumRandomPermutations = TINIT == 0 ? 20 /*10*/ : 12 /*6*/; + if (max_threads >= 2) { + for (int tid = 0; tid + 1 < max_threads; ++tid) th[tid] = new thread([tid, kNumRandomPermutations]{ + RandomPermutations(tid, kNumRandomPermutations); + }); + } + RandomPermutations(max_threads - 1, kNumRandomPermutations); + if (max_threads >= 2) { + for (int tid = 0; tid + 1 < max_threads; ++tid) { + auto& th_tid = th[tid]; + th_tid->join(); + delete th_tid; + } + delete th; + } + } else RandomPermutations(0, 1); + + if (updated_best_solution) { + for (int aid = 0; aid < N; ++aid) CopyPath(path[aid], &ipath[aid]); + any_best_solution_updates = true; + } + } + + if (any_best_solution_updates) RecomputeCheckpoints(); +} + +int nodecnt[MAXNODES], nodecnt_marked[MAXNODES], nodecnt_marked_idx; +char is_free[MAXNODES]; + +int next_aidx[NMAX], next_vidx[MAXNODES]; + +void SwapVisitingOrder(int aid1, int idx1, int aid2) { + const auto& checkpoints_aid1 = checkpoints[aid1]; + const auto& checkpoints_aid2 = checkpoints[aid2]; + const int node = checkpoints_aid1[idx1]; + int idx2 = next_aidx[aid2] - 1; + while (idx2 >= 0 && checkpoints_aid2[idx2] != node) --idx2; + assert(idx2 >= 0); + const auto& num_checkpoints_aid1 = num_checkpoints[aid1]; + const auto& num_checkpoints_aid2 = num_checkpoints[aid2]; + const auto& checkpoints_cnt_aid1 = checkpoints_cnt[aid1]; + const auto& checkpoints_cnt_aid2 = checkpoints_cnt[aid2]; + + int num_swaps = 0; + while (idx1 < num_checkpoints_aid1 && idx2 < num_checkpoints_aid2 && checkpoints_aid1[idx1] == checkpoints_aid2[idx2]) { + int vidx1 = -1, cnt1 = 0, vidx2 = -1, cnt2 = 0; + auto& ipath_visiting_order_node = ipath_visiting_order[checkpoints_aid1[idx1]]; + for (int idx = 0; idx < ipath_visiting_order_node.size() && (vidx1 < 0 || vidx2 < 0); ++idx) { + const auto& elem_pair = ipath_visiting_order_node[idx]; + if (elem_pair.second == aid1) { + ++cnt1; + if (cnt1 == checkpoints_cnt_aid1[idx1]) vidx1 = idx; + } + if (elem_pair.second == aid2) { + ++cnt2; + if (cnt2 == checkpoints_cnt_aid2[idx2]) vidx2 = idx; + } + } + assert(vidx1 >= 0 && vidx2 >= 0); + assert(vidx1 > vidx2); + ipath_visiting_order_node[vidx1].second = aid2; + ipath_visiting_order_node[vidx2].second = aid1; + ++idx1; + ++idx2; + ++num_swaps; + } + + /*for (int node = 0; node < nnodes; ++node) { + int vidx1 = -1, cnt1 = 0, vidx2 = -1, cnt2 = 0; + auto& ipath_visiting_order_node = ipath_visiting_order[node]; + for (int idx = 0; idx < ipath_visiting_order_node.size() && (vidx1 < 0 || vidx2 < 0); ++idx) { + const auto& elem_pair = ipath_visiting_order_node[idx]; + if (elem_pair.second == aid1) vidx1 = idx; + if (elem_pair.second == aid2) vidx2 = idx; + } + if (vidx1 >= 0 && vidx2 >= 0) { + ipath_visiting_order_node[vidx1].second = aid2; + ipath_visiting_order_node[vidx2].second = aid1; + ++num_swaps; + } + }*/ + + DBG(2, "[SwapVisitingOrder] aid1=%d aid2=%d idx1=%d num_swaps=%d\n", aid1, aid2, idx1, num_swaps); + + //exit(1); +} + +#define QMOD 255 +int qaid[QMOD + 1]; + +bool AdjustIPaths() { + /*for (int aid = 0; aid < N; ++aid) { + if (aid == 46) { + const auto& ipath_aid = ipath[aid]; + for (int t = max(TINIT, 795); t <= 805 && t <= ipath_aid.tmax; ++t) { + const auto& elem = ipath_aid.p[t]; + DBG(0, "aid=%d t=%d node=%d npt=%d\n", aid, t, elem.node, elem.num_partial_turns); + } + } + }*/ + + ++num_adjust_ipaths; + + nodecnt_marked_idx = 0; + for (int node = 0; node < nnodes; ++node) { + ipath_visiting_order[node].clear(); + nodecnt_marked[node] = 0; + } + + int max_tmax = 0; + + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + const auto& ipath_aid = ipath[aid]; + auto& path_aid = path[aid]; + if (agent_aid.status == DONE_REMOVED) { + CopyPath(ipath_aid, &path_aid); + continue; + } + + if (ipath_aid.p[ipath_aid.tmax].node == agent_aid.target_node && ipath_aid.tmax > max_tmax) max_tmax = ipath_aid.tmax; + + auto& new_path_elem = path_aid.p[TINIT]; + new_path_elem.node = agent_aid.poz_node; + new_path_elem.o = agent_aid.poz_o; + new_path_elem.num_partial_turns = 0; + while (fabs(agent_aid.poz_frac - new_path_elem.num_partial_turns * agent_aid.speed) >= ZERO) + ++new_path_elem.num_partial_turns; + new_path_elem.moving_to_node = new_path_elem.moving_to_o = -1; + if (agent_aid.inside_poz) { + const auto& first_expected_step = ipath_aid.p[TINIT]; + if (new_path_elem.num_partial_turns >= 1) { + if (first_expected_step.num_partial_turns >= 1) { + if (agent_aid.fresh_malfunc) + assert(first_expected_step.num_partial_turns >= new_path_elem.num_partial_turns); + assert(first_expected_step.node == agent_aid.poz_node); + assert(first_expected_step.o == agent_aid.poz_o); + new_path_elem.moving_to_node = first_expected_step.moving_to_node; + new_path_elem.moving_to_o = first_expected_step.moving_to_o; + assert(0 <= new_path_elem.moving_to_node && new_path_elem.moving_to_node < nnodes); + assert(0 <= new_path_elem.moving_to_o && new_path_elem.moving_to_o < nnodes); + } else { + assert(new_path_elem.num_partial_turns >= agent_aid.cturns - 1); + assert(first_expected_step.node != agent_aid.poz_node || first_expected_step.o != agent_aid.poz_o); + assert(first_expected_step.moving_to_node < 0); + assert(first_expected_step.moving_to_o < 0); + new_path_elem.moving_to_node = first_expected_step.node; + new_path_elem.moving_to_o = first_expected_step.o; + } + } + if (agent_aid.fresh_malfunc) new_path_elem.how_i_got_here = MALFUNCTIONED; + else new_path_elem.how_i_got_here = first_expected_step.how_i_got_here; + } else new_path_elem.how_i_got_here = OUTSIDE_SRC; + + const int tmin = TINIT + max(0, agent_aid.malfunc - (agent_aid.inside_poz ? 0 : 1)); + for (int t = TINIT + 1; t <= tmin && t <= T; ++t) { + auto& new_path_elem = path_aid.p[t]; + memcpy(&new_path_elem, &path_aid.p[t - 1], sizeof(PathElem)); + new_path_elem.how_i_got_here = agent_aid.inside_poz ? MALFUNCTIONED : OUTSIDE_SRC; + } + + const auto& next_checkpoint_aid = next_checkpoint[aid]; + const auto& num_checkpoints_aid = num_checkpoints[aid]; + + if (next_checkpoint_aid == num_checkpoints_aid) { + assert(!agent_aid.inside_poz); + continue; + } + + assert(1 <= next_checkpoint_aid && next_checkpoint_aid < num_checkpoints_aid); + + auto& tcheckpoints_aid = tcheckpoints[aid]; + tcheckpoints_aid[next_checkpoint_aid - 1] = path_aid.tmax = tmin; + + const auto& checkpoints_aid = checkpoints[aid]; + const auto& checkpoints_o_aid = checkpoints_o[aid]; + auto& checkpoints_cnt_aid = checkpoints_cnt[aid]; + + ++nodecnt_marked_idx; + + if (agent_aid.inside_poz) { + nodecnt_marked[agent_aid.poz_node] = nodecnt_marked_idx; + nodecnt[agent_aid.poz_node] = checkpoints_cnt_aid[next_checkpoint_aid - 1] = 1; + assert(checkpoints_aid[next_checkpoint_aid - 1] == agent_aid.poz_node); + } + + for (int cid = next_checkpoint_aid; cid < num_checkpoints_aid; ++cid) { + const auto& node = checkpoints_aid[cid]; + if (nodecnt_marked[node] != nodecnt_marked_idx) { + nodecnt_marked[node] = nodecnt_marked_idx; + nodecnt[node] = 0; + } + checkpoints_cnt_aid[cid] = ++nodecnt[node]; + } + } + + RepopulateVisitingOrders(); + + auto& is_covered_0 = is_covered[0]; + auto& is_covered_idx_0 = is_covered_idx[0]; + auto& covered_by_0 = covered_by[0]; + + bool updated_visiting_order = true; + int nelems = 0; + + while (updated_visiting_order) { + updated_visiting_order = false; + ++is_covered_idx_0; + + for (int node = 0; node < nnodes; ++node) is_free[node] = 1; + + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + next_aidx[aid] = next_checkpoint[aid]; + auto& path_aid = path[aid]; + const int tmin = TINIT + max(0, agent_aid.malfunc - (agent_aid.inside_poz ? /*1*/ 0 : /*2*/ 1)); + for (int t = TINIT + 1; t <= tmin && t <= T; ++t) { + auto& new_path_elem = path_aid.p[t]; + memcpy(&new_path_elem, &path_aid.p[t - 1], sizeof(PathElem)); + new_path_elem.how_i_got_here = agent_aid.inside_poz ? MALFUNCTIONED : OUTSIDE_SRC; + if (agent_aid.inside_poz) { + assert(is_covered_0[t][new_path_elem.node] != is_covered_idx_0); + is_covered_0[t][new_path_elem.node] = is_covered_idx_0; + covered_by_0[t][new_path_elem.node] = aid; + } + } + + path_aid.tmax = tmin; + + if (agent_aid.inside_poz) { + is_free[agent_aid.poz_node] = 0; + is_covered_0[TINIT][agent_aid.poz_node] = is_covered_idx_0; + covered_by_0[TINIT][agent_aid.poz_node] = aid; + } + } + + int qli = 0, qls = 0; + + for (int node = 0; node < nnodes; ++node) { + next_vidx[node] = 0; + auto& ipath_visiting_order_node = ipath_visiting_order[node]; + if (ipath_visiting_order_node.empty()) continue; + for (auto& elem_pair : ipath_visiting_order_node) elem_pair.first = TINIT; + const auto& aid_0 = ipath_visiting_order_node[0].second; + if (is_free[node] && checkpoints[aid_0][next_aidx[aid_0]] == node) { + qaid[qls] = aid_0; + qls = (qls + 1) & QMOD; + } + } + + nelems = 0; + + int tmin_incomplete = -1, aid_incomplete = -1; + + while (qli != qls) { + ++nelems; + + const auto& aid = qaid[qli]; + const auto& agent_aid = agent[aid]; + const auto& checkpoints_aid = checkpoints[aid]; + const auto& checkpoints_o_aid = checkpoints_o[aid]; + auto& tcheckpoints_aid = tcheckpoints[aid]; + auto& next_aidx_aid = next_aidx[aid]; + const auto& next_checkpoint_aid = next_checkpoint[aid]; + assert(next_checkpoint_aid <= next_aidx_aid && next_aidx_aid < num_checkpoints[aid]); + const auto& curr_node = checkpoints_aid[next_aidx_aid - 1]; + const auto& next_node = checkpoints_aid[next_aidx_aid]; + + qli = (qli + 1) & QMOD; + + assert(0 <= next_node && next_node < nnodes); + assert(is_free[next_node]); + if (curr_node >= 0) assert(!is_free[curr_node]); + + const auto& t_curr_node = tcheckpoints_aid[next_aidx_aid - 1]; + const auto& next_o = checkpoints_o_aid[next_aidx_aid]; + + auto& next_vidx_next_node = next_vidx[next_node]; + auto& ipath_visiting_order_next_node = ipath_visiting_order[next_node]; + assert(next_vidx_next_node < ipath_visiting_order_next_node.size()); + assert(ipath_visiting_order_next_node[next_vidx_next_node].second == aid); + + int tend_move = ipath_visiting_order_next_node[next_vidx_next_node].first; + + //const bool print_debug = (aid == 76 || aid == 24) && (curr_node == 117 || next_node == 117); + const bool print_debug = false; + + if (print_debug) DBG(0, "\n[AdjustIPaths-Debug-A] aid=%d next_aidx_aid=%d next_node=%d:(%d %d) next_vidx_next_node=%d curr_node=%d:(%d %d) t_curr_node=%d tend_move=%d(init) \n", aid, next_aidx_aid, next_node, node[next_node].row, node[next_node].col, next_vidx_next_node, curr_node, node[curr_node].row, node[curr_node].col, t_curr_node, tend_move); + + auto& path_aid = path[aid]; + + if (next_aidx_aid > next_checkpoint_aid && path_aid.tmax <= T) assert(path_aid.p[path_aid.tmax].num_partial_turns == 0); + + const int move_duration = max(1, curr_node < 0 ? 1 : (next_aidx_aid == next_checkpoint_aid ? agent_aid.cturns - path_aid.p[TINIT].num_partial_turns : agent_aid.cturns)); + int tstart_move = tend_move - move_duration; + if (tstart_move < t_curr_node) tstart_move = t_curr_node; + + if (print_debug) DBG(0, "\n[AdjustIPaths-Debug-B] aid=%d next_aidx_aid=%d next_node=%d:(%d %d) next_vidx_next_node=%d curr_node=%d:(%d %d) t_curr_node=%d tstart_move=%d tend_move=%d move_duration=%d\n", aid, next_aidx_aid, next_node, node[next_node].row, node[next_node].col, next_vidx_next_node, curr_node, node[curr_node].row, node[curr_node].col, t_curr_node, tstart_move, tend_move, move_duration); + + assert(path_aid.tmax == t_curr_node); + if (t_curr_node <= T && curr_node >= 0) assert(path_aid.p[t_curr_node].node == curr_node); + int t = t_curr_node + 1; + + tend_move = tstart_move + move_duration; + + if (!agent_aid.inside_poz && next_aidx_aid == next_checkpoint_aid) { + for (; t <= tstart_move; ++t) { + assert(path_aid.tmax == t - 1); + path_aid.tmax = t; + if (t <= T) { + auto& new_path_elem = path_aid.p[t]; + memcpy(&new_path_elem, &path_aid.p[t - 1], sizeof(PathElem)); + new_path_elem.how_i_got_here = OUTSIDE_SRC; + } + } + assert(t == tend_move); + path_aid.tmax = t; + if (t <= T) { + auto& new_path_elem = path_aid.p[t]; + memcpy(&new_path_elem, &path_aid.p[t - 1], sizeof(PathElem)); + new_path_elem.how_i_got_here = ENTERED_SRC; + is_covered_0[t][new_path_elem.node] = is_covered_idx_0; + covered_by_0[t][new_path_elem.node] = aid; + assert(t == tend_move); + } + ++t; + } + + if (curr_node >= 0) { + if (path_aid.p[TINIT].num_partial_turns >= 1) assert(agent_aid.moving_to_node >= 0); + if (next_aidx_aid > next_checkpoint_aid || /*path_aid.p[TINIT].num_partial_turns == 0*/ agent_aid.moving_to_node < 0) { + for (; t <= tstart_move; ++t) { + assert(path_aid.tmax == t - 1); + path_aid.tmax = t; + if (t <= T) { + auto& new_path_elem = path_aid.p[t]; + memcpy(&new_path_elem, &path_aid.p[t - 1], sizeof(PathElem)); + new_path_elem.how_i_got_here = WAITED; + assert(new_path_elem.num_partial_turns == 0); + is_covered_0[t][new_path_elem.node] = is_covered_idx_0; + covered_by_0[t][new_path_elem.node] = aid; + } + } + } + int num_partial_turns = next_aidx_aid > next_checkpoint_aid ? 0 : path_aid.p[TINIT].num_partial_turns; + for (; 1; ++t) { + assert(path_aid.tmax == t - 1); + assert(t > TINIT); + path_aid.tmax = t; + PathElem* new_path_elem = nullptr; + if (t <= T) new_path_elem = &path_aid.p[t]; + if (new_path_elem != nullptr) memcpy(new_path_elem, &path_aid.p[t - 1], sizeof(PathElem)); + ++num_partial_turns; + if (print_debug) DBG(0, " aid=%d t=%d/%d npt=%d\n", aid, t, tend_move, num_partial_turns); + if (new_path_elem != nullptr) { + new_path_elem->num_partial_turns = num_partial_turns; + if (new_path_elem->num_partial_turns == 1) new_path_elem->how_i_got_here = STARTED_MOVING; + else new_path_elem->how_i_got_here = CONTINUED_MOVING; + new_path_elem->moving_to_node = next_node; + new_path_elem->moving_to_o = next_o; + if (new_path_elem->num_partial_turns >= 2) { + if (print_debug) DBG(0, " prev_moving_to=(%d %d)\n", path_aid.p[t - 1].moving_to_node, path_aid.p[t - 1].moving_to_o); + assert(path_aid.p[t - 1].moving_to_node == next_node); + assert(path_aid.p[t - 1].moving_to_o == next_o); + } + } + if (num_partial_turns >= agent_aid.cturns) { + if (t >= tend_move) { + if (new_path_elem != nullptr) { + new_path_elem->node = next_node; + new_path_elem->o = next_o; + new_path_elem->moving_to_node = new_path_elem->moving_to_o = -1; + new_path_elem->num_partial_turns = 0; + if (new_path_elem->node != agent_aid.target_node) { + is_covered_0[t][new_path_elem->node] = is_covered_idx_0; + covered_by_0[t][new_path_elem->node] = aid; + } + } + tend_move = t; + ++t; + break; + } else if (new_path_elem != nullptr) { + if (print_debug) DBG(0, " >>> is_cov_next_node=%d cov_by=%d\n", is_covered_0[t][next_node] == is_covered_idx_0, covered_by_0[t][next_node]); + if ((is_covered_0[t][next_node] != is_covered_idx_0 && + (is_covered_0[t - 1][next_node] != is_covered_idx_0 || + covered_by_0[t - 1][next_node] < aid)) || + (is_covered_0[t][next_node] == is_covered_idx_0 && covered_by_0[t][next_node] > aid && + (is_covered_0[t - 1][next_node] != is_covered_idx_0 || + covered_by_0[t - 1][next_node] != covered_by_0[t][next_node]))) { + DBG(0, "||| [AdjustIPaths] Agent in motion cannot wait for delayed agent: aid=%d next_aidx_aid=%d nextcp=%d tend=%d t=%d curr_node=%d:(%d %d) next_node=%d:(%d %d) next_vidx_next_node=%d target_node=%d:(%d %d) nelems=%d\n", aid, next_aidx_aid, next_checkpoint[aid], tend_move, t, curr_node, node[curr_node].row, node[curr_node].col, next_node, node[next_node].row, node[next_node].col, next_vidx_next_node, agent_aid.target_node, node[agent_aid.target_node].row, node[agent_aid.target_node].col, nelems); + assert(next_vidx_next_node >= 1); + const int prev_aid = ipath_visiting_order_next_node[next_vidx_next_node - 1].second; + DBG(0, " prev_aid=%d\n", prev_aid); + SwapVisitingOrder(aid, next_aidx_aid, prev_aid); + updated_visiting_order = true; + break; + } + if (new_path_elem->node != agent_aid.target_node) { + is_covered_0[t][new_path_elem->node] = is_covered_idx_0; + covered_by_0[t][new_path_elem->node] = aid; + } + } + } else if (new_path_elem != nullptr) { + is_covered_0[t][new_path_elem->node] = is_covered_idx_0; + covered_by_0[t][new_path_elem->node] = aid; + assert(num_partial_turns >= 1); + assert(0 <= new_path_elem->moving_to_node && new_path_elem->moving_to_node < nnodes); + } + } + } + + if (updated_visiting_order) break; + + if (print_debug) DBG(0, "\n[AdjustIPaths-Debug-C] aid=%d next_aidx_aid=%d next_node=%d:(%d %d) next_vidx_next_node=%d curr_node=%d:(%d %d) t_curr_node=%d tstart_move=%d tend_move=%d move_duration=%d\n", aid, next_aidx_aid, next_node, node[next_node].row, node[next_node].col, next_vidx_next_node, curr_node, node[curr_node].row, node[curr_node].col, t_curr_node, tstart_move, tend_move, move_duration); + + if (t != tend_move + 1) { + DBG(0, "!!!A aid=%d next_aidx_aid=%d curr_node=%d curr_npt=%d curr_how=%d next_node=%d tstart_move=%d tend_move=%d t=%d: last_path_elem=(node=%d npt=%d/%d how=%d)\n", aid, next_aidx_aid, curr_node, path_aid.p[t_curr_node].num_partial_turns, path_aid.p[t_curr_node].how_i_got_here, next_node, tstart_move, tend_move, t, path_aid.p[path_aid.tmax].node, path_aid.p[path_aid.tmax].num_partial_turns, agent_aid.cturns, path_aid.p[path_aid.tmax].how_i_got_here); + exit(1); + } + + assert(path_aid.tmax == tend_move); + if (tend_move <= T && path_aid.p[tend_move].node != next_node) { + DBG(0, "!!!B aid=%d next_aidx_aid=%d curr_node=%d curr_npt=%d curr_how=%d next_node=%d tstart_move=%d tend_move=%d: last_path_elem=(node=%d npt=%d/%d how=%d)\n", aid, next_aidx_aid, curr_node, path_aid.p[t_curr_node].num_partial_turns, path_aid.p[t_curr_node].how_i_got_here, next_node, tstart_move, tend_move, path_aid.p[path_aid.tmax].node, path_aid.p[path_aid.tmax].num_partial_turns, agent_aid.cturns, path_aid.p[path_aid.tmax].how_i_got_here); + exit(1); + } + + tcheckpoints_aid[next_aidx_aid] = tend_move; + if (curr_node >= 0) is_free[curr_node] = 1; + is_free[next_node] = 0; + ++next_aidx_aid; + ++next_vidx_next_node; + + if (next_aidx_aid < num_checkpoints[aid]) { + const auto& next2_node = checkpoints_aid[next_aidx_aid]; + auto& next_vidx2_next2_node = next_vidx[next2_node]; + auto& ipath_visiting_order_next2_node = ipath_visiting_order[next2_node]; + if (next2_node != curr_node && ipath_visiting_order_next2_node[next_vidx2_next2_node].second == aid && is_free[next2_node]) { + qaid[qls] = aid; + qls = (qls + 1) & QMOD; + } + } else if (next_node == agent_aid.target_node) { + // Free up next_node right away. + is_free[next_node] = 1; + if (next_vidx_next_node < ipath_visiting_order_next_node.size()) { + const auto& aid1 = ipath_visiting_order_next_node[next_vidx_next_node].second; + const auto& path_aid1 = path[aid1]; + const auto& last_path_elem = path_aid1.p[path_aid1.tmax]; + int tend_move_aid1 = tend_move + (aid1 < aid && agent[aid1].target_node != next_node ? 1 : 0); + const auto& agent_aid1 = agent[aid1]; + if (USE_SPACING_TO_AVOID_DEADLOCKS && last_path_elem.num_partial_turns == 0 && (next_aidx[aid1] > next_checkpoint[aid1] || agent[aid1].moving_to_node < 0)) { + const int min_tstart = tend_move;//USE_STRICT_SPACING_TO_AVOID_DEADLOCKS ? tend_move : t_curr_node; + assert(t_curr_node < tend_move); + if (tend_move_aid1 - agent_aid1.cturns < min_tstart) tend_move_aid1 = min_tstart + agent_aid1.cturns; + } + ipath_visiting_order_next_node[next_vidx_next_node].first = tend_move_aid1; + if (checkpoints[aid1][next_aidx[aid1]] == next_node) { + qaid[qls] = aid1; + qls = (qls + 1) & QMOD; + } + } + } + + if (curr_node >= 0) { + const auto& next_vidx_curr_node = next_vidx[curr_node]; + auto& ipath_visiting_order_curr_node = ipath_visiting_order[curr_node]; + if (next_vidx_curr_node < ipath_visiting_order_curr_node.size()) { + const auto& aid1 = ipath_visiting_order_curr_node[next_vidx_curr_node].second; + const auto& path_aid1 = path[aid1]; + const auto& last_path_elem = path_aid1.p[path_aid1.tmax]; + int tend_move_aid1 = tend_move + (aid1 < aid ? 1 : 0); + const auto& agent_aid1 = agent[aid1]; + if (USE_SPACING_TO_AVOID_DEADLOCKS && last_path_elem.num_partial_turns == 0 && (next_aidx[aid1] > next_checkpoint[aid1] || agent[aid1].moving_to_node < 0)) { + const int min_tstart = t_curr_node;//USE_STRICT_SPACING_TO_AVOID_DEADLOCKS ? tend_move : t_curr_node; + assert(t_curr_node < tend_move); + if (tend_move_aid1 - agent_aid1.cturns < min_tstart) tend_move_aid1 = min_tstart + agent_aid1.cturns; + } + ipath_visiting_order_curr_node[next_vidx_curr_node].first = tend_move_aid1; + if (checkpoints[aid1][next_aidx[aid1]] == curr_node) { + qaid[qls] = aid1; + qls = (qls + 1) & QMOD; + } + } + } + } + + DBG(2, "[AdjustIPaths] nelems=%d updvis=%d\n", nelems, updated_visiting_order); + if (updated_visiting_order) continue; + + if (aid_incomplete < 0) { + for (int node = 0; node < nnodes; ++node) { + const auto& next_vidx_node = next_vidx[node]; + const auto& ipath_visiting_order_node = ipath_visiting_order[node]; + if (next_vidx_node < ipath_visiting_order_node.size()) { + const auto& aid = ipath_visiting_order_node[next_vidx_node].second; + const auto& next_aidx_aid = next_aidx[aid]; + DBG(0, "[AdjustIPaths] incomplete: node=%d is_free=%d next_vidx=%d/%d: aid=%d next_aidx_aid=%d/%d:node=%d/t=%d nextcp=%d\n", node, is_free[node], next_vidx_node, ipath_visiting_order_node.size(), aid, next_aidx_aid, num_checkpoints[aid], checkpoints[aid][next_aidx_aid], checkpoints_t[aid][next_aidx_aid], next_checkpoint[aid]); + assert(next_aidx_aid < num_checkpoints[aid]); + assert(!is_free[node] || checkpoints[aid][next_aidx_aid] != node); + const auto& t_inc = max(ipath_visiting_order_node[next_vidx_node].first, tcheckpoints[aid][next_aidx_aid - 1]); + if (aid_incomplete < 0 || t_inc < tmin_incomplete) { + aid_incomplete = aid; + tmin_incomplete = t_inc; + } + } + } + + assert(aid_incomplete < 0); + } + } + + ++is_covered_idx_0; + + for (int aid = 0; aid < N; ++aid) { + auto& ipath_aid = ipath[aid]; + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + + const auto& num_checkpoints_aid = num_checkpoints[aid]; + const auto& checkpoints_aid = checkpoints[aid]; + const auto& tcheckpoints_aid = tcheckpoints[aid]; + const auto& next_aidx_aid = next_aidx[aid]; + + if (next_aidx_aid < num_checkpoints_aid) { + const auto& v = checkpoints_aid[next_aidx_aid]; + const auto& ipath_visiting_order_v = ipath_visiting_order[v]; + const auto& next_vidx_v = next_vidx[v]; + assert(next_vidx_v < ipath_visiting_order_v.size()); + DBG(0, "!!! [AdjustIPaths] aid=%d next_aidx_aid=%d/%d: v=%d(%d) next_vidx_v=%d/%d: t=%d vaid=%d\n", aid, next_aidx_aid, num_checkpoints_aid, v, is_free[v], next_vidx_v, ipath_visiting_order_v.size(), ipath_visiting_order_v[next_vidx_v].first, ipath_visiting_order_v[next_vidx_v].second); + exit(1); + } + + // Construct the path. + auto& path_aid = path[aid]; + if (path_aid.tmax > T) path_aid.tmax = T; + + if (path_aid.p[path_aid.tmax].how_i_got_here == OUTSIDE_SRC) { + for (int t = path_aid.tmax + 1; t <= T; ++t) { + auto& new_path_elem = path_aid.p[t]; + new_path_elem.node = agent_aid.poz_node; + new_path_elem.o = agent_aid.poz_o; + new_path_elem.moving_to_node = new_path_elem.moving_to_o = -1; + new_path_elem.num_partial_turns = 0; + new_path_elem.how_i_got_here = OUTSIDE_SRC; + } + path_aid.tmax = T; + } else if (path_aid.tmax < T && path_aid.p[path_aid.tmax].node != agent_aid.target_node) { + const auto& last_num_partial_turns = path_aid.p[path_aid.tmax].num_partial_turns; + const auto& last_how_i_got_here = path_aid.p[path_aid.tmax].how_i_got_here; + DBG(3, "!!! [AdjustIPaths] aid=%d next_aidx_aid=%d/%d tmax=%d/%d last_node=%d:(%d %d) npt=%d/%d target_node=%d:(%d %d)\n", aid, next_aidx[aid], num_checkpoints[aid], path_aid.tmax, T, path_aid.p[path_aid.tmax].node, node[path_aid.p[path_aid.tmax].node].row, node[path_aid.p[path_aid.tmax].node].col, last_num_partial_turns, agent_aid.cturns, agent_aid.target_node, node[agent_aid.target_node].row, node[agent_aid.target_node].col); + while (path_aid.tmax < T) { + ++path_aid.tmax; + auto& new_path_elem = path_aid.p[path_aid.tmax]; + memcpy(&new_path_elem, &path_aid.p[path_aid.tmax - 1], sizeof(PathElem)); + if (last_num_partial_turns == 0) + new_path_elem.how_i_got_here = last_how_i_got_here == OUTSIDE_SRC ? OUTSIDE_SRC : WAITED; + else { + ++new_path_elem.num_partial_turns; + new_path_elem.how_i_got_here = CONTINUED_MOVING; + } + } + } + + assert(path_aid.tmax <= T); + for (int t = TINIT; t <= path_aid.tmax; ++t) { + const auto& path_elem = path_aid.p[t]; + if (path_elem.how_i_got_here == OUTSIDE_SRC) continue; + if (path_elem.node == agent_aid.target_node) { + assert(t == path_aid.tmax); + continue; + } + assert(0 <= path_elem.node && path_elem.node < nnodes); + if (is_covered_0[t][path_elem.node] == is_covered_idx_0) { + DBG(0, "!!! [AdjustIPaths] aid=%d t=%d node=%d already covered by %d\n", aid, t, path_elem.node, covered_by_0[t][path_elem.node]); + exit(1); + } + is_covered_0[t][path_elem.node] = is_covered_idx_0; + covered_by_0[t][path_elem.node] = aid; + } + + if (path_aid.tmax != ipath_aid.tmax || path_aid.p[path_aid.tmax].node != ipath_aid.p[path_aid.tmax].node) { + DBG(3, "[AdjustIPaths] aid=%d diff: prev:(tmax=%d node=%d) curr:(tmax=%d node=%d)\n", aid, path_aid.tmax, path_aid.p[path_aid.tmax].node, ipath_aid.tmax, ipath_aid.p[ipath_aid.tmax].node); + } + + CopyPath(path_aid, &ipath_aid); + } + + RunConsistencyChecks(path, covered_by_0, is_covered_0, is_covered_idx_0); + + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + auto& checkpoints_t_aid = checkpoints_t[aid]; + const auto& tcheckpoints_aid = tcheckpoints[aid]; + const auto& num_checkpoints_aid = num_checkpoints[aid]; + for (int cid = next_checkpoint[aid]; cid < num_checkpoints_aid; ++cid) + checkpoints_t_aid[cid] = tcheckpoints_aid[cid]; + } + + MAX_DONE_AGENTS = 0; + MIN_COST = 0.0; + int new_max_tmax = 0; + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + if (agent_aid.status == DONE_REMOVED) continue; + const auto& path_aid = path[aid]; + assert(path_aid.tmax > TINIT); + if (path_aid.p[path_aid.tmax].node == agent_aid.target_node) { + ++MAX_DONE_AGENTS; + MIN_COST += GetScore(path_aid.tmax); + if (path_aid.tmax > new_max_tmax) new_max_tmax = path_aid.tmax; + } else { + assert(path_aid.tmax == T); + } + } + if (MAX_DONE_AGENTS >= 1) MIN_COST /= MAX_DONE_AGENTS; + + const bool changed_important_data = MAX_DONE_AGENTS != num_planned || new_max_tmax > max_tmax; + if (changed_important_data) { + DBG(0, ">>> [AdjustIPaths] mda=%d/%d minc=%.6lf new_max_tmax=%d/%d\n", MAX_DONE_AGENTS, num_planned, MIN_COST, new_max_tmax, max_tmax); + } + + CheckNonDeadlockPaths(); + + return !changed_important_data; +} + +void ReinitDataStructures() { + MAX_DONE_AGENTS = 0; + MIN_COST = 1e10; + for (int aid = 0; aid < N; ++aid) path[aid].tmax = -1000; + xor128[0].reset(14012019U); + for (int tid = 1; tid < MAX_NUM_THREADS; ++tid) xor128[tid].reset(19999997U * tid + 29997U); + for (int tid = 0; tid < MAX_NUM_THREADS; ++tid) { + can_reach_idx[tid] = is_covered_idx[tid] = 0; + auto& can_reach_tid = can_reach[tid]; + auto& is_covered_tid = is_covered[tid]; + for (int t = 0; t <= T + 2; ++t) { + auto& can_reach_tid_t = can_reach_tid[t]; + auto& is_covered_tid_t = is_covered_tid[t]; + for (int i = 0; i < nnodes; ++i) { + is_covered_tid_t[i] = 0; + auto& can_reach_tid_t_i = can_reach_tid_t[i]; + for (int o = 0; o <= 3; ++o) can_reach_tid_t_i[o] = 0; + } + } + } +} + +int GetMove(int aid) { + if (num_planned == 0) return DO_NOTHING; + const auto& path_aid = path[aid]; + auto& agent_aid = agent[aid]; + if (path_aid.tmax < TINIT + 1) return DO_NOTHING; + const auto& path_elem = path_aid.p[TINIT]; + const auto& path_elem_end_turn = path_aid.p[TINIT + 1]; + int action = DO_NOTHING; + DBG(2, " GetMove for aid=%d: tmax=%d\n", aid, path_aid.tmax); + if (path_elem_end_turn.how_i_got_here == ENTERED_SRC) { + assert(path_elem.node == path_elem_end_turn.node); + assert(path_elem.o == path_elem_end_turn.o); + assert(path_elem.moving_to_node < 0); + assert(path_elem.moving_to_o < 0); + assert(path_elem_end_turn.num_partial_turns == 0); + action = MOVE_FORWARD; + assert(agent_aid.moving_to_node < 0); + } else if (path_elem_end_turn.how_i_got_here == WAITED) { + assert(path_elem.node == path_elem_end_turn.node); + assert(path_elem.o == path_elem_end_turn.o); + assert(path_elem.moving_to_node < 0); + assert(path_elem.moving_to_o < 0); + assert(path_elem.num_partial_turns == 0); + assert(path_elem_end_turn.num_partial_turns == 0); + action = STOP_MOVING; + assert(agent_aid.moving_to_node < 0); + } else if (path_elem_end_turn.how_i_got_here == STARTED_MOVING) { + assert(path_elem_end_turn.num_partial_turns <= 1); + int dst_node = -1, dst_o = -1; + if (path_elem_end_turn.moving_to_node >= 0 && path_elem_end_turn.moving_to_o >= 0) { + assert(path_elem_end_turn.num_partial_turns == 1); + dst_node = path_elem_end_turn.moving_to_node; + dst_o = path_elem_end_turn.moving_to_o; + } else { + assert(path_elem_end_turn.num_partial_turns == 0); + dst_node = path_elem_end_turn.node; + dst_o = path_elem_end_turn.o; + } + assert(path_elem.node != dst_node); + assert(next[path_elem.node][path_elem.o][dst_o] == dst_node); + if (dst_o == path_elem.o || dst_o == ((path_elem.o + 2) & 3)) + action = MOVE_FORWARD; + else if (dst_o == ((path_elem.o + 1) & 3)) + action = MOVE_RIGHT; + else if (dst_o == ((path_elem.o + 3) & 3)) + action = MOVE_LEFT; + else { + DBG(0, "Incorrect move!!!\n"); + exit(1); + } + assert(agent_aid.moving_to_node < 0 || (agent_aid.moving_to_node == dst_node && agent_aid.moving_to_o == dst_o)); + agent_aid.moving_to_node = dst_node; + agent_aid.moving_to_o = dst_o; + } else if (path_elem_end_turn.how_i_got_here == CONTINUED_MOVING) { + if (path_elem.node == path_elem_end_turn.node) { + assert(path_elem.o == path_elem_end_turn.o); + assert(path_elem.moving_to_node == path_elem_end_turn.moving_to_node); + assert(path_elem_end_turn.num_partial_turns == path_elem.num_partial_turns + 1); + } else { + assert(path_elem_end_turn.moving_to_node < 0); + assert(path_elem_end_turn.moving_to_o < 0); + assert(path_elem_end_turn.num_partial_turns == 0); + } + } else if (path_elem_end_turn.how_i_got_here == MALFUNCTIONED) { + assert(path_elem.node == path_elem_end_turn.node); + assert(path_elem.o == path_elem_end_turn.o); + assert(path_elem.moving_to_node == path_elem_end_turn.moving_to_node); + assert(path_elem.moving_to_o == path_elem_end_turn.moving_to_o); + assert(path_elem.num_partial_turns == path_elem_end_turn.num_partial_turns); + } + return action; +} + +void WriteMoves(const char* testid) { + num_planned = 0; + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + const auto& ipath_aid = ipath[aid]; + if (ipath_aid.tmax > TINIT && ipath_aid.p[ipath_aid.tmax].node == agent_aid.target_node) ++num_planned; + } + sprintf(fname, "output-%s.txt", testid); + FILE* f = fopen(fname, "w"); + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + const int action = GetMove(aid); + fprintf(f, "%d ", action); + if (action != DO_NOTHING) DBG(2, " Move aid=%d: %d\n", aid, action); + } + fprintf(f, "\n"); + fclose(f); +} + +void SaveDataForReplay(const char* testid) { + sprintf(fname, "saved-%s-%d.txt", testid, TINIT); + FILE* f = fopen(fname, "w"); + fprintf(f, "1\n%d %d\n", H, W); + for (int v = 0; v < nnodes; ++v) { + const auto& node_v = node[v]; + const auto& next_v = next[v]; + for (int o1 = 0; o1 <= 3; ++o1) for (int o2 = 0; o2 <= 3; ++o2) + if (next_v[o1][o2] >= 0) fprintf(f, "%d %d %d %d\n", node_v.row, node_v.col, o1, o2); + } + fprintf(f, "-1 -1 -1 -1\n%d %d\n%d %d %d\n", N, TINIT, num_reschedules, num_planned, num_adjust_ipaths_without_full_plan_regeneration); + for (int aid = 0; aid < N; ++aid) { + const auto& agent_aid = agent[aid]; + fprintf(f, "%d %d %d %d %d %d %.10lf %.10lf %d %d %d %d 1 1 %d %d %d\n", agent_aid.aid, agent_aid.poz_row, agent_aid.poz_col, agent_aid.poz_o, agent_aid.target_row, agent_aid.target_col, agent_aid.speed, agent_aid.poz_frac, agent_aid.malfunc, agent_aid.nr_malfunc, agent_aid.status, agent_aid.fresh_malfunc, agent_aid.moving_to_node >= 0 ? node[agent_aid.moving_to_node].row : -1, agent_aid.moving_to_node >= 0 ? node[agent_aid.moving_to_node].col : -1, agent_aid.moving_to_o); + const auto& ipath_aid = ipath[aid]; + fprintf(f, "%d\n", ipath_aid.tmax); + for (int t = TINIT; t <= ipath_aid.tmax; ++t) { + const auto& path_elem = ipath_aid.p[t]; + fprintf(f, "%d %d %d %d %d %d %d %d\n", node[path_elem.node].row, node[path_elem.node].col, path_elem.o, path_elem.moving_to_node < 0 ? -1 : node[path_elem.moving_to_node].row, path_elem.moving_to_node < 0 ? -1 : node[path_elem.moving_to_node].col, path_elem.moving_to_o, path_elem.num_partial_turns, path_elem.how_i_got_here); + } + const auto& num_checkpoints_aid = num_checkpoints[aid]; + const auto& next_checkpoint_aid = next_checkpoint[aid]; + fprintf(f, "%d\n", num_checkpoints_aid - next_checkpoint_aid); + const auto& checkpoints_aid = checkpoints[aid]; + const auto& checkpoints_o_aid = checkpoints_o[aid]; + const auto& checkpoints_t_aid = checkpoints_t[aid]; + for (int cid = next_checkpoint_aid; cid < num_checkpoints_aid; ++cid) { + fprintf(f, "%d %d %d %d\n", node[checkpoints_aid[cid]].row, node[checkpoints_aid[cid]].col, checkpoints_o_aid[cid], checkpoints_t_aid[cid]); + } + } + fprintf(f, "%d\n", T); + fclose(f); +} + +double total_time; + +void GetMoves(const char* testid, bool replay_mode = false) { + TSTART = GetTime(); + sprintf(fname, "input-%s.txt", testid); + fin = fopen(fname, "r"); + ReadTransitionsMap(); + ReadAgentsData(replay_mode); + fclose(fin); + if (TINIT == 0 || replay_mode) { + ReinitDataStructures(); + ComputeShortestPaths(); + } + SCORE_EXPONENT1 = 2.0; + SCORE_EXPONENT2 = 4.0; + DBG(2, "testid=%s TINIT=%d: resc=%d nda=%d npl=%d\n", testid, TINIT, reschedule, num_done_agents, num_planned); + if (reschedule) { + if (TINIT >= MIN_TINIT_FOR_SAVE_DATA_FOR_REPLAY) SaveDataForReplay(testid); + bool updated_paths_ok = false; + if (TINIT >= 1) { + updated_paths_ok = AdjustIPaths(); + ++num_adjust_ipaths_without_full_plan_regeneration; + } + const int kMaxNumAdjustIPathsWithoutFullPlanRegenartion = 5;//10; + if (!updated_paths_ok || num_adjust_ipaths_without_full_plan_regeneration > kMaxNumAdjustIPathsWithoutFullPlanRegenartion) { + RegenerateFullPlan(); + if (TINIT >= 1 && any_best_solution_updates) AdjustIPaths(); + num_adjust_ipaths_without_full_plan_regeneration = 0; + } + } + WriteMoves(testid); + if (TINIT == 0) total_time = 0.0; + total_time += GetTime() - TSTART; + DBG(0, "[GetMoves] testid=%s TINIT=%d/%d ttime=%.3lf nresc=%d nadjip=%d nadjipwofpr=%d nda=%d npl=%d sum=%d/%d(%.2lf)\n", testid, TINIT, TEST, total_time, num_reschedules, num_adjust_ipaths, num_adjust_ipaths_without_full_plan_regeneration, num_done_agents, num_planned, num_done_agents + num_planned, N, 100.0 * (num_done_agents + num_planned) / N); + + /*for (int aid = 0; aid < N; ++aid) { + if (aid == 27 || aid == 49 || aid == 56) { + const auto& ipath_aid = ipath[aid]; + for (int t = max(TINIT, 450); t <= 490 && t <= ipath_aid.tmax; ++t) { + const auto& elem = ipath_aid.p[t]; + DBG(0, "aid=%d t=%d node=%d npt=%d\n", aid, t, elem.node, elem.num_partial_turns); + } + } + }*/ +} + +} + +void GetMoves(const char* testid) { + SOLVE::GetMoves(testid, false); +} + +int main() { + SOLVE::GetMoves("1", true); + return 0; +} +