├── .gitignore ├── README.md ├── allMaps ├── map1.txt ├── map2.txt ├── map3.txt ├── room.txt └── room2.txt ├── code ├── CMakeLists.txt ├── berth.hpp ├── berth_centre.hpp ├── config.hpp ├── count.hpp ├── estimator.hpp ├── grid.hpp ├── input.hpp ├── item.hpp ├── logger.hpp ├── main.cpp ├── para.txt ├── path.hpp ├── pos.hpp ├── robot.hpp └── ship.hpp ├── dcode ├── include │ └── fmt │ │ ├── args.h │ │ ├── chrono.h │ │ ├── color.h │ │ ├── compile.h │ │ ├── core.h │ │ ├── format-inl.h │ │ ├── format.h │ │ ├── os.h │ │ ├── ostream.h │ │ ├── printf.h │ │ ├── ranges.h │ │ ├── std.h │ │ └── xchar.h └── src │ ├── fmt.cc │ ├── format.cc │ └── os.cc ├── img ├── map.png └── replay.png ├── testMaps ├── blank.txt ├── blank2.txt ├── blank3.txt └── single_path.txt ├── testMaps_legacy ├── PleasePartitionThisMap.txt ├── fullMap.txt ├── juhua.txt ├── juhua2.txt ├── juhua3.txt ├── largeMap.txt ├── map1.txt ├── map2.txt ├── map2_1.txt ├── map3.txt ├── map4.txt ├── map5.txt ├── map6.txt ├── map7.txt ├── map8.txt ├── map9.txt ├── mediaMap.txt ├── real_juhua.txt ├── smallMap.txt ├── tt0.txt ├── tt1.txt ├── tt2.txt ├── tt3.txt ├── tt4.txt ├── tt5.txt ├── worst_map.txt ├── zss_map1.txt └── zss_map2.txt └── tools ├── MapEditor_pygame.py ├── Replayer_pygame_fast.py ├── analysis.py ├── legacy ├── MapEditor.py ├── Mapeditor.sh ├── Replayer_pygame.py └── vis.py ├── llt.ttf ├── run.bat ├── run.py ├── run.sh ├── runall.sh ├── seed_selector.py ├── test.py ├── tune.py ├── upload.bat ├── upload.py └── upload.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | judge/ 3 | upload/ 4 | problem/ 5 | oldFile/ 6 | test/ 7 | log/ 8 | .vscode/ 9 | main 10 | code/output.txt 11 | *.img 12 | *.zip 13 | *.a 14 | *.o 15 | *.exe 16 | main.dSYM 17 | *.rep 18 | __pycache__ 19 | my_map.txt 20 | *.png 21 | *.pkl 22 | para.txt 23 | time.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 华为软件精英挑战赛 2024 江山赛区 年年旅游嘎嘎开心 2 | 3 | ## 亮点: 4 | ### 基于 pygame 的 replayer 5 | 我们基于 pygame 写了一套播放器,支持 0.25~16x的倍速,支持任意帧的跳转,支持机器人路径的显示,支持标注机器人状态,支持暂停时前后帧的移动 6 | ![](img/replay.png) 7 | 8 | ### 基于 pygame 的地图编辑器 9 | 我们基于 pygame 写了一套地图编辑器,可以支持从一个地图文件打开进行编辑,支持单点修改和区间修改 10 | ![](img/map.png) 11 | 12 | ### 多环境的测试脚本 13 | 我们的`run.py`支持在 Windows、linux、mac 上执行同样的运行测试逻辑,并支持各种细节的参数。 14 | `upload.py`支持在 Windows、linux、mac 上执行同样的打包逻辑,并按照时间戳命名,并自动将旧的压缩包移动到 OldFile 中备份。 15 | 16 | ### 多线程 logger 17 | 为了不影响 logger 对实际运行速度的影响,我们写了一套多线程的 logger 用来将中间日志输出到文件中。 18 | 19 | 为了更好的编写 log,我们加入了c++20中的 format 函数。得益于编译选项,所有的测试部分都只会在-DDEBUG 下运行。 20 | 21 | ### 高效的寻路和避障 22 | 我们基于 bitset 设计了一个极快的 BFS,可以在0.2ms 实现从一个点到全图的 BFS,并记录下每个点到 BFS 起始点的最短路。同时我们实现了一个基于紧密度的避障思路,这个思路可以基于 bitset 实现的寻路算法实现 O1 的避障,并保证最优的。 23 | 24 | 我们同时还实现了一套极快的基于时空 A* 的路径规划算法,可以实现机器人在规划完路径后绝不跳帧。 25 | 26 | 船的寻路我们将地图中每个点抽象成了四个点,BFS 过程中我们每一步的合理操作位:左旋、右旋、直行。 27 | 28 | 经过我们测试即使一百个机器人也可以正常运行。 29 | 30 | ### 生成货物的估计和地图区域的判断 31 | 我们基于概率估算了一个港口会独占的一片区域(并在 replayer 中有所展示),并根据独占区域去自适应购买机器人和分配机器人绑定的港口信息。 32 | 33 | 对于海洋的板块,我们对船购买点-泊位-销售点-船构建了一个连通块和参数排序,用于自适应购买船。 34 | 35 | ## 文件结构 36 | - allMaps: 存储地图文件 37 | - code:代码文件 38 | - tools:可视化、编译、upload等工具 39 | - refCode:可参考的无关代码文件 40 | - dcode:本地增加了对c++20 std::format的支持,用在存放链接库 41 | 42 | ## Python Env: 43 | tools 中的文件全部基于 python 编写 44 | ``` 45 | conda create -n cc24 python=3.7.3 46 | conda activate cc24 47 | pip install numpy==1.19.4 matplotlib tqdm opencv-python pygame 48 | ``` 49 | ## 代码结构 50 | `berth.hpp`: 所有泊位的控制代码 51 | 52 | `ship.hpp`: 所有船的控制代码 53 | 54 | `robot.hpp`: 所有机器人的控制代码 55 | 56 | `berth_center.hpp`: 调度中心,控制所有的泊位,船,机器人的策略 57 | 58 | `config.hpp`: 所有的配置参数,高精度Timer的实现,不定长参数bugs的实现 59 | 60 | `count.hpp`: 统计所有的信息,例如货物信息 61 | 62 | `logger.hpp`: 一个多线程的 log 记录,会由额外的线程写入到相关文件里 63 | 64 | ### 测试工具 65 | 66 | `upload.py`:用于提交代码 67 | 68 | `tune.py`:用于调参 69 | 70 | `run.py`:用于在不同环境下测试代码,并进行数据分析 71 | 72 | `analysis.py`:对运行数据(例如时间,剩余货物等)进行分析 73 | 74 | `Replayer_pygame_fast.py`:基于 pygame 的播放器 75 | 76 | `MapEditor_pygame.py`:基于 pygame 的地图编辑器 77 | -------------------------------------------------------------------------------- /code/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(CodeCraftSDK) 2 | cmake_minimum_required (VERSION 3.8) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_C_STANDARD 11) 6 | 7 | if (!WIN32) 8 | link_libraries(pthread rt m) 9 | endif (!WIN32) 10 | 11 | AUX_SOURCE_DIRECTORY(. src) 12 | ADD_EXECUTABLE(main ${src}) -------------------------------------------------------------------------------- /code/berth.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __BERTH_H__ 2 | #define __BERTH_H__ 3 | #include "config.hpp" 4 | #include "path.hpp" 5 | #include "estimator.hpp" 6 | #include 7 | 8 | struct Berth { 9 | int id; 10 | Pos pos; 11 | std::vector usePos; // 使用的位置 12 | std::vector usePosNavigator; // 使用的位置的导航器 13 | int velocity; // 装载速度 14 | int disWithTimeBerth[MAX_Line_Length + 1][MAX_Col_Length + 1]; 15 | //上面的是原始值,别改 16 | 17 | std::vector shipId; // 表示当前泊位上的船的 id,可能有多个,用empty()判断是否有船 18 | int goodsNum; // 表示当前泊位上的货物数量 19 | int on_way_ship; 20 | int on_way_robot; 21 | int waitting_ship; 22 | int ship_wait_start_time; 23 | std::queue item_value_queue; 24 | int sum_value; 25 | int total_value; 26 | int total_goods; 27 | 28 | int robotNumLeft = 0; 29 | 30 | Berth(int id, int x, int y, int velocity) : id(id), velocity(velocity) { 31 | this->pos = Pos(x, y); 32 | goodsNum = 0; 33 | on_way_ship = 0; 34 | on_way_robot = 0; 35 | waitting_ship = 0; 36 | ship_wait_start_time =0; 37 | this->shipId.clear(); 38 | this->item_value_queue = std::queue(); 39 | this->sum_value = 0; 40 | this->total_value = 0; 41 | this->total_goods = 0; 42 | this->robotNumLeft = 0; 43 | } 44 | void findUsePos() { 45 | usePos.clear(); 46 | std::vector> arr; 47 | std::unordered_set visited; 48 | std::queue q; 49 | q.push(pos); 50 | while (!q.empty()) { 51 | auto top = q.front(); q.pop(); 52 | int haveGround = 0; 53 | for (int d = 0; d <= 3; d++) { 54 | Pos next = top + dir[d]; 55 | if (checkPos(next) == false) continue; 56 | if (checkRobotAble(next) && grids[next.x][next.y]->type != 3) haveGround++; 57 | if (visited.find(next) != visited.end()) continue; 58 | if (grids[next.x][next.y]->type == 3) { 59 | q.push(next); 60 | visited.insert(next); 61 | } 62 | } 63 | arr.emplace_back(top, haveGround); 64 | } 65 | std::sort(arr.begin(), arr.end(), [](const std::pair &a, const std::pair &b) { 66 | return a.second > b.second; 67 | }); 68 | for (int i = 0; i < 2; i++) { 69 | usePos.push_back(arr[i].first); 70 | usePosNavigator.push_back(sovleGrid(arr[i].first)); 71 | } 72 | } 73 | void recordBerth() { 74 | std::queue q; q.push(pos); 75 | while (!q.empty()) { 76 | auto top = q.front(); q.pop(); 77 | for (int d = 0; d <= 3; d++) { 78 | Pos next = top + dir[d]; 79 | if (checkPos(next) && (grids[next.x][next.y]->type == 3 || grids[next.x][next.y]->type == 8)) { 80 | if (grids[next.x][next.y]->berthId == -1) { 81 | grids[next.x][next.y]->berthId = id; 82 | q.push(next); 83 | } 84 | } 85 | } 86 | } 87 | } 88 | }; 89 | 90 | std::vector berths; 91 | std::unordered_map pos2berth; 92 | 93 | void solveBerth() { 94 | // 预处理每个泊位到每个虚拟点的时间 95 | for (int i = 0; i < MAX_Berth_Num; i++) { 96 | berths[i]->findUsePos(); 97 | berths[i]->recordBerth(); 98 | for (auto & pos : berths[i]->usePos) { 99 | pos2berth[pos] = berths[i]; 100 | } 101 | solveGridWithTime(berths[i]->pos, -1); 102 | for (int j = 0; j < MAX_Line_Length; j++) { 103 | for (int k = 0; k < MAX_Col_Length; k++) { 104 | berths[i]->disWithTimeBerth[j][k] = disWithTime[j][k]; 105 | } 106 | } 107 | } 108 | } 109 | 110 | 111 | struct BuyRobotSorter { 112 | int berthId; 113 | double avgDistange; // second priority 114 | double reqTotal; 115 | int buyId; // first priority 116 | bool buyed = false; 117 | bool operator < (const BuyRobotSorter &a) const { 118 | if (buyId != a.buyId) return buyId < a.buyId; 119 | return reqTotal > a.reqTotal; 120 | } 121 | }; 122 | 123 | std::vector _buyRobotQueue; 124 | 125 | void initBerthEstimator(const int &totalSpawnPlace, const int &berthNumber) { 126 | berthEstimator = BerthEstimator(totalSpawnPlace, berthNumber); 127 | /* 128 | for (int i = 0; i < berthNumber; i++) { 129 | std::vector beginPosList; 130 | for (auto & pos : berths[i]->usePos) { 131 | beginPosList.push_back(pos); 132 | } 133 | berthEstimator.checkBertehWithRobotNum(beginPosList, i, 3.0, 150); 134 | } 135 | */ 136 | int avgRobotPerBerth = _maxRobotCnt / berthNumber; 137 | std::vector> beginPosList(berthNumber); 138 | std::vector robotControlLengths(berthNumber, 99999.0); 139 | std::vector controlNumber(berthNumber, 9999999.0); 140 | for (int i = 0; i < berthNumber; i++) { 141 | for (auto & pos : berths[i]->usePos) { 142 | beginPosList[i].push_back(pos); 143 | } 144 | } 145 | berthEstimator.checkBerthAll(beginPosList, controlNumber, robotControlLengths); 146 | double estRobotFull = 0; 147 | 148 | for (int i = 0; i < berthNumber; i++) { 149 | estRobotFull += berthEstimator.berthState[i].avgNewItemPerPull(totalSpawnPlace); 150 | } 151 | estimatorLogger.log(0, "estRobotFull={},{}", estRobotFull, estRobotFull * _pulledItemAtEnd / _itemAtEnd); 152 | for (int i = 0; i < berthNumber; i++) { 153 | controlNumber[i] = berthEstimator.berthState[i].avgNewItemPerPull(totalSpawnPlace) * _pulledItemAtEnd / _itemAtEnd; 154 | estimatorLogger.log(0, "berthId={},controlNumber={}", i, controlNumber[i]); 155 | } 156 | 157 | berthEstimator.reset(); 158 | berthEstimator.checkBerthAll(beginPosList, controlNumber, robotControlLengths); 159 | 160 | std::vector buyRobotSorter; 161 | for (int i = 0; i < berthNumber; i++) { 162 | 163 | auto avgNewItemPerPull = berthEstimator.berthState[i].avgNewItemPerPull(totalSpawnPlace); 164 | int robotNumber = int(avgNewItemPerPull + 1.0); 165 | 166 | for (int j = 1; j <= robotNumber; j++) { 167 | _buyRobotQueue.push_back({i, berthEstimator.berthState[i].avgDistanceToItem(), (double)robotNumber, j, false}); 168 | exptRobotCnt += 1; 169 | // out << i << " " << robotNumber << " " << exptRobotCnt << std::endl; 170 | } 171 | 172 | estimatorLogger.log(0, "berthId={},totalGrid={},totalItemGrid={},avgDistanceToItem={},avgNewItemPerPull={},totalItemGrid/avgDistanceToItem={}", 173 | i, 174 | berthEstimator.berthState[i].totalGrid, 175 | berthEstimator.berthState[i].totalItemGrid, 176 | berthEstimator.berthState[i].avgDistanceToItem(), 177 | avgNewItemPerPull, 178 | berthEstimator.berthState[i].totalItemGrid / berthEstimator.berthState[i].avgDistanceToItem()); 179 | } 180 | std::sort(_buyRobotQueue.begin(), _buyRobotQueue.end()); 181 | estimatorLogger.log(0, "totalRobot={},queueSize={}", exptRobotCnt, _buyRobotQueue.size()); 182 | 183 | #ifdef DEBUG 184 | std::ofstream out("../log/berthbelong.txt"); 185 | for (int i = 0; i < MAX_Line_Length; i++) { 186 | for (int j = 0; j < MAX_Col_Length; j++) { 187 | if (grids[i][j]->belongToBerth == -1) 188 | out << 0; 189 | else 190 | out << grids[i][j]->belongToBerth + 1; 191 | } 192 | out << std::endl; 193 | } 194 | #endif 195 | } 196 | 197 | #endif -------------------------------------------------------------------------------- /code/berth_centre.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __BERTH_CENTRE_H__ 2 | #define __BERTH_CENTRE_H__ 3 | #include "config.hpp" 4 | #include "grid.hpp" 5 | #include "ship.hpp" 6 | #include "berth.hpp" 7 | // #include "robot.hpp" 8 | #include 9 | 10 | /** 11 | * @brief 机器人和船只的购买位置 12 | */ 13 | struct RobotBuyer { 14 | Pos pos; 15 | RobotBuyer(Pos _pos) : pos(_pos) {} 16 | }; 17 | struct ShipBuyer { 18 | Pos pos; 19 | ShipBuyer(Pos _pos) : pos(_pos) {} 20 | }; 21 | 22 | /** 23 | * @brief 交货点 24 | */ 25 | struct Delivery { 26 | Pos pos; 27 | Delivery(Pos _pos) : pos(_pos) {} 28 | }; 29 | 30 | /** 31 | * Berth_center即船坞、轮船控制中心(塔台),进行统一调配,并指引机器人进入泊位 32 | */ 33 | class Berth_center { 34 | public: 35 | // 地图上的购买销售点 36 | std::vector robot_buyer; // 机器人购买点 37 | std::vector ship_buyer; // 船只购买点 38 | std::vector delivery; // 交货点 39 | // 港口优选的参数 40 | std::vector group_sorted_id; // 初始的分组排序 41 | std::vector > group; // 泊位分组 42 | std::vector sort_value; // 每个组的排序值 43 | // 机器人和泊位的对应关系 44 | std::vector robot_pos; // 机器人的位置 45 | std::vector > robot_choose_berth; //机器人选择的泊位 46 | // 泊位到最近的销售点的距离 47 | std::vector> delivery2berth; 48 | 49 | Berth_center() { 50 | robot_buyer.clear(); 51 | ship_buyer.clear(); 52 | delivery.clear(); 53 | group_sorted_id.clear(); 54 | robot_pos.clear(); 55 | } 56 | 57 | // 用于指引船只进入最佳的泊位 58 | int ship_choose_berth() { 59 | int max_goods = -1; 60 | int max_goods_id = -1; 61 | for (int i = 0; i < MAX_Berth_Num; i++) { 62 | if (berths[i]->shipId.empty() == false) continue; 63 | if (berths[i]->sum_value > 0 && berths[i]->sum_value > max_goods) { 64 | max_goods = berths[i]->sum_value; 65 | max_goods_id = i; 66 | } 67 | } 68 | 69 | // centerLogger.log(nowTime, "ship_choose_berth:{}with goods:{}", max_goods_id, max_goods); 70 | if (max_goods_id == -1) { 71 | bugs("ship_choose_berth error"); 72 | // throw; 73 | } 74 | return max_goods_id; 75 | } 76 | // 用于指引机器人进入最佳的泊位 77 | std::vector get_robot_berth(int id) { 78 | if (nowTime + Only_Run_On_Berth_with_Ship > MAX_TIME) { 79 | std::vector ret; 80 | for (int i = 0; i < MAX_Berth_Num; i++) { 81 | if (berths[i]->shipId.size() != 0) ret.push_back(i); 82 | } 83 | if (ret.size() != 0) return ret; 84 | else return robot_choose_berth[id]; 85 | } else { 86 | return robot_choose_berth[id]; 87 | } 88 | } 89 | // 机器人告知塔台卸货 90 | void declare_robot_pull_good(int bert_id, int item_value){ 91 | berths[bert_id]->goodsNum++; 92 | tmpTotalGoods++; 93 | berths[bert_id]->item_value_queue.push(item_value); 94 | berths[bert_id]->sum_value += item_value; 95 | berths[bert_id]->total_goods++; 96 | berths[bert_id]->total_value += item_value; 97 | } 98 | // 船只告知塔台进入泊位 99 | void declare_ship(int bert_id,int ship_id){ 100 | berths[bert_id]->shipId.push_back(ship_id); 101 | } 102 | // 如果船在港口而且没装满,把货物运到船上 103 | void bert_ship_goods_check(int bert_id){ 104 | if (!berths[bert_id]->shipId.empty() && ships[berths[bert_id]->shipId[0]]->status == 2) { 105 | if (berths[bert_id]->goodsNum > 0){ 106 | int loaded_goods = berths[bert_id]->goodsNum; 107 | if (loaded_goods > berths[bert_id]->velocity) loaded_goods = berths[bert_id]->velocity; 108 | ships[berths[bert_id]->shipId[0]]->capacity += loaded_goods; 109 | berths[bert_id]->goodsNum -= loaded_goods; 110 | while (loaded_goods--) { 111 | berths[bert_id]->sum_value -= berths[bert_id]->item_value_queue.front(); 112 | berths[bert_id]->item_value_queue.pop(); 113 | } 114 | } 115 | } 116 | } 117 | // 检查港口的状态 118 | void normal_berth_check(int bert_id){ 119 | auto berth_ptr = berths[bert_id]; 120 | // 因为先移动,所以先检查船的状态 121 | if (!berth_ptr->shipId.empty()) { 122 | auto ship_ptr = ships[berth_ptr->shipId[0]]; 123 | if (ship_ptr->status != 2) return; 124 | // 让船去虚拟点的几种情况 125 | // line1: 如果船只装满了 126 | // line2: 或者是最后一轮了(暂时没法判断了) 127 | // line3: 如果港口没货物了, 并且船装满了百分之 ratio 128 | if ( ship_ptr->leftCapacity() == 0 129 | || nowTime + 350 > MAX_TIME 130 | || (berth_ptr->goodsNum == 0 && ship_ptr->capacity > MAX_Capacity * Sell_Ration && nowTime + 350 * 2 + lastRoundRuningTime < MAX_TIME) 131 | ) { 132 | berth_ptr->shipId.clear(); 133 | ship_ptr->goSell(delivery2berth[bert_id].first); 134 | shipLogger.log(nowTime, "center command ship{0} goSell", ship_ptr->id); 135 | return; 136 | } 137 | // 让船去别的地方的情况 138 | // 港口没货了,并且船没装满Sell_Ration 139 | // 但是去了之后不能超时 140 | if (berth_ptr->goodsNum == 0 /*&& berth_ptr->time + nowTime + 10 + 500 < MAX_TIME*/) { 141 | int best_bert_id = ship_choose_berth(); 142 | if (best_bert_id == -1) return; 143 | if (berths[best_bert_id]->sum_value < Min_Next_Berth_Value) return; 144 | berth_ptr->shipId.clear(); 145 | declare_ship(best_bert_id, ship_ptr->id); 146 | ship_ptr->moveToBerth(best_bert_id, berths[best_bert_id]->pos); 147 | shipLogger.log(nowTime, "center command ship{0} move_berth to berth{1}", ship_ptr->id, best_bert_id); 148 | return; 149 | } 150 | } 151 | } 152 | void solvedelivery2berth() { 153 | delivery2berth = std::vector>(MAX_Berth_Num, std::make_pair(Pos(-1, -1), INT_MAX)); 154 | for (int i = 0; i < MAX_Berth_Num; i++) { 155 | auto berth_ptr = berths[i]; 156 | for (int d = 0; d < 4; d++) { 157 | if (checkShipAllAble(berth_ptr->pos, d) == false) continue; 158 | sovleShip(berth_ptr->pos, d, berth_ptr->pos, false); 159 | for (auto & delivery_pos : delivery) { 160 | for (int _d = 0; _d < 4; _d++) { 161 | if (_dis_s[delivery_pos.pos.x][delivery_pos.pos.y][_d] < delivery2berth[i].second) { 162 | delivery2berth[i].first = delivery_pos.pos; 163 | delivery2berth[i].second = _dis_s[delivery_pos.pos.x][delivery_pos.pos.y][_d]; 164 | } 165 | } 166 | } 167 | } 168 | } 169 | } 170 | void find_private_space() { 171 | // 计算每个泊位到每个销售点的时间 172 | solvedelivery2berth(); 173 | // 对所有的泊位进行分组 174 | std::vector is_grouped(MAX_Berth_Num, -1); 175 | group = std::vector >(MAX_Berth_Num, std::vector()); 176 | for (int i = 0; i < MAX_Berth_Num; i++) { 177 | if (is_grouped[i] != -1) continue; 178 | is_grouped[i] = i; 179 | group[i].push_back(i); 180 | group_sorted_id.push_back(i); 181 | for (int j = i + 1; j < MAX_Berth_Num; j++) { 182 | if (is_grouped[j] != -1) continue; 183 | // 如果两个泊位之间的距离小于 MAX_Berth_Control_Length / 2,那么就是一个组 184 | if (berths[i]->disWithTimeBerth[berths[j]->pos.x][berths[j]->pos.y] < MAX_Berth_Merge_Length) { 185 | group[i].push_back(j); 186 | is_grouped[j] = i; 187 | } 188 | } 189 | } 190 | // 输出一下分组信息 191 | for (auto & i : group_sorted_id) { 192 | // 选择分组内最优的泊位 193 | std::sort(group[i].begin(), group[i].end(), [](const int& a, const int& b) { 194 | // MAX_Capacity / berths[i]->velocity + berths[i]->time 195 | return MAX_Capacity / berths[a]->velocity/* + berths[a]->time*/ < MAX_Capacity / berths[b]->velocity/* + berths[b]->time*/; 196 | }); 197 | centerLogger.log(nowTime, "group{}:", i); 198 | for (int j = 0; j < group[i].size(); j++) { 199 | centerLogger.log(nowTime, " {}", group[i][j]); 200 | } 201 | } 202 | // 每个组所拥有的私有区域的面积 203 | std::vector > berth_onwer_space(MAX_Berth_Num, std::vector()); 204 | // 空地大小 205 | int ground_num = 0; 206 | for (int x = 0; x < MAX_Line_Length; x++) { 207 | for (int y = 0; y < MAX_Col_Length; y++) { 208 | // 排除障碍物和海洋 209 | if (checkRobotAble(Pos(x, y)) == false) continue; 210 | ground_num++; 211 | std::set owner; 212 | // 我们只考虑 MAX_Berth_Control_Length 帧内的情况 213 | int min_num = MAX_Berth_Control_Length; 214 | for (int i = 0; i < MAX_Berth_Num; i++) { 215 | if (berths[i]->disWithTimeBerth[x][y] < min_num) { 216 | min_num = berths[i]->disWithTimeBerth[x][y]; 217 | owner.clear(); 218 | owner.insert(is_grouped[i]); 219 | } else if (berths[i]->disWithTimeBerth[x][y] == min_num) { 220 | owner.insert(is_grouped[i]); 221 | } 222 | } 223 | for (auto &i : owner) berth_onwer_space[i].push_back(min_num); 224 | } 225 | } 226 | // 按照私有区域的大小排序 227 | // 可选参数有 228 | // berth_onwer_space[a].size() 越大越好 229 | // avg_onwer_space_length[a] 越小越好 230 | // berth_onwer_space[a].size() / avg_onwer_space_length[a] 越大越好 231 | std::vector avg_onwer_space_length(MAX_Berth_Num, 0); 232 | sort_value = std::vector(MAX_Berth_Num, 0); 233 | for (auto & i : group_sorted_id) { 234 | double sum = 0; 235 | for (auto &len : berth_onwer_space[i]) sum += len; 236 | avg_onwer_space_length[i] = sum / berth_onwer_space[i].size(); 237 | sort_value[i] = berth_onwer_space[i].size() / avg_onwer_space_length[i]; 238 | int min2sell = INT_MAX; 239 | for (auto & berth : group[i]) { 240 | if (delivery2berth[berth].second < min2sell) min2sell = delivery2berth[berth].second; 241 | } 242 | // sort_value[i] += (300 - min2sell); 243 | // sort_value[i] += min2sell; 244 | } 245 | std::sort(group_sorted_id.begin(), group_sorted_id.end(), [&](const int& a, const int& b) { 246 | return sort_value[a] > sort_value[b]; 247 | }); 248 | for (auto & i : group_sorted_id) { 249 | centerLogger.log(nowTime, "berth group{}, onwer_space{}, avg_onwer_space_length{}, 参数{}", i, berth_onwer_space[i].size(), avg_onwer_space_length[i], sort_value[i]); 250 | } 251 | } 252 | void update_robot_choose_berth() { 253 | robot_choose_berth = std::vector >(robot_pos.size(), std::vector()); 254 | // 需要考虑的: 组可以接触到哪些机器人(一个购买点暂定一个组) 组是否太烂了 255 | std::vector > group_can_reach_robot(MAX_Berth_Num, std::vector()); 256 | std::vector robot_selected(robot_pos.size(), false); 257 | bool need_select_worst = false; 258 | while (true) { 259 | bool flag = false; 260 | // 按照优先级,每个组选择一个最近的机器人购买点 261 | for (auto & i : group_sorted_id) { 262 | // 如果这个组的评分*3小于最好的组的评分,那么就不考虑这个组 263 | if (sort_value[i] * Worst_Rate < sort_value[group_sorted_id.front()] && need_select_worst == false) continue; 264 | int min_dis = INT_MAX; 265 | int min_robot = -1; 266 | for (int robot = 0; robot < robot_pos.size(); robot++) { 267 | if (robot_selected[robot]) continue; 268 | for (auto & berth_id : group[i]) { 269 | if (berths[berth_id]->disWithTimeBerth[robot_pos[robot].x][robot_pos[robot].y] < min_dis) { 270 | min_dis = berths[berth_id]->disWithTimeBerth[robot_pos[robot].x][robot_pos[robot].y]; 271 | min_robot = robot; 272 | } 273 | } 274 | } 275 | if (min_dis != INT_MAX) { 276 | group_can_reach_robot[i].push_back(min_robot); 277 | robot_selected[min_robot] = true; 278 | flag = true; 279 | } 280 | } 281 | if (!flag) { 282 | // 如果在need_select_worst状态下仍然没更新,那么就退出 283 | if (need_select_worst) break; 284 | // 如果一个机器人购买点没有被选择,那说明 1. 没有组可以 reach 2. 组太烂了被 skip 了 组可能有多个组 285 | bool isEnd = true; 286 | for (int i = 0; i < robot_pos.size(); i++) if (!robot_selected[i]) isEnd = false; 287 | // 如果所有的机器人购买点都被选择了,那么就退出. 不然设定 need_select_worst = true 继续跑 288 | if (isEnd) break; 289 | else need_select_worst = true; 290 | } 291 | } 292 | for (auto & i : group_sorted_id) { 293 | centerLogger.log(nowTime, "group{} can reach robot:", i); 294 | for (auto & j : group_can_reach_robot[i]) { 295 | centerLogger.log(nowTime, " {}", j); 296 | for (auto & berth_id : group[i]) robot_choose_berth[j].push_back(berth_id); 297 | } 298 | } 299 | } 300 | void finish_log(); 301 | void normal_check_ship(int shipId){ 302 | auto ship_ptr = ships[shipId]; 303 | ship_ptr->output(); 304 | if (ship_ptr->status == 1) return; 305 | // 到达了销售点卖掉了. 或者船刚出生 306 | if ((ship_ptr->berthId == -2) || (ship_ptr->pos == ship_ptr->targetPos && ship_ptr->berthId == -1)) { 307 | int best_bert_id = ship_choose_berth(); 308 | // 一个个都没货是吧,死了得了 309 | if (best_bert_id == -1) best_bert_id = 0; 310 | declare_ship(best_bert_id, shipId); 311 | ship_ptr->moveToBerth(best_bert_id, berths[best_bert_id]->pos); 312 | shipLogger.log(nowTime, "center command ship{0} move_berth to berth{1}", ship_ptr->id, best_bert_id); 313 | return; 314 | } 315 | // 到达了目标泊位(而不是虚拟点), 并且船是运行状态,当前位置是靠泊区或者泊位 而且是我们要去的泊位 316 | auto grids_ptr = grids[ship_ptr->pos.x][ship_ptr->pos.y]; 317 | if (ship_ptr->berthId != -1 318 | && ship_ptr->status == 0 319 | && (grids_ptr->type == 8 || grids_ptr->type == 3) 320 | && ship_ptr->berthId == grids_ptr->berthId) { 321 | ship_ptr->berth(); 322 | return; 323 | } 324 | } 325 | // 每一轮都要执行的检查状态 326 | void call_ship_and_berth_check(){ 327 | for(int i = 0; i < MAX_Berth_Num; i++){ 328 | /* 检查港口船的状态*/ 329 | normal_berth_check(i); 330 | // 卸货 331 | bert_ship_goods_check(i); 332 | } 333 | // 判断船是否需要前往港口,如果需要就前往 334 | for (int i = 0; i < MAX_Ship_Num; i++) { 335 | normal_check_ship(i); 336 | } 337 | if (nowTime > 14940) finish_log(); 338 | } 339 | }; 340 | 341 | Berth_center *berth_center = new Berth_center(); 342 | 343 | // 最后一回合的 统计信息 344 | void Berth_center::finish_log() { 345 | static bool flag = false; 346 | if (flag) return; 347 | flag = true; 348 | int leftTotal = 0; 349 | for (int i = 0; i < MAX_Berth_Num; i++) { 350 | berthLogger.log(nowTime, "berth{},goodsNum:{}", i, berths[i]->sum_value); 351 | leftTotal += berths[i]->sum_value; 352 | } 353 | berthLogger.log(nowTime, "leftTotal:{}", leftTotal); 354 | // berthLogger.log(nowTime, "tmpTotalGoods:{}", tmpTotalGoods + leftTotal); 355 | } 356 | #endif -------------------------------------------------------------------------------- /code/config.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H__ 2 | #define __CONFIG_H__ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "pos.hpp" 27 | using namespace std::chrono; 28 | #include "logger.hpp" 29 | #include "count.hpp" 30 | #include 31 | #include 32 | 33 | /** 34 | * 常量定义 35 | * 用于定义比赛中一些基本不会变动的参数 36 | */ 37 | const int MAX_Line_Length = 200; // 地图有多少行 38 | const int MAX_Col_Length = 200; // 地图有多少列 39 | const int MAX_TIME = 5 * 60 * 50; // 最大帧数 40 | const int Item_Continue_Time = 1000; // 物品持续时间 41 | #define BitsetSize 40000 42 | 43 | /** 44 | * 全局变量 45 | * 用于存储控制整体流程的一些变量 46 | */ 47 | int MAX_Robot_Num = 0; // 机器人数量 [) 48 | int MAX_Ship_Num = 0; // 船的数量 [) 49 | int MAX_Berth_Num = 0; // 泊位数量 [) 50 | int MAX_Capacity; // 船的容量 51 | int money = 25000; // 当前金钱 52 | int nowTime = 0; // 当前帧数 53 | bool inputFlag = true; // 是否input是否结束 54 | std::vector robotPriority; // 机器人的优先级 55 | int priorityTimeControl = -1; // 优先级控制时间 56 | 57 | /** 58 | * 预处理&多线程控制相关变量 59 | */ 60 | auto programStart = high_resolution_clock::now(); // 计时器 61 | 62 | 63 | /** 64 | * 超参数 160 80 0.85 200 是一组经典参数,适合大部分地图能跑一个不错的成绩 65 | * 孤军奋战: 40 1 0.7 800 66 | * 全员一锅粥: 40 500 0.7 800 67 | * MAX_Berth_Control_Length的建议参数 40 左右 68 | * MAX_Berth_Merge_Length的建议参数 1 / 40 / 80 69 | * Sell_Ration的建议参数 0.7 左右 70 | * Min_Next_Berth_Value的建议参数 0, 200, 800, 1000 71 | */ 72 | int MAX_Berth_Control_Length = 160; // 机器人搜索长度,用来判断私有区域, 10~200, 5 73 | int MAX_Berth_Merge_Length = 80; // 泊位合并长度,用来判断是否可以合并, 1~200, 5 74 | int Worst_Rate = 3; // 用来筛选多差的港口不要选, 1~10 75 | double Sell_Ration = 0.7; // 还剩多少港口空了就去卖, 0.5~1 76 | int Min_Next_Berth_Value = 1700; // another 港口的货物价值少于这个值就不去, 0~1000 77 | int Only_Run_On_Berth_with_Ship = 350; // 最后这些帧,只在有船的泊位上运行, 78 | int lastRoundRuningTime = 600; // 估计的最后一轮的运行时间 79 | 80 | // 暂时不要调的参数,不一定有用 | 策略已经放弃了 81 | int Min_Next_Berth_Goods = 10; // another 港口的货物少于这个值就不去, 0~100 82 | int Last_Round_delay_time = 4500; // 预留给最后一轮的时间,含去 回 去 83 | 84 | const int _maxRobotCnt = 17; 85 | const int _maxShipCnt = 2; 86 | 87 | const double _itemAtEnd = 4800; 88 | const double _pulledItemAtEnd = 1900; 89 | 90 | int exptRobotCnt = 0; 91 | 92 | Pos dir[4] = {Pos(0, 1), Pos(0, -1), Pos(-1, 0), Pos(1, 0)}; 93 | // 0 表示右移一格 1 表示左移一格 2 表示上移一格 3 表示下移一格 94 | std::unordered_map Pos2move = { 95 | {Pos(0, 1), 0}, 96 | {Pos(0, -1), 1}, 97 | {Pos(-1, 0), 2}, 98 | {Pos(1, 0), 3} 99 | }; 100 | 101 | /** 102 | * 日志记录 103 | * 用于全局的日志器 104 | * 建议写日志时少用空格,使用逗号分隔 105 | */ 106 | 107 | 108 | FileLogger shipLogger("../log/ship_log.txt"); 109 | FileLogger robotLogger("../log/robot_log.txt"); 110 | FileLogger berthLogger("../log/berth_log.txt"); 111 | FileLogger itemLogger("../log/item_log.txt"); 112 | FileLogger centerLogger("../log/center_log.txt"); 113 | // 用来输出每一帧和各个主要函数的开始和结束,还有运行时间,主要是用来定位 bug 位置 114 | FileLogger flowLogger("../log/flow_log.txt"); 115 | FileLogger bcenterlogger("../log/bcenter_log.txt"); 116 | FileLogger pathLogger("../log/path_log.txt"); 117 | FileLogger allPathLogger("../log/allPath_log.txt"); 118 | FileLogger estimatorLogger("../log/estimator_log.txt"); 119 | 120 | #ifdef DEBUG 121 | #define TEST(x) x 122 | std::ofstream fout("output.txt"); // 测试用输出 123 | std::ofstream tout("time.txt"); 124 | #else 125 | #define TEST(x) 126 | #endif 127 | 128 | #ifdef DEBUG 129 | Counter counter; 130 | #else 131 | Void_Counter counter; 132 | #endif 133 | 134 | #ifdef CREATE 135 | #define CREATEMAP(x) x 136 | std::ofstream mapOut("../genMap/path.txt"); // 测试用输出 137 | #else 138 | #define CREATEMAP(x) 139 | #endif 140 | 141 | template 142 | void bugs_output(T x) { 143 | #ifdef DEBUG 144 | fout << x << " "; 145 | #endif 146 | } 147 | template 148 | void bugs(Args... args) { 149 | #ifdef DEBUG 150 | (..., bugs_output(args)); 151 | fout << std::endl; 152 | #endif 153 | } 154 | class Timer { 155 | public: 156 | #ifdef DEBUG 157 | template 158 | static auto measure(const std::string& description, Func func, Args&&... args) { 159 | auto start = std::chrono::high_resolution_clock::now(); 160 | 161 | if constexpr (std::is_same_v, void>) { 162 | // If the function returns void 163 | func(std::forward(args)...); 164 | auto end = std::chrono::high_resolution_clock::now(); 165 | std::chrono::duration elapsed = end - start; 166 | tout << nowTime <<" "<< description << "\t - Elapsed time: \t" << elapsed.count() * 1000 << "\tmirco seconds.\n"; 167 | } else { 168 | // If the function returns a value 169 | auto result = func(std::forward(args)...); 170 | auto end = std::chrono::high_resolution_clock::now(); 171 | std::chrono::duration elapsed = end - start; 172 | tout << nowTime <<" "<< description << "\t - Elapsed time: \t" << elapsed.count() * 1000 << "\tmicro seconds.\n"; 173 | return result; 174 | } 175 | } 176 | #else 177 | template 178 | static auto measure(const std::string& description, Func func, Args&&... args) -> decltype(func(std::forward(args)...)) { 179 | return func(std::forward(args)...); 180 | } 181 | #endif 182 | }; 183 | #ifdef DEBUG 184 | void measureAndExecute(const std::string& description, const std::function& action) { 185 | auto start = std::chrono::high_resolution_clock::now(); 186 | action(); 187 | auto end = std::chrono::high_resolution_clock::now(); 188 | std::chrono::duration elapsed = end - start; 189 | tout << description << " - Elapsed time: " << elapsed.count() << " ms\n"; 190 | } 191 | #else 192 | void measureAndExecute(const std::string& description, const std::function& action) { 193 | action(); 194 | } 195 | #endif 196 | 197 | #endif -------------------------------------------------------------------------------- /code/count.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | class Counter{ 8 | private: 9 | std::unordered_map variables; 10 | std::unordered_map locks; 11 | std::unordered_map> vectors; 12 | std::unordered_map>> vectors2d; 13 | 14 | public: 15 | // 注册变量 16 | void registerVariable(const std::string& name, int initialValue = 0) { 17 | variables[name] = initialValue; 18 | locks[name] = false; // 默认未锁定 19 | } 20 | 21 | void registerVector(const std::string& name) { 22 | vectors[name] = std::vector(); 23 | locks[name] = false; 24 | } 25 | 26 | void registerVector2D(const std::string& name){ 27 | vectors2d[name] = std::vector>(); 28 | locks[name] = false; 29 | } 30 | 31 | void push_back(const std::string& name, int value) { 32 | // 给 vector 添加值 33 | if (vectors.find(name) != vectors.end() && !locks[name]) { 34 | vectors[name].push_back(value); 35 | } 36 | } 37 | 38 | void push_back(const std::string& name, int value1 ,int value2) { 39 | // 给 vector 添加值 40 | if (vectors2d.find(name) != vectors2d.end() && !locks[name]) { 41 | vectors2d[name].push_back(std::make_pair(value1, value2)); 42 | } 43 | } 44 | 45 | // 给变量加上某个值 46 | void add(const std::string& name, int value) { 47 | if (variables.find(name) != variables.end() && !locks[name]) { 48 | variables[name] += value; 49 | } 50 | } 51 | 52 | // 给变量减去某个值 53 | void subtract(const std::string& name, int value) { 54 | if (variables.find(name) != variables.end() && !locks[name]) { 55 | variables[name] -= value; 56 | } 57 | } 58 | 59 | // 锁定变量 60 | void lock(const std::string& name) { 61 | if (variables.find(name) != variables.end()) { 62 | locks[name] = true; 63 | } 64 | } 65 | 66 | void max_put(const std::string& name, int value) { 67 | if (variables.find(name) != variables.end() && !locks[name]) { 68 | variables[name] = std::max(variables[name], value); 69 | } 70 | } 71 | 72 | void min_put(const std::string& name, int value) { 73 | if (variables.find(name) != variables.end() && !locks[name]) { 74 | variables[name] = std::min(variables[name], value); 75 | } 76 | } 77 | 78 | // 解锁变量 79 | void unlock(const std::string& name) { 80 | if (variables.find(name) != variables.end()) { 81 | locks[name] = false; 82 | } 83 | } 84 | 85 | // 获取变量的值 86 | int getValue(const std::string& name) { 87 | if (variables.find(name) != variables.end()) { 88 | return variables[name]; 89 | } 90 | return 0; // 如果变量不存在,返回0 91 | } 92 | 93 | void writeToFile(const std::string& filename) { 94 | std::ofstream outFile(filename, std::ios::app); 95 | outFile << "============================================" << "\n"; 96 | for (const auto& var : variables) { 97 | outFile << "Variable: " << var.first << ",\t Value: " << var.second << ",\t Locked: " << (locks[var.first] ? "Yes" : "No") << "\n"; 98 | } 99 | outFile << "=====================" << "\n"; 100 | outFile << "avg_robot_move_length: " << (getValue("robot_move_length") / getValue("robot_get_nums")) << "\n"; 101 | outFile << "max_robot_move_length: " << getValue("robot_move_length_max") << "\n"; 102 | outFile << "min_robot_move_length: " << getValue("robot_move_length_min") << "\n"; 103 | outFile << "============================================" << "\n"; 104 | outFile.close(); 105 | for (const auto& vec : vectors) { 106 | std::ofstream outFile(filename + "_" + vec.first + ".txt"); 107 | for (int i = 0; i < vec.second.size(); i++) { 108 | outFile << vec.second[i] << "\n"; 109 | } 110 | outFile.close(); 111 | } 112 | for (const auto& vec : vectors2d){ 113 | std::ofstream outFile(filename + "_" + vec.first + ".txt"); 114 | for (int i = 0; i < vec.second.size(); i++) { 115 | outFile << vec.second[i].first << " " << vec.second[i].second << "\n"; 116 | } 117 | outFile.close(); 118 | } 119 | } 120 | }; 121 | 122 | class Void_Counter { 123 | public: 124 | void registerVariable(const std::string& name, int initialValue = 0) {return;} 125 | void registerVector(const std::string& name) {return;} 126 | void registerVector2D(const std::string& name) {return;} 127 | void push_back(const std::string& name, int value1 ,int value2) {return;} 128 | void push_back(const std::string& name, int value) {return;} 129 | void add(const std::string& name, int value) {return;} 130 | void max_put(const std::string& name, int value) {return;} 131 | void min_put(const std::string& name, int value) {return;} 132 | void subtract(const std::string& name, int value) {return;} 133 | void lock(const std::string& name) {return;} 134 | void unlock(const std::string& name) {return;} 135 | int getValue(const std::string& name) {return 0;} 136 | void writeToFile(const std::string& filename) {return;} 137 | }; -------------------------------------------------------------------------------- /code/estimator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ESTIMATOR_H__ 2 | #define __ESTIMATOR_H__ 3 | 4 | #include "config.hpp" 5 | #include "grid.hpp" 6 | 7 | struct BerthEstState { 8 | Pos pos; 9 | int dis; 10 | int belongTo; 11 | BerthEstState(Pos pos, int dis) : pos(pos), dis(dis) {} 12 | BerthEstState(Pos pos, int dis, int belongTo) : pos(pos), dis(dis), belongTo(belongTo) {} 13 | BerthEstState() {} 14 | 15 | }; 16 | 17 | class BerthState { 18 | public: 19 | double totItemDistance; 20 | int totalGrid; 21 | int totalItemGrid; 22 | int realBerthItem; 23 | BerthState() { 24 | totItemDistance = 0; 25 | totalGrid = 0; 26 | totalItemGrid = 0; 27 | realBerthItem = 0; 28 | } 29 | 30 | inline double avgDistanceToItem() { 31 | if (totalItemGrid == 0) return 0; 32 | return totItemDistance / (double)totalItemGrid; 33 | } 34 | 35 | inline double avgNewItemPerPull(const int &totalSpawnGrid) { 36 | if (totalItemGrid == 0) return 0; 37 | double avgDistance = this->avgDistanceToItem(); 38 | double spawnRatePerFrame = _itemAtEnd / 15000.0; 39 | double spwanRatePerFrameInArea = (double)spawnRatePerFrame * (double)totalItemGrid / (double)totalSpawnGrid; 40 | double avgPullTime = avgDistance * 2.0; 41 | return spwanRatePerFrameInArea * avgPullTime; 42 | } 43 | }; 44 | 45 | std::vector _berthDone; 46 | BerthEstState _estQueue[400010]; 47 | 48 | class BerthEstimator { 49 | public: 50 | std::vector berthState; 51 | int totalSpawnPlace; 52 | BerthEstimator() { } 53 | BerthEstimator(int totalSpawnPlace, int berthNumber) { 54 | this->totalSpawnPlace = totalSpawnPlace; 55 | berthState = std::vector(berthNumber); 56 | } 57 | 58 | void reset() { 59 | resetbelong(); 60 | berthState = std::vector(berthState.size()); 61 | _berthDone = std::vector(_berthDone.size(), false); 62 | } 63 | 64 | void checkBertehWithRobotNum(const std::vector &beginPosList, const int &berthId, const double &controlNumber, const double &robotControlLength) { 65 | 66 | int start = 0; 67 | int end = 0; 68 | for (auto beginPos : beginPosList) { 69 | _estQueue[end++] = BerthEstState(beginPos, 0); 70 | // _estimatorDistance[beginPos.x][beginPos.y] = 0; 71 | } 72 | estimatorLogger.log(0, "berthId={} robotNum={}, totalSpawnPlace={}", berthId, beginPosList.size(), totalSpawnPlace); 73 | int lastDis = 0; 74 | 75 | while (start != end) { 76 | auto nowS = _estQueue[start++]; 77 | auto now = nowS.pos; 78 | auto nowDis = nowS.dis; 79 | if (start == 400010) start = 0; 80 | 81 | if (grids[now.x][now.y]->belongToBerth != -1) continue; 82 | if (nowDis > robotControlLength) break; 83 | 84 | 85 | berthState[berthId].totalGrid += 1; 86 | if (grids[now.x][now.y]->type == 0) { // 可刷新物品的格子 87 | berthState[berthId].totalItemGrid += 1; 88 | berthState[berthId].totItemDistance += nowDis; 89 | } 90 | 91 | grids[now.x][now.y]->belongToBerth = berthId; 92 | 93 | auto avgNewItemPerPull = berthState[berthId].avgNewItemPerPull(totalSpawnPlace); 94 | if (nowDis != lastDis) { 95 | lastDis = nowDis; 96 | estimatorLogger.log(0, "nowDis={} avgNewItemPerPull={}, totalItemGrid={}, totalItemDistance={}", nowDis, avgNewItemPerPull, berthState[berthId].totalItemGrid, berthState[berthId].totItemDistance); 97 | } 98 | 99 | if (avgNewItemPerPull > controlNumber) { 100 | break; 101 | } 102 | 103 | for (int d = 0; d <= 3; d++) { 104 | Pos next = now + dir[d]; 105 | if (NOT_VALID_GRID(next.x, next.y) or 106 | (not IS_ROBOT_ABLE(grids[next.x][next.y]->bit_type)) or 107 | (grids[next.x][next.y]->belongToBerth != -1)) 108 | continue; 109 | _estQueue[end++] = BerthEstState(next, nowDis + 1); 110 | if (end == 400010) end = 0; 111 | } 112 | } 113 | estimatorLogger.log(0, "berthId={} totalGrid={} totalItemGrid={} avgDistanceToItem={}", berthId, berthState[berthId].totalGrid, berthState[berthId].totalItemGrid, berthState[berthId].avgDistanceToItem()); 114 | estimatorLogger.log(0, "avgNewItemPerPull={}", berthState[berthId].avgNewItemPerPull(totalSpawnPlace)); 115 | } 116 | 117 | 118 | // 这个函数会更改:grids, berthState, _berthDone 119 | void checkBerthAll(const std::vector> &beginPosLists, const std::vector &controlNumbers, const std::vector &robotControlLengths) { 120 | _berthDone = std::vector(beginPosLists.size(), false); 121 | 122 | int start = 0; 123 | int end = 0; 124 | 125 | int maxPosCnt = 0; 126 | for (int betrhId = 0; betrhId < beginPosLists.size(); betrhId++) { 127 | maxPosCnt = std::max(maxPosCnt, (int)beginPosLists[betrhId].size()); 128 | } 129 | for (int i = 0; i < maxPosCnt; i++) { 130 | for (int betrhId = 0; betrhId < beginPosLists.size(); betrhId++) { 131 | if (i < beginPosLists[betrhId].size()) { 132 | _estQueue[end++] = BerthEstState(beginPosLists[betrhId][i], 0, betrhId); 133 | } 134 | } 135 | } 136 | 137 | while (start != end) { 138 | auto nowS = _estQueue[start++]; 139 | auto now = nowS.pos; 140 | auto nowDis = nowS.dis; 141 | auto berthId = nowS.belongTo; 142 | if (start == 400010) start = 0; 143 | 144 | if (grids[now.x][now.y]->belongToBerth != -1) continue; 145 | if (_berthDone[berthId]) continue; 146 | auto avgDistance = berthState[berthId].avgDistanceToItem(); 147 | if (avgDistance > robotControlLengths[berthId]) { 148 | _berthDone[berthId] = true; 149 | continue; 150 | } 151 | 152 | 153 | berthState[berthId].totalGrid += 1; 154 | if (grids[now.x][now.y]->type == 0) { // 可刷新物品的格子 155 | berthState[berthId].totalItemGrid += 1; 156 | berthState[berthId].totItemDistance += nowDis; 157 | } 158 | 159 | grids[now.x][now.y]->belongToBerth = berthId; 160 | 161 | auto avgNewItemPerPull = berthState[berthId].avgNewItemPerPull(totalSpawnPlace); 162 | 163 | if (avgNewItemPerPull > controlNumbers[berthId]) { 164 | _berthDone[berthId] = true; 165 | } 166 | 167 | for (int d = 0; d <= 3; d++) { 168 | Pos next = now + dir[d]; 169 | if (NOT_VALID_GRID(next.x, next.y) or 170 | (not IS_ROBOT_ABLE(grids[next.x][next.y]->bit_type)) or 171 | (grids[next.x][next.y]->belongToBerth != -1)) 172 | continue; 173 | _estQueue[end++] = BerthEstState(next, nowDis + 1, berthId); 174 | if (end == 400010) end = 0; 175 | } 176 | } 177 | } 178 | }; 179 | 180 | 181 | BerthEstimator berthEstimator; 182 | 183 | #endif -------------------------------------------------------------------------------- /code/grid.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __GRID_H__ 2 | #define __GRID_H__ 3 | 4 | #include "config.hpp" 5 | struct Navigator { 6 | std::bitset visited; // 用于记录是否访问过 7 | std::bitset dirNext; // 用于记录方向 00 表示右移一格 01 表示左移一格 10 表示上移一格 11 表示下移一格 8 | Navigator(){ 9 | visited.reset(); 10 | dirNext.reset(); 11 | } 12 | int getVisitedIndex(int x, int y) { 13 | return x * MAX_Col_Length + y; 14 | } 15 | int getDirIndex(int x, int y) { 16 | return x * MAX_Col_Length * 2 + y * 2; 17 | } 18 | void setVisited(int x, int y) { 19 | visited[getVisitedIndex(x, y)] = 1; 20 | } 21 | bool isVisited(int x, int y) { 22 | return visited[getVisitedIndex(x, y)]; 23 | } 24 | void setDir(int x, int y, int d) { 25 | int index = getDirIndex(x, y); 26 | if (d & 1) dirNext[index] = 1; 27 | if (d & 2) dirNext[index + 1] = 1; 28 | } 29 | int getDir(int x, int y) { 30 | int ans = 0; 31 | int index = getDirIndex(x, y); 32 | if (dirNext[index] == 1) ans += 1; 33 | if (dirNext[index + 1] == 1) ans += 2; 34 | return ans; 35 | } 36 | }; 37 | struct Navigator_ship { 38 | std::bitset visited; // 用于记录是否访问过 39 | Navigator_ship(){ 40 | visited.reset(); 41 | } 42 | int getVisitedIndex(int x, int y,int d) { 43 | return x * MAX_Col_Length * 4 + y * 4 + d; 44 | } 45 | void setVisited(int x, int y,int d) { 46 | visited[getVisitedIndex(x, y, d)] = 1; 47 | } 48 | bool isVisited(int x, int y, int d) { 49 | return visited[getVisitedIndex(x, y, d)]; 50 | } 51 | }; 52 | 53 | /** 54 | * @brief 网格类 55 | * 解释一些 type 的类型 56 | * 0‘.’ : 空地 | 机器人可以走 会发生碰撞 57 | * 1‘*’ : 海洋 | 船可以走 会发生碰撞 58 | * 2‘#’ : 障碍 | 谁都不可以走 59 | * 3‘B’ : 泊位 同时算主干道主航道 | 船和机器人都可以走 不会发生碰撞 60 | * 61 | * 4‘>’ : 陆地主干道 | 机器人可以走 不会发生碰撞 62 | * 5‘~’ : 海洋主航道 | 船可以走 不会发生碰撞 63 | * 6‘R’ : 机器人购买地块,同时该地块也是主干道. | 机器人可以走, 不会发生碰撞 64 | * 7‘S’ : 船舶购买地块,同时该地块也是主航道 | 船可以走, 不会发生碰撞 65 | * 66 | * 8‘K’ : 靠泊区 算主航道 | 船可以走 不会发生碰撞 67 | * 9‘C’ : 海陆立体交通地块 | 船和机器人都可以走 会发生碰撞 68 | * 10 : 机器人 69 | * 11‘c’ : 海陆立体交通地块,同时为主干道和主航道 |船和机器人都可以走 不会发生碰撞 70 | 71 | * 12‘T’ : 交货点 特殊的靠泊区 所以也算主航道 | 船可以走 不会发生碰撞 72 | 73 | */ 74 | 75 | 76 | /* 77 | #define BLANK 0b0000 0000 0000 0001 78 | #define SEA 0b0000 0000 0000 0010 79 | #define OBSTACLE 0b0000 0000 0000 0100 80 | #define BERTH 0b0000 0000 0000 1000 // ROBOT_NOCOL // SJHIP_NOCOL 81 | 82 | #define ROUTE 0b0000 0000 0001 0000 // ROBOT_NOCOL 83 | #define SEA_ROUTE 0b0000 0000 0010 0000 // SHIP_NOCOL 84 | #define ROBOT_BUYER 0b0000 0000 0100 0000 // ROBOT_NOCOL 85 | #define SHIP_BUYER 0b0000 0000 1000 0000 // SHIP_NOCOL 86 | 87 | #define BERTH_CENTER 0b0000 0001 0000 0000 // SHIP_NOCOL 88 | #define CROSS 0b0000 0010 0000 0000 89 | #define CROSS_ROUTE 0b0000 1000 0000 0000 // ROBOT_NOCOL // SHIP_NOCOL 90 | #define DELIVERY 0b0001 0000 0000 0000 // SHIP_NOCOL 91 | 92 | #define SHIP_NOCOL 0b0001 1001 1010 1000 93 | #define ROBOT_NOCOL 0b0000 1000 0101 1000 94 | 95 | #define ROBOT_ABLE 0b0000 1010 0101 1001 96 | #define SHIP_ABLE 0b0001 1011 1010 1010 97 | */ 98 | 99 | #define BLANK 0b0000000000000001 100 | #define SEA 0b0000000000000010 101 | #define OBSTACLE 0b0000000000000100 102 | #define BERTH 0b0000000000001000 // ROBOT_NOCOL // SJHIP_NOCOL 103 | 104 | #define ROUTE 0b0000000000010000 // ROBOT_NOCOL 105 | #define SEA_ROUTE 0b0000000000100000 // SHIP_NOCOL 106 | #define ROBOT_BUYER 0b0000000001000000 // ROBOT_NOCOL 107 | #define SHIP_BUYER 0b0000000010000000 // SHIP_NOCOL 108 | 109 | #define BERTH_CENTER 0b0000000100000000 // SHIP_NOCOL 110 | #define CROSS 0b0000001000000000 111 | #define CROSS_ROUTE 0b0000100000000000 // ROBOT_NOCOL // SHIP_NOCOL 112 | #define DELIVERY 0b0001000000000000 // SHIP_NOCOL 113 | 114 | #define SHIP_NOCOL 0b0001100110101000 115 | #define ROBOT_NOCOL 0b0000100001011000 116 | 117 | #define ROBOT_ABLE 0b0000101001011001 118 | #define SHIP_ABLE 0b0001101110101010 119 | 120 | #define NOT_VALID_GRID(x, y) (x < 0 or x >= MAX_Line_Length or y < 0 or y >= MAX_Col_Length) 121 | #define IS_SHIP_NOCOL(x) (x & SHIP_NOCOL) 122 | #define IS_ROBOT_NOCOL(x) (x & ROBOT_NOCOL) 123 | #define IS_ROBOT_ABLE(x) (x & ROBOT_ABLE) 124 | #define IS_SHIP_ABLE(x) (x & SHIP_ABLE) 125 | 126 | struct Grid { 127 | Pos pos; // 位置 128 | int type; 129 | bool robotOnIt; 130 | Navigator *gridDir; // 用来导航从起点到终点的路径 131 | int berthId; // 如果是泊位或者靠泊区,则记录泊位的 id 132 | int bit_type; 133 | int shipAble[4]; // 记录这个位置四个方向是否船是否可以停在这里 134 | 135 | int belongToBerth; // 这个格子是属于哪个港口的独占区,-1表示公共区域 136 | Grid(){ 137 | this->pos = Pos(-1, -1); 138 | this->type = -1; 139 | this->gridDir = nullptr; 140 | this->robotOnIt = false; 141 | this->berthId = -1; 142 | this->bit_type = 0; 143 | this->belongToBerth = -1; 144 | } 145 | Grid(int x, int y, int type) : type(type){ 146 | this->pos = Pos(x, y); 147 | this->gridDir = nullptr; 148 | this->robotOnIt = false; 149 | this->berthId = -1; 150 | this->bit_type = 1 << type; 151 | this->belongToBerth = -1; 152 | } 153 | }; 154 | 155 | Grid *grids[MAX_Line_Length + 1][MAX_Col_Length + 1]; 156 | /** 157 | * @brief 检查位置是否合法 158 | * @param pos 表示位置 159 | * @return true 表示合法, false 表示不合法 160 | */ 161 | bool checkPos(Pos pos) { 162 | return pos.x >= 0 && pos.x < MAX_Line_Length && pos.y >= 0 && pos.y < MAX_Col_Length; 163 | } 164 | /** 165 | * @brief 检查机器人是否可以走这个位置 166 | * @param pos 表示位置 167 | * @return true 表示可以走, false 表示不可以走 168 | */ 169 | bool checkRobotAble(Pos pos) { 170 | if (checkPos(pos) == false) return false; 171 | auto type = grids[pos.x][pos.y]->type; 172 | return (type == 0 || type == 3 || type == 4 || type == 6 || type == 9 || type == 11); 173 | } 174 | /** 175 | * @brief 检查船是否可以走这个位置 176 | * @param pos 表示位置 177 | * @return true 表示可以走, false 表示不可以走 178 | */ 179 | bool checkShipAble(Pos pos) { 180 | if (checkPos(pos) == false) return false; 181 | auto type = grids[pos.x][pos.y]->type; 182 | return (type == 1 || type == 3 || type == 5 || type == 7 || type == 8 || type == 9 || type == 11 || type == 12); 183 | } 184 | int SHIPSHIFT[4][6][2] = { //x,y是反的!!!注意别用错!!! 185 | {{0,0},{1,0},{2,0},{0,1},{1,1},{2,1}}, 186 | {{0,0},{-1,0},{-2,0},{0,-1},{-1,-1},{-2,-1}}, 187 | {{0,0},{1,0},{0,-1},{1,-1},{0,-2},{1,-2}}, 188 | {{0,0},{-1,0},{0,1},{-1,1},{0,2},{-1,2}} 189 | }; 190 | bool checkShipAble_with_dir_main(Pos pos, int dir){ 191 | for (int i = 0; i < 6; i++){ 192 | Pos next = pos + Pos(SHIPSHIFT[dir][i][1], SHIPSHIFT[dir][i][0]); 193 | auto type = grids[next.x][next.y]->type; 194 | if (checkShipAble(next) == false) return false; 195 | } 196 | return true; 197 | } 198 | /** 199 | * @brief 检查这个位置是否是主道路 200 | * @param pos 表示位置 201 | * @return true 表示是主道路, false 表示不是主道路 202 | */ 203 | bool checkRobotNoColl(Pos pos) { 204 | if (checkPos(pos) == false) return false; 205 | auto type = grids[pos.x][pos.y]->type; 206 | return (type == 3 || type == 4 || type == 6 || type == 11); 207 | } 208 | /** 209 | * @brief 检查这个位置是否是主航道 210 | * @param pos 表示位置 211 | * @return true 表示是主航道, false 表示不是主航道 212 | */ 213 | bool checkShipNoColl(Pos pos) { 214 | if (checkPos(pos) == false) return false; 215 | auto type = grids[pos.x][pos.y]->type; 216 | return (type == 3 || type == 5 || type == 7 || type == 8 || type == 11 || type == 12); 217 | } 218 | 219 | /** 220 | * @brief 计算船的旋转后的核心点位置 221 | * @param dir表示原始的方向, 0 到 3 分别对应右、左、上、下。(和机器人移动的方向表示一致) 222 | * @param rot表示旋转的方向, 0 表示顺时针, 1 表示逆时针 223 | * @return std::pair 返回旋转后的核心点位置和旋转后的方向 224 | * 225 | */ 226 | ShipPos calShipRotPos(Pos pos, int dir, int rot) { 227 | // 顺时针 228 | if (rot == 0) { 229 | if (dir == 0) { 230 | return ShipPos(pos + Pos(0, 2), 3); 231 | } else if (dir == 1) { 232 | return ShipPos(pos + Pos(0, -2), 2); 233 | } else if (dir == 2) { 234 | return ShipPos(pos + Pos(-2, 0), 0); 235 | } else if (dir == 3) { 236 | return ShipPos(pos + Pos(2, 0), 1); 237 | } 238 | } else { 239 | // 逆时针 240 | if (dir == 0) { 241 | return ShipPos(pos + Pos(1, 1) , 2); 242 | } else if (dir == 1) { 243 | return ShipPos(pos + Pos(-1, -1) , 3); 244 | } else if (dir == 2) { 245 | return ShipPos(pos + Pos(-1, 1) , 1); 246 | } else if (dir == 3) { 247 | return ShipPos(pos + Pos(1, -1) , 0); 248 | } 249 | } 250 | return ShipPos(-1, -1, -1); 251 | } 252 | /** 253 | * @brief 计算船的六个位置 254 | * @param pos 表示船的核心点 255 | * @param dir 表示船的方向 256 | * @return std::vector 返回船的六个位置 257 | */ 258 | std::vector getShipAllPos(Pos pos, int dir) { 259 | std::vector ret; 260 | if (dir == 0) { 261 | ret.push_back(pos); 262 | ret.push_back(pos + Pos(0, 1)); 263 | ret.push_back(pos + Pos(0, 2)); 264 | ret.push_back(pos + Pos(1, 0)); 265 | ret.push_back(pos + Pos(1, 1)); 266 | ret.push_back(pos + Pos(1, 2)); 267 | } else if (dir == 1) { 268 | ret.push_back(pos); 269 | ret.push_back(pos + Pos(0, -1)); 270 | ret.push_back(pos + Pos(0, -2)); 271 | ret.push_back(pos + Pos(-1, 0)); 272 | ret.push_back(pos + Pos(-1, -1)); 273 | ret.push_back(pos + Pos(-1, -2)); 274 | } else if (dir == 2) { 275 | ret.push_back(pos); 276 | ret.push_back(pos + Pos(-1, 0)); 277 | ret.push_back(pos + Pos(-2, 0)); 278 | ret.push_back(pos + Pos(0, 1)); 279 | ret.push_back(pos + Pos(-1, 1)); 280 | ret.push_back(pos + Pos(-2, 1)); 281 | } else if (dir == 3) { 282 | ret.push_back(pos); 283 | ret.push_back(pos + Pos(1, 0)); 284 | ret.push_back(pos + Pos(2, 0)); 285 | ret.push_back(pos + Pos(0, -1)); 286 | ret.push_back(pos + Pos(1, -1)); 287 | ret.push_back(pos + Pos(2, -1)); 288 | } 289 | return ret; 290 | } 291 | /** 292 | * @brief 检查船六个点是否都可以走 293 | * @param pos 表示船的核心点 294 | * @return 0 表示不能走, 1 表示可以走(正常道路), 2 表示主航道道路 295 | */ 296 | int checkShipAllAble(Pos pos, int dir) { 297 | auto allPos = getShipAllPos(pos, dir); 298 | int ret = 1; 299 | for (auto &p : allPos) { 300 | if (checkShipAble(p) == false) return 0; 301 | if (checkShipNoColl(p)) ret = 2; 302 | } 303 | return ret; 304 | } 305 | void PreproShipAllAble() { 306 | for (int x = 0; x < MAX_Line_Length; x++) { 307 | for (int y = 0; y < MAX_Col_Length; y++) { 308 | for (int i = 0; i < 4; i++) { 309 | grids[x][y]->shipAble[i] = checkShipAllAble(Pos(x, y), i); 310 | } 311 | } 312 | } 313 | } 314 | 315 | int _dis_s[MAX_Line_Length + 1][MAX_Col_Length + 1][4]; 316 | ShipPos _pre_s[MAX_Line_Length + 1][MAX_Col_Length + 1][4]; 317 | int _pre_dir_s[MAX_Line_Length + 1][MAX_Col_Length + 1][4]; 318 | /** 319 | * @brief 计算船的最短路径 320 | * 2. 三方向 SPFA:直行2、顺时针0、逆时针1 321 | * 3. SPFA 每个点要存某个方向有没有到达。已经到达的时间,因为主航道 delay 322 | * 4. 存路径:直行2、顺时针0、逆时针1 323 | */ 324 | ShipPos _queue_ship[120010]; 325 | std::deque *sovleShip_ori(Pos origin, int direction, Pos target, bool needPath = true) { 326 | allPathLogger.log(nowTime, "sovleShip origin{},{} direction{} target{},{}", origin.x, origin.y, direction, target.x, target.y); 327 | for (int i = 0; i < MAX_Line_Length; i++) { 328 | for (int j = 0; j < MAX_Col_Length; j++) { 329 | for (int k = 0; k < 4; k++) { 330 | _dis_s[i][j][k] = INT_MAX; 331 | _pre_s[i][j][k] = ShipPos(-1, -1, -1); 332 | _pre_dir_s[i][j][k] = -1; 333 | } 334 | } 335 | } 336 | int start = 0; 337 | int end = 0; 338 | _queue_ship[end++] = ShipPos(origin, direction); 339 | _dis_s[origin.x][origin.y][direction] = 0; 340 | while (start != end) { 341 | ShipPos now = _queue_ship[start++]; 342 | if (start == 120010) start = 0; 343 | // 直行 344 | ShipPos next = now + dir[now.direction]; 345 | // 判断是否可以走 0 表示不能走, 1 表示可以走(正常道路), 2 表示主航道道路 346 | auto checkRes = grids[next.x][next.y]->shipAble[next.direction]; 347 | if (checkRes && _dis_s[next.x][next.y][next.direction] > _dis_s[now.x][now.y][now.direction] + checkRes) { 348 | _dis_s[next.x][next.y][next.direction] = _dis_s[now.x][now.y][now.direction] + checkRes; 349 | _pre_s[next.x][next.y][next.direction] = now; 350 | _pre_dir_s[next.x][next.y][next.direction] = 2; 351 | _queue_ship[end++] = next; 352 | if (end == 120010) end = 0; 353 | } 354 | // 顺时针 355 | next = calShipRotPos(now.toPos(), now.direction, 0); 356 | checkRes = grids[next.x][next.y]->shipAble[next.direction]; 357 | if (checkRes && _dis_s[next.x][next.y][next.direction] > _dis_s[now.x][now.y][now.direction] + checkRes) { 358 | _dis_s[next.x][next.y][next.direction] = _dis_s[now.x][now.y][now.direction] + checkRes; 359 | _pre_s[next.x][next.y][next.direction] = now; 360 | _pre_dir_s[next.x][next.y][next.direction] = 0; 361 | _queue_ship[end++] = next; 362 | if (end == 120010) end = 0; 363 | } 364 | // 逆时针 365 | next = calShipRotPos(now.toPos(), now.direction, 1); 366 | checkRes = grids[next.x][next.y]->shipAble[next.direction]; 367 | if (checkRes && _dis_s[next.x][next.y][next.direction] > _dis_s[now.x][now.y][now.direction] + checkRes) { 368 | _dis_s[next.x][next.y][next.direction] = _dis_s[now.x][now.y][now.direction] + checkRes; 369 | _pre_s[next.x][next.y][next.direction] = now; 370 | _pre_dir_s[next.x][next.y][next.direction] = 1; 371 | _queue_ship[end++] = next; 372 | if (end == 120010) end = 0; 373 | } 374 | } 375 | std::deque *result = new std::deque; 376 | // 首先找到重点的四个方向里 dis 最小的 377 | ShipPos now = ShipPos(target, 0); 378 | for (int i = 1; i < 4; i++) { 379 | if (_dis_s[target.x][target.y][i] < _dis_s[now.x][now.y][now.direction]) { 380 | now.direction = i; 381 | } 382 | } 383 | // std::string allPos = std::to_string(target.x) + "," + std::to_string(target.y) + "," + std::to_string(now.direction) + "<"; 384 | // std::string allDir = std::to_string(_pre_dir_s[now.x][now.y][now.direction]) + "<"; 385 | // 每次找到前一个的位置 386 | while (true && needPath) { 387 | result->push_front(_pre_dir_s[now.x][now.y][now.direction]); 388 | now = _pre_s[now.x][now.y][now.direction]; 389 | if (now.toPos() == origin && now.direction == direction) break; 390 | // allPos += std::to_string(now.x) + "," + std::to_string(now.y) + "," + std::to_string(now.direction) + "<"; 391 | // allDir += std::to_string(_pre_dir_s[now.x][now.y][now.direction]) + "<"; 392 | } 393 | // allPathLogger.log(nowTime, "allPos:{}", allPos); 394 | // allPathLogger.log(nowTime, "allDir:{}", allDir); 395 | return result; 396 | } 397 | 398 | Pos _arr[40010]; 399 | Navigator * sovleGrid(Pos origin) { 400 | Navigator * result = new Navigator; 401 | result->setVisited(origin.x, origin.y); 402 | Pos _arr[40010]; 403 | int start = 0, end = 0; 404 | _arr[end++] = origin; 405 | while (start < end) { 406 | Pos &now = _arr[start++]; 407 | for (int i = 0; i < 4; i++) { 408 | Pos next = now + dir[i]; // 下一个点 409 | if (checkRobotAble(next) == false) continue; // 不是机器人可以走的地方 410 | if (result->isVisited(next.x, next.y)) continue; //记录过前序, 跳过 411 | result->setVisited(next.x, next.y); 412 | result->setDir(next.x, next.y, ((i == 0 || i == 2) ? i + 1 : i - 1)); 413 | _arr[end++] = next; 414 | } 415 | } 416 | return result; 417 | } 418 | 419 | int _ship_map_front[120010]; 420 | int _ship_map_front_pos[120010]; 421 | std::deque *return_path(int now); 422 | std::deque *sovleShip(Pos origin, int direction, Pos target, bool needPath = true) { 423 | Navigator_ship *map = new Navigator_ship; 424 | Navigator_ship *map_main_channel = new Navigator_ship; 425 | int start = 0, end = 0; 426 | _queue_ship[end++] = ShipPos(origin, direction); 427 | while (start < end){ 428 | ShipPos now = _queue_ship[start++]; 429 | if (grids[now.x][now.y]->shipAble[now.direction] == 2){ 430 | if (map_main_channel->isVisited(now.x, now.y, now.direction) == 0) { //第一次访问 431 | map_main_channel->setVisited(now.x, now.y, now.direction); 432 | _ship_map_front[end] = start - 1; 433 | _ship_map_front_pos[end] = 4; 434 | _queue_ship[end++] = now; 435 | } 436 | } 437 | ShipPos next[3] = { // 三个方向 2直行 0顺时针 1逆时针 438 | calShipRotPos(now.toPos(), now.direction, 0), 439 | calShipRotPos(now.toPos(), now.direction, 1), 440 | now + dir[now.direction]}; 441 | for (int i = 0; i < 3; i++) { // 遍历三个方向 442 | if (map->isVisited(next[i].x, next[i].y, next[i].direction)) continue; 443 | if (grids[next[i].x][next[i].y]->shipAble[next[i].direction] == 0) continue; 444 | map->setVisited(next[i].x, next[i].y, next[i].direction); 445 | _ship_map_front[end] = start - 1; // 记录前一个位置 446 | _ship_map_front_pos[end] = i; // 记录来这个位置的方向 447 | if (next[i].toPos() == target) { 448 | if (needPath) { 449 | return return_path(end); 450 | } 451 | return new std::deque; 452 | } 453 | _queue_ship[end++] = next[i]; 454 | 455 | } 456 | } 457 | return new std::deque; 458 | } 459 | std::deque *return_path(int now) { //返回查找路径怎么走 460 | std::deque *result = new std::deque; 461 | while (now != 0) { 462 | result->push_front(_ship_map_front_pos[now]); 463 | now = _ship_map_front[now]; 464 | } 465 | return result; 466 | } 467 | 468 | void resetbelong() { 469 | for (int i = 0; i < MAX_Line_Length; i++) { 470 | for (int j = 0; j < MAX_Col_Length; j++) { 471 | grids[i][j]->belongToBerth = -1; 472 | } 473 | } 474 | } 475 | 476 | #endif -------------------------------------------------------------------------------- /code/input.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __INPUT_H__ 2 | #define __INPUT_H__ 3 | #include "config.hpp" 4 | #include "grid.hpp" 5 | #include "robot.hpp" 6 | #include "ship.hpp" 7 | #include "berth.hpp" 8 | #include "item.hpp" 9 | #include "logger.hpp" 10 | #include "berth_centre.hpp" 11 | #include "estimator.hpp" 12 | 13 | // * 0‘.’ : 空地 | 机器人可以走 会发生碰撞 14 | // * 1‘*’ : 海洋 | 船可以走 会发生碰撞 15 | // * 2‘#’ : 障碍 | 谁都不可以走 16 | // * 3‘B’ : 泊位 同时算主干道主航道 | 船和机器人都可以走 不会发生碰撞 17 | // * 4‘>’ : 陆地主干道 | 机器人可以走 不会发生碰撞 18 | // * 5‘~’ : 海洋主航道 | 船可以走 不会发生碰撞 19 | // * 6‘R’ : 机器人购买地块,同时该地块也是主干道. | 机器人可以走, 不会发生碰撞 20 | // * 7‘S’ : 船舶购买地块,同时该地块也是主航道 | 船可以走, 不会发生碰撞 21 | // * 8‘K’ : 靠泊区 算主航道 | 船可以走 不会发生碰撞 22 | // * 9‘C’ : 海陆立体交通地块 | 船和机器人都可以走 会发生碰撞 23 | // * 11‘c’ : 海陆立体交通地块,同时为主干道和主航道 |船和机器人都可以走 不会发生碰撞 24 | // * 12‘T’ : 交货点 特殊的靠泊区 所以也算主航道 | 船可以走 不会发生碰撞 25 | 26 | 27 | void inputMap(){ 28 | int totalSpawnPlace = 0; 29 | for (int i = 0; i < MAX_Line_Length; i++) { 30 | std::string line; 31 | getline(std::cin, line); 32 | for (int j = 0; j < MAX_Col_Length; j++) { 33 | switch (line[j]) { 34 | case '.': 35 | totalSpawnPlace++; 36 | grids[i][j] = new Grid(i, j, 0); 37 | break; 38 | case '*': 39 | grids[i][j] = new Grid(i, j, 1); 40 | break; 41 | case '#': 42 | grids[i][j] = new Grid(i, j, 2); 43 | break; 44 | case 'B': 45 | grids[i][j] = new Grid(i, j, 3); 46 | break; 47 | case '>': 48 | grids[i][j] = new Grid(i, j, 4); 49 | break; 50 | case '~': 51 | grids[i][j] = new Grid(i, j, 5); 52 | break; 53 | case 'R': 54 | grids[i][j] = new Grid(i, j, 6); 55 | berth_center->robot_buyer.emplace_back(Pos(i, j)); 56 | break; 57 | case 'S': 58 | grids[i][j] = new Grid(i, j, 7); 59 | berth_center->ship_buyer.emplace_back(Pos(i, j)); 60 | break; 61 | case 'K': 62 | grids[i][j] = new Grid(i, j, 8); 63 | break; 64 | case 'C': 65 | grids[i][j] = new Grid(i, j, 9); 66 | break; 67 | case 'c': 68 | grids[i][j] = new Grid(i, j, 11); 69 | break; 70 | case 'T': 71 | grids[i][j] = new Grid(i, j, 12); 72 | berth_center->delivery.emplace_back(Pos(i, j)); 73 | break; 74 | default: 75 | throw; 76 | } 77 | } 78 | } 79 | scanf("%d", &MAX_Berth_Num); 80 | for (int i = 0; i < MAX_Berth_Num; i++) { 81 | int id, x, y, velocity; 82 | scanf("%d%d%d%d", &id, &x, &y, &velocity); 83 | berths.emplace_back(new Berth(id, x, y, velocity)); 84 | berthLogger.log(nowTime, "Berth{0} :id={1} x={2} y={3} v={4}", i, id, x, y, velocity); 85 | } 86 | std::cin >> MAX_Capacity; 87 | std::string line; 88 | while(getline(std::cin, line) && line != "OK"); 89 | solveBerth(); 90 | PreproShipAllAble(); 91 | berth_center->find_private_space(); 92 | initBerthEstimator(totalSpawnPlace, MAX_Berth_Num); 93 | 94 | // srand(time(0)); 95 | puts("OK"); 96 | fflush(stdout); 97 | 98 | counter.registerVariable("shipNum", MAX_Ship_Num); 99 | counter.registerVariable("robotNum", MAX_Robot_Num); 100 | counter.registerVariable("robot_move_length", 0); 101 | counter.registerVariable("robot_get_nums", 0); 102 | counter.registerVariable("robot_get_value", 0); 103 | counter.registerVariable("robot_get_value_before_lastgame", 0); 104 | counter.registerVariable("robot_move_length_max", 0); 105 | counter.registerVariable("robot_move_length_min", 40000); 106 | counter.registerVector("robot_move_length_vector"); 107 | counter.registerVector2D("robot_path"); 108 | counter.registerVector2D("robot_pos"); 109 | counter.registerVector2D("ship_pos"); 110 | counter.registerVector2D("gds"); 111 | counter.registerVariable("sum_goods", 0); 112 | counter.registerVariable("sum_goods_value", 0); 113 | } 114 | 115 | void do_special_frame() { 116 | 117 | if (nowTime == 15000-lastRoundRuningTime) { 118 | counter.lock("robot_move_length"); 119 | counter.lock("robot_get_nums"); 120 | counter.add("robot_get_value_before_lastgame", counter.getValue("robot_get_value")); 121 | counter.lock("robot_get_value_before_lastgame"); 122 | } 123 | if (nowTime == 14999) counter.writeToFile("../log/counter.txt"); 124 | if (nowTime == 14999) { 125 | for (auto berth : berths) { 126 | berthLogger.log(nowTime, "Berth={},sum_goods={},sum_value={}", berth->id, berth->total_goods, berth->total_value); 127 | } 128 | } 129 | } 130 | 131 | 132 | bool inputFrame() { 133 | if (scanf("%d%d",&nowTime, &money ) == EOF) { 134 | inputFlag = false; 135 | return false; 136 | } 137 | int K; 138 | scanf("%d", &K); 139 | counter.push_back("gds",-1000,nowTime); 140 | for (int i = 1; i <= K; i++) { 141 | int x, y, value; 142 | scanf("%d%d%d", &x, &y, &value); 143 | if (value != 0) { 144 | unsolvedItems.emplace_back(x, y, value); 145 | unsolvedItems.back().beginTime = nowTime; 146 | counter.push_back("gds",x,y); 147 | counter.push_back("gds",-1,value); 148 | } 149 | counter.add("sum_goods", 1); 150 | counter.add("sum_goods_value", value); 151 | } 152 | int R; 153 | scanf("%d", &R); 154 | counter.push_back("robot_pos",-1000,nowTime); 155 | for (int i = 1; i <= R; i++) { 156 | int id, bring, x, y; 157 | scanf("%d%d%d%d", &id, &bring, &x, &y); 158 | robots[id]->bring = bring; 159 | robots[id]->pos = Pos(x, y); 160 | counter.push_back("robot_pos",x,y); 161 | } 162 | int B; 163 | scanf("%d", &B); 164 | counter.push_back("ship_pos",-1000,nowTime); 165 | for (int i = 1; i <= B; i++) { 166 | int id, bring, x, y, direction, status; 167 | scanf("%d%d%d%d%d%d", &id, &bring, &x, &y, &direction, &status); 168 | ships[id]->capacity = bring; 169 | ships[id]->pos = Pos(x, y); 170 | ships[id]->direction = direction; 171 | ships[id]->status = status; 172 | counter.push_back("ship_pos",x,y); 173 | counter.push_back("ship_pos",direction,status); 174 | } 175 | std::string line; 176 | while(getline(std::cin, line) && line != "OK"); 177 | return true; 178 | } 179 | 180 | void buyRobot() { 181 | // 按顺序选择买去哪个港口的机器人 182 | for (int i = 0; i < _buyRobotQueue.size(); i++) { 183 | if (_buyRobotQueue[i].buyed) 184 | continue; 185 | int berthId = _buyRobotQueue[i].berthId; 186 | int minDis = 0x3f3f3f3f; 187 | int choosedBuyerId = -1; 188 | 189 | // 遍历所有的buyer看能否买到 190 | for (int j = 0; j < berth_center->robot_buyer.size(); j++) { 191 | auto buyerX = berth_center->robot_buyer[j].pos.x; 192 | auto buyerY = berth_center->robot_buyer[j].pos.y; 193 | int berthToBuyerDis = berths[berthId]->disWithTimeBerth[buyerX][buyerY]; 194 | 195 | // 能买到,找最近的一个买 196 | if (berthToBuyerDis < minDis) { 197 | minDis = berthToBuyerDis; 198 | choosedBuyerId = j; 199 | } 200 | } 201 | 202 | // 如果能买到,且钱够,且机器人数量不超过预期,就买 203 | if (minDis != 0x3f3f3f3f && ((nowTime != 1 and money > 2000) or (nowTime == 1 and money > 10000)) && robots.size() < exptRobotCnt) { 204 | newRobot(berth_center->robot_buyer[choosedBuyerId].pos.x, berth_center->robot_buyer[choosedBuyerId].pos.y, berthId); 205 | _buyRobotQueue[i].buyed = true; 206 | } 207 | } 208 | } 209 | 210 | void buyShip() { 211 | for (auto & shipBuyer : berth_center->ship_buyer) { 212 | if ((nowTime == 1 or (nowTime > 5000 and nowTime < 100000) ) and money > 8000 && ships.size() < _maxShipCnt) newShip(shipBuyer.pos.x, shipBuyer.pos.y); 213 | break; 214 | } 215 | } 216 | 217 | void solveFrame() { 218 | flowLogger.log(nowTime, "当前帧数={0}", nowTime); 219 | measureAndExecute("Action for all robots", [&]() {for (auto & robot : robots) robot->action();}); 220 | // 碰撞检测 221 | // solveCollision(); 222 | // 移动 223 | measureAndExecute("Move all robots", [&]() {for (auto & robot : robots) robot->move();}); 224 | // 时间向前推进 225 | if (allPath.size() > 0) allPath.pop_front(); 226 | // 船只调度 227 | measureAndExecute("Move all ships", [&]() { 228 | berth_center->call_ship_and_berth_check(); 229 | // 船只移动 230 | for (auto & ship : ships) ship->move(); 231 | }); 232 | do_special_frame(); 233 | 234 | if (robots.size() < exptRobotCnt) { 235 | buyRobot(); 236 | berth_center->update_robot_choose_berth(); 237 | } 238 | 239 | // TODO: 在机器人拿货速度大于船运货速度时,买新的船 240 | if (ships.size() < _maxShipCnt) buyShip(); 241 | 242 | puts("OK"); 243 | fflush(stdout); 244 | } 245 | #endif -------------------------------------------------------------------------------- /code/item.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ITEM_H__ 2 | #define __ITEM_H__ 3 | #include "config.hpp" 4 | 5 | struct Item { 6 | Pos pos; 7 | int value; 8 | int beginTime; 9 | Item(int x, int y, int value) : value(value) { 10 | this->pos = Pos(x, y); 11 | } 12 | Item() {} 13 | bool checkDead() { 14 | return nowTime - beginTime > Item_Continue_Time; 15 | } 16 | }; 17 | std::list unsolvedItems; 18 | 19 | #endif -------------------------------------------------------------------------------- /code/logger.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __LOGGER_H__ 2 | #define __LOGGER_H__ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef DEBUG 11 | #include "fmt/format.h" 12 | #endif 13 | 14 | // 基类 Logger 15 | class Logger { 16 | #ifdef DEBUG 17 | public: 18 | Logger() : isRunning(true) { 19 | // 启动日志记录线程 20 | 21 | logThread = std::thread(&Logger::logThreadFunction, this); 22 | } 23 | 24 | virtual ~Logger() { 25 | { 26 | std::lock_guard lock(mutex); 27 | isRunning = false; 28 | } 29 | // 通知日志线程退出 30 | condition.notify_one(); 31 | // 等待日志线程退出 32 | logThread.join(); 33 | } 34 | 35 | // 添加日志接口 36 | template 37 | void log(const int& nowFrame, const std::string& formatStr, const Args&... args) { 38 | // std::string result = std::format(formatStr, args...); 39 | // concatenate the nowFrame to the front of the result 40 | // std::string result = std::format("{0}: {1}", nowFrame, result); 41 | // merge the above two lines 42 | std::string result = fmt::format("{0}:{1}", nowFrame, fmt::format(formatStr, args...)); 43 | 44 | std::lock_guard lock(mutex); 45 | logQueue.push(result); 46 | // 通知日志线程有新日志 47 | condition.notify_one(); 48 | } 49 | 50 | // 添加日志接口 51 | /* 52 | void log(const std::string& message) { 53 | std::lock_guard lock(mutex); 54 | logQueue.push(message); 55 | // 通知日志线程有新日志 56 | condition.notify_one(); 57 | } 58 | */ 59 | 60 | protected: 61 | // 日志线程函数 62 | void logThreadFunction() { 63 | while (isRunning) { 64 | std::unique_lock lock(mutex); 65 | // 等待有新日志到来或者线程终止 66 | condition.wait(lock, [this] { return !logQueue.empty() || !isRunning; }); 67 | // 输出日志 68 | while (!logQueue.empty()) { 69 | writeLog(logQueue.front()); 70 | logQueue.pop(); 71 | } 72 | } 73 | } 74 | 75 | std::thread logThread; 76 | std::mutex mutex; 77 | std::condition_variable condition; 78 | std::queue logQueue; 79 | 80 | #else 81 | public: 82 | Logger() : isRunning(true) {} 83 | 84 | virtual ~Logger() {} 85 | 86 | template 87 | 88 | void log(const int& nowFrame, const std::string& formatStr, const Args&... args) {} 89 | #endif 90 | 91 | protected: 92 | bool isRunning; 93 | // 写日志函数,需要子类实现 94 | virtual void writeLog(const std::string& message) = 0; 95 | 96 | 97 | 98 | }; 99 | 100 | // 文件日志记录器 101 | class FileLogger : public Logger { 102 | #ifdef DEBUG 103 | public: 104 | FileLogger(const std::string& filename) : outputStream(filename) {} 105 | 106 | ~FileLogger() { 107 | if (outputStream.is_open()) { 108 | outputStream.close(); 109 | } 110 | } 111 | 112 | private: 113 | void writeLog(const std::string& message) override { 114 | if (outputStream.is_open()) { 115 | outputStream << message << std::endl; 116 | } 117 | } 118 | 119 | std::ofstream outputStream; 120 | #else 121 | public: 122 | FileLogger(const std::string& filename) {} 123 | private: 124 | void writeLog(const std::string& message) override {} 125 | #endif 126 | }; 127 | 128 | 129 | #endif -------------------------------------------------------------------------------- /code/main.cpp: -------------------------------------------------------------------------------- 1 | #include "config.hpp" 2 | #include "input.hpp" 3 | 4 | int main() { 5 | #ifdef TUNE 6 | std::ifstream fin("para.txt"); 7 | fin >> MAX_Berth_Control_Length; 8 | fin >> MAX_Berth_Merge_Length; 9 | fin >> Worst_Rate; 10 | fin >> Sell_Ration; 11 | fin >> Min_Next_Berth_Value; 12 | fin >> Only_Run_On_Berth_with_Ship; 13 | fin >> lastRoundRuningTime; 14 | #endif 15 | inputMap(); 16 | while (1) { 17 | Timer::measure("input_frame",inputFrame); 18 | if (inputFlag == false) break; 19 | Timer::measure("solve_Frame",solveFrame); 20 | } 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /code/para.txt: -------------------------------------------------------------------------------- 1 | 150 2 | 16 3 | 3 4 | 0.7 5 | 1700 6 | 2000 7 | 500 8 | -------------------------------------------------------------------------------- /code/path.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __PATH_H__ 2 | #define __PATH_H__ 3 | 4 | #include "config.hpp" 5 | #include "grid.hpp" 6 | 7 | 8 | struct TPos { 9 | Pos pos; 10 | int dis; 11 | TPos(Pos pos, int dis) : pos(pos), dis(dis) {} 12 | TPos() {} 13 | bool operator < (const TPos &a) const { 14 | return dis < a.dis; 15 | } 16 | }; 17 | 18 | int disWithTime[MAX_Line_Length + 1][MAX_Col_Length + 1]; 19 | Pos preWithTime[MAX_Line_Length + 1][MAX_Col_Length + 1]; 20 | int delayWithTime[MAX_Line_Length + 1][MAX_Col_Length + 1]; 21 | std::deque> allPath; 22 | std::vector fixPos(MAX_Robot_Num, Pos(-1, -1)); 23 | TPos _queueRobot[40010]; 24 | 25 | void solveGridWithTime(Pos beginPos, int nowRobotId, int beginFrame=0) { 26 | int waitTime = 2; 27 | memset(disWithTime, 0x3f, sizeof(disWithTime)); 28 | memset(preWithTime, 0xff, sizeof(preWithTime)); 29 | memset(delayWithTime, 0, sizeof(delayWithTime)); 30 | 31 | for (int i = 0; i < fixPos.size(); i++) { 32 | if (i != nowRobotId and fixPos[i].x != -1 and not IS_ROBOT_NOCOL(grids[fixPos[i].x][fixPos[i].y]->bit_type)) { 33 | grids[fixPos[i].x][fixPos[i].y]->robotOnIt = true; 34 | } 35 | } 36 | 37 | int start = 0; 38 | int end = 0; 39 | _queueRobot[end++] = TPos(beginPos, beginFrame); 40 | disWithTime[beginPos.x][beginPos.y] = beginFrame; 41 | 42 | int lastSeenDis = -1; 43 | 44 | while (start != end) { 45 | TPos now_s = _queueRobot[start++]; 46 | auto now = now_s.pos; 47 | auto now_dis = now_s.dis; 48 | if (start == 40010) start = 0; 49 | 50 | /* 51 | if (disWithTime[now.x][now.y] < allPath.size()) { 52 | for (Pos tar : allPath[disWithTime[now.x][now.y]]) { 53 | if (tar.x == -1) continue; 54 | grids[tar.x][tar.y]->robotOnIt = true; 55 | } 56 | } 57 | if (disWithTime[now.x][now.y] + 1 < allPath.size()) { 58 | for (Pos tar : allPath[disWithTime[now.x][now.y] + 1]) { 59 | if (tar.x == -1) continue; 60 | grids[tar.x][tar.y]->robotOnIt = true; 61 | } 62 | } 63 | */ 64 | 65 | 66 | if (lastSeenDis != now_dis) { 67 | // pathLogger.log(nowTime, "lastSeen={},nowDis={}", lastSeenDis, disWithTime[now.x][now.y]); 68 | // remove last robot 69 | if (lastSeenDis != -1 and lastSeenDis < allPath.size()) { 70 | for (int i = 0; i < allPath[lastSeenDis].size(); i++) { 71 | auto tar = allPath[lastSeenDis][i]; 72 | if (i == nowRobotId or tar.x == -1 or NOT_VALID_GRID(tar.x, tar.y) or IS_ROBOT_NOCOL(grids[tar.x][tar.y]->bit_type)) continue; 73 | grids[tar.x][tar.y]->robotOnIt = false; 74 | } 75 | } 76 | if (lastSeenDis != -1 and lastSeenDis + 1 < allPath.size()) { 77 | for (int i = 0; i < allPath[lastSeenDis + 1].size(); i++) { 78 | auto tar = allPath[lastSeenDis + 1][i]; 79 | if (i == nowRobotId or tar.x == -1 or NOT_VALID_GRID(tar.x, tar.y) or IS_ROBOT_NOCOL(grids[tar.x][tar.y]->bit_type)) continue; 80 | grids[tar.x][tar.y]->robotOnIt = false; 81 | } 82 | } 83 | 84 | lastSeenDis = now_dis; 85 | 86 | // add new robot 87 | if (lastSeenDis < allPath.size()) { 88 | for (int i = 0; i < allPath[lastSeenDis].size(); i++) { 89 | auto tar = allPath[lastSeenDis][i]; 90 | if (i == nowRobotId or tar.x == -1 or NOT_VALID_GRID(tar.x, tar.y) or IS_ROBOT_NOCOL(grids[tar.x][tar.y]->bit_type)) continue; 91 | grids[tar.x][tar.y]->robotOnIt = true; 92 | } 93 | } 94 | if (lastSeenDis + 1 < allPath.size()) { 95 | for (int i = 0; i < allPath[lastSeenDis + 1].size(); i++) { 96 | auto tar = allPath[lastSeenDis + 1][i]; 97 | if (i == nowRobotId or tar.x == -1 or NOT_VALID_GRID(tar.x, tar.y) or IS_ROBOT_NOCOL(grids[tar.x][tar.y]->bit_type)) continue; 98 | grids[tar.x][tar.y]->robotOnIt = true; 99 | } 100 | } 101 | } 102 | 103 | if (grids[now.x][now.y]->robotOnIt) continue; 104 | 105 | 106 | for (int i = 0; i < 4; i++) { 107 | Pos next = now + dir[i]; 108 | // if (checkRobotAble(next) == false) continue; 109 | if (NOT_VALID_GRID(next.x, next.y) or 110 | not IS_ROBOT_ABLE(grids[next.x][next.y]->bit_type) or 111 | disWithTime[next.x][next.y] <= now_dis + 1 or 112 | grids[next.x][next.y]->robotOnIt) continue; 113 | // never reached before or reached with longer time 114 | _queueRobot[end++] = TPos(next, now_dis + 1); 115 | if (end == 40010) end = 0; 116 | disWithTime[next.x][next.y] = now_dis + 1; 117 | preWithTime[next.x][next.y] = now; 118 | // could reach through delay 119 | // delay at now position 120 | delayWithTime[next.x][next.y] = now_dis - disWithTime[now.x][now.y]; 121 | } 122 | 123 | 124 | if (now_dis - disWithTime[now.x][now.y] <= waitTime) { 125 | _queueRobot[end++] = TPos(now, now_dis + 1); 126 | if (end == 40010) end = 0; 127 | } 128 | 129 | /* 130 | if (disWithTime[now.x][now.y] < allPath.size()) { 131 | for (Pos tar : allPath[disWithTime[now.x][now.y]]) { 132 | if (tar.x == -1) continue; 133 | grids[tar.x][tar.y]->robotOnIt = false; 134 | } 135 | } 136 | if (disWithTime[now.x][now.y] + 1 < allPath.size()) { 137 | for (Pos tar : allPath[disWithTime[now.x][now.y] + 1]) { 138 | if (tar.x == -1) continue; 139 | grids[tar.x][tar.y]->robotOnIt = false; 140 | } 141 | } 142 | */ 143 | } 144 | 145 | if (lastSeenDis != -1 and lastSeenDis < allPath.size()) { 146 | for (int i = 0; i < allPath[lastSeenDis].size(); i++) { 147 | auto tar = allPath[lastSeenDis][i]; 148 | if (tar.x == -1 or NOT_VALID_GRID(tar.x, tar.y) or IS_ROBOT_NOCOL(grids[tar.x][tar.y]->bit_type)) continue; 149 | grids[tar.x][tar.y]->robotOnIt = false; 150 | } 151 | } 152 | if (lastSeenDis != -1 and lastSeenDis + 1 < allPath.size()) { 153 | for (int i = 0; i < allPath[lastSeenDis + 1].size(); i++) { 154 | auto tar = allPath[lastSeenDis + 1][i]; 155 | if (tar.x == -1 or NOT_VALID_GRID(tar.x, tar.y) or IS_ROBOT_NOCOL(grids[tar.x][tar.y]->bit_type)) continue; 156 | grids[tar.x][tar.y]->robotOnIt = false; 157 | } 158 | } 159 | 160 | for (int i = 0; i < fixPos.size(); i++) { 161 | if (i != nowRobotId and fixPos[i].x != -1 and not IS_ROBOT_NOCOL(grids[fixPos[i].x][fixPos[i].y]->bit_type)) { 162 | grids[fixPos[i].x][fixPos[i].y]->robotOnIt = false; 163 | } 164 | } 165 | 166 | return; 167 | } 168 | 169 | void addPathToAllPath(std::deque path, int nowRobotId) { 170 | for (int nowFrame = 0; nowFrame < path.size(); nowFrame++) { 171 | if (nowFrame >= allPath.size()) { 172 | // vector size is equal to robotNum 173 | allPath.push_back(std::vector (MAX_Robot_Num)); 174 | } 175 | if (nowRobotId >= allPath[nowFrame].size()) allPath[nowFrame].resize(MAX_Robot_Num); 176 | allPath[nowFrame][nowRobotId] = path[nowFrame]; 177 | } 178 | for (int nowFrame = path.size(); nowFrame < allPath.size(); nowFrame++) { 179 | if (nowRobotId >= allPath[nowFrame].size()) allPath[nowFrame].resize(MAX_Robot_Num); 180 | allPath[nowFrame][nowRobotId] = Pos(-1, -1); 181 | } 182 | fixPos[nowRobotId] = Pos(-1, -1); 183 | } 184 | 185 | void deletePathFromAllPath(int nowRobotId) { 186 | for (int nowFrame = 0; nowFrame < allPath.size(); nowFrame++) { 187 | if (nowRobotId >= allPath[nowFrame].size()) continue; 188 | allPath[nowFrame][nowRobotId] = Pos(-1, -1); 189 | } 190 | } 191 | 192 | void updateFixPos(Pos pos, int nowRobotId) { 193 | fixPos[nowRobotId] = pos; 194 | } 195 | 196 | int getDirWithPath(Pos now, Pos next) { 197 | if (now.x == next.x and now.y == next.y) return -1; 198 | if (now.x == next.x) { 199 | if (now.y < next.y) return 0; 200 | else return 1; 201 | } else { 202 | if (now.x < next.x) return 3; 203 | else return 2; 204 | } 205 | } 206 | 207 | std::deque findPathWithTime(Pos beginPos, Pos endPos) { 208 | std::deque path; 209 | auto now = endPos; 210 | path.push_back(now); 211 | while (!(now == beginPos)) { 212 | if (NOT_VALID_GRID(now.x, now.y) or not IS_ROBOT_ABLE(grids[now.x][now.y]->bit_type)) { 213 | path.clear(); 214 | return path; 215 | } 216 | 217 | 218 | while (delayWithTime[now.x][now.y] > 0) { 219 | path.push_back(preWithTime[now.x][now.y]); 220 | delayWithTime[now.x][now.y]--; 221 | pathLogger.log(nowTime, "delayWithTime={}, nowx={}, nowy={}, disWithTime={}", delayWithTime[now.x][now.y], now.x, now.y, disWithTime[now.x][now.y]); 222 | } 223 | 224 | path.push_back(preWithTime[now.x][now.y]); 225 | now = preWithTime[now.x][now.y]; 226 | } 227 | // path.push_back(beginPos); 228 | std::reverse(path.begin(), path.end()); 229 | return path; 230 | } 231 | 232 | #endif -------------------------------------------------------------------------------- /code/pos.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VECTOR_HPP 2 | #define VECTOR_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // 定义二维向量结构体 9 | struct Pos { 10 | int x, y; 11 | Pos(int x = -1, int y = -1) : x(x), y(y) {} 12 | Pos operator+(const Pos v)const { return Pos(x + v.x, y + v.y); } 13 | Pos operator-(const Pos v)const { return Pos(x - v.x, y - v.y); } 14 | bool operator==(const Pos v)const {// 重载等于号 15 | return x == v.x && y == v.y; 16 | } 17 | bool operator!=(const Pos v)const {// 重载不等于号 18 | return x != v.x || y != v.y; 19 | } 20 | int length(const Pos v)const {// 计算两点之间的距离 21 | return abs(x - v.x) + abs(y - v.y); 22 | } 23 | }; 24 | 25 | 26 | namespace std { 27 | template <> 28 | struct hash { 29 | std::size_t operator()(const Pos& obj) const { 30 | std::string temp = std::to_string(obj.x) + std::to_string(obj.y); 31 | return std::hash{}(temp); 32 | } 33 | }; 34 | } 35 | 36 | struct ShipPos { 37 | int x, y, direction; 38 | ShipPos(int x = -1, int y = -1, int direction = -1) : x(x), y(y), direction(direction) {} 39 | ShipPos(Pos pos, int direction) : x(pos.x), y(pos.y), direction(direction) {} 40 | ShipPos operator+(const Pos v)const { return ShipPos(x + v.x, y + v.y, direction); } 41 | bool operator==(const ShipPos v)const { 42 | return x == v.x && y == v.y && direction == v.direction; 43 | } 44 | bool operator!=(const ShipPos v)const { 45 | return x != v.x || y != v.y || direction != v.direction; 46 | } 47 | Pos toPos() { 48 | return Pos(x, y); 49 | } 50 | }; 51 | namespace std { 52 | template <> 53 | struct hash { 54 | std::size_t operator()(const ShipPos& obj) const { 55 | std::string temp = std::to_string(obj.x) + "_" + std::to_string(obj.y) + "_" + std::to_string(obj.direction); 56 | return std::hash{}(temp); 57 | } 58 | }; 59 | } 60 | 61 | #endif -------------------------------------------------------------------------------- /code/ship.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __SHIP_H__ 2 | #define __SHIP_H__ 3 | #include "config.hpp" 4 | #include "berth.hpp" 5 | #include 6 | 7 | int tmpTotalGoods = 0; 8 | 9 | struct Ship { 10 | int id; 11 | int capacity; // 货物数量 12 | Pos pos; // 船的核心点的位置(左后方) 13 | int status; // 0 正常行驶状态 1恢复状态 2装载状态 14 | int direction; // 船的朝向 0 到 3 分别对应右、左、上、下。(和机器人移动的方向表示一致) 15 | /** 16 | * 船所在的泊位 -1表示销售点 -2表示船刚卖完,或者刚出生 没有目标 17 | * 如果 status 是 2 则表示船所在的泊位. 如果 status 是 1 则表示船即将到达的泊位(正在恢复状态) 如果 status 是 0 则表示船想去的泊位. 18 | */ 19 | int berthId; 20 | std::deque *path; // 船的路径, 0 表示顺时针, 1 表示逆时针 2 表示直线 21 | int isLastRound; // 是否是最后一轮 22 | Pos targetPos; // 目标位置 23 | Ship(int id): id(id) { 24 | status = 1; 25 | capacity = 0; 26 | isLastRound = 0; 27 | berthId = -2; 28 | path = nullptr; 29 | 30 | } 31 | void output() { 32 | shipLogger.log(nowTime, "ship{} pos{},{} capacity{} status{} direction{} berthId{} targetPos{},{}", id, pos.x, pos.y, capacity, status, direction, berthId, targetPos.x, targetPos.y); 33 | } 34 | inline int leftCapacity() {return MAX_Capacity - capacity;} 35 | // 靠泊命令 36 | void berth() { 37 | printf("berth %d\n", id); 38 | flowLogger.log(nowTime, "ship{} berth", id); 39 | status = 1; 40 | } 41 | // 离开命令 42 | void dept() { 43 | printf("dept %d\n", id); 44 | flowLogger.log(nowTime, "ship{} dept", id); 45 | status = 1; 46 | } 47 | // 去卖 48 | void goSell(Pos delivery) { 49 | dept(); 50 | this->berthId = -1; 51 | // 这里不需要找路径,因为要先移动到主航道上,然后状态从 2 变成 0. path 设置成空 52 | path = nullptr; 53 | targetPos = delivery; 54 | } 55 | // 去另一个港口 56 | void moveToBerth(int _berthId, Pos to) { 57 | if (berthId >= 0) dept(); 58 | this->berthId = _berthId; 59 | // 这里不需要找路径,因为要先移动到主航道上,然后状态从 2 变成 0. path 设置成空 60 | path = nullptr; 61 | targetPos = to; 62 | } 63 | void move() { 64 | if (status != 0) return; 65 | if (targetPos == pos) return; 66 | // 没有到达目标位置 如果路径为空,则找路径 67 | if (path == nullptr) { 68 | path = sovleShip( pos, direction, targetPos, true); 69 | // path = Timer::measure("sovleShip_ori",sovleShip_ori, pos, direction, targetPos, true); 70 | } 71 | if (path->empty()) { 72 | path = nullptr; 73 | return; 74 | } 75 | int nextDir = path->front(); path->pop_front(); 76 | if (nextDir ==4) { 77 | nextDir = path->front();path->pop_front(); 78 | } 79 | 80 | if (nextDir == 2) { 81 | printf("ship %d\n", id); 82 | flowLogger.log(nowTime, "ship{} move", id); 83 | } else{ 84 | printf("rot %d %d\n", id, nextDir); 85 | flowLogger.log(nowTime, "ship{} rot{}", id, nextDir); 86 | } 87 | 88 | } 89 | }; 90 | 91 | std::vector ships; 92 | void newShip(int x, int y) { 93 | printf("lboat %d %d\n", x, y); 94 | ships.push_back(new Ship(MAX_Ship_Num++)); 95 | money -= 8000; 96 | } 97 | 98 | 99 | #endif -------------------------------------------------------------------------------- /dcode/include/fmt/args.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - dynamic argument lists 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_ARGS_H_ 9 | #define FMT_ARGS_H_ 10 | 11 | #include // std::reference_wrapper 12 | #include // std::unique_ptr 13 | #include 14 | 15 | #include "core.h" 16 | 17 | FMT_BEGIN_NAMESPACE 18 | 19 | namespace detail { 20 | 21 | template struct is_reference_wrapper : std::false_type {}; 22 | template 23 | struct is_reference_wrapper> : std::true_type {}; 24 | 25 | template auto unwrap(const T& v) -> const T& { return v; } 26 | template 27 | auto unwrap(const std::reference_wrapper& v) -> const T& { 28 | return static_cast(v); 29 | } 30 | 31 | class dynamic_arg_list { 32 | // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for 33 | // templates it doesn't complain about inability to deduce single translation 34 | // unit for placing vtable. So storage_node_base is made a fake template. 35 | template struct node { 36 | virtual ~node() = default; 37 | std::unique_ptr> next; 38 | }; 39 | 40 | template struct typed_node : node<> { 41 | T value; 42 | 43 | template 44 | FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} 45 | 46 | template 47 | FMT_CONSTEXPR typed_node(const basic_string_view& arg) 48 | : value(arg.data(), arg.size()) {} 49 | }; 50 | 51 | std::unique_ptr> head_; 52 | 53 | public: 54 | template auto push(const Arg& arg) -> const T& { 55 | auto new_node = std::unique_ptr>(new typed_node(arg)); 56 | auto& value = new_node->value; 57 | new_node->next = std::move(head_); 58 | head_ = std::move(new_node); 59 | return value; 60 | } 61 | }; 62 | } // namespace detail 63 | 64 | /** 65 | \rst 66 | A dynamic version of `fmt::format_arg_store`. 67 | It's equipped with a storage to potentially temporary objects which lifetimes 68 | could be shorter than the format arguments object. 69 | 70 | It can be implicitly converted into `~fmt::basic_format_args` for passing 71 | into type-erased formatting functions such as `~fmt::vformat`. 72 | \endrst 73 | */ 74 | template 75 | class dynamic_format_arg_store 76 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 77 | // Workaround a GCC template argument substitution bug. 78 | : public basic_format_args 79 | #endif 80 | { 81 | private: 82 | using char_type = typename Context::char_type; 83 | 84 | template struct need_copy { 85 | static constexpr detail::type mapped_type = 86 | detail::mapped_type_constant::value; 87 | 88 | enum { 89 | value = !(detail::is_reference_wrapper::value || 90 | std::is_same>::value || 91 | std::is_same>::value || 92 | (mapped_type != detail::type::cstring_type && 93 | mapped_type != detail::type::string_type && 94 | mapped_type != detail::type::custom_type)) 95 | }; 96 | }; 97 | 98 | template 99 | using stored_type = conditional_t< 100 | std::is_convertible>::value && 101 | !detail::is_reference_wrapper::value, 102 | std::basic_string, T>; 103 | 104 | // Storage of basic_format_arg must be contiguous. 105 | std::vector> data_; 106 | std::vector> named_info_; 107 | 108 | // Storage of arguments not fitting into basic_format_arg must grow 109 | // without relocation because items in data_ refer to it. 110 | detail::dynamic_arg_list dynamic_args_; 111 | 112 | friend class basic_format_args; 113 | 114 | auto get_types() const -> unsigned long long { 115 | return detail::is_unpacked_bit | data_.size() | 116 | (named_info_.empty() 117 | ? 0ULL 118 | : static_cast(detail::has_named_args_bit)); 119 | } 120 | 121 | auto data() const -> const basic_format_arg* { 122 | return named_info_.empty() ? data_.data() : data_.data() + 1; 123 | } 124 | 125 | template void emplace_arg(const T& arg) { 126 | data_.emplace_back(detail::make_arg(arg)); 127 | } 128 | 129 | template 130 | void emplace_arg(const detail::named_arg& arg) { 131 | if (named_info_.empty()) { 132 | constexpr const detail::named_arg_info* zero_ptr{nullptr}; 133 | data_.insert(data_.begin(), {zero_ptr, 0}); 134 | } 135 | data_.emplace_back(detail::make_arg(detail::unwrap(arg.value))); 136 | auto pop_one = [](std::vector>* data) { 137 | data->pop_back(); 138 | }; 139 | std::unique_ptr>, decltype(pop_one)> 140 | guard{&data_, pop_one}; 141 | named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); 142 | data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; 143 | guard.release(); 144 | } 145 | 146 | public: 147 | constexpr dynamic_format_arg_store() = default; 148 | 149 | /** 150 | \rst 151 | Adds an argument into the dynamic store for later passing to a formatting 152 | function. 153 | 154 | Note that custom types and string types (but not string views) are copied 155 | into the store dynamically allocating memory if necessary. 156 | 157 | **Example**:: 158 | 159 | fmt::dynamic_format_arg_store store; 160 | store.push_back(42); 161 | store.push_back("abc"); 162 | store.push_back(1.5f); 163 | std::string result = fmt::vformat("{} and {} and {}", store); 164 | \endrst 165 | */ 166 | template void push_back(const T& arg) { 167 | if (detail::const_check(need_copy::value)) 168 | emplace_arg(dynamic_args_.push>(arg)); 169 | else 170 | emplace_arg(detail::unwrap(arg)); 171 | } 172 | 173 | /** 174 | \rst 175 | Adds a reference to the argument into the dynamic store for later passing to 176 | a formatting function. 177 | 178 | **Example**:: 179 | 180 | fmt::dynamic_format_arg_store store; 181 | char band[] = "Rolling Stones"; 182 | store.push_back(std::cref(band)); 183 | band[9] = 'c'; // Changing str affects the output. 184 | std::string result = fmt::vformat("{}", store); 185 | // result == "Rolling Scones" 186 | \endrst 187 | */ 188 | template void push_back(std::reference_wrapper arg) { 189 | static_assert( 190 | need_copy::value, 191 | "objects of built-in types and string views are always copied"); 192 | emplace_arg(arg.get()); 193 | } 194 | 195 | /** 196 | Adds named argument into the dynamic store for later passing to a formatting 197 | function. ``std::reference_wrapper`` is supported to avoid copying of the 198 | argument. The name is always copied into the store. 199 | */ 200 | template 201 | void push_back(const detail::named_arg& arg) { 202 | const char_type* arg_name = 203 | dynamic_args_.push>(arg.name).c_str(); 204 | if (detail::const_check(need_copy::value)) { 205 | emplace_arg( 206 | fmt::arg(arg_name, dynamic_args_.push>(arg.value))); 207 | } else { 208 | emplace_arg(fmt::arg(arg_name, arg.value)); 209 | } 210 | } 211 | 212 | /** Erase all elements from the store */ 213 | void clear() { 214 | data_.clear(); 215 | named_info_.clear(); 216 | dynamic_args_ = detail::dynamic_arg_list(); 217 | } 218 | 219 | /** 220 | \rst 221 | Reserves space to store at least *new_cap* arguments including 222 | *new_cap_named* named arguments. 223 | \endrst 224 | */ 225 | void reserve(size_t new_cap, size_t new_cap_named) { 226 | FMT_ASSERT(new_cap >= new_cap_named, 227 | "Set of arguments includes set of named arguments"); 228 | data_.reserve(new_cap); 229 | named_info_.reserve(new_cap_named); 230 | } 231 | }; 232 | 233 | FMT_END_NAMESPACE 234 | 235 | #endif // FMT_ARGS_H_ 236 | -------------------------------------------------------------------------------- /dcode/include/fmt/os.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - optional OS-specific functionality 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_OS_H_ 9 | #define FMT_OS_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include // std::system_error 15 | 16 | #include "format.h" 17 | 18 | #if defined __APPLE__ || defined(__FreeBSD__) 19 | # if FMT_HAS_INCLUDE() 20 | # include // for LC_NUMERIC_MASK on OS X 21 | # endif 22 | #endif 23 | 24 | #ifndef FMT_USE_FCNTL 25 | // UWP doesn't provide _pipe. 26 | # if FMT_HAS_INCLUDE("winapifamily.h") 27 | # include 28 | # endif 29 | # if (FMT_HAS_INCLUDE() || defined(__APPLE__) || \ 30 | defined(__linux__)) && \ 31 | (!defined(WINAPI_FAMILY) || \ 32 | (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) 33 | # include // for O_RDONLY 34 | # define FMT_USE_FCNTL 1 35 | # else 36 | # define FMT_USE_FCNTL 0 37 | # endif 38 | #endif 39 | 40 | #ifndef FMT_POSIX 41 | # if defined(_WIN32) && !defined(__MINGW32__) 42 | // Fix warnings about deprecated symbols. 43 | # define FMT_POSIX(call) _##call 44 | # else 45 | # define FMT_POSIX(call) call 46 | # endif 47 | #endif 48 | 49 | // Calls to system functions are wrapped in FMT_SYSTEM for testability. 50 | #ifdef FMT_SYSTEM 51 | # define FMT_HAS_SYSTEM 52 | # define FMT_POSIX_CALL(call) FMT_SYSTEM(call) 53 | #else 54 | # define FMT_SYSTEM(call) ::call 55 | # ifdef _WIN32 56 | // Fix warnings about deprecated symbols. 57 | # define FMT_POSIX_CALL(call) ::_##call 58 | # else 59 | # define FMT_POSIX_CALL(call) ::call 60 | # endif 61 | #endif 62 | 63 | // Retries the expression while it evaluates to error_result and errno 64 | // equals to EINTR. 65 | #ifndef _WIN32 66 | # define FMT_RETRY_VAL(result, expression, error_result) \ 67 | do { \ 68 | (result) = (expression); \ 69 | } while ((result) == (error_result) && errno == EINTR) 70 | #else 71 | # define FMT_RETRY_VAL(result, expression, error_result) result = (expression) 72 | #endif 73 | 74 | #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) 75 | 76 | FMT_BEGIN_NAMESPACE 77 | FMT_BEGIN_EXPORT 78 | 79 | /** 80 | \rst 81 | A reference to a null-terminated string. It can be constructed from a C 82 | string or ``std::string``. 83 | 84 | You can use one of the following type aliases for common character types: 85 | 86 | +---------------+-----------------------------+ 87 | | Type | Definition | 88 | +===============+=============================+ 89 | | cstring_view | basic_cstring_view | 90 | +---------------+-----------------------------+ 91 | | wcstring_view | basic_cstring_view | 92 | +---------------+-----------------------------+ 93 | 94 | This class is most useful as a parameter type to allow passing 95 | different types of strings to a function, for example:: 96 | 97 | template 98 | std::string format(cstring_view format_str, const Args & ... args); 99 | 100 | format("{}", 42); 101 | format(std::string("{}"), 42); 102 | \endrst 103 | */ 104 | template class basic_cstring_view { 105 | private: 106 | const Char* data_; 107 | 108 | public: 109 | /** Constructs a string reference object from a C string. */ 110 | basic_cstring_view(const Char* s) : data_(s) {} 111 | 112 | /** 113 | \rst 114 | Constructs a string reference from an ``std::string`` object. 115 | \endrst 116 | */ 117 | basic_cstring_view(const std::basic_string& s) : data_(s.c_str()) {} 118 | 119 | /** Returns the pointer to a C string. */ 120 | auto c_str() const -> const Char* { return data_; } 121 | }; 122 | 123 | using cstring_view = basic_cstring_view; 124 | using wcstring_view = basic_cstring_view; 125 | 126 | #ifdef _WIN32 127 | FMT_API const std::error_category& system_category() noexcept; 128 | 129 | namespace detail { 130 | FMT_API void format_windows_error(buffer& out, int error_code, 131 | const char* message) noexcept; 132 | } 133 | 134 | FMT_API std::system_error vwindows_error(int error_code, string_view format_str, 135 | format_args args); 136 | 137 | /** 138 | \rst 139 | Constructs a :class:`std::system_error` object with the description 140 | of the form 141 | 142 | .. parsed-literal:: 143 | **: ** 144 | 145 | where ** is the formatted message and ** is the 146 | system message corresponding to the error code. 147 | *error_code* is a Windows error code as given by ``GetLastError``. 148 | If *error_code* is not a valid error code such as -1, the system message 149 | will look like "error -1". 150 | 151 | **Example**:: 152 | 153 | // This throws a system_error with the description 154 | // cannot open file 'madeup': The system cannot find the file specified. 155 | // or similar (system message may vary). 156 | const char *filename = "madeup"; 157 | LPOFSTRUCT of = LPOFSTRUCT(); 158 | HFILE file = OpenFile(filename, &of, OF_READ); 159 | if (file == HFILE_ERROR) { 160 | throw fmt::windows_error(GetLastError(), 161 | "cannot open file '{}'", filename); 162 | } 163 | \endrst 164 | */ 165 | template 166 | std::system_error windows_error(int error_code, string_view message, 167 | const Args&... args) { 168 | return vwindows_error(error_code, message, fmt::make_format_args(args...)); 169 | } 170 | 171 | // Reports a Windows error without throwing an exception. 172 | // Can be used to report errors from destructors. 173 | FMT_API void report_windows_error(int error_code, const char* message) noexcept; 174 | #else 175 | inline auto system_category() noexcept -> const std::error_category& { 176 | return std::system_category(); 177 | } 178 | #endif // _WIN32 179 | 180 | // std::system is not available on some platforms such as iOS (#2248). 181 | #ifdef __OSX__ 182 | template > 183 | void say(const S& format_str, Args&&... args) { 184 | std::system(format("say \"{}\"", format(format_str, args...)).c_str()); 185 | } 186 | #endif 187 | 188 | // A buffered file. 189 | class buffered_file { 190 | private: 191 | FILE* file_; 192 | 193 | friend class file; 194 | 195 | explicit buffered_file(FILE* f) : file_(f) {} 196 | 197 | public: 198 | buffered_file(const buffered_file&) = delete; 199 | void operator=(const buffered_file&) = delete; 200 | 201 | // Constructs a buffered_file object which doesn't represent any file. 202 | buffered_file() noexcept : file_(nullptr) {} 203 | 204 | // Destroys the object closing the file it represents if any. 205 | FMT_API ~buffered_file() noexcept; 206 | 207 | public: 208 | buffered_file(buffered_file&& other) noexcept : file_(other.file_) { 209 | other.file_ = nullptr; 210 | } 211 | 212 | auto operator=(buffered_file&& other) -> buffered_file& { 213 | close(); 214 | file_ = other.file_; 215 | other.file_ = nullptr; 216 | return *this; 217 | } 218 | 219 | // Opens a file. 220 | FMT_API buffered_file(cstring_view filename, cstring_view mode); 221 | 222 | // Closes the file. 223 | FMT_API void close(); 224 | 225 | // Returns the pointer to a FILE object representing this file. 226 | auto get() const noexcept -> FILE* { return file_; } 227 | 228 | FMT_API auto descriptor() const -> int; 229 | 230 | void vprint(string_view format_str, format_args args) { 231 | fmt::vprint(file_, format_str, args); 232 | } 233 | 234 | template 235 | inline void print(string_view format_str, const Args&... args) { 236 | vprint(format_str, fmt::make_format_args(args...)); 237 | } 238 | }; 239 | 240 | #if FMT_USE_FCNTL 241 | // A file. Closed file is represented by a file object with descriptor -1. 242 | // Methods that are not declared with noexcept may throw 243 | // fmt::system_error in case of failure. Note that some errors such as 244 | // closing the file multiple times will cause a crash on Windows rather 245 | // than an exception. You can get standard behavior by overriding the 246 | // invalid parameter handler with _set_invalid_parameter_handler. 247 | class FMT_API file { 248 | private: 249 | int fd_; // File descriptor. 250 | 251 | // Constructs a file object with a given descriptor. 252 | explicit file(int fd) : fd_(fd) {} 253 | 254 | public: 255 | // Possible values for the oflag argument to the constructor. 256 | enum { 257 | RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. 258 | WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. 259 | RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing. 260 | CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist. 261 | APPEND = FMT_POSIX(O_APPEND), // Open in append mode. 262 | TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file. 263 | }; 264 | 265 | // Constructs a file object which doesn't represent any file. 266 | file() noexcept : fd_(-1) {} 267 | 268 | // Opens a file and constructs a file object representing this file. 269 | file(cstring_view path, int oflag); 270 | 271 | public: 272 | file(const file&) = delete; 273 | void operator=(const file&) = delete; 274 | 275 | file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } 276 | 277 | // Move assignment is not noexcept because close may throw. 278 | auto operator=(file&& other) -> file& { 279 | close(); 280 | fd_ = other.fd_; 281 | other.fd_ = -1; 282 | return *this; 283 | } 284 | 285 | // Destroys the object closing the file it represents if any. 286 | ~file() noexcept; 287 | 288 | // Returns the file descriptor. 289 | auto descriptor() const noexcept -> int { return fd_; } 290 | 291 | // Closes the file. 292 | void close(); 293 | 294 | // Returns the file size. The size has signed type for consistency with 295 | // stat::st_size. 296 | auto size() const -> long long; 297 | 298 | // Attempts to read count bytes from the file into the specified buffer. 299 | auto read(void* buffer, size_t count) -> size_t; 300 | 301 | // Attempts to write count bytes from the specified buffer to the file. 302 | auto write(const void* buffer, size_t count) -> size_t; 303 | 304 | // Duplicates a file descriptor with the dup function and returns 305 | // the duplicate as a file object. 306 | static auto dup(int fd) -> file; 307 | 308 | // Makes fd be the copy of this file descriptor, closing fd first if 309 | // necessary. 310 | void dup2(int fd); 311 | 312 | // Makes fd be the copy of this file descriptor, closing fd first if 313 | // necessary. 314 | void dup2(int fd, std::error_code& ec) noexcept; 315 | 316 | // Creates a pipe setting up read_end and write_end file objects for reading 317 | // and writing respectively. 318 | // DEPRECATED! Taking files as out parameters is deprecated. 319 | static void pipe(file& read_end, file& write_end); 320 | 321 | // Creates a buffered_file object associated with this file and detaches 322 | // this file object from the file. 323 | auto fdopen(const char* mode) -> buffered_file; 324 | 325 | # if defined(_WIN32) && !defined(__MINGW32__) 326 | // Opens a file and constructs a file object representing this file by 327 | // wcstring_view filename. Windows only. 328 | static file open_windows_file(wcstring_view path, int oflag); 329 | # endif 330 | }; 331 | 332 | // Returns the memory page size. 333 | auto getpagesize() -> long; 334 | 335 | namespace detail { 336 | 337 | struct buffer_size { 338 | buffer_size() = default; 339 | size_t value = 0; 340 | auto operator=(size_t val) const -> buffer_size { 341 | auto bs = buffer_size(); 342 | bs.value = val; 343 | return bs; 344 | } 345 | }; 346 | 347 | struct ostream_params { 348 | int oflag = file::WRONLY | file::CREATE | file::TRUNC; 349 | size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; 350 | 351 | ostream_params() {} 352 | 353 | template 354 | ostream_params(T... params, int new_oflag) : ostream_params(params...) { 355 | oflag = new_oflag; 356 | } 357 | 358 | template 359 | ostream_params(T... params, detail::buffer_size bs) 360 | : ostream_params(params...) { 361 | this->buffer_size = bs.value; 362 | } 363 | 364 | // Intel has a bug that results in failure to deduce a constructor 365 | // for empty parameter packs. 366 | # if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 367 | ostream_params(int new_oflag) : oflag(new_oflag) {} 368 | ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} 369 | # endif 370 | }; 371 | 372 | class file_buffer final : public buffer { 373 | file file_; 374 | 375 | FMT_API void grow(size_t) override; 376 | 377 | public: 378 | FMT_API file_buffer(cstring_view path, const ostream_params& params); 379 | FMT_API file_buffer(file_buffer&& other); 380 | FMT_API ~file_buffer(); 381 | 382 | void flush() { 383 | if (size() == 0) return; 384 | file_.write(data(), size() * sizeof(data()[0])); 385 | clear(); 386 | } 387 | 388 | void close() { 389 | flush(); 390 | file_.close(); 391 | } 392 | }; 393 | 394 | } // namespace detail 395 | 396 | // Added {} below to work around default constructor error known to 397 | // occur in Xcode versions 7.2.1 and 8.2.1. 398 | constexpr detail::buffer_size buffer_size{}; 399 | 400 | /** A fast output stream which is not thread-safe. */ 401 | class FMT_API ostream { 402 | private: 403 | FMT_MSC_WARNING(suppress : 4251) 404 | detail::file_buffer buffer_; 405 | 406 | ostream(cstring_view path, const detail::ostream_params& params) 407 | : buffer_(path, params) {} 408 | 409 | public: 410 | ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {} 411 | 412 | ~ostream(); 413 | 414 | void flush() { buffer_.flush(); } 415 | 416 | template 417 | friend auto output_file(cstring_view path, T... params) -> ostream; 418 | 419 | void close() { buffer_.close(); } 420 | 421 | /** 422 | Formats ``args`` according to specifications in ``fmt`` and writes the 423 | output to the file. 424 | */ 425 | template void print(format_string fmt, T&&... args) { 426 | vformat_to(std::back_inserter(buffer_), fmt, 427 | fmt::make_format_args(args...)); 428 | } 429 | }; 430 | 431 | /** 432 | \rst 433 | Opens a file for writing. Supported parameters passed in *params*: 434 | 435 | * ````: Flags passed to `open 436 | `_ 437 | (``file::WRONLY | file::CREATE | file::TRUNC`` by default) 438 | * ``buffer_size=``: Output buffer size 439 | 440 | **Example**:: 441 | 442 | auto out = fmt::output_file("guide.txt"); 443 | out.print("Don't {}", "Panic"); 444 | \endrst 445 | */ 446 | template 447 | inline auto output_file(cstring_view path, T... params) -> ostream { 448 | return {path, detail::ostream_params(params...)}; 449 | } 450 | #endif // FMT_USE_FCNTL 451 | 452 | FMT_END_EXPORT 453 | FMT_END_NAMESPACE 454 | 455 | #endif // FMT_OS_H_ 456 | -------------------------------------------------------------------------------- /dcode/include/fmt/ostream.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - std::ostream support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_OSTREAM_H_ 9 | #define FMT_OSTREAM_H_ 10 | 11 | #include // std::filebuf 12 | 13 | #ifdef _WIN32 14 | # ifdef __GLIBCXX__ 15 | # include 16 | # include 17 | # endif 18 | # include 19 | #endif 20 | 21 | #include "format.h" 22 | 23 | FMT_BEGIN_NAMESPACE 24 | namespace detail { 25 | 26 | template class formatbuf : public Streambuf { 27 | private: 28 | using char_type = typename Streambuf::char_type; 29 | using streamsize = decltype(std::declval().sputn(nullptr, 0)); 30 | using int_type = typename Streambuf::int_type; 31 | using traits_type = typename Streambuf::traits_type; 32 | 33 | buffer& buffer_; 34 | 35 | public: 36 | explicit formatbuf(buffer& buf) : buffer_(buf) {} 37 | 38 | protected: 39 | // The put area is always empty. This makes the implementation simpler and has 40 | // the advantage that the streambuf and the buffer are always in sync and 41 | // sputc never writes into uninitialized memory. A disadvantage is that each 42 | // call to sputc always results in a (virtual) call to overflow. There is no 43 | // disadvantage here for sputn since this always results in a call to xsputn. 44 | 45 | auto overflow(int_type ch) -> int_type override { 46 | if (!traits_type::eq_int_type(ch, traits_type::eof())) 47 | buffer_.push_back(static_cast(ch)); 48 | return ch; 49 | } 50 | 51 | auto xsputn(const char_type* s, streamsize count) -> streamsize override { 52 | buffer_.append(s, s + count); 53 | return count; 54 | } 55 | }; 56 | 57 | // Generate a unique explicit instantion in every translation unit using a tag 58 | // type in an anonymous namespace. 59 | namespace { 60 | struct file_access_tag {}; 61 | } // namespace 62 | template 63 | class file_access { 64 | friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } 65 | }; 66 | 67 | #if FMT_MSC_VERSION 68 | template class file_access; 70 | auto get_file(std::filebuf&) -> FILE*; 71 | #endif 72 | 73 | inline auto write_ostream_unicode(std::ostream& os, fmt::string_view data) 74 | -> bool { 75 | FILE* f = nullptr; 76 | #if FMT_MSC_VERSION 77 | if (auto* buf = dynamic_cast(os.rdbuf())) 78 | f = get_file(*buf); 79 | else 80 | return false; 81 | #elif defined(_WIN32) && defined(__GLIBCXX__) 82 | auto* rdbuf = os.rdbuf(); 83 | if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf*>(rdbuf)) 84 | f = sfbuf->file(); 85 | else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf*>(rdbuf)) 86 | f = fbuf->file(); 87 | else 88 | return false; 89 | #else 90 | ignore_unused(os, data, f); 91 | #endif 92 | #ifdef _WIN32 93 | if (f) { 94 | int fd = _fileno(f); 95 | if (_isatty(fd)) { 96 | os.flush(); 97 | return write_console(fd, data); 98 | } 99 | } 100 | #endif 101 | return false; 102 | } 103 | inline auto write_ostream_unicode(std::wostream&, 104 | fmt::basic_string_view) -> bool { 105 | return false; 106 | } 107 | 108 | // Write the content of buf to os. 109 | // It is a separate function rather than a part of vprint to simplify testing. 110 | template 111 | void write_buffer(std::basic_ostream& os, buffer& buf) { 112 | const Char* buf_data = buf.data(); 113 | using unsigned_streamsize = std::make_unsigned::type; 114 | unsigned_streamsize size = buf.size(); 115 | unsigned_streamsize max_size = to_unsigned(max_value()); 116 | do { 117 | unsigned_streamsize n = size <= max_size ? size : max_size; 118 | os.write(buf_data, static_cast(n)); 119 | buf_data += n; 120 | size -= n; 121 | } while (size != 0); 122 | } 123 | 124 | template 125 | void format_value(buffer& buf, const T& value) { 126 | auto&& format_buf = formatbuf>(buf); 127 | auto&& output = std::basic_ostream(&format_buf); 128 | #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) 129 | output.imbue(std::locale::classic()); // The default is always unlocalized. 130 | #endif 131 | output << value; 132 | output.exceptions(std::ios_base::failbit | std::ios_base::badbit); 133 | } 134 | 135 | template struct streamed_view { 136 | const T& value; 137 | }; 138 | 139 | } // namespace detail 140 | 141 | // Formats an object of type T that has an overloaded ostream operator<<. 142 | template 143 | struct basic_ostream_formatter : formatter, Char> { 144 | void set_debug_format() = delete; 145 | 146 | template 147 | auto format(const T& value, basic_format_context& ctx) const 148 | -> OutputIt { 149 | auto buffer = basic_memory_buffer(); 150 | detail::format_value(buffer, value); 151 | return formatter, Char>::format( 152 | {buffer.data(), buffer.size()}, ctx); 153 | } 154 | }; 155 | 156 | using ostream_formatter = basic_ostream_formatter; 157 | 158 | template 159 | struct formatter, Char> 160 | : basic_ostream_formatter { 161 | template 162 | auto format(detail::streamed_view view, 163 | basic_format_context& ctx) const -> OutputIt { 164 | return basic_ostream_formatter::format(view.value, ctx); 165 | } 166 | }; 167 | 168 | /** 169 | \rst 170 | Returns a view that formats `value` via an ostream ``operator<<``. 171 | 172 | **Example**:: 173 | 174 | fmt::print("Current thread id: {}\n", 175 | fmt::streamed(std::this_thread::get_id())); 176 | \endrst 177 | */ 178 | template 179 | constexpr auto streamed(const T& value) -> detail::streamed_view { 180 | return {value}; 181 | } 182 | 183 | namespace detail { 184 | 185 | inline void vprint_directly(std::ostream& os, string_view format_str, 186 | format_args args) { 187 | auto buffer = memory_buffer(); 188 | detail::vformat_to(buffer, format_str, args); 189 | detail::write_buffer(os, buffer); 190 | } 191 | 192 | } // namespace detail 193 | 194 | FMT_EXPORT template 195 | void vprint(std::basic_ostream& os, 196 | basic_string_view> format_str, 197 | basic_format_args>> args) { 198 | auto buffer = basic_memory_buffer(); 199 | detail::vformat_to(buffer, format_str, args); 200 | if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return; 201 | detail::write_buffer(os, buffer); 202 | } 203 | 204 | /** 205 | \rst 206 | Prints formatted data to the stream *os*. 207 | 208 | **Example**:: 209 | 210 | fmt::print(cerr, "Don't {}!", "panic"); 211 | \endrst 212 | */ 213 | FMT_EXPORT template 214 | void print(std::ostream& os, format_string fmt, T&&... args) { 215 | const auto& vargs = fmt::make_format_args(args...); 216 | if (detail::is_utf8()) 217 | vprint(os, fmt, vargs); 218 | else 219 | detail::vprint_directly(os, fmt, vargs); 220 | } 221 | 222 | FMT_EXPORT 223 | template 224 | void print(std::wostream& os, 225 | basic_format_string...> fmt, 226 | Args&&... args) { 227 | vprint(os, fmt, fmt::make_format_args>(args...)); 228 | } 229 | 230 | FMT_EXPORT template 231 | void println(std::ostream& os, format_string fmt, T&&... args) { 232 | fmt::print(os, "{}\n", fmt::format(fmt, std::forward(args)...)); 233 | } 234 | 235 | FMT_EXPORT 236 | template 237 | void println(std::wostream& os, 238 | basic_format_string...> fmt, 239 | Args&&... args) { 240 | print(os, L"{}\n", fmt::format(fmt, std::forward(args)...)); 241 | } 242 | 243 | FMT_END_NAMESPACE 244 | 245 | #endif // FMT_OSTREAM_H_ 246 | -------------------------------------------------------------------------------- /dcode/include/fmt/std.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - formatters for standard library types 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_STD_H_ 9 | #define FMT_STD_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "format.h" 23 | #include "ostream.h" 24 | 25 | #if FMT_HAS_INCLUDE() 26 | # include 27 | #endif 28 | // Checking FMT_CPLUSPLUS for warning suppression in MSVC. 29 | #if FMT_CPLUSPLUS >= 201703L 30 | # if FMT_HAS_INCLUDE() 31 | # include 32 | # endif 33 | # if FMT_HAS_INCLUDE() 34 | # include 35 | # endif 36 | # if FMT_HAS_INCLUDE() 37 | # include 38 | # endif 39 | #endif 40 | 41 | #if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE() 42 | # include 43 | #endif 44 | 45 | // GCC 4 does not support FMT_HAS_INCLUDE. 46 | #if FMT_HAS_INCLUDE() || defined(__GLIBCXX__) 47 | # include 48 | // Android NDK with gabi++ library on some architectures does not implement 49 | // abi::__cxa_demangle(). 50 | # ifndef __GABIXX_CXXABI_H__ 51 | # define FMT_HAS_ABI_CXA_DEMANGLE 52 | # endif 53 | #endif 54 | 55 | // Check if typeid is available. 56 | #ifndef FMT_USE_TYPEID 57 | // __RTTI is for EDG compilers. In MSVC typeid is available without RTTI. 58 | # if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \ 59 | defined(__INTEL_RTTI__) || defined(__RTTI) 60 | # define FMT_USE_TYPEID 1 61 | # else 62 | # define FMT_USE_TYPEID 0 63 | # endif 64 | #endif 65 | 66 | // For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined. 67 | #ifndef FMT_CPP_LIB_FILESYSTEM 68 | # ifdef __cpp_lib_filesystem 69 | # define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem 70 | # else 71 | # define FMT_CPP_LIB_FILESYSTEM 0 72 | # endif 73 | #endif 74 | 75 | #ifndef FMT_CPP_LIB_VARIANT 76 | # ifdef __cpp_lib_variant 77 | # define FMT_CPP_LIB_VARIANT __cpp_lib_variant 78 | # else 79 | # define FMT_CPP_LIB_VARIANT 0 80 | # endif 81 | #endif 82 | 83 | #if FMT_CPP_LIB_FILESYSTEM 84 | FMT_BEGIN_NAMESPACE 85 | 86 | namespace detail { 87 | 88 | template 89 | auto get_path_string(const std::filesystem::path& p, 90 | const std::basic_string& native) { 91 | if constexpr (std::is_same_v && std::is_same_v) 92 | return to_utf8(native, to_utf8_error_policy::replace); 93 | else 94 | return p.string(); 95 | } 96 | 97 | template 98 | void write_escaped_path(basic_memory_buffer& quoted, 99 | const std::filesystem::path& p, 100 | const std::basic_string& native) { 101 | if constexpr (std::is_same_v && 102 | std::is_same_v) { 103 | auto buf = basic_memory_buffer(); 104 | write_escaped_string(std::back_inserter(buf), native); 105 | bool valid = to_utf8::convert(quoted, {buf.data(), buf.size()}); 106 | FMT_ASSERT(valid, "invalid utf16"); 107 | } else if constexpr (std::is_same_v) { 108 | write_escaped_string( 109 | std::back_inserter(quoted), native); 110 | } else { 111 | write_escaped_string(std::back_inserter(quoted), p.string()); 112 | } 113 | } 114 | 115 | } // namespace detail 116 | 117 | FMT_EXPORT 118 | template struct formatter { 119 | private: 120 | format_specs specs_; 121 | detail::arg_ref width_ref_; 122 | bool debug_ = false; 123 | char path_type_ = 0; 124 | 125 | public: 126 | FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } 127 | 128 | template FMT_CONSTEXPR auto parse(ParseContext& ctx) { 129 | auto it = ctx.begin(), end = ctx.end(); 130 | if (it == end) return it; 131 | 132 | it = detail::parse_align(it, end, specs_); 133 | if (it == end) return it; 134 | 135 | it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); 136 | if (it != end && *it == '?') { 137 | debug_ = true; 138 | ++it; 139 | } 140 | if (it != end && (*it == 'g')) path_type_ = *it++; 141 | return it; 142 | } 143 | 144 | template 145 | auto format(const std::filesystem::path& p, FormatContext& ctx) const { 146 | auto specs = specs_; 147 | # ifdef _WIN32 148 | auto path_string = !path_type_ ? p.native() : p.generic_wstring(); 149 | # else 150 | auto path_string = !path_type_ ? p.native() : p.generic_string(); 151 | # endif 152 | 153 | detail::handle_dynamic_spec(specs.width, width_ref_, 154 | ctx); 155 | if (!debug_) { 156 | auto s = detail::get_path_string(p, path_string); 157 | return detail::write(ctx.out(), basic_string_view(s), specs); 158 | } 159 | auto quoted = basic_memory_buffer(); 160 | detail::write_escaped_path(quoted, p, path_string); 161 | return detail::write(ctx.out(), 162 | basic_string_view(quoted.data(), quoted.size()), 163 | specs); 164 | } 165 | }; 166 | FMT_END_NAMESPACE 167 | #endif // FMT_CPP_LIB_FILESYSTEM 168 | 169 | FMT_BEGIN_NAMESPACE 170 | FMT_EXPORT 171 | template 172 | struct formatter, Char> : nested_formatter { 173 | private: 174 | // Functor because C++11 doesn't support generic lambdas. 175 | struct writer { 176 | const std::bitset& bs; 177 | 178 | template 179 | FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt { 180 | for (auto pos = N; pos > 0; --pos) { 181 | out = detail::write(out, bs[pos - 1] ? Char('1') : Char('0')); 182 | } 183 | 184 | return out; 185 | } 186 | }; 187 | 188 | public: 189 | template 190 | auto format(const std::bitset& bs, FormatContext& ctx) const 191 | -> decltype(ctx.out()) { 192 | return write_padded(ctx, writer{bs}); 193 | } 194 | }; 195 | 196 | FMT_EXPORT 197 | template 198 | struct formatter : basic_ostream_formatter {}; 199 | FMT_END_NAMESPACE 200 | 201 | #ifdef __cpp_lib_optional 202 | FMT_BEGIN_NAMESPACE 203 | FMT_EXPORT 204 | template 205 | struct formatter, Char, 206 | std::enable_if_t::value>> { 207 | private: 208 | formatter underlying_; 209 | static constexpr basic_string_view optional = 210 | detail::string_literal{}; 212 | static constexpr basic_string_view none = 213 | detail::string_literal{}; 214 | 215 | template 216 | FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set) 217 | -> decltype(u.set_debug_format(set)) { 218 | u.set_debug_format(set); 219 | } 220 | 221 | template 222 | FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} 223 | 224 | public: 225 | template FMT_CONSTEXPR auto parse(ParseContext& ctx) { 226 | maybe_set_debug_format(underlying_, true); 227 | return underlying_.parse(ctx); 228 | } 229 | 230 | template 231 | auto format(const std::optional& opt, FormatContext& ctx) const 232 | -> decltype(ctx.out()) { 233 | if (!opt) return detail::write(ctx.out(), none); 234 | 235 | auto out = ctx.out(); 236 | out = detail::write(out, optional); 237 | ctx.advance_to(out); 238 | out = underlying_.format(*opt, ctx); 239 | return detail::write(out, ')'); 240 | } 241 | }; 242 | FMT_END_NAMESPACE 243 | #endif // __cpp_lib_optional 244 | 245 | #ifdef __cpp_lib_source_location 246 | FMT_BEGIN_NAMESPACE 247 | FMT_EXPORT 248 | template <> struct formatter { 249 | template FMT_CONSTEXPR auto parse(ParseContext& ctx) { 250 | return ctx.begin(); 251 | } 252 | 253 | template 254 | auto format(const std::source_location& loc, FormatContext& ctx) const 255 | -> decltype(ctx.out()) { 256 | auto out = ctx.out(); 257 | out = detail::write(out, loc.file_name()); 258 | out = detail::write(out, ':'); 259 | out = detail::write(out, loc.line()); 260 | out = detail::write(out, ':'); 261 | out = detail::write(out, loc.column()); 262 | out = detail::write(out, ": "); 263 | out = detail::write(out, loc.function_name()); 264 | return out; 265 | } 266 | }; 267 | FMT_END_NAMESPACE 268 | #endif 269 | 270 | #if FMT_CPP_LIB_VARIANT 271 | FMT_BEGIN_NAMESPACE 272 | namespace detail { 273 | 274 | template 275 | using variant_index_sequence = 276 | std::make_index_sequence::value>; 277 | 278 | template struct is_variant_like_ : std::false_type {}; 279 | template 280 | struct is_variant_like_> : std::true_type {}; 281 | 282 | // formattable element check. 283 | template class is_variant_formattable_ { 284 | template 285 | static std::conjunction< 286 | is_formattable, C>...> 287 | check(std::index_sequence); 288 | 289 | public: 290 | static constexpr const bool value = 291 | decltype(check(variant_index_sequence{}))::value; 292 | }; 293 | 294 | template 295 | auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt { 296 | if constexpr (is_string::value) 297 | return write_escaped_string(out, detail::to_string_view(v)); 298 | else if constexpr (std::is_same_v) 299 | return write_escaped_char(out, v); 300 | else 301 | return write(out, v); 302 | } 303 | 304 | } // namespace detail 305 | 306 | template struct is_variant_like { 307 | static constexpr const bool value = detail::is_variant_like_::value; 308 | }; 309 | 310 | template struct is_variant_formattable { 311 | static constexpr const bool value = 312 | detail::is_variant_formattable_::value; 313 | }; 314 | 315 | FMT_EXPORT 316 | template struct formatter { 317 | template 318 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 319 | return ctx.begin(); 320 | } 321 | 322 | template 323 | auto format(const std::monostate&, FormatContext& ctx) const 324 | -> decltype(ctx.out()) { 325 | return detail::write(ctx.out(), "monostate"); 326 | } 327 | }; 328 | 329 | FMT_EXPORT 330 | template 331 | struct formatter< 332 | Variant, Char, 333 | std::enable_if_t, is_variant_formattable>>> { 335 | template 336 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 337 | return ctx.begin(); 338 | } 339 | 340 | template 341 | auto format(const Variant& value, FormatContext& ctx) const 342 | -> decltype(ctx.out()) { 343 | auto out = ctx.out(); 344 | 345 | out = detail::write(out, "variant("); 346 | FMT_TRY { 347 | std::visit( 348 | [&](const auto& v) { 349 | out = detail::write_variant_alternative(out, v); 350 | }, 351 | value); 352 | } 353 | FMT_CATCH(const std::bad_variant_access&) { 354 | detail::write(out, "valueless by exception"); 355 | } 356 | *out++ = ')'; 357 | return out; 358 | } 359 | }; 360 | FMT_END_NAMESPACE 361 | #endif // FMT_CPP_LIB_VARIANT 362 | 363 | FMT_BEGIN_NAMESPACE 364 | FMT_EXPORT 365 | template struct formatter { 366 | template 367 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 368 | return ctx.begin(); 369 | } 370 | 371 | template 372 | FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const 373 | -> decltype(ctx.out()) { 374 | auto out = ctx.out(); 375 | out = detail::write_bytes(out, ec.category().name(), format_specs()); 376 | out = detail::write(out, Char(':')); 377 | out = detail::write(out, ec.value()); 378 | return out; 379 | } 380 | }; 381 | 382 | FMT_EXPORT 383 | template 384 | struct formatter< 385 | T, Char, // DEPRECATED! Mixing code unit types. 386 | typename std::enable_if::value>::type> { 387 | private: 388 | bool with_typename_ = false; 389 | 390 | public: 391 | FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) 392 | -> decltype(ctx.begin()) { 393 | auto it = ctx.begin(); 394 | auto end = ctx.end(); 395 | if (it == end || *it == '}') return it; 396 | if (*it == 't') { 397 | ++it; 398 | with_typename_ = FMT_USE_TYPEID != 0; 399 | } 400 | return it; 401 | } 402 | 403 | template 404 | auto format(const std::exception& ex, 405 | basic_format_context& ctx) const -> OutputIt { 406 | format_specs spec; 407 | auto out = ctx.out(); 408 | if (!with_typename_) 409 | return detail::write_bytes(out, string_view(ex.what()), spec); 410 | 411 | #if FMT_USE_TYPEID 412 | const std::type_info& ti = typeid(ex); 413 | # ifdef FMT_HAS_ABI_CXA_DEMANGLE 414 | int status = 0; 415 | std::size_t size = 0; 416 | std::unique_ptr demangled_name_ptr( 417 | abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); 418 | 419 | string_view demangled_name_view; 420 | if (demangled_name_ptr) { 421 | demangled_name_view = demangled_name_ptr.get(); 422 | 423 | // Normalization of stdlib inline namespace names. 424 | // libc++ inline namespaces. 425 | // std::__1::* -> std::* 426 | // std::__1::__fs::* -> std::* 427 | // libstdc++ inline namespaces. 428 | // std::__cxx11::* -> std::* 429 | // std::filesystem::__cxx11::* -> std::filesystem::* 430 | if (demangled_name_view.starts_with("std::")) { 431 | char* begin = demangled_name_ptr.get(); 432 | char* to = begin + 5; // std:: 433 | for (char *from = to, *end = begin + demangled_name_view.size(); 434 | from < end;) { 435 | // This is safe, because demangled_name is NUL-terminated. 436 | if (from[0] == '_' && from[1] == '_') { 437 | char* next = from + 1; 438 | while (next < end && *next != ':') next++; 439 | if (next[0] == ':' && next[1] == ':') { 440 | from = next + 2; 441 | continue; 442 | } 443 | } 444 | *to++ = *from++; 445 | } 446 | demangled_name_view = {begin, detail::to_unsigned(to - begin)}; 447 | } 448 | } else { 449 | demangled_name_view = string_view(ti.name()); 450 | } 451 | out = detail::write_bytes(out, demangled_name_view, spec); 452 | # elif FMT_MSC_VERSION 453 | string_view demangled_name_view(ti.name()); 454 | if (demangled_name_view.starts_with("class ")) 455 | demangled_name_view.remove_prefix(6); 456 | else if (demangled_name_view.starts_with("struct ")) 457 | demangled_name_view.remove_prefix(7); 458 | out = detail::write_bytes(out, demangled_name_view, spec); 459 | # else 460 | out = detail::write_bytes(out, string_view(ti.name()), spec); 461 | # endif 462 | *out++ = ':'; 463 | *out++ = ' '; 464 | return detail::write_bytes(out, string_view(ex.what()), spec); 465 | #endif 466 | } 467 | }; 468 | 469 | namespace detail { 470 | 471 | template 472 | struct has_flip : std::false_type {}; 473 | 474 | template 475 | struct has_flip().flip())>> 476 | : std::true_type {}; 477 | 478 | template struct is_bit_reference_like { 479 | static constexpr const bool value = 480 | std::is_convertible::value && 481 | std::is_nothrow_assignable::value && has_flip::value; 482 | }; 483 | 484 | #ifdef _LIBCPP_VERSION 485 | 486 | // Workaround for libc++ incompatibility with C++ standard. 487 | // According to the Standard, `bitset::operator[] const` returns bool. 488 | template 489 | struct is_bit_reference_like> { 490 | static constexpr const bool value = true; 491 | }; 492 | 493 | #endif 494 | 495 | } // namespace detail 496 | 497 | // We can't use std::vector::reference and 498 | // std::bitset::reference because the compiler can't deduce Allocator and N 499 | // in partial specialization. 500 | FMT_EXPORT 501 | template 502 | struct formatter::value>> 504 | : formatter { 505 | template 506 | FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const 507 | -> decltype(ctx.out()) { 508 | return formatter::format(v, ctx); 509 | } 510 | }; 511 | 512 | FMT_EXPORT 513 | template 514 | struct formatter, Char, 515 | enable_if_t::value>> 516 | : formatter { 517 | template 518 | auto format(const std::atomic& v, FormatContext& ctx) const 519 | -> decltype(ctx.out()) { 520 | return formatter::format(v.load(), ctx); 521 | } 522 | }; 523 | 524 | #ifdef __cpp_lib_atomic_flag_test 525 | FMT_EXPORT 526 | template 527 | struct formatter : formatter { 528 | template 529 | auto format(const std::atomic_flag& v, FormatContext& ctx) const 530 | -> decltype(ctx.out()) { 531 | return formatter::format(v.test(), ctx); 532 | } 533 | }; 534 | #endif // __cpp_lib_atomic_flag_test 535 | 536 | FMT_END_NAMESPACE 537 | #endif // FMT_STD_H_ 538 | -------------------------------------------------------------------------------- /dcode/include/fmt/xchar.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - optional wchar_t and exotic character support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_XCHAR_H_ 9 | #define FMT_XCHAR_H_ 10 | 11 | #include 12 | 13 | #include "format.h" 14 | 15 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR 16 | # include 17 | #endif 18 | 19 | FMT_BEGIN_NAMESPACE 20 | namespace detail { 21 | 22 | template 23 | using is_exotic_char = bool_constant::value>; 24 | 25 | inline auto write_loc(std::back_insert_iterator> out, 26 | loc_value value, const format_specs& specs, 27 | locale_ref loc) -> bool { 28 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR 29 | auto& numpunct = 30 | std::use_facet>(loc.get()); 31 | auto separator = std::wstring(); 32 | auto grouping = numpunct.grouping(); 33 | if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep()); 34 | return value.visit(loc_writer{out, specs, separator, grouping, {}}); 35 | #endif 36 | return false; 37 | } 38 | } // namespace detail 39 | 40 | FMT_BEGIN_EXPORT 41 | 42 | using wstring_view = basic_string_view; 43 | using wformat_parse_context = basic_format_parse_context; 44 | using wformat_context = buffer_context; 45 | using wformat_args = basic_format_args; 46 | using wmemory_buffer = basic_memory_buffer; 47 | 48 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 49 | // Workaround broken conversion on older gcc. 50 | template using wformat_string = wstring_view; 51 | inline auto runtime(wstring_view s) -> wstring_view { return s; } 52 | #else 53 | template 54 | using wformat_string = basic_format_string...>; 55 | inline auto runtime(wstring_view s) -> runtime_format_string { 56 | return {{s}}; 57 | } 58 | #endif 59 | 60 | template <> struct is_char : std::true_type {}; 61 | template <> struct is_char : std::true_type {}; 62 | template <> struct is_char : std::true_type {}; 63 | template <> struct is_char : std::true_type {}; 64 | 65 | template 66 | constexpr auto make_wformat_args(const T&... args) 67 | -> format_arg_store { 68 | return {args...}; 69 | } 70 | 71 | inline namespace literals { 72 | #if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS 73 | constexpr auto operator""_a(const wchar_t* s, size_t) 74 | -> detail::udl_arg { 75 | return {s}; 76 | } 77 | #endif 78 | } // namespace literals 79 | 80 | template 81 | auto join(It begin, Sentinel end, wstring_view sep) 82 | -> join_view { 83 | return {begin, end, sep}; 84 | } 85 | 86 | template 87 | auto join(Range&& range, wstring_view sep) 88 | -> join_view, detail::sentinel_t, 89 | wchar_t> { 90 | return join(std::begin(range), std::end(range), sep); 91 | } 92 | 93 | template 94 | auto join(std::initializer_list list, wstring_view sep) 95 | -> join_view { 96 | return join(std::begin(list), std::end(list), sep); 97 | } 98 | 99 | template ::value)> 100 | auto vformat(basic_string_view format_str, 101 | basic_format_args>> args) 102 | -> std::basic_string { 103 | auto buf = basic_memory_buffer(); 104 | detail::vformat_to(buf, format_str, args); 105 | return to_string(buf); 106 | } 107 | 108 | template 109 | auto format(wformat_string fmt, T&&... args) -> std::wstring { 110 | return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); 111 | } 112 | 113 | // Pass char_t as a default template parameter instead of using 114 | // std::basic_string> to reduce the symbol size. 115 | template , 116 | FMT_ENABLE_IF(!std::is_same::value && 117 | !std::is_same::value)> 118 | auto format(const S& format_str, T&&... args) -> std::basic_string { 119 | return vformat(detail::to_string_view(format_str), 120 | fmt::make_format_args>(args...)); 121 | } 122 | 123 | template , 124 | FMT_ENABLE_IF(detail::is_locale::value&& 125 | detail::is_exotic_char::value)> 126 | inline auto vformat( 127 | const Locale& loc, const S& format_str, 128 | basic_format_args>> args) 129 | -> std::basic_string { 130 | return detail::vformat(loc, detail::to_string_view(format_str), args); 131 | } 132 | 133 | template , 134 | FMT_ENABLE_IF(detail::is_locale::value&& 135 | detail::is_exotic_char::value)> 136 | inline auto format(const Locale& loc, const S& format_str, T&&... args) 137 | -> std::basic_string { 138 | return detail::vformat(loc, detail::to_string_view(format_str), 139 | fmt::make_format_args>(args...)); 140 | } 141 | 142 | template , 143 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 144 | detail::is_exotic_char::value)> 145 | auto vformat_to(OutputIt out, const S& format_str, 146 | basic_format_args>> args) 147 | -> OutputIt { 148 | auto&& buf = detail::get_buffer(out); 149 | detail::vformat_to(buf, detail::to_string_view(format_str), args); 150 | return detail::get_iterator(buf, out); 151 | } 152 | 153 | template , 155 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 156 | detail::is_exotic_char::value)> 157 | inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { 158 | return vformat_to(out, detail::to_string_view(fmt), 159 | fmt::make_format_args>(args...)); 160 | } 161 | 162 | template , 164 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 165 | detail::is_locale::value&& 166 | detail::is_exotic_char::value)> 167 | inline auto vformat_to( 168 | OutputIt out, const Locale& loc, const S& format_str, 169 | basic_format_args>> args) -> OutputIt { 170 | auto&& buf = detail::get_buffer(out); 171 | vformat_to(buf, detail::to_string_view(format_str), args, 172 | detail::locale_ref(loc)); 173 | return detail::get_iterator(buf, out); 174 | } 175 | 176 | template , 178 | bool enable = detail::is_output_iterator::value && 179 | detail::is_locale::value && 180 | detail::is_exotic_char::value> 181 | inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, 182 | T&&... args) -> 183 | typename std::enable_if::type { 184 | return vformat_to(out, loc, detail::to_string_view(format_str), 185 | fmt::make_format_args>(args...)); 186 | } 187 | 188 | template ::value&& 190 | detail::is_exotic_char::value)> 191 | inline auto vformat_to_n( 192 | OutputIt out, size_t n, basic_string_view format_str, 193 | basic_format_args>> args) 194 | -> format_to_n_result { 195 | using traits = detail::fixed_buffer_traits; 196 | auto buf = detail::iterator_buffer(out, n); 197 | detail::vformat_to(buf, format_str, args); 198 | return {buf.out(), buf.count()}; 199 | } 200 | 201 | template , 203 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 204 | detail::is_exotic_char::value)> 205 | inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) 206 | -> format_to_n_result { 207 | return vformat_to_n(out, n, detail::to_string_view(fmt), 208 | fmt::make_format_args>(args...)); 209 | } 210 | 211 | template , 212 | FMT_ENABLE_IF(detail::is_exotic_char::value)> 213 | inline auto formatted_size(const S& fmt, T&&... args) -> size_t { 214 | auto buf = detail::counting_buffer(); 215 | detail::vformat_to(buf, detail::to_string_view(fmt), 216 | fmt::make_format_args>(args...)); 217 | return buf.count(); 218 | } 219 | 220 | inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { 221 | auto buf = wmemory_buffer(); 222 | detail::vformat_to(buf, fmt, args); 223 | buf.push_back(L'\0'); 224 | if (std::fputws(buf.data(), f) == -1) 225 | FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); 226 | } 227 | 228 | inline void vprint(wstring_view fmt, wformat_args args) { 229 | vprint(stdout, fmt, args); 230 | } 231 | 232 | template 233 | void print(std::FILE* f, wformat_string fmt, T&&... args) { 234 | return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); 235 | } 236 | 237 | template void print(wformat_string fmt, T&&... args) { 238 | return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); 239 | } 240 | 241 | template 242 | void println(std::FILE* f, wformat_string fmt, T&&... args) { 243 | return print(f, L"{}\n", fmt::format(fmt, std::forward(args)...)); 244 | } 245 | 246 | template void println(wformat_string fmt, T&&... args) { 247 | return print(L"{}\n", fmt::format(fmt, std::forward(args)...)); 248 | } 249 | 250 | /** 251 | Converts *value* to ``std::wstring`` using the default format for type *T*. 252 | */ 253 | template inline auto to_wstring(const T& value) -> std::wstring { 254 | return format(FMT_STRING(L"{}"), value); 255 | } 256 | FMT_END_EXPORT 257 | FMT_END_NAMESPACE 258 | 259 | #endif // FMT_XCHAR_H_ 260 | -------------------------------------------------------------------------------- /dcode/src/fmt.cc: -------------------------------------------------------------------------------- 1 | module; 2 | 3 | // Put all implementation-provided headers into the global module fragment 4 | // to prevent attachment to this module. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #if __has_include() 39 | # include 40 | #endif 41 | #if defined(_MSC_VER) || defined(__MINGW32__) 42 | # include 43 | #endif 44 | #if defined __APPLE__ || defined(__FreeBSD__) 45 | # include 46 | #endif 47 | #if __has_include() 48 | # include 49 | #endif 50 | #if (__has_include() || defined(__APPLE__) || \ 51 | defined(__linux__)) && \ 52 | (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) 53 | # include 54 | # include 55 | # include 56 | # ifndef _WIN32 57 | # include 58 | # else 59 | # include 60 | # endif 61 | #endif 62 | #ifdef _WIN32 63 | # if defined(__GLIBCXX__) 64 | # include 65 | # include 66 | # endif 67 | # define WIN32_LEAN_AND_MEAN 68 | # include 69 | #endif 70 | 71 | export module fmt; 72 | 73 | #define FMT_EXPORT export 74 | #define FMT_BEGIN_EXPORT export { 75 | #define FMT_END_EXPORT } 76 | 77 | // If you define FMT_ATTACH_TO_GLOBAL_MODULE 78 | // - all declarations are detached from module 'fmt' 79 | // - the module behaves like a traditional static library, too 80 | // - all library symbols are mangled traditionally 81 | // - you can mix TUs with either importing or #including the {fmt} API 82 | #ifdef FMT_ATTACH_TO_GLOBAL_MODULE 83 | extern "C++" { 84 | #endif 85 | 86 | #ifndef FMT_OS 87 | # define FMT_OS 1 88 | #endif 89 | 90 | // All library-provided declarations and definitions must be in the module 91 | // purview to be exported. 92 | #include "fmt/args.h" 93 | #include "fmt/chrono.h" 94 | #include "fmt/color.h" 95 | #include "fmt/compile.h" 96 | #include "fmt/format.h" 97 | #if FMT_OS 98 | # include "fmt/os.h" 99 | #endif 100 | #include "fmt/printf.h" 101 | #include "fmt/std.h" 102 | #include "fmt/xchar.h" 103 | 104 | #ifdef FMT_ATTACH_TO_GLOBAL_MODULE 105 | } 106 | #endif 107 | 108 | // gcc doesn't yet implement private module fragments 109 | #if !FMT_GCC_VERSION 110 | module :private; 111 | #endif 112 | 113 | #include "format.cc" 114 | #if FMT_OS 115 | # include "os.cc" 116 | #endif 117 | -------------------------------------------------------------------------------- /dcode/src/format.cc: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #include "fmt/format-inl.h" 9 | 10 | FMT_BEGIN_NAMESPACE 11 | namespace detail { 12 | 13 | template FMT_API auto dragonbox::to_decimal(float x) noexcept 14 | -> dragonbox::decimal_fp; 15 | template FMT_API auto dragonbox::to_decimal(double x) noexcept 16 | -> dragonbox::decimal_fp; 17 | 18 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR 19 | template FMT_API locale_ref::locale_ref(const std::locale& loc); 20 | template FMT_API auto locale_ref::get() const -> std::locale; 21 | #endif 22 | 23 | // Explicit instantiations for char. 24 | 25 | template FMT_API auto thousands_sep_impl(locale_ref) 26 | -> thousands_sep_result; 27 | template FMT_API auto decimal_point_impl(locale_ref) -> char; 28 | 29 | template FMT_API void buffer::append(const char*, const char*); 30 | 31 | template FMT_API void vformat_to(buffer&, string_view, 32 | typename vformat_args<>::type, locale_ref); 33 | 34 | // Explicit instantiations for wchar_t. 35 | 36 | template FMT_API auto thousands_sep_impl(locale_ref) 37 | -> thousands_sep_result; 38 | template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; 39 | 40 | template FMT_API void buffer::append(const wchar_t*, const wchar_t*); 41 | 42 | } // namespace detail 43 | FMT_END_NAMESPACE 44 | -------------------------------------------------------------------------------- /dcode/src/os.cc: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - optional OS-specific functionality 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | // Disable bogus MSVC warnings. 9 | #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER) 10 | # define _CRT_SECURE_NO_WARNINGS 11 | #endif 12 | 13 | #include "fmt/os.h" 14 | 15 | #include 16 | 17 | #if FMT_USE_FCNTL 18 | # include 19 | # include 20 | 21 | # ifdef _WRS_KERNEL // VxWorks7 kernel 22 | # include // getpagesize 23 | # endif 24 | 25 | # ifndef _WIN32 26 | # include 27 | # else 28 | # ifndef WIN32_LEAN_AND_MEAN 29 | # define WIN32_LEAN_AND_MEAN 30 | # endif 31 | # include 32 | 33 | # ifndef S_IRUSR 34 | # define S_IRUSR _S_IREAD 35 | # endif 36 | # ifndef S_IWUSR 37 | # define S_IWUSR _S_IWRITE 38 | # endif 39 | # ifndef S_IRGRP 40 | # define S_IRGRP 0 41 | # endif 42 | # ifndef S_IWGRP 43 | # define S_IWGRP 0 44 | # endif 45 | # ifndef S_IROTH 46 | # define S_IROTH 0 47 | # endif 48 | # ifndef S_IWOTH 49 | # define S_IWOTH 0 50 | # endif 51 | # endif // _WIN32 52 | #endif // FMT_USE_FCNTL 53 | 54 | #ifdef _WIN32 55 | # include 56 | #endif 57 | 58 | namespace { 59 | #ifdef _WIN32 60 | // Return type of read and write functions. 61 | using rwresult = int; 62 | 63 | // On Windows the count argument to read and write is unsigned, so convert 64 | // it from size_t preventing integer overflow. 65 | inline unsigned convert_rwcount(std::size_t count) { 66 | return count <= UINT_MAX ? static_cast(count) : UINT_MAX; 67 | } 68 | #elif FMT_USE_FCNTL 69 | // Return type of read and write functions. 70 | using rwresult = ssize_t; 71 | 72 | inline std::size_t convert_rwcount(std::size_t count) { return count; } 73 | #endif 74 | } // namespace 75 | 76 | FMT_BEGIN_NAMESPACE 77 | 78 | #ifdef _WIN32 79 | namespace detail { 80 | 81 | class system_message { 82 | system_message(const system_message&) = delete; 83 | void operator=(const system_message&) = delete; 84 | 85 | unsigned long result_; 86 | wchar_t* message_; 87 | 88 | static bool is_whitespace(wchar_t c) noexcept { 89 | return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0'; 90 | } 91 | 92 | public: 93 | explicit system_message(unsigned long error_code) 94 | : result_(0), message_(nullptr) { 95 | result_ = FormatMessageW( 96 | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 97 | FORMAT_MESSAGE_IGNORE_INSERTS, 98 | nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 99 | reinterpret_cast(&message_), 0, nullptr); 100 | if (result_ != 0) { 101 | while (result_ != 0 && is_whitespace(message_[result_ - 1])) { 102 | --result_; 103 | } 104 | } 105 | } 106 | ~system_message() { LocalFree(message_); } 107 | explicit operator bool() const noexcept { return result_ != 0; } 108 | operator basic_string_view() const noexcept { 109 | return basic_string_view(message_, result_); 110 | } 111 | }; 112 | 113 | class utf8_system_category final : public std::error_category { 114 | public: 115 | const char* name() const noexcept override { return "system"; } 116 | std::string message(int error_code) const override { 117 | auto&& msg = system_message(error_code); 118 | if (msg) { 119 | auto utf8_message = to_utf8(); 120 | if (utf8_message.convert(msg)) { 121 | return utf8_message.str(); 122 | } 123 | } 124 | return "unknown error"; 125 | } 126 | }; 127 | 128 | } // namespace detail 129 | 130 | FMT_API const std::error_category& system_category() noexcept { 131 | static const detail::utf8_system_category category; 132 | return category; 133 | } 134 | 135 | std::system_error vwindows_error(int err_code, string_view format_str, 136 | format_args args) { 137 | auto ec = std::error_code(err_code, system_category()); 138 | return std::system_error(ec, vformat(format_str, args)); 139 | } 140 | 141 | void detail::format_windows_error(detail::buffer& out, int error_code, 142 | const char* message) noexcept { 143 | FMT_TRY { 144 | auto&& msg = system_message(error_code); 145 | if (msg) { 146 | auto utf8_message = to_utf8(); 147 | if (utf8_message.convert(msg)) { 148 | fmt::format_to(appender(out), FMT_STRING("{}: {}"), message, 149 | string_view(utf8_message)); 150 | return; 151 | } 152 | } 153 | } 154 | FMT_CATCH(...) {} 155 | format_error_code(out, error_code, message); 156 | } 157 | 158 | void report_windows_error(int error_code, const char* message) noexcept { 159 | report_error(detail::format_windows_error, error_code, message); 160 | } 161 | #endif // _WIN32 162 | 163 | buffered_file::~buffered_file() noexcept { 164 | if (file_ && FMT_SYSTEM(fclose(file_)) != 0) 165 | report_system_error(errno, "cannot close file"); 166 | } 167 | 168 | buffered_file::buffered_file(cstring_view filename, cstring_view mode) { 169 | FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 170 | nullptr); 171 | if (!file_) 172 | FMT_THROW(system_error(errno, FMT_STRING("cannot open file {}"), 173 | filename.c_str())); 174 | } 175 | 176 | void buffered_file::close() { 177 | if (!file_) return; 178 | int result = FMT_SYSTEM(fclose(file_)); 179 | file_ = nullptr; 180 | if (result != 0) 181 | FMT_THROW(system_error(errno, FMT_STRING("cannot close file"))); 182 | } 183 | 184 | int buffered_file::descriptor() const { 185 | #if !defined(fileno) 186 | int fd = FMT_POSIX_CALL(fileno(file_)); 187 | #elif defined(FMT_HAS_SYSTEM) 188 | // fileno is a macro on OpenBSD so we cannot use FMT_POSIX_CALL. 189 | # define FMT_DISABLE_MACRO 190 | int fd = FMT_SYSTEM(fileno FMT_DISABLE_MACRO(file_)); 191 | #else 192 | int fd = fileno(file_); 193 | #endif 194 | if (fd == -1) 195 | FMT_THROW(system_error(errno, FMT_STRING("cannot get file descriptor"))); 196 | return fd; 197 | } 198 | 199 | #if FMT_USE_FCNTL 200 | # ifdef _WIN32 201 | using mode_t = int; 202 | # endif 203 | 204 | constexpr mode_t default_open_mode = 205 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 206 | 207 | file::file(cstring_view path, int oflag) { 208 | # if defined(_WIN32) && !defined(__MINGW32__) 209 | fd_ = -1; 210 | auto converted = detail::utf8_to_utf16(string_view(path.c_str())); 211 | *this = file::open_windows_file(converted.c_str(), oflag); 212 | # else 213 | FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, default_open_mode))); 214 | if (fd_ == -1) 215 | FMT_THROW( 216 | system_error(errno, FMT_STRING("cannot open file {}"), path.c_str())); 217 | # endif 218 | } 219 | 220 | file::~file() noexcept { 221 | // Don't retry close in case of EINTR! 222 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html 223 | if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) 224 | report_system_error(errno, "cannot close file"); 225 | } 226 | 227 | void file::close() { 228 | if (fd_ == -1) return; 229 | // Don't retry close in case of EINTR! 230 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html 231 | int result = FMT_POSIX_CALL(close(fd_)); 232 | fd_ = -1; 233 | if (result != 0) 234 | FMT_THROW(system_error(errno, FMT_STRING("cannot close file"))); 235 | } 236 | 237 | long long file::size() const { 238 | # ifdef _WIN32 239 | // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT 240 | // is less than 0x0500 as is the case with some default MinGW builds. 241 | // Both functions support large file sizes. 242 | DWORD size_upper = 0; 243 | HANDLE handle = reinterpret_cast(_get_osfhandle(fd_)); 244 | DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); 245 | if (size_lower == INVALID_FILE_SIZE) { 246 | DWORD error = GetLastError(); 247 | if (error != NO_ERROR) 248 | FMT_THROW(windows_error(GetLastError(), "cannot get file size")); 249 | } 250 | unsigned long long long_size = size_upper; 251 | return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; 252 | # else 253 | using Stat = struct stat; 254 | Stat file_stat = Stat(); 255 | if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) 256 | FMT_THROW(system_error(errno, FMT_STRING("cannot get file attributes"))); 257 | static_assert(sizeof(long long) >= sizeof(file_stat.st_size), 258 | "return type of file::size is not large enough"); 259 | return file_stat.st_size; 260 | # endif 261 | } 262 | 263 | std::size_t file::read(void* buffer, std::size_t count) { 264 | rwresult result = 0; 265 | FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); 266 | if (result < 0) 267 | FMT_THROW(system_error(errno, FMT_STRING("cannot read from file"))); 268 | return detail::to_unsigned(result); 269 | } 270 | 271 | std::size_t file::write(const void* buffer, std::size_t count) { 272 | rwresult result = 0; 273 | FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); 274 | if (result < 0) 275 | FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); 276 | return detail::to_unsigned(result); 277 | } 278 | 279 | file file::dup(int fd) { 280 | // Don't retry as dup doesn't return EINTR. 281 | // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html 282 | int new_fd = FMT_POSIX_CALL(dup(fd)); 283 | if (new_fd == -1) 284 | FMT_THROW(system_error( 285 | errno, FMT_STRING("cannot duplicate file descriptor {}"), fd)); 286 | return file(new_fd); 287 | } 288 | 289 | void file::dup2(int fd) { 290 | int result = 0; 291 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); 292 | if (result == -1) { 293 | FMT_THROW(system_error( 294 | errno, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_, 295 | fd)); 296 | } 297 | } 298 | 299 | void file::dup2(int fd, std::error_code& ec) noexcept { 300 | int result = 0; 301 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); 302 | if (result == -1) ec = std::error_code(errno, std::generic_category()); 303 | } 304 | 305 | buffered_file file::fdopen(const char* mode) { 306 | // Don't retry as fdopen doesn't return EINTR. 307 | # if defined(__MINGW32__) && defined(_POSIX_) 308 | FILE* f = ::fdopen(fd_, mode); 309 | # else 310 | FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode)); 311 | # endif 312 | if (!f) { 313 | FMT_THROW(system_error( 314 | errno, FMT_STRING("cannot associate stream with file descriptor"))); 315 | } 316 | buffered_file bf(f); 317 | fd_ = -1; 318 | return bf; 319 | } 320 | 321 | # if defined(_WIN32) && !defined(__MINGW32__) 322 | file file::open_windows_file(wcstring_view path, int oflag) { 323 | int fd = -1; 324 | auto err = _wsopen_s(&fd, path.c_str(), oflag, _SH_DENYNO, default_open_mode); 325 | if (fd == -1) { 326 | FMT_THROW(system_error(err, FMT_STRING("cannot open file {}"), 327 | detail::to_utf8(path.c_str()).c_str())); 328 | } 329 | return file(fd); 330 | } 331 | # endif 332 | 333 | pipe::pipe() { 334 | int fds[2] = {}; 335 | # ifdef _WIN32 336 | // Make the default pipe capacity same as on Linux 2.6.11+. 337 | enum { DEFAULT_CAPACITY = 65536 }; 338 | int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); 339 | # else 340 | // Don't retry as the pipe function doesn't return EINTR. 341 | // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html 342 | int result = FMT_POSIX_CALL(pipe(fds)); 343 | # endif 344 | if (result != 0) 345 | FMT_THROW(system_error(errno, FMT_STRING("cannot create pipe"))); 346 | // The following assignments don't throw. 347 | read_end = file(fds[0]); 348 | write_end = file(fds[1]); 349 | } 350 | 351 | # if !defined(__MSDOS__) 352 | long getpagesize() { 353 | # ifdef _WIN32 354 | SYSTEM_INFO si; 355 | GetSystemInfo(&si); 356 | return si.dwPageSize; 357 | # else 358 | # ifdef _WRS_KERNEL 359 | long size = FMT_POSIX_CALL(getpagesize()); 360 | # else 361 | long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); 362 | # endif 363 | 364 | if (size < 0) 365 | FMT_THROW(system_error(errno, FMT_STRING("cannot get memory page size"))); 366 | return size; 367 | # endif 368 | } 369 | # endif 370 | 371 | namespace detail { 372 | 373 | void file_buffer::grow(buffer& buf, size_t) { 374 | if (buf.size() == buf.capacity()) static_cast(buf).flush(); 375 | } 376 | 377 | file_buffer::file_buffer(cstring_view path, const ostream_params& params) 378 | : buffer(grow), file_(path, params.oflag) { 379 | set(new char[params.buffer_size], params.buffer_size); 380 | } 381 | 382 | file_buffer::file_buffer(file_buffer&& other) 383 | : buffer(grow, other.data(), other.size(), other.capacity()), 384 | file_(std::move(other.file_)) { 385 | other.clear(); 386 | other.set(nullptr, 0); 387 | } 388 | 389 | file_buffer::~file_buffer() { 390 | flush(); 391 | delete[] data(); 392 | } 393 | } // namespace detail 394 | 395 | ostream::~ostream() = default; 396 | #endif // FMT_USE_FCNTL 397 | FMT_END_NAMESPACE 398 | -------------------------------------------------------------------------------- /img/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yqylh/hw_2024_cpp/45866e42a6a3d7f17b9a3315eae1b04d630cd2ac/img/map.png -------------------------------------------------------------------------------- /img/replay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yqylh/hw_2024_cpp/45866e42a6a3d7f17b9a3315eae1b04d630cd2ac/img/replay.png -------------------------------------------------------------------------------- /tools/analysis.py: -------------------------------------------------------------------------------- 1 | import re 2 | from collections import defaultdict 3 | import matplotlib.pyplot as plt 4 | 5 | from cv2 import Mat 6 | 7 | def analyze_judger_output_v3(file_path): 8 | # 初始化统计字典 9 | duration_stats = { 10 | '0~6ms': 0, 11 | '7~12ms': 0, 12 | '13~16ms': 0, 13 | '异常情况': 0 14 | } 15 | # 分别存储13~16ms和异常情况的时间戳 16 | timestamps_13_to_16 = [] 17 | timestamps_abnormal = [] 18 | 19 | with open(file_path, 'r') as file: 20 | for line in file: 21 | match = re.search(r'step (\d+)\s+(\d+) ms,', line) 22 | if match: 23 | timestamp, duration = int(match.group(1)), int(match.group(2)) 24 | # 根据耗时分别统计 25 | if 0 <= duration <= 6: 26 | duration_stats['0~6ms'] += 1 27 | elif 7 <= duration <= 12: 28 | duration_stats['7~12ms'] += 1 29 | elif 13 <= duration <= 16: 30 | duration_stats['13~16ms'] += 1 31 | timestamps_13_to_16.append(timestamp) 32 | else: 33 | duration_stats['异常情况'] += 1 34 | timestamps_abnormal.append(timestamp) 35 | 36 | # 输出统计结果和相关时间戳 37 | print("耗时分布情况及特定情况时间戳:") 38 | for category, count in duration_stats.items(): 39 | print(f"{category}: {count} 次") 40 | if category == '13~16ms' and count > 0: 41 | print(" 对应时间戳:", ', '.join(map(str, timestamps_13_to_16))) 42 | elif category == '异常情况' and count > 0: 43 | print(" 对应时间戳:", ', '.join(map(str, timestamps_abnormal))) 44 | 45 | def analyze_time_distribution(file_path): 46 | time_distribution = defaultdict(int) 47 | total_time = 0 48 | total_count = 0 49 | max_time = 0 50 | 51 | with open(file_path, 'r') as file: 52 | for line in file: 53 | match = re.search(r'rId=\d+solveGridWithTime time=(\d+)', line) 54 | if match: 55 | time = int(match.group(1)) 56 | # 分组统计,每100为一个区间 57 | group = (time // 100) * 100 58 | time_distribution[group] += 1 59 | 60 | # 计算总时间和次数,用于计算平均值 61 | total_time += time 62 | total_count += 1 63 | 64 | # 更新最大值 65 | if time > max_time: 66 | max_time = time 67 | 68 | # 计算平均值 69 | average_time = total_time / total_count if total_count else 0 70 | 71 | # 输出分组统计结果 72 | print("Time的分布情况(按100的尺度):") 73 | for group in sorted(time_distribution): 74 | print(f"Time {group}-{group+99}: {time_distribution[group]}次") 75 | 76 | # 输出平均值和最大值 77 | print(f"\n平均值:{average_time:.2f}") 78 | print(f"最大值:{max_time}") 79 | 80 | def analyze_goods_distribution(file_path): 81 | 82 | with open(file_path, 'r') as file: 83 | for line in file: 84 | # target is like 123:tmpTotalGoods:456, what we need is 456 85 | matchTotal = re.search(r'tmpTotalGoods:(\d+)', line) 86 | if matchTotal: 87 | goods = int(matchTotal.group(1)) 88 | print("货物总量", goods) 89 | matchLeft = re.search(r'leftTotal:(\d+)', line) 90 | if matchLeft: 91 | left = int(matchLeft.group(1)) 92 | print("剩余货物", left) 93 | 94 | def analyse_robot_path(file_path,map = None): 95 | leng = [] 96 | plt.clf() 97 | with open(file_path, 'r') as file: 98 | for line in file: 99 | leng.append(int(line)) 100 | plt.hist(leng, bins=range(0, 100, 5), edgecolor='black') 101 | plt.xlabel('Path Length') 102 | plt.ylabel('Frequency') 103 | plt.title('Path Length Distribution') 104 | save_name = 'path_length_distribution.png' if map is None else f'path_length_distribution_{map}.png' 105 | plt.savefig('../log/'+save_name) 106 | 107 | def analyze_goods_detailed_distribution(file_path,map = None): 108 | goods_value = [] 109 | with open(file_path, 'r') as file: 110 | for line in file: 111 | x,y = line.strip().split() 112 | x = int(x) 113 | y = int(y) 114 | if x == -1: 115 | goods_value.append(y) 116 | plt.clf() 117 | plt.hist(goods_value, bins=range(0, 200,5), edgecolor='black') 118 | plt.xlabel('Goods Value') 119 | plt.ylabel('Frequency') 120 | plt.title('Goods Value Distribution') 121 | save_name = 'goods_value_distribution.png' if map is None else f'goods_value_distribution_{map}.png' 122 | plt.savefig('../log/'+save_name) 123 | 124 | analyze_goods_detailed_distribution("../log/counter.txt_gds.txt") 125 | 126 | -------------------------------------------------------------------------------- /tools/legacy/MapEditor.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import numpy as np 3 | import argparse 4 | 5 | result = np.zeros((200, 200)) 6 | 7 | help = "\ 8 | 定义: 0 : 障碍物 \n \ 9 | 1 : 陆地 (通行区域) \n \ 10 | 2 : 海洋 \n \ 11 | 3 : 泊位 \n \ 12 | 4 : 机器人出生点 \n \ 13 | 按e切换单选、框选\n \ 14 | 按s保存地图\n \ 15 | " 16 | 17 | BLOCK_COLOR = (156, 140, 128) 18 | TEXT_COLOR = (255, 255, 255) 19 | EARTH_COLOR = (201, 223, 153) 20 | OCEAN_COLOR = (206, 222, 254) 21 | ROBOT_COLOR = (0, 0, 255) 22 | SHIP_COLOR = (251, 241, 51) 23 | PORT_COLOR = (190, 193, 198) 24 | ITEM_COLOR = (249, 139, 228) 25 | 26 | color_map = [BLOCK_COLOR, EARTH_COLOR, OCEAN_COLOR, PORT_COLOR, ROBOT_COLOR, SHIP_COLOR] 27 | map_name = None 28 | 29 | 30 | now_type = 0 31 | 32 | class MapEditor: 33 | def __init__(self, master,map_height=200,map_width=200,cell_size=20): 34 | self.master = master 35 | self.map_height = map_height 36 | self.map_width = map_width 37 | self.cell_size = cell_size # 每个格子的大小(像素),增加格子大小以便于查看和操作 38 | self.canvas = tk.Canvas(master, width=map_width * self.cell_size, height=map_height * self.cell_size) 39 | self.canvas.grid(row=0, column=0) 40 | self.text_display = tk.Text(master, height=25, width=30) # Text widget for displaying keyboard input 41 | self.text_display.grid(row=0, column=1, padx=10, pady=10) 42 | # self.canvas.pack() 43 | self.draw_grid() 44 | self.choose_type = 0 # 0 for 单选,1 for 框选 45 | self.canvas.bind("", self.cell_choose_start) 46 | self.canvas.bind("", self.cell_choose_end) 47 | self.canvas.bind("", self.cell_choose) 48 | self.canvas.bind("", self.cell_remove) 49 | self.canvas.bind("", self.cell_remove) 50 | self.master.bind("", self.key_input) 51 | self.text_display.insert(tk.END, help) 52 | self.canvas.focus_set() 53 | 54 | self.now_type = 0 55 | self.now_color = color_map[self.now_type] 56 | 57 | def rgbtofill(self,rgb): 58 | return '#%02x%02x%02x' % rgb 59 | 60 | def key_input(self, event): 61 | # Update text_display with the key pressed 62 | # self.text_display.insert(tk.END, event.char) 63 | self.text_display.delete(1.0, tk.END) 64 | self.text_display.insert(tk.END, help) 65 | self.canvas.focus_set() # Refocus to canvas after key input 66 | if event.char == 's': 67 | save_map() 68 | if event.char == 'e': 69 | self.choose_type = 1 if self.choose_type == 0 else 0 70 | self.text_display.insert(tk.END, "Choose type: " + str(self.choose_type) + "\n") 71 | elif event.char == 'q': 72 | exit() 73 | elif event.char in ['0', '1', '2', '3', '4']: 74 | self.now_type = int(event.char) 75 | self.now_color = color_map[self.now_type] 76 | self.text_display.insert(tk.END, "Input type: " + str(self.now_type) + "\n") 77 | else: 78 | self.text_display.insert(tk.END, "Invalid input: " + event.char + "\n") 79 | 80 | def draw_grid(self): 81 | for i in range(self.map_width * self.cell_size): 82 | for j in range(self.map_height): 83 | self.canvas.create_rectangle(i*self.cell_size, j*self.cell_size, (i+1)*self.cell_size, (j+1)*self.cell_size, fill=self.rgbtofill(BLOCK_COLOR), outline="gray") 84 | 85 | def cell_choose(self, event): 86 | if self.choose_type == 0: 87 | grid_x, grid_y = event.x // self.cell_size, event.y // self.cell_size 88 | if self.now_type != 3: 89 | result[grid_y][grid_x] = self.now_type 90 | self.canvas.create_rectangle(grid_x*self.cell_size, grid_y*self.cell_size, (grid_x+1)*self.cell_size, (grid_y+1)*self.cell_size, fill=self.rgbtofill(self.now_color), outline="gray") 91 | else: 92 | for i in range(grid_x, grid_x+4): 93 | for j in range(grid_y, grid_y+4): 94 | if 0 <= i < self.map_width and 0 <= j < self.map_height: 95 | result[j][i] = self.now_type 96 | self.canvas.create_rectangle(i*self.cell_size, j*self.cell_size, (i+1)*self.cell_size, (j+1)*self.cell_size, fill=self.rgbtofill(self.now_color), outline="gray") 97 | 98 | def cell_remove(self, event): 99 | if self.choose_type == 0: 100 | grid_x, grid_y = event.x // self.cell_size, event.y // self.cell_size 101 | result[grid_y][grid_x] = 0 102 | self.canvas.create_rectangle(grid_x*self.cell_size, grid_y*self.cell_size, (grid_x+1)*self.cell_size, (grid_y+1)*self.cell_size, fill=self.rgbtofill(BLOCK_COLOR), outline="gray") 103 | 104 | def cell_choose_start(self, event): 105 | if self.choose_type == 1: 106 | self.start_x, self.start_y = event.x // self.cell_size, event.y // self.cell_size 107 | else: 108 | self.cell_choose(event) 109 | 110 | def cell_choose_end(self, event): 111 | if self.choose_type == 1: 112 | self.end_x, self.end_y = event.x // self.cell_size, event.y // self.cell_size 113 | for i in range(min(self.start_x, self.end_x), max(self.start_x, self.end_x)): 114 | for j in range(min(self.start_y, self.end_y), max(self.start_y, self.end_y)): 115 | result[j][i] = self.now_type 116 | self.canvas.create_rectangle(i*self.cell_size, j*self.cell_size, (i+1)*self.cell_size, (j+1)*self.cell_size, fill=self.rgbtofill(self.now_color), outline="gray") 117 | self.choose_type = 0 118 | 119 | def save_map(): 120 | print("Saving map as " + map_name) 121 | with open(map_name, 'w') as map_file: 122 | for line in result: 123 | for grid_content in line: 124 | if grid_content == 0: 125 | map_file.write('#') 126 | if grid_content == 1: 127 | map_file.write('.') 128 | if grid_content == 2: 129 | map_file.write('*') 130 | if grid_content == 3: 131 | map_file.write('B') 132 | if grid_content == 4: 133 | map_file.write('A') 134 | map_file.write('\n') 135 | print("Map saved as " + map_name) 136 | 137 | def main(): 138 | parser = argparse.ArgumentParser(description='Map Editor') 139 | parser.add_argument('--cell_size', '-c', nargs='?',type=int,default=5, help='Cell size') 140 | parser.add_argument('--map_name', '-m', nargs='?',type=str,default='my_map.txt', help='Cell size') 141 | args = parser.parse_args() 142 | global map_name 143 | map_name = args.map_name 144 | 145 | root = tk.Tk() 146 | root.title("Map Editor") 147 | # print("Input the map size (e.g. 200 200):") 148 | # map_size = input().split() 149 | print("Please click on the grid to edit the map") 150 | app = MapEditor(root,cell_size=args.cell_size) 151 | root.mainloop() 152 | 153 | if __name__ == "__main__": 154 | main() 155 | -------------------------------------------------------------------------------- /tools/legacy/Mapeditor.sh: -------------------------------------------------------------------------------- 1 | python MapEditor_pygame.py -l ../allMaps tt0.txt -------------------------------------------------------------------------------- /tools/legacy/vis.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import sys 4 | 5 | EARTH=-1 6 | OCEAN=-2 7 | BLOCK=-3 8 | ROBOT=10 9 | SHIP=20 10 | 11 | 12 | grid_interval = 0.5 13 | scale_factor = 100 14 | # gridSize = 100 15 | # stageSize = 0.4 16 | # robotSize = 0.45 17 | # robotItemSize = 0.53 18 | 19 | BLOCK_COLOR = (156, 140, 128) 20 | TEXT_COLOR = (255, 255, 255) 21 | EARTH_COLOR = (201, 223, 153) 22 | OCEAN_COLOR = (206, 222, 254) 23 | ROBOT_COLOR = (0, 0, 255) 24 | SHIP_COLOR = (251, 241, 51) 25 | PORT_COLOR = (190, 193, 198) 26 | ITEM_COLOR = (249, 139, 228) 27 | 28 | def read_map(map_filename, map_size=200): 29 | 30 | grid = [[0] * map_size for i in range(map_size)] 31 | robot_init_pos = [] 32 | ship_init_pos = [] 33 | 34 | with open(map_filename, 'r') as map_file: 35 | lines = map_file.readlines() 36 | for line_cnt, line_content in enumerate(lines): 37 | if line_cnt >= map_size: continue 38 | for row_cnt, grid_content in enumerate(line_content): 39 | if row_cnt >= map_size: continue 40 | if grid_content is '.': 41 | grid[line_cnt][row_cnt] = EARTH 42 | if grid_content is '*': 43 | grid[line_cnt][row_cnt] = OCEAN 44 | if grid_content is '#': 45 | grid[line_cnt][row_cnt] = BLOCK 46 | if grid_content is "A": 47 | grid[line_cnt][row_cnt] = EARTH 48 | robot_init_pos.append([line_cnt, row_cnt]) 49 | if grid_content is "B": 50 | grid[line_cnt][row_cnt] = OCEAN 51 | ship_init_pos.append([line_cnt, row_cnt]) 52 | 53 | return grid, robot_init_pos, ship_init_pos 54 | 55 | def plot_grid(map_grid, plot_target): 56 | for i, line in enumerate(map_grid): 57 | now_y = int(i * grid_interval * scale_factor) 58 | for j, tar in enumerate(line): 59 | now_x = int(j * grid_interval * scale_factor) 60 | if tar == EARTH: 61 | pt1 = (now_x, now_y) 62 | pt2 = (int(now_x + grid_interval * scale_factor), int(now_y + grid_interval * scale_factor)) 63 | cv2.rectangle(plot_target, pt1, pt2, EARTH_COLOR, thickness=-1) 64 | if tar == OCEAN: 65 | pt1 = (now_x, now_y) 66 | pt2 = (int(now_x + grid_interval * scale_factor), int(now_y + grid_interval * scale_factor)) 67 | cv2.rectangle(plot_target, pt1, pt2, OCEAN_COLOR, thickness=-1) 68 | if tar == BLOCK: 69 | pt1 = (now_x, now_y) 70 | pt2 = (int(now_x + grid_interval * scale_factor), int(now_y + grid_interval * scale_factor)) 71 | cv2.rectangle(plot_target, pt1, pt2, BLOCK_COLOR, thickness=-1) 72 | 73 | def plot_port(plot_target, port_pos, port_size): 74 | for pos in port_pos: 75 | pt1 = (int(pos[1] * grid_interval * scale_factor), int(pos[0] * grid_interval * scale_factor)) 76 | pt2 = (int((pos[1] + port_size) * grid_interval * scale_factor), int((pos[0] + port_size) * grid_interval * scale_factor)) 77 | cv2.rectangle(plot_target, pt1, pt2, PORT_COLOR, thickness=-1) 78 | 79 | 80 | # item is a circle and the item_time will be transfer to alpha with range (0, 1000) to (1.0, 0) 81 | def plot_item(plot_target, item_pos, item_time): 82 | for i in range(len(item_pos)): 83 | pos = item_pos[i] 84 | alpha = 1 - item_time[i] / 1000 85 | overlay = np.zeros_like(plot_target) 86 | center = (int((pos[1] + 0.5) * grid_interval * scale_factor), int((pos[0] + 0.5) * grid_interval * scale_factor)) 87 | cv2.circle(overlay, center, int(0.2 * scale_factor), ITEM_COLOR, -1) 88 | cv2.addWeighted(overlay, alpha, plot_target, alpha, 0, plot_target) 89 | 90 | def plot_drone(map_grid, ship_pos, ship_size, robot_pos, robot_size): 91 | for pos in ship_pos: 92 | pt1 = (int(pos[1] * grid_interval * scale_factor), int(pos[0] * grid_interval * scale_factor)) 93 | pt2 = (int((pos[1] + ship_size[1]) * grid_interval * scale_factor), int((pos[0] + ship_size[0]) * grid_interval * scale_factor)) 94 | cv2.rectangle(map_grid, pt1, pt2, SHIP_COLOR, thickness=-1) 95 | 96 | # robot is a circle 97 | for pos in robot_pos: 98 | center = (int((pos[1] + 0.5) * grid_interval * scale_factor), int((pos[0] + 0.5) * grid_interval * scale_factor)) 99 | cv2.circle(map_grid, center, int(0.2 * scale_factor), ROBOT_COLOR, -1) 100 | 101 | def draw_img(grid, port_size=(4, 4), ship_size=(2, 4), robot_size=1, port_pos=None, item_pos=None, item_time=None, ship_pos=None, robot_pos=None): 102 | img = np.zeros((int(grid_interval * scale_factor * len(grid)), int(grid_interval * scale_factor * len(grid[0])), 3), np.uint8) 103 | plot_grid(grid, img) 104 | if port_pos is not None: 105 | plot_port(img, port_pos, port_size) 106 | if item_pos is not None: 107 | plot_item(img, item_pos, item_time) 108 | if ship_pos is not None and robot_pos is not None: 109 | plot_drone(img, ship_pos, ship_size, robot_pos, robot_size) 110 | 111 | print("hi") 112 | to_show = cv2.resize(img, (1250, 1250)) 113 | cv2.imshow('map', to_show) 114 | 115 | 116 | def main(map_id): 117 | map_filename = "../allMaps/map" + str(map_id) + ".txt" 118 | map_grid, robot_pos, ship_pos = read_map(map_filename) 119 | 120 | draw_img(map_grid, ship_pos=ship_pos, robot_pos=robot_pos) 121 | cv2.waitKey(0) 122 | cv2.destroyAllWindows() 123 | 124 | if __name__ == "__main__": 125 | main(1) -------------------------------------------------------------------------------- /tools/llt.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yqylh/hw_2024_cpp/45866e42a6a3d7f17b9a3315eae1b04d630cd2ac/tools/llt.ttf -------------------------------------------------------------------------------- /tools/run.bat: -------------------------------------------------------------------------------- 1 | python run.py --debug False -s False --map map1.txt --random_seed 123 -------------------------------------------------------------------------------- /tools/run.py: -------------------------------------------------------------------------------- 1 | import os,sys,shutil 2 | import argparse 3 | import subprocess 4 | from analysis import analyze_judger_output_v3,analyze_time_distribution,analyze_goods_distribution,analyse_robot_path 5 | import time 6 | from time import sleep 7 | 8 | if sys.platform.startswith('linux'): 9 | print("System: Linux") 10 | system = 'linux' 11 | elif sys.platform.startswith('win'): 12 | print("System: Windows") 13 | system = 'win' 14 | elif sys.platform.startswith('darwin'): 15 | print("System: Mac") 16 | system = 'mac' 17 | 18 | def setup_args(): 19 | config = {} 20 | parser = argparse.ArgumentParser(description='Upload a file to the server') 21 | parser.add_argument('--stdout', '-s', nargs='?',type=str,default="1", help='File name to upload') 22 | parser.add_argument('--debug', '-d', nargs='?',type=str,default="1", help='Destination on the server') 23 | parser.add_argument('--map', '-m', nargs='?',type=str,default='map1.txt', help='Map to use') 24 | parser.add_argument('--random_seed', '-r', nargs='?',type=int,default=123, help='Random seed to use') 25 | parser.add_argument('--map_folder', '-f', nargs='?',type=str,default="allMaps", help='Random seed to use') 26 | args = parser.parse_args() 27 | config['debug'] = (args.debug == 'True' or args.debug == 'true' or args.debug == '1') 28 | config['map'] = args.map 29 | config['random_seed'] = args.random_seed 30 | config['stdout'] = (args.stdout == 'True' or args.stdout == 'true' or args.stdout == '1') 31 | config['map_folder'] = args.map_folder 32 | 33 | return argparse.Namespace(**config) 34 | 35 | def run_all(args): 36 | mapList = os.listdir(f'../{args.map_folder}') 37 | resList = [] 38 | for map in mapList: 39 | args.map = map 40 | res = Do_cmd(args) 41 | resList.append(res) 42 | # 对 mapList 和 resList 进行排序 43 | mapList, resList = (list(t) for t in zip(*sorted(zip(mapList, resList)))) 44 | for i in range(len(mapList)): 45 | print(mapList[i], resList[i]) 46 | 47 | def del_files_win(): 48 | if os.path.isfile('main.exe'): 49 | remove_file('main.exe') 50 | if os.path.exists('replay'): 51 | os.rmdir('replay') 52 | 53 | def del_files_linux(): 54 | if os.path.isfile('main'): 55 | os.remove('main') 56 | if os.path.exists('main.dSYM'): 57 | shutil.rmtree('main.dSYM') 58 | if os.path.exists('replay'): 59 | os.rmdir('replay') 60 | 61 | def del_files(): 62 | if system == 'win': 63 | del_files_win() 64 | else: 65 | del_files_linux() 66 | 67 | def wirte_counter_logger(str): 68 | with open('../log/counter.txt', 'a') as f: 69 | f.write(str) 70 | f.write('\n') 71 | 72 | 73 | def Do_cmd(args): 74 | wirte_counter_logger(args.map + ' ' + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) 75 | if system == 'win': 76 | res = win_cmd(args) 77 | else: 78 | res = linux_cmd(args) 79 | if args.debug: 80 | file_path = '../log/judger_output.txt' 81 | analyze_judger_output_v3(file_path) 82 | file_path = '../log/path_log.txt' 83 | analyze_time_distribution(file_path) 84 | file_path = '../log/berth_log.txt' 85 | analyze_goods_distribution(file_path) 86 | file_path = '../log/counter.txt_robot_move_length_vector.txt' 87 | analyse_robot_path(file_path,args.map) 88 | print('=====================nextMap=====================') 89 | 90 | return res 91 | 92 | def remove_file(file_path, attempts=10): 93 | for i in range(attempts): 94 | try: 95 | # check file or folder 96 | if os.path.isfile(file_path): 97 | os.remove(file_path) 98 | else: 99 | shutil.rmtree(file_path) 100 | break 101 | except Exception as e: 102 | if i == attempts - 1: 103 | print(e) 104 | else: 105 | sleep(0.5) 106 | 107 | def win_cmd(args): 108 | Win_Cmd = '%CD%/../judge/SemiFinalJudge.exe -s ' + str(args.random_seed) + f' -m ../{args.map_folder}/' + args.map +' -r ./{}%Y-%m-%d.%H.%M.%S.rep ./main'.format(args.map) 109 | print(Win_Cmd) 110 | 111 | # check if '../log' exists 112 | if not os.path.exists('../log'): 113 | os.makedirs('../log') 114 | 115 | 116 | if args.stdout: 117 | os.system(Win_Cmd) 118 | else: 119 | process = subprocess.Popen(Win_Cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 120 | stdout, stderr = process.communicate() 121 | 122 | if stdout: 123 | with open('../log/judger_output.txt', 'w') as f: 124 | f.write("stdout:") 125 | f.write(stdout.decode('utf-8')) 126 | print(stdout.decode('utf-8')) 127 | 128 | if stderr: 129 | with open('../log/judger_output.txt', 'a') as f: 130 | f.write("stderr:") 131 | f.write(stderr.decode('utf-8')) 132 | 133 | for files in os.listdir('./replay'): 134 | if files.endswith('.rep'): 135 | shutil.move('replay/' + files, '../judge/replay/' + files) 136 | 137 | if not args.stdout: 138 | return stdout.decode('utf-8') 139 | else: 140 | return 0 141 | # sleep(1) 142 | 143 | 144 | def linux_cmd(args): 145 | Linux_Cmd = '../judge/SemiFinalJudge -s ' + str(args.random_seed) + f' -m ../{args.map_folder}/' + args.map +' -r ./{}%Y-%m-%d.%H.%M.%S.rep ./main'.format(args.map) 146 | print(Linux_Cmd) 147 | 148 | # check if '../log' exists 149 | if not os.path.exists('../log'): 150 | os.makedirs('../log') 151 | 152 | if args.stdout: 153 | os.system(Linux_Cmd) 154 | else: 155 | process = subprocess.Popen(Linux_Cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 156 | stdout, stderr = process.communicate() 157 | 158 | if stdout: 159 | with open('../log/judger_output.txt', 'w') as f: 160 | f.write("stdout:") 161 | f.write(stdout.decode('utf-8')) 162 | print(stdout.decode('utf-8')) 163 | 164 | if stderr: 165 | with open('../log/judger_output.txt', 'a') as f: 166 | f.write("stderr:") 167 | f.write(stderr.decode('utf-8')) 168 | for files in os.listdir('./replay'): 169 | if files.endswith('.rep'): 170 | shutil.move('./replay/' + files, '../judge/replay/' + files) 171 | if not args.stdout: 172 | return stdout.decode('utf-8') 173 | else : 174 | return 0 175 | 176 | def compile_fmt(): 177 | fmt_lib_path = "../dcode/libfmt.a" 178 | if not os.path.exists(fmt_lib_path): 179 | # 如果静态库不存在,先编译fmt库 180 | print("Compiling fmt library...") 181 | fmt_compile_cmd = "g++ -c -o ../dcode/fmt.o ../dcode/src/format.cc -I../dcode/include" 182 | if os.system(fmt_compile_cmd) == 0: 183 | print("fmt library compile success") 184 | else: 185 | print("fmt library compile failed") 186 | raise Exception("fmt library compile failed") 187 | ar_cmd = "ar rcs " + fmt_lib_path + " ../dcode/fmt.o" 188 | os.system(ar_cmd) 189 | else: 190 | print("fmt library exists") 191 | 192 | def main(): 193 | args = setup_args() 194 | print(args) 195 | now_path = os.getcwd() 196 | if not now_path.endswith("tools"): 197 | os.chdir("tools") 198 | 199 | if not os.path.exists("../judge/replay"): 200 | os.makedirs("../judge/replay") 201 | print("Created replay folder") 202 | 203 | try: 204 | os.chdir("../code") 205 | if system == 'win' or system == 'linux': 206 | cmd = "g++ main.cpp -o main -std=c++17 -O2" 207 | else: 208 | cmd = "g++-13 main.cpp -o main -std=c++17 -O2" 209 | 210 | if args.debug: 211 | compile_fmt() 212 | cmd += " -g -DDEBUG -DEBUG" 213 | # cmd = cmd + " ../dcode/src/format.cc -I../dcode/include" 214 | cmd += " -L../dcode -lfmt -I../dcode/include" 215 | print(cmd) 216 | if os.system(cmd) == 0: 217 | print("Compile success") 218 | else: 219 | print("Compile failed") 220 | return 221 | except Exception as e: 222 | print("Compile failed") 223 | print(e) 224 | return 225 | 226 | try: 227 | if args.map == 'all': 228 | run_all(args) 229 | else: 230 | Do_cmd(args) 231 | except Exception as e: 232 | print("Run failed") 233 | print(e) 234 | return 235 | print("Run success") 236 | 237 | 238 | try: 239 | del_files() 240 | except Exception as e: 241 | print("Delete failed") 242 | print(e) 243 | return 244 | print("Delete success") 245 | 246 | if __name__ == "__main__": 247 | main() -------------------------------------------------------------------------------- /tools/run.sh: -------------------------------------------------------------------------------- 1 | python run.py --d 1 --map map2.txt --random_seed 10 --stdout 1 -------------------------------------------------------------------------------- /tools/runall.sh: -------------------------------------------------------------------------------- 1 | python run.py --map 'all' --random_seed 10 --stdout 0 --debug False -------------------------------------------------------------------------------- /tools/seed_selector.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from audioop import avg 3 | import os 4 | import sys 5 | import pickle 6 | import random 7 | import shutil 8 | import subprocess 9 | from time import sleep 10 | import matplotlib.pyplot as plt 11 | from tqdm import trange 12 | 13 | from multiprocessing import Pool 14 | from functools import partial 15 | 16 | if sys.platform.startswith('linux'): 17 | system = 'linux' 18 | elif sys.platform.startswith('win'): 19 | system = 'win' 20 | elif sys.platform.startswith('darwin'): 21 | system = 'mac' 22 | 23 | 24 | para_input = [ 25 | [150,16,3,0.7,1700,2000,700], 26 | [150,16,3,0.76,800,1700,1000], 27 | [160,80,3,0.7,800,1600,1000], 28 | [150,16,3,0.7,1700,2000,500], 29 | ] 30 | score_input = [ 31 | 255136, 32 | 240418, 33 | 250954, 34 | 241682, 35 | ] 36 | 37 | def del_files_win(): 38 | if os.path.isfile('main.exe'): 39 | remove_file('main.exe') 40 | if os.path.exists('replay'): 41 | os.rmdir('replay') 42 | 43 | def del_files_linux(): 44 | if os.path.isfile('main'): 45 | os.remove('main') 46 | if os.path.exists('main.dSYM'): 47 | shutil.rmtree('main.dSYM') 48 | if os.path.exists('replay'): 49 | os.rmdir('replay') 50 | 51 | def del_files(): 52 | if system == 'win': 53 | del_files_win() 54 | else: 55 | del_files_linux() 56 | 57 | def setup_args(): 58 | parser = argparse.ArgumentParser(description='Upload a file to the server') 59 | parser.add_argument('--map', '-m', nargs='?', type=str, default='map1.txt', help='Map to use') 60 | parser.add_argument('--test_times', '-t', nargs='?', type=int, default=5, help='Random times') 61 | parser.add_argument('--map_folder', '-f', nargs='?', type=str, default="allMaps", help='Random seed to use') 62 | 63 | return parser.parse_args() 64 | 65 | def save_para(params): 66 | with open('para.txt', 'w') as f: 67 | for para in params: 68 | f.write(str(para) + '\n') 69 | 70 | def remove_file(file_path, attempts=10): 71 | for i in range(attempts): 72 | try: 73 | # check file or folder 74 | if os.path.isfile(file_path): 75 | os.remove(file_path) 76 | else: 77 | shutil.rmtree(file_path) 78 | break 79 | except Exception as e: 80 | if i == attempts - 1: 81 | print(e) 82 | else: 83 | sleep(0.5) 84 | 85 | 86 | def run_one(args, random_seed): 87 | Win_Cmd = f'%CD%/../judge/SemiFinalJudge.exe -s {str(random_seed)} -m ../{args.map_folder}/{args.map} -r ./{args.map}{str(random_seed)}%Y-%m-%d.%H.%M.%S.rep ./main' 88 | Linux_Cmd = f'../judge/SemiFinalJudge -s {str(random_seed)} -m ../{args.map_folder}/{args.map} -r ./{args.map}{str(random_seed)}%Y-%m-%d.%H.%M.%S.rep ./main' 89 | 90 | if not os.path.exists('../log'): 91 | os.makedirs('../log') 92 | 93 | process = subprocess.Popen(Linux_Cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 94 | stdout, stderr = process.communicate() 95 | 96 | for files in os.listdir('./replay'): 97 | if files.endswith('.rep'): 98 | # remove it 99 | remove_file(f'./replay/{files}') 100 | 101 | if stdout: 102 | score_str = stdout.decode('utf-8').split(':')[2].split('}')[0] 103 | score_str = score_str.strip() # Remove leading/trailing whitespace 104 | score_str = score_str.split('\r\n')[0] # Remove additional characters after the numeric value 105 | score = int(score_str) 106 | return score 107 | else: 108 | return 0 109 | 110 | 111 | def run_one_all_seed(args, now_para, seed_list): 112 | save_para(now_para) 113 | 114 | with Pool(processes=6) as pool: 115 | func = partial(run_one, args) 116 | score_list = pool.map(func, seed_list) 117 | return score_list 118 | 119 | def result_with_seed(args, all_paras, seed_list): 120 | all_scores = [] 121 | 122 | for i in trange(len(all_paras)): 123 | now_para = all_paras[i] 124 | score_list = run_one_all_seed(args, now_para, seed_list) 125 | all_scores.append(score_list) 126 | 127 | return all_paras, all_scores 128 | 129 | 130 | def cal_mse(source, target): 131 | mse = 0 132 | for i in range(len(source)): 133 | mse += (source[i] - target[i]) ** 2 134 | return mse 135 | 136 | # 交换输入的维度 137 | def swap_input_dim(input_list): 138 | swap_list = [] 139 | for i in range(len(input_list[0])): 140 | now_list = [] 141 | for j in range(len(input_list)): 142 | now_list.append(input_list[j][i]) 143 | swap_list.append(now_list) 144 | return swap_list 145 | 146 | # tar_score: 5~6个参数的真实分数 147 | # all_scores: 5~6个参数的分数,每个里面有随机种子个数个分数 148 | # swaped_all_scores: 所有随机种子的分数,每个里面有5~6个参数的分数 149 | def select_seed(tar_scores, all_scores, all_seeds): 150 | swaped_all_scores = swap_input_dim(all_scores) 151 | min_mse = 1e9 152 | best_seed = -1 153 | for i in range(len(all_seeds)): 154 | now_mse = cal_mse(tar_scores, swaped_all_scores[i]) 155 | if now_mse < min_mse: 156 | min_mse = now_mse 157 | best_seed = all_seeds[i] 158 | return best_seed, min_mse 159 | 160 | 161 | 162 | 163 | def main(): 164 | # random.seed(990321) 165 | args = setup_args() 166 | print(args) 167 | now_path = os.getcwd() 168 | if not now_path.endswith("tools"): 169 | os.chdir("tools") 170 | 171 | if not os.path.exists("../judge/replay"): 172 | os.makedirs("../judge/replay") 173 | print("Created replay folder") 174 | 175 | try: 176 | os.chdir("../code") 177 | cmd = "g++-13 main.cpp -o main -std=c++17 -O2 -DTUNE" 178 | 179 | if os.system(cmd) == 0: 180 | print("Compile success") 181 | else: 182 | print("Compile failed") 183 | return 184 | except Exception as e: 185 | print("Compile failed") 186 | print(e) 187 | return 188 | 189 | seed_list = [random.randint(0, 32767) for i in range(args.test_times)] 190 | all_paras, all_scores = result_with_seed(args, para_input, seed_list) 191 | 192 | tune_res_file_pickle = 'seed_res.pkl' 193 | with open(tune_res_file_pickle, 'wb') as f: 194 | pickle.dump(seed_list, f) 195 | pickle.dump(all_scores, f) 196 | 197 | best_seed, min_mse = select_seed(score_input, all_scores, seed_list) 198 | 199 | print(f'Best seed: {best_seed}, min mse: {min_mse}') 200 | 201 | 202 | del_files() 203 | 204 | if __name__ == "__main__": 205 | main() -------------------------------------------------------------------------------- /tools/test.py: -------------------------------------------------------------------------------- 1 | def gen_all_paras(para_list): 2 | if len(para_list) == 1: 3 | return [[i] for i in para_list[0]] 4 | else: 5 | sub_paras = gen_all_paras(para_list[1:]) 6 | result = [] 7 | for para in para_list[0]: 8 | for sub_para in sub_paras: 9 | result.append([para] + sub_para) 10 | return result 11 | 12 | if __name__ == "__main__": 13 | para_list = [[160, 150, 130], [0.5, 0.3], [1, 2], [3, 4, 5]] 14 | print(gen_all_paras(para_list)) -------------------------------------------------------------------------------- /tools/tune.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from audioop import avg 3 | import os 4 | import sys 5 | import pickle 6 | import random 7 | import shutil 8 | import subprocess 9 | from time import sleep 10 | import matplotlib.pyplot as plt 11 | from tqdm import trange 12 | 13 | from multiprocessing import Pool 14 | from functools import partial 15 | 16 | if sys.platform.startswith('linux'): 17 | system = 'linux' 18 | elif sys.platform.startswith('win'): 19 | system = 'win' 20 | elif sys.platform.startswith('darwin'): 21 | system = 'mac' 22 | 23 | ''' 24 | 160 25 | 80 26 | 0.85 27 | 10 28 | 29 | para_input = [ 30 | [10, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200], # MAX_Berth_Control_Length, 10~200, 5 31 | [80], # MAX_Berth_Merge_Length, 1~200, 5 32 | [0.85], # Sell_Ration, 0.5~1 33 | [10] # Min_Next_Berth_Goods, 0~100 34 | ] 35 | 36 | 37 | para_input = [ 38 | [160], # MAX_Berth_Control_Length, 10~200, 5 39 | [1, 5, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200], # MAX_Berth_Merge_Length, 1~200, 5 40 | [0.85], # Sell_Ration, 0.5~1 41 | [10] # Min_Next_Berth_Goods, 0~100 42 | ] 43 | 44 | 45 | 46 | para_input = [ 47 | [160], # MAX_Berth_Control_Length, 10~200, 5 48 | [80], # MAX_Berth_Merge_Length, 1~200, 5 49 | [0.5, 0.6, 0.7, 0.8, 0.9, 1.0], # Sell_Ration, 0.5~1 50 | [10] # Min_Next_Berth_Goods, 0~100 51 | ] 52 | 53 | 54 | para_input = [ 55 | [160], # MAX_Berth_Control_Length, 10~200, 5 56 | [80], # MAX_Berth_Merge_Length, 1~200, 5 57 | [0.85], # Sell_Ration, 0.5~1 58 | [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100] # Min_Next_Berth_Goods, 0~100 59 | ] 60 | ''' 61 | 62 | ''' 在这里设置参数的可选项 ''' 63 | para_input = [ 64 | [40], # MAX_Berth_Control_Length, 10~200, 5 65 | [1, 40, 80, 120], # MAX_Berth_Merge_Length, 1~200, 5 66 | [3], # Worst_Rate, 1~10 67 | [0.7], # Sell_Ration, 0.5~1 68 | [800], # Min_Next_Berth_Value, 0~3000 69 | [1600], # Only_Run_On_Berth_with_Ship, 0~2000 70 | ] 71 | 72 | ''' 如果要进行可视化,-1是要可视化的参数 ''' 73 | para_select_input = [ 74 | 40, 75 | -1, 76 | 3, 77 | 0.7, 78 | 800, 79 | 1600 80 | ] 81 | 82 | def del_files_win(): 83 | if os.path.isfile('main.exe'): 84 | remove_file('main.exe') 85 | if os.path.exists('replay'): 86 | os.rmdir('replay') 87 | 88 | def del_files_linux(): 89 | if os.path.isfile('main'): 90 | os.remove('main') 91 | if os.path.exists('main.dSYM'): 92 | shutil.rmtree('main.dSYM') 93 | if os.path.exists('replay'): 94 | os.rmdir('replay') 95 | 96 | def del_files(): 97 | if system == 'win': 98 | del_files_win() 99 | else: 100 | del_files_linux() 101 | 102 | def setup_args(): 103 | parser = argparse.ArgumentParser(description='Upload a file to the server') 104 | parser.add_argument('--map', '-m', nargs='?', type=str, default='map1.txt', help='Map to use') 105 | parser.add_argument('--test_times', '-t', nargs='?', type=int, default=5, help='Random times') 106 | parser.add_argument('--map_folder', '-f', nargs='?', type=str, default="allMaps", help='Random seed to use') 107 | 108 | return parser.parse_args() 109 | 110 | def save_para(params): 111 | with open('para.txt', 'w') as f: 112 | for para in params: 113 | f.write(str(para) + '\n') 114 | 115 | def remove_file(file_path, attempts=10): 116 | for i in range(attempts): 117 | try: 118 | # check file or folder 119 | if os.path.isfile(file_path): 120 | os.remove(file_path) 121 | else: 122 | shutil.rmtree(file_path) 123 | break 124 | except Exception as e: 125 | if i == attempts - 1: 126 | print(e) 127 | else: 128 | sleep(0.5) 129 | 130 | 131 | def run_one(args, random_seed): 132 | Win_Cmd = f'%CD%/../judge/SemiFinalJudge.exe -s {str(random_seed)} -m ../{args.map_folder}/{args.map} -r ./{args.map}{str(random_seed)}%Y-%m-%d.%H.%M.%S.rep ./main' 133 | Linux_Cmd = f'../judge/SemiFinalJudge -s {str(random_seed)} -m ../{args.map_folder}/{args.map} -r ./{args.map}{str(random_seed)}%Y-%m-%d.%H.%M.%S.rep ./main' 134 | 135 | if not os.path.exists('../log'): 136 | os.makedirs('../log') 137 | 138 | process = subprocess.Popen(Win_Cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 139 | stdout, stderr = process.communicate() 140 | 141 | for files in os.listdir('./replay'): 142 | if files.endswith('.rep'): 143 | # remove it 144 | remove_file(f'./replay/{files}') 145 | 146 | if stdout: 147 | score_str = stdout.decode('utf-8').split(':')[2].split('}')[0] 148 | score_str = score_str.strip() # Remove leading/trailing whitespace 149 | score_str = score_str.split('\r\n')[0] # Remove additional characters after the numeric value 150 | score = int(score_str) 151 | return score 152 | else: 153 | return 0 154 | 155 | def gen_all_paras(para_list): 156 | if len(para_list) == 1: 157 | return [[i] for i in para_list[0]] 158 | else: 159 | sub_paras = gen_all_paras(para_list[1:]) 160 | result = [] 161 | for para in para_list[0]: 162 | for sub_para in sub_paras: 163 | result.append([para] + sub_para) 164 | return result 165 | 166 | 167 | def run_one_all_seed(args, now_para, seed_list): 168 | save_para(now_para) 169 | ''' 170 | score_list = [] 171 | for j in range(args.test_times): 172 | res = run_one(args, seed_list[j]) 173 | score_list.append(res) 174 | ''' 175 | 176 | 177 | with Pool(processes=6) as pool: 178 | func = partial(run_one, args) 179 | score_list = pool.map(func, seed_list) 180 | return score_list 181 | 182 | def tune(args, para_list, seed_list): 183 | all_paras = gen_all_paras(para_list) 184 | all_scores = [] 185 | 186 | for i in trange(len(all_paras)): 187 | now_para = all_paras[i] 188 | score_list = run_one_all_seed(args, now_para, seed_list) 189 | all_scores.append(score_list) 190 | 191 | return all_paras, all_scores 192 | 193 | 194 | def draw_one_param(para_select, all_paras, all_scores): 195 | selected_para_values = [] 196 | selected_scores = [] 197 | for i, para in enumerate(all_paras): 198 | will_select = True 199 | select_pos = 0 200 | for j, select_value in enumerate(para_select): 201 | if select_value != -1 and para[j] != select_value: 202 | will_select = False 203 | break 204 | if select_value == -1: 205 | select_pos = j 206 | if will_select: 207 | selected_para_values.append(para[select_pos]) 208 | selected_scores.append(all_scores[i]) 209 | min_score = [] 210 | max_score = [] 211 | avg_scores = [] 212 | for scores in selected_scores: 213 | min_score.append(min(scores)) 214 | max_score.append(max(scores)) 215 | avg_scores.append(sum(scores) / len(scores)) 216 | print(selected_para_values) 217 | print(avg_scores) 218 | # plot node with selected_para_values and selected_scores 219 | plt.figure() 220 | for i, para in enumerate(selected_para_values): 221 | plt.scatter([para] * len(selected_scores[i]), selected_scores[i], c='b', marker='o', alpha=0.5) 222 | 223 | 224 | plt.plot(selected_para_values, min_score, label='min') 225 | plt.plot(selected_para_values, max_score, label='max') 226 | plt.plot(selected_para_values, avg_scores, label='avg') 227 | plt.legend() 228 | plt.savefig('tune.png') 229 | # plt.show() 230 | plt.close() 231 | 232 | def select_best_para(all_paras, all_scores): 233 | avg_scores = [] 234 | min_scores = [] 235 | max_scores = [] 236 | for i, para in enumerate(all_paras): 237 | score = all_scores[i] 238 | avg_scores.append(sum(score) / len(score)) 239 | min_scores.append(min(score)) 240 | max_scores.append(max(score)) 241 | max_avg_index = avg_scores.index(max(avg_scores)) 242 | print("平均最佳:", all_paras[max_avg_index], avg_scores[max_avg_index], min_scores[max_avg_index], max_scores[max_avg_index]) 243 | max_min_index = min_scores.index(max(min_scores)) 244 | print("最小最佳:", all_paras[max_min_index], avg_scores[max_min_index], min_scores[max_min_index], max_scores[max_min_index]) 245 | max_max_index = max_scores.index(max(max_scores)) 246 | print("最大最佳:", all_paras[max_max_index], avg_scores[max_max_index], min_scores[max_max_index], max_scores[max_max_index]) 247 | 248 | def main(): 249 | random.seed(990321) 250 | args = setup_args() 251 | print(args) 252 | now_path = os.getcwd() 253 | if not now_path.endswith("tools"): 254 | os.chdir("tools") 255 | 256 | if not os.path.exists("../judge/replay"): 257 | os.makedirs("../judge/replay") 258 | print("Created replay folder") 259 | 260 | try: 261 | os.chdir("../code") 262 | cmd = "g++ main.cpp -o main -std=c++17 -O2 -DTUNE" 263 | 264 | if os.system(cmd) == 0: 265 | print("Compile success") 266 | else: 267 | print("Compile failed") 268 | return 269 | except Exception as e: 270 | print("Compile failed") 271 | print(e) 272 | return 273 | 274 | seed_list = [random.randint(0, 1024) for i in range(args.test_times)] 275 | all_paras, all_scores = tune(args, para_input, seed_list) 276 | 277 | tune_res_file_pickle = 'tune_res.pkl' 278 | with open(tune_res_file_pickle, 'wb') as f: 279 | pickle.dump(all_paras, f) 280 | pickle.dump(all_scores, f) 281 | 282 | draw_one_param(para_select_input, all_paras, all_scores) 283 | select_best_para(all_paras, all_scores) 284 | 285 | del_files() 286 | 287 | if __name__ == "__main__": 288 | main() -------------------------------------------------------------------------------- /tools/upload.bat: -------------------------------------------------------------------------------- 1 | python upload.py -------------------------------------------------------------------------------- /tools/upload.py: -------------------------------------------------------------------------------- 1 | import os, sys, shutil, glob 2 | import zipfile 3 | import argparse 4 | 5 | def setup_args(): 6 | parser = argparse.ArgumentParser(description='Upload a file to the server') 7 | parser.add_argument('--file_name',nargs='?',type=str,default=None, help='File name to upload') 8 | return parser.parse_args() 9 | 10 | def create_zipfile(zip_name, files): 11 | with zipfile.ZipFile(zip_name, 'w') as zipf: 12 | for file in files: 13 | zipf.write(file) 14 | 15 | def main(): 16 | args = setup_args() 17 | os.chdir("..") 18 | if not os.path.exists("upload"): 19 | os.mkdir("upload") 20 | if not os.path.exists("oldFile"): 21 | os.mkdir("oldFile") 22 | 23 | # 复制所有的 .cpp 文件到 upload/ 24 | for cpp_file in glob.glob('code/*.cpp'): 25 | shutil.copy(cpp_file, 'upload/') 26 | 27 | # 复制所有的 .hpp 文件到 upload/ 28 | for hpp_file in glob.glob('code/*.hpp'): 29 | shutil.copy(hpp_file, 'upload/') 30 | 31 | # 复制 CMakeLists.txt 文件到 upload/ 32 | shutil.copy('code/CMakeLists.txt', 'upload/') 33 | 34 | #默认日期为zip_name: 35 | if args.file_name is None: 36 | import datetime 37 | current_time = datetime.datetime.now() 38 | zip_name = current_time.strftime("%Y-%m-%d-%H-%M-%S") + ".zip" 39 | else: 40 | zip_name = args.file_name + ".zip" if not args.file_name.endswith(".zip") else args.file_name 41 | while os.path.exists(zip_name): 42 | zip_name = zip_name[:-4] + "_2.zip" 43 | 44 | 45 | # 移动旧的到 oldFile/ 46 | old_file = glob.glob('*.zip') 47 | if len(old_file) > 0: 48 | shutil.move(old_file[0], 'oldFile/' + old_file[0]) 49 | 50 | # 创建压缩文件 51 | create_zipfile(zip_name, glob.glob('upload/*')) 52 | 53 | # 删除 upload 文件夹 54 | shutil.rmtree('upload') 55 | 56 | 57 | 58 | 59 | 60 | 61 | if __name__ == "__main__": 62 | main() -------------------------------------------------------------------------------- /tools/upload.sh: -------------------------------------------------------------------------------- 1 | python upload.py 2 | --------------------------------------------------------------------------------