├── README.md ├── README_20200423.md ├── README_JAVA.md ├── eleme_round2_dispatch_master_20200420 ├── .gitignore ├── Dockerfile ├── DockerfileJudge ├── Makefile ├── README.md ├── deploy.png ├── dispatch-api │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── dispatch │ │ │ ├── api │ │ │ ├── DispatchClient.java │ │ │ ├── dto │ │ │ │ ├── ActionNode.java │ │ │ │ ├── Courier.java │ │ │ │ ├── CourierPlan.java │ │ │ │ ├── DispatchRequest.java │ │ │ │ ├── DispatchSolution.java │ │ │ │ ├── Location.java │ │ │ │ ├── Order.java │ │ │ │ └── Response.java │ │ │ ├── exception │ │ │ │ └── DispatchException.java │ │ │ └── impl │ │ │ │ ├── HttpClientManager.java │ │ │ │ └── HttpDispatchClientImpl.java │ │ │ └── judge │ │ │ ├── CourierRecord.java │ │ │ ├── DispatchContext.java │ │ │ ├── DispatchJudge.java │ │ │ ├── DispatchLog.java │ │ │ ├── IllegalMsg.java │ │ │ ├── JudgeUtil.java │ │ │ ├── OrderRecord.java │ │ │ ├── RawData.java │ │ │ ├── Score.java │ │ │ └── SequentialJudge.java │ │ └── test │ │ └── java │ │ └── dispatch │ │ └── api │ │ └── impl │ │ └── HttpDispatchClientImplTest.java ├── dispatch-demo-go │ ├── dispatch │ │ ├── cmd.go │ │ ├── dispatcher.go │ │ ├── dto.go │ │ ├── log.go │ │ └── server.go │ ├── go.mod │ └── main.go ├── dispatch-demo-py │ ├── app.py │ ├── demo │ │ ├── __init__.py │ │ └── dto.py │ └── setup.py ├── dispatch-demo │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ ├── src │ │ ├── main │ │ │ ├── .DS_Store │ │ │ ├── java │ │ │ │ ├── .DS_Store │ │ │ │ └── dispatch │ │ │ │ │ ├── .DS_Store │ │ │ │ │ └── demo │ │ │ │ │ ├── DispatchDemoApplication.java │ │ │ │ │ ├── controller │ │ │ │ │ └── DispatchController.java │ │ │ │ │ ├── core │ │ │ │ │ ├── DispatchService.java │ │ │ │ │ ├── context │ │ │ │ │ │ └── DispatchContext.java │ │ │ │ │ ├── pool │ │ │ │ │ │ ├── CourierPool.java │ │ │ │ │ │ └── OrderPool.java │ │ │ │ │ ├── route │ │ │ │ │ │ ├── Planner.java │ │ │ │ │ │ └── TailAppendPlan.java │ │ │ │ │ └── solver │ │ │ │ │ │ └── BaseSolver.java │ │ │ │ │ ├── dto │ │ │ │ │ ├── ActionNode.java │ │ │ │ │ ├── Courier.java │ │ │ │ │ ├── CourierPlan.java │ │ │ │ │ ├── DispatchRequest.java │ │ │ │ │ ├── DispatchSolution.java │ │ │ │ │ ├── Location.java │ │ │ │ │ ├── Order.java │ │ │ │ │ └── Response.java │ │ │ │ │ └── utils │ │ │ │ │ └── DistanceUtils.java │ │ │ └── resources │ │ │ │ └── application.properties │ │ └── test │ │ │ └── java │ │ │ └── dispatch │ │ │ └── dispatchdemo │ │ │ └── DispatchDemoApplicationTests.java │ └── target │ │ └── dispatch-demo.jar ├── open_test │ ├── 680507 │ │ ├── courier │ │ └── order │ ├── 725011 │ │ ├── courier │ │ └── order │ └── 730221 │ │ ├── courier │ │ └── order ├── pom.xml ├── run.sh └── start_judge.sh ├── eleme_round2_dispatch_master_20200421 ├── .gitignore ├── Dockerfile ├── DockerfileJ ├── Makefile ├── README.md ├── base-dockerfile │ ├── java-dockerfile │ └── python-dockerfile ├── deploy.png ├── dispatch-api │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── dispatch │ │ │ ├── api │ │ │ ├── DispatchClient.java │ │ │ ├── dto │ │ │ │ ├── ActionNode.java │ │ │ │ ├── Courier.java │ │ │ │ ├── CourierPlan.java │ │ │ │ ├── DispatchRequest.java │ │ │ │ ├── DispatchSolution.java │ │ │ │ ├── Location.java │ │ │ │ ├── Order.java │ │ │ │ └── Response.java │ │ │ ├── exception │ │ │ │ └── DispatchException.java │ │ │ └── impl │ │ │ │ ├── HttpClientManager.java │ │ │ │ └── HttpDispatchClientImpl.java │ │ │ └── judge │ │ │ ├── CourierRecord.java │ │ │ ├── DispatchContext.java │ │ │ ├── DispatchJudge.java │ │ │ ├── DispatchLog.java │ │ │ ├── IllegalMsg.java │ │ │ ├── JudgeUtil.java │ │ │ ├── OrderRecord.java │ │ │ ├── RawData.java │ │ │ ├── Score.java │ │ │ └── SequentialJudge.java │ │ └── test │ │ └── java │ │ └── dispatch │ │ └── api │ │ └── impl │ │ └── HttpDispatchClientImplTest.java ├── dispatch-demo-go │ ├── dispatch │ │ ├── cmd.go │ │ ├── dispatcher.go │ │ ├── dto.go │ │ ├── log.go │ │ └── server.go │ ├── go.mod │ └── main.go ├── dispatch-demo-py │ ├── app.py │ ├── demo │ │ ├── __init__.py │ │ ├── context.py │ │ ├── dto.py │ │ ├── plan.py │ │ ├── pool.py │ │ ├── service.py │ │ ├── solver.py │ │ └── util.py │ ├── dispatch-judge-jar-with-dependencies.jar │ ├── local_judge.py │ ├── open_test │ │ ├── 680507 │ │ │ ├── courier │ │ │ └── order │ │ ├── 725011 │ │ │ ├── courier │ │ │ └── order │ │ └── 730221 │ │ │ ├── courier │ │ │ └── order │ ├── open_test_small │ │ └── 680507 │ │ │ ├── courier │ │ │ └── order │ └── setup.py ├── dispatch-demo │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── dispatch │ │ │ │ └── demo │ │ │ │ ├── DispatchDemoApplication.java │ │ │ │ ├── controller │ │ │ │ └── DispatchController.java │ │ │ │ ├── core │ │ │ │ ├── DispatchService.java │ │ │ │ ├── context │ │ │ │ │ └── DispatchContext.java │ │ │ │ ├── pool │ │ │ │ │ ├── CourierPool.java │ │ │ │ │ └── OrderPool.java │ │ │ │ ├── route │ │ │ │ │ ├── Planner.java │ │ │ │ │ └── TailAppendPlan.java │ │ │ │ └── solver │ │ │ │ │ └── BaseSolver.java │ │ │ │ ├── dto │ │ │ │ ├── ActionNode.java │ │ │ │ ├── Courier.java │ │ │ │ ├── CourierPlan.java │ │ │ │ ├── DispatchRequest.java │ │ │ │ ├── DispatchSolution.java │ │ │ │ ├── Location.java │ │ │ │ ├── Order.java │ │ │ │ └── Response.java │ │ │ │ └── utils │ │ │ │ └── DistanceUtils.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── dispatch │ │ └── dispatchdemo │ │ └── DispatchDemoApplicationTests.java ├── pom.xml ├── run.sh ├── run_py.sh ├── run_py_dev.sh └── start_judge.sh └── 复赛 Baseline 流程部署分享 ├── Screen Shot 2020-04-21 at 6.06.29 AM.png ├── Screen Shot 2020-04-21 at 6.55.34 AM.png └── deploy.png /README.md: -------------------------------------------------------------------------------- 1 | # 复赛 Baseline - Python 移植版本 2 | https://tianchi.aliyun.com/forum/postDetail?spm=5176.12586969.1002.3.1f7f48c8KyMyxa&postId=104509 3 | [https://tianchi.aliyun.com/competition/entrance/231777](https://tianchi.aliyun.com/competition/entrance/231777) 4 | 5 | 智慧物流:新冠期间饿了么骑士行为预估 复赛 6 | 复赛 Baseline - Python 移植版本 **已经获得线上baseline 结果** 7 | 8 | ## 版本更新 9 | 10 | **23/04/2020 -2** 11 | 12 | 实现docker化配置,镜像构建以及达到官方Java线上baseline结果 13 | 14 | **23/04/2020** 15 | 16 | - 修复`local_judge.py` 调用 import module 以及异常输出问题,实现本地一体化评测 17 | - 修复Demo后台挂起时异常输出问题 18 | 19 | 旧版 Readme 见同目录 20 | 21 | ## 前情提要 22 | 23 | **23/04/2020-2** 24 | 25 | 分析发现按照之前配置,返回code127报错。本地进入docker镜像实验,猜测可能官方评测包位置差异,导致java命令没找到,抛出127错误。通过反向分析 java版本基础镜像,Dockerfile直接对环境安装 jdk 13, 线上实验达到baseline结果。全链路畅通。 26 | 27 | **23/04/2020** 28 | 29 | 更新修复了调试时候配置, 镜像生成配置,由于我在国外镜像上传太慢,有jar包存在比较大还不能走自动构建,镜像的准确性有待继续测试 30 | 31 | **22/04/2020** 32 | 33 | 其实在准备考试了,但是有时候想起这个题目,遗憾没有 python 版本进行实验。于是抽出一天进行了移植。我本身不是 python 企业级开发,之前 python 也仅限于写 pytorch,基本上是官方 Java 版本的移植。我已经本地测试通了,但是没有镜像上传。不保证代码质量。(json之间传值其实花费我挺久。。) 34 | 35 | ## 路径 36 | 37 | demo: `eleme_round2_dispatch_master_20200421/dispatch-demo-py` 38 | 39 | demo 挂起(非后台版本,不用杀进程)`eleme_round2_dispatch_master_20200421/run_py_dev.sh` 40 | 41 | demo 挂起(后台版本)`eleme_round2_dispatch_master_20200421/run_py.sh` 42 | 43 | 评测数据:`eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test` 44 | 45 | 评测数据(少量,我debug用的)`eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test_small` 46 | 47 | 本地一体评测(需要JDK环境), `local_judge.py` 48 | 49 | 评测 jar 包:`eleme_round2_dispatch_master_20200421/dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar` 50 | 51 | ## 流程 52 | 53 | ### 本地调用 54 | 55 | #### Dev 推荐流程 56 | 57 | 启动 Demo 58 | 59 | ```shell 60 | cd eleme_round2_dispatch_master_20200421 61 | bash run_py_dev.sh 62 | ``` 63 | 64 | 启动评测 65 | 66 | ```shell 67 | cd eleme_round2_dispatch_master_20200421 68 | java -jar dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar `pwd`/dispatch-demo-py/open_test/ 69 | ``` 70 | 71 | 测试完,关闭进程 72 | 73 | #### 一体化评测流程 74 | 75 | 直接调用 local_judge.py 76 | 77 | ```shell 78 | cd eleme_round2_dispatch_master_20200421/dispatch-demo-py 79 | python local_judge.py 80 | ``` 81 | 82 | #### 使用镜像 83 | 84 | 如果之前已经构建镜像了,也可以使用镜像 85 | 86 | ``` 87 | docker run -t -i registry.cn-shenzhen.aliyuncs.com/${name}:${tag} /bin/bash 88 | ``` 89 | 90 | 进入容器,下载本项目 91 | 92 | ``` 93 | git clone https://github.com/NorwinYu/eleme_round2_baseline_py 94 | ``` 95 | 96 | 启动镜像里之前复制进去的run.sh 97 | 98 | ``` 99 | /run.sh 100 | ``` 101 | 102 | ctrl c 关闭,但是还在后台运行。打开评测包 103 | 104 | ``` 105 | cd eleme_round2_dispatch_master_20200421 106 | java -jar dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar `pwd`/dispatch-demo-py/open_test/ 107 | ``` 108 | 109 | 测试完成 110 | 111 | exit 退出镜像 112 | 113 | ### 线上 114 | 115 | 之前线上返回一直报错127,所以猜测是java环境问题,之前那种方法可能会导致 java命令找不到(仅仅猜测)。因为不知道官方评测包路径,曲线救国,直接逆向查看 java 基础镜像的构建过程,将部分java环境构建copy到本项目的构建中,实现 python java 环境同时存在 116 | 117 | 逆向代码 118 | 119 | ``` 120 | docker history --no-trunc=true registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2 > java-dockerfile 121 | docker history --no-trunc=true registry.cn-shanghai.aliyuncs.com/tcc-public/python:3 > python-dockerfile 122 | ref:http://dockone.io/article/527 123 | ``` 124 | 125 | java、python 基础镜像逆向结果在 `eleme_round2_dispatch_master_20200421/base-dockerfile` 下 126 | 127 | 因此 对 `Dockerfile` 进行了更新 128 | 129 | #### 镜像打包 130 | 131 | - 下载 https://download.java.net/java/GA/jdk13.0.2/d4173c853231432d94f001e99d882ca7/8/GPL/openjdk-13.0.2_linux-x64_bin.tar.gz 132 | 133 | - 重命名为 `openjdk.tgz` 134 | 135 | - 把 jdk 包放到 `eleme_round2_dispatch_master_20200421` 目录下 136 | 137 | - 没有登录的先登录 138 | 139 | ```shell 140 | docker build -t registry.cn-shenzhen.aliyuncs.com/${name}:${tag} . 141 | docker push registry.cn-shenzhen.aliyuncs.com/${name}:${tag} 142 | ``` 143 | 144 | #### 线上测试 145 | 146 | 已到达我之前 用 官方 Java 版本的结果,移植结束。 147 | -------------------------------------------------------------------------------- /README_20200423.md: -------------------------------------------------------------------------------- 1 | # 复赛 Baseline - Python 移植版本 2 | [https://tianchi.aliyun.com/competition/entrance/231777](https://tianchi.aliyun.com/competition/entrance/231777) 3 | 4 | 智慧物流:新冠期间饿了么骑士行为预估 复赛 5 | 复赛 Baseline - Python 移植版本 6 | 7 | ## 前情提要 8 | 9 | 其实在准备考试了,但是有时候想起这个题目,遗憾没有 python 版本进行实验。于是抽出一天进行了移植。我本身不是 python 企业级开发,之前 python 也仅限于写 pytorch,基本上是官方 Java 版本的移植。我已经本地测试通了,但是没有镜像上传。不保证代码质量。(json之间传值其实花费我挺久。。) 10 | 11 | ## 路径 12 | 13 | demo: `eleme_round2_dispatch_master_20200421/dispatch-demo-py` 14 | 15 | 评测包:``eleme_round2_dispatch_master_20200421/dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar` 16 | 17 | demo 挂起(非后台版本,不用杀进程)`eleme_round2_dispatch_master_20200421/run_py_dev.sh` 18 | 19 | 评测数据:`eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test` 20 | 21 | 评测数据(少量,我debug用的)`eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test_small` 22 | 23 | 我用的 Java 进行评测的, `local_judge.py` 没调整,实在不想看了,移植太费精力 24 | 25 | ## 流程 26 | 27 | 启动 Demo 28 | 29 | ```shell 30 | cd eleme_round2_dispatch_master_20200421 31 | bash run_py_dev.sh 32 | ``` 33 | 34 | 启动评测 35 | 36 | ```shell 37 | cd eleme_round2_dispatch_master_20200421 38 | java -jar dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar `pwd`/dispatch-demo-py/open_test/ 39 | ``` 40 | 41 | 测试完,关闭进程 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /README_JAVA.md: -------------------------------------------------------------------------------- 1 | # 复赛 Baseline 流程部署分享 2 | [https://tianchi.aliyun.com/competition/entrance/231777](https://tianchi.aliyun.com/competition/entrance/231777) 3 | 4 | 智慧物流:新冠期间饿了么骑士行为预估 复赛 5 | Baseline 流程部署分享 6 | 7 | ## 官方源码更新 4.21版本 8 | * 我起来发现官方源码更新了,需要官网重新下载,相关描述是基于 4.20版本,可能有出入 9 | * 由于我没找到更新日志,错过直播,我用 git 比较了两个版本源码,详情见https://github.com/NorwinYu/eleme_round2_baseline/commit/f7ad6ea50cd9fcdcefcd650cf5d940896589d09e 10 | * 根据比对,主要更新是 py 版本的评测程序的联动,docker化,优化交互,更新少量描述和配置,具体如下,个人见解,具体见官方源码 11 | * 更新 解决了我之前提到的 run.sh 替换问题 12 | * 更新 增加 DockerfileP,应该是用于python demo docker 化 13 | * 更新 README.md 相关说明 14 | * 更新了 Java 里的 HttpDispatchClientImplTest.java 这个影响不大,测试文件 15 | * 更新了 dispatch-demo-py/app.py 16 | * 更新了 dispatch-demo-py/demo/dto.py 17 | * 把 dispatch-judge-jar-with-dependencies.jar open_test 数据 放入了 py 版本中 18 | * 更新了 DispatchController.java 19 | * 更新了 run.sh 配置 20 | 21 | ## 数据下载 22 | * 下载 官方 Baseline 源码 `eleme_round2_dispatch_master_20200420.zip` , 解压在目录 23 | `eleme_round2_dispatch_master_20200420` 下 24 | * 下载 官方 线下测试数据池 `eleme_round2_open_test_20200420.zip` , 解压在目录 25 | `eleme_round2_dispatch_master_20200420/open_test` 下 26 | * 官方 Baseline 并没有对数据进行挖掘,可供挖掘历史订单数据可于 比赛页面下载 27 | `eleme_round2_order_history_20200419.zip` 28 | 29 | ## 结构剖析 30 | ![](%E5%A4%8D%E8%B5%9B%20Baseline%20%E6%B5%81%E7%A8%8B%E9%83%A8%E7%BD%B2%E5%88%86%E4%BA%AB/Screen%20Shot%202020-04-21%20at%206.06.29%20AM.png) 31 | 上图为官方给的交互时序图。在 `eleme_round2_dispatch_master_20200420` 中, 也给了一个 POD 示例图。 32 | ![](%E5%A4%8D%E8%B5%9B%20Baseline%20%E6%B5%81%E7%A8%8B%E9%83%A8%E7%BD%B2%E5%88%86%E4%BA%AB/deploy.png) 33 | 34 | **Module说明 (来自官方 Readme)** 35 | dispatch-api 官方评测程序,Java DTO等 36 | dispatch-demo Java版本的Http Server框架和Demo实现,选手可以任意实现,仅做参考 37 | dispatch-py python版本简单Http Server框架,没有实现逻辑,选手可以任意修改 38 | dispatch-go go版本简单Http Server框架,没有实现逻辑,选手可以任意修改 39 | 40 | * 也就是说,官方给了 Java (SpringBoot), go, py (flask) 版本的Http Server框架,但是只实现了 Java 的 Demo实现。因此我昨天先尝试了打通 Java 版本的提交。 41 | 42 | * `选手Restful Sever` = `eleme_round2_dispatch_master_20200420/dispatch-demo` or `eleme_round2_dispatch_master_20200420/dispatch-py` or `eleme_round2_dispatch_master_20200420/dispatch-go` or `S调度程序(选手) + Http通信` 43 | * `评测程序 Http Client` = `eleme_round2_dispatch_master_20200420/dispatch-api` or `M发单器 + J评测程序 + Http通信 + 文件存储读取` 44 | * `D文件存储` =`eleme_round2_dispatch_master_20200420/open_test` 45 | * 通俗来讲,评测程序就好像一个模拟的环境,模拟生成状态下实时订单需求和骑手运力。选手Restful Sever就好像生成系统线上程序,一个智能体,对于所收到的信息,进行智能配单的决策。 46 | ## Baseline 流程部署 47 | 我尝试写这篇分享的原因是觉得这个提交过程对于非这个生态的开发者跨度有点大,看到群里好多同学都在问相关的(甚至提到了我提交的,其实我就是测试了下 Baseline, 第一次参赛)。我之前是做 Java Web 开发的,现在在学 NLP 相关,希望这篇分享能帮助大家关注算法上,而不是繁琐的配置。由于我目前在国外,上传镜像速度慢,部分步骤我基于我的情况进行了改动。 48 | 49 | 官方有 Readme ,有很多信息,不全部复制了,可以自行查看。以下只是个人见解。 50 | 51 | 我的这次部署尝试是基于 Java 版本, 也就是没有改过代码,本地编译出 jar 包以后,将 jar 包上传 git,然后通过镜像自动构建进行的。 52 | 53 | ### 环境 54 | 所有需要的环境我都安装过了,我这里就列下环境需求,主要是针对 Mac OS 用户。 55 | * Cmake(gcc) 应该可以Homebrew 装 56 | * Java 57 | * Maven 应该可以Homebrew 装 58 | * docker 可以Homebrew 装 59 | * Mac OS 60 | ``` 61 | $ brew install docker docker-machine 62 | $ brew cask install virtualbox 63 | -> need password 64 | -> possibly need to address System Preference setting 65 | $ docker-machine create --driver virtualbox default 66 | $ docker-machine env default 67 | $ eval "$(docker-machine env default)" 68 | $ docker run hello-world 69 | $ docker-machine stop default 70 | ``` 71 | 72 | https://medium.com/@yutafujii_59175/a-complete-one-by-one-guide-to-install-docker-on-your-mac-os-using-homebrew-e818eb4cfc3 73 | * 可能有遗漏 74 | 75 | ### 本地调试 官方的其中一种方式 76 | `cd eleme_round2_dispatch_master_20200420` 77 | #### 编译 78 | `make build-java` 79 | #### 开一个终端,启动选手 http server 80 | ``` 81 | java -jar dispatch-demo/target/dispatch-demo.jar 82 | ``` 83 | #### 开另一个终端,启动评测程序,进行评测 84 | ``` 85 | java -jar dispatch-api/target/dispatch-judge-jar-with-dependencies.jar `pwd`/open_test/ 86 | ``` 87 | #### 关闭 选手 http server Ctrl C 88 | 89 | ### 构建镜像并上传 90 | ! 如果大家在国内,可以按照 https://tianchi.aliyun.com/competition/entrance/231759/tab/174 进行部署 91 | ? 我有对 `eleme_round2_dispatch_master_20200420/Dockerfile` 进行更改,把所有 `start.sh` 换成了`run.sh` ,按照说明要求。不过不确定会不会影响,但是如果不改,由于目录下没有 `start.sh`, 会出现问题。 92 | 。 如果有同样在国外的同学,可以参照我的步骤,选择通过代码进行自动构建。 93 | * 自动构建和官方说明类似,只是在创建时候选取通过代码进行自动构建,然后我关联了Github,本来想关联阿里云的代码托管,结果发现 git push 也很慢。 94 | * 自动构建可以设置构建触发规则已经目录,目录一定要设置正确。 95 | ![](%E5%A4%8D%E8%B5%9B%20Baseline%20%E6%B5%81%E7%A8%8B%E9%83%A8%E7%BD%B2%E5%88%86%E4%BA%AB/Screen%20Shot%202020-04-21%20at%206.55.34%20AM.png) 96 | 图中是我自己的Private 项目,本个分享的话 文件目录是 `/eleme_round2_dispatch_master_20200420/` , 文件名还是 `Dockerfile` , 版本号可以自己设置或者通过触发的参量。如果经常改代码的不如关了 代码变更自动构建镜像 功能,一键构建。建议版本号每次构建进行更改,或者通过触发规则参量传递每次构建更新版本号,这样可以体现镜像的功能。 97 | * 有一点,由于构建需要 jar 包,之前编译完后,需要把 jar git add force, 因为一般是 git ignore 98 | 99 | ``` 100 | git add dispatch-demo/target/dispatch-demo.jar -f 101 | git commit -m "Your message" 102 | git push 103 | ``` 104 | 105 | * 然后手动开始构建。 106 | * 构建成功在提交界面输入镜像地址和用户密码即可。 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | __pycache__ 3 | dispatch-demo/dispatch-demo.iml 4 | dispatch-server/dispatchserver.iml 5 | dispatch-demo-py/dispatch-demo-py.iml 6 | dispatch-demo-py/venv 7 | dispatch-demo-go/dispatch-demo-go.iml 8 | target/ 9 | dispatch-api/target 10 | dispatch-demo/target 11 | dispatch-server/target 12 | *.iml 13 | dispatch-demo-go/go.sum 14 | 15 | .DS_Store 16 | dispatch-demo-py/demo/__init__.pyc 17 | dispatch-demo-py/demo/dto.pyc 18 | jdk11.tar.gz 19 | go1.14.1.linux-amd64.tar.gz 20 | dispatch-demo-py/build/ 21 | dispatch-demo-go/dispatch-demo-go 22 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2 2 | #FROM registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2 3 | MAINTAINER annoymous 4 | 5 | WORKDIR /data 6 | 7 | # 根据需要打包,如果你依赖的base image自身没有带jdk,需要你手动打包进去,并且在run.sh中指定$JAVA_HOME 8 | #ADD jdk11.tar.gz /data 9 | # 根据需要打包 10 | #ADD go1.14.1.linux-amd64.tar.gz /data 11 | 12 | # 根据需要编译你自己的代码,如果是java/python代码,可以本地编译之后copy进image,否则的话, 13 | # 需要在相关linux环境下编译之后copy进运行image,或者直接在下面RUN编译指令 14 | COPY dispatch-demo/target/dispatch-demo.jar /data/ 15 | 16 | # 按照run.sh文件中说明,提供run.sh 脚本 17 | COPY run.sh /data/ 18 | 19 | EXPOSE 8080 20 | 21 | RUN chmod u+x /data/run.sh 22 | 23 | CMD ["/bin/bash","/data/run.sh"] 24 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/DockerfileJudge: -------------------------------------------------------------------------------- 1 | FROM registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2 2 | MAINTAINER annoymous 3 | 4 | WORKDIR /data 5 | 6 | RUN mkdir -p /data/mock 7 | 8 | # copy 官方评测包到/data目录 9 | COPY dispatch-api/target/dispatch-judge-jar-with-dependencies.jar /data/ 10 | 11 | COPY open_test /data/mock/data 12 | 13 | COPY start_judge.sh /data/ 14 | 15 | ENV API_SERVER "http://172.17.0.1:8080" 16 | ENV MOCK_DATA_DIR "/data/mock/data" 17 | 18 | RUN chmod u+x start_judge.sh 19 | 20 | CMD ["/bin/bash","start_judge.sh"] 21 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all build build-java build-py build-go build-image build-image-judge clean clean-java clean-py clean-go 2 | 3 | NOW=$(shell date '+%Y-%m-%d_%H:%M:%S') 4 | USER=${shell whoami} 5 | 6 | all: build 7 | 8 | build: build-java build-py build-go build-image build-image-judge 9 | 10 | clean: clean-java clean-py clean-go 11 | 12 | build-java: 13 | echo "start build java" && \ 14 | mvn -f pom.xml clean package install -DskipTests && mvn -f dispatch-demo/pom.xml clean package -DskipTests 15 | 16 | build-py: 17 | echo "start build python" && \ 18 | cd dispatch-demo-py && python setup.py build 19 | 20 | build-go: 21 | echo "start build go" && \ 22 | cd dispatch-demo-go && go build 23 | 24 | build-image: 25 | docker build -t registry.cn-shanghai.aliyuncs.com/tcc-public/${USER}:v${NOW} . 26 | 27 | build-image-judge: 28 | docker build -t registry.cn-shanghai.aliyuncs.com/tcc-public/${USER}:v${NOW} -f DockerfileJudge 29 | 30 | clean-java: 31 | mvn clean && mvn clean -f dispatch-demo/pom.xml 32 | 33 | clean-py: 34 | cd dispatch-demo-py && python setup.py clean && rm -rf dispatch_demo_py.egg-info 35 | 36 | clean-go: 37 | cd dispatch-demo-go && go mod tidy && rm -rf dispatch-demo-go 38 | 39 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/deploy.png -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | dispatch 7 | dispatch 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | tianchi-dispatch-api 13 | 14 | 15 | 16 | org.projectlombok 17 | lombok 18 | 19 | 20 | 21 | com.alibaba 22 | fastjson 23 | 24 | 25 | com.google.guava 26 | guava 27 | 28.1-jre 28 | 29 | 30 | org.apache.commons 31 | commons-lang3 32 | 3.9 33 | 34 | 35 | joda-time 36 | joda-time 37 | 2.10.3 38 | 39 | 40 | org.apache.httpcomponents 41 | httpclient 42 | 4.5.12 43 | 44 | 45 | org.slf4j 46 | slf4j-api 47 | 48 | 49 | ch.qos.logback 50 | logback-classic 51 | 1.2.3 52 | 53 | 54 | 55 | ch.qos.logback 56 | logback-core 57 | 1.2.3 58 | 59 | 60 | 61 | junit 62 | junit 63 | 4.12 64 | test 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.apache.maven.plugins 73 | maven-assembly-plugin 74 | 2.5.5 75 | 76 | 77 | 78 | dispatch.judge.DispatchJudge 79 | 80 | 81 | 82 | jar-with-dependencies 83 | 84 | 85 | 86 | 87 | make-assembly 88 | package 89 | 90 | single 91 | 92 | 93 | 94 | 95 | 96 | dispatch-judge 97 | 98 | 99 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/DispatchClient.java: -------------------------------------------------------------------------------- 1 | package dispatch.api; 2 | 3 | import dispatch.api.dto.DispatchRequest; 4 | import dispatch.api.dto.DispatchSolution; 5 | import dispatch.api.dto.Response; 6 | import dispatch.api.exception.DispatchException; 7 | 8 | import java.io.Closeable; 9 | 10 | /** 11 | * @author fangyu.fu 12 | */ 13 | public interface DispatchClient extends Closeable { 14 | Response dispatch(DispatchRequest dispatchRequest) throws DispatchException; 15 | 16 | Response ping() throws DispatchException; 17 | } 18 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/ActionNode.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ActionNode { 7 | private String orderId; 8 | private int actionType; 9 | private long actionTime; 10 | } 11 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/Courier.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.Accessors; 5 | 6 | 7 | @Data 8 | @Accessors(chain = true) 9 | public class Courier { 10 | private String areaId; 11 | private String id; 12 | private Location loc; 13 | private Double speed; 14 | private Integer maxLoads; 15 | } 16 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/CourierPlan.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | @Data 8 | public class CourierPlan { 9 | private String courierId; 10 | private List planRoutes; 11 | } 12 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/DispatchRequest.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.Accessors; 5 | 6 | import java.util.List; 7 | 8 | @Data 9 | @Accessors(chain = true) 10 | public class DispatchRequest { 11 | private long requestTime; 12 | private String areaId; 13 | private boolean isFirstRound; 14 | private boolean isLastRound; 15 | private List couriers; 16 | private List orders; 17 | } 18 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/DispatchSolution.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | @Data 8 | public class DispatchSolution { 9 | private List courierPlans; 10 | } 11 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/Location.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Location { 7 | private Double latitude; 8 | private Double longitude; 9 | 10 | public Location(Double latitude, Double longitude) { 11 | this.latitude = latitude; 12 | this.longitude = longitude; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/Order.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.Accessors; 5 | 6 | @Data 7 | @Accessors(chain = true) 8 | public class Order { 9 | private String areaId; 10 | private String id; 11 | private Location srcLoc; 12 | private Location dstLoc; 13 | private long createTime; 14 | private long promiseDeliverTime; 15 | private long estimatedPrepareCompletedTime; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/dto/Response.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | 6 | @Data 7 | @NoArgsConstructor 8 | public class Response { 9 | 10 | private int code; 11 | private T result; 12 | private String message; 13 | 14 | 15 | public Response(T result) { 16 | this.code = 200; 17 | this.result = result; 18 | } 19 | 20 | public Response(int code, T result, String message) { 21 | this.code = code; 22 | this.result = result; 23 | this.message = message; 24 | } 25 | 26 | public Response(int code, T result) { 27 | this.code = code; 28 | this.result = result; 29 | } 30 | 31 | public static Response NewErrResponse(String message) { 32 | return new Response(500, message); 33 | } 34 | 35 | public static Response NewErrResponse(int code, String message) { 36 | return new Response(500, message); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/exception/DispatchException.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.exception; 2 | 3 | public class DispatchException extends Exception { 4 | public DispatchException(int code, String message) { 5 | super(message); 6 | } 7 | 8 | public DispatchException(int code, String message, Throwable t) { 9 | super(message, t); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/impl/HttpClientManager.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.impl; 2 | 3 | import lombok.Setter; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.apache.http.HttpHost; 6 | import org.apache.http.client.HttpClient; 7 | import org.apache.http.client.HttpRequestRetryHandler; 8 | import org.apache.http.client.config.RequestConfig; 9 | import org.apache.http.client.methods.HttpGet; 10 | import org.apache.http.client.methods.HttpPost; 11 | import org.apache.http.conn.routing.HttpRoute; 12 | import org.apache.http.entity.StringEntity; 13 | import org.apache.http.impl.client.CloseableHttpClient; 14 | import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; 15 | import org.apache.http.impl.client.HttpClientBuilder; 16 | import org.apache.http.impl.client.HttpClients; 17 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; 18 | import org.apache.http.protocol.HttpContext; 19 | import org.apache.http.util.EntityUtils; 20 | 21 | import java.io.IOException; 22 | import java.util.function.Function; 23 | 24 | /** 25 | * @author fangyu.fu 26 | */ 27 | @Slf4j 28 | public class HttpClientManager { 29 | private static final String LEFT_SLASH = "/"; 30 | private PoolingHttpClientConnectionManager connectionManager; 31 | private HttpClientBuilder httpBuilder; 32 | private RequestConfig requestConfig; 33 | @Setter 34 | private int maxConnection = 10; 35 | @Setter 36 | private String hostPort = "http://localhost:8080"; 37 | 38 | private HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() { 39 | @Override 40 | public boolean retryRequest(IOException exception, 41 | int executionCount, HttpContext context) { 42 | return false; 43 | }}; 44 | 45 | private HttpRequestRetryHandler requestRetryHandler = myRetryHandler; 46 | 47 | public HttpClientManager(String hostPort, RequestConfig requestConfig) { 48 | this(hostPort, requestConfig, 0); 49 | } 50 | 51 | public HttpClientManager(String hostPort, RequestConfig requestConfig, int retry) { 52 | this.hostPort = hostPort; 53 | this.requestConfig = requestConfig; 54 | 55 | if (hostPort.endsWith(LEFT_SLASH)) { 56 | this.hostPort = hostPort.substring(0, hostPort.length() - 1); 57 | } 58 | HttpHost target = new HttpHost(this.hostPort); 59 | connectionManager = new PoolingHttpClientConnectionManager(); 60 | connectionManager.setMaxTotal(maxConnection); 61 | connectionManager.setDefaultMaxPerRoute(maxConnection); 62 | connectionManager.setMaxPerRoute(new HttpRoute(target), maxConnection); 63 | httpBuilder = HttpClients.custom(); 64 | httpBuilder.setConnectionManager(connectionManager); 65 | if (retry > 0) { 66 | requestRetryHandler = new DefaultHttpRequestRetryHandler(retry, false); 67 | httpBuilder.setRetryHandler(requestRetryHandler); 68 | }else{ 69 | httpBuilder.setRetryHandler(myRetryHandler); 70 | } 71 | } 72 | 73 | public HttpClientManager(String hostPort, int connectionTimeInMillis, int readTimeInMillis, 74 | int connectionRequestTimeInMillis, int retry) { 75 | this(hostPort, RequestConfig.custom() 76 | .setSocketTimeout(readTimeInMillis) 77 | .setConnectTimeout(connectionTimeInMillis) 78 | .setConnectionRequestTimeout(connectionRequestTimeInMillis) 79 | .build(), retry); 80 | } 81 | 82 | public HttpClient getConnection() { 83 | CloseableHttpClient httpClient = httpBuilder.setRetryHandler(myRetryHandler).build(); 84 | return httpClient; 85 | } 86 | 87 | public T get(String url, Function function) throws Exception { 88 | HttpClient client = getConnection(); 89 | HttpGet get = new HttpGet(String.format("%s%s", this.hostPort, url)); 90 | get.setConfig(requestConfig); 91 | return client.execute(get, (httpResponse) -> { 92 | String body = EntityUtils.toString(httpResponse.getEntity(), "UTF-8"); 93 | return function.apply(body); 94 | }); 95 | } 96 | 97 | public T post(String url, String request, Function function) throws Exception { 98 | HttpClient client = getConnection(); 99 | HttpPost post = new HttpPost(String.format("%s%s", this.hostPort, url)); 100 | post.setConfig(requestConfig); 101 | String json = request; 102 | StringEntity requestEntity = new StringEntity(json, "utf-8"); 103 | requestEntity.setContentEncoding("UTF-8"); 104 | post.setHeader("Content-type", "application/json"); 105 | post.setEntity(requestEntity); 106 | return client.execute(post, (httpResponse) -> { 107 | String body = EntityUtils.toString(httpResponse.getEntity(), "UTF-8"); 108 | return function.apply(body); 109 | }); 110 | } 111 | 112 | public void close() { 113 | try { 114 | connectionManager.close(); 115 | } finally { 116 | //ignore exception. 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/api/impl/HttpDispatchClientImpl.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.impl; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.TypeReference; 5 | import dispatch.api.DispatchClient; 6 | import dispatch.api.dto.DispatchRequest; 7 | import dispatch.api.dto.DispatchSolution; 8 | import dispatch.api.dto.Response; 9 | import dispatch.api.exception.DispatchException; 10 | import lombok.Data; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.apache.http.HttpStatus; 13 | import org.apache.http.client.config.RequestConfig; 14 | 15 | import java.io.Closeable; 16 | import java.io.IOException; 17 | 18 | /** 19 | * @author fangyu.fu 20 | */ 21 | @Data 22 | @Slf4j 23 | public class HttpDispatchClientImpl implements DispatchClient, Closeable { 24 | 25 | private static final String DISPATCH_PATH_V1 = "/api/v1/dispatch"; 26 | private static final String PING_PATH_V1 = "/api/v1/ping"; 27 | private static String DEFAULT_URL = "http://localhost:8080"; 28 | private HttpClientManager httpClientManager; 29 | 30 | public HttpDispatchClientImpl(String url) { 31 | httpClientManager = new HttpClientManager(url, 5000, 5000,5000,0); 32 | } 33 | 34 | public HttpDispatchClientImpl() { 35 | httpClientManager = new HttpClientManager(DEFAULT_URL, 5000, 5000, 5000, 0); 36 | } 37 | 38 | public HttpDispatchClientImpl(String url, RequestConfig requestConfig, int retry) { 39 | httpClientManager = new HttpClientManager(url, requestConfig, retry); 40 | } 41 | 42 | @Override 43 | public Response dispatch(DispatchRequest dispatchRequest) throws DispatchException { 44 | try { 45 | return httpClientManager.post(DISPATCH_PATH_V1, JSON.toJSONString(dispatchRequest), (body) -> 46 | JSON.parseObject(body, new TypeReference>() { 47 | }) 48 | ); 49 | } catch (Exception e) { 50 | log.error("", e); 51 | throw new DispatchException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e); 52 | } 53 | } 54 | 55 | @Override 56 | public Response ping() throws DispatchException { 57 | try { 58 | return httpClientManager.get(PING_PATH_V1, (body) -> 59 | JSON.parseObject(body, new TypeReference>() { 60 | }) 61 | ); 62 | } catch (Exception e) { 63 | log.error("", e); 64 | throw new DispatchException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e); 65 | } 66 | } 67 | 68 | @Override 69 | public void close() throws IOException { 70 | httpClientManager.close(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/CourierRecord.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import com.google.common.collect.Lists; 4 | import dispatch.api.dto.Courier; 5 | import dispatch.api.dto.CourierPlan; 6 | import dispatch.api.dto.Location; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | 10 | import java.util.List; 11 | 12 | @Getter 13 | public class CourierRecord { 14 | private Courier courier; 15 | @Setter 16 | private Location location; 17 | private Long courierTime; 18 | private List courierPlans; 19 | 20 | public CourierRecord(Courier courier, Long courierTime) { 21 | this.courier = courier; 22 | this.location = courier.getLoc(); 23 | this.courierTime = courierTime; 24 | this.courierPlans = Lists.newArrayList(); 25 | } 26 | 27 | public void timeChange(Long time) { 28 | if (time > courierTime) { 29 | courierTime = time; 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/DispatchJudge.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import dispatch.api.DispatchClient; 4 | import dispatch.api.impl.HttpDispatchClientImpl; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import java.io.File; 8 | 9 | @Slf4j 10 | public class DispatchJudge { 11 | 12 | public static void main(String[] args) { 13 | String directory = ""; 14 | String api = "http://localhost:8080"; 15 | if (args.length > 0) { 16 | directory = args[0]; 17 | log.error(String.format("Data directory is %s", directory)); 18 | } 19 | if (args.length > 1) { 20 | api = args[1]; 21 | log.error(String.format("Api is %s", api)); 22 | } 23 | File rootDirectory = new File(directory); 24 | if(!rootDirectory.isDirectory()){ 25 | log.error("Input path must be a directory."); 26 | System.exit(1); 27 | } 28 | File[] dataFiles = rootDirectory.listFiles((f)->f.isDirectory() && f.getName().matches("\\d+")); 29 | for(File dataFile:dataFiles){ 30 | String orderPath = String.format("%s/%s",dataFile.getAbsolutePath(),"order"); 31 | String courierPath = String.format("%s/%s",dataFile.getAbsolutePath(), "courier"); 32 | DispatchClient dispatchClient = new HttpDispatchClientImpl(api); 33 | // 从文件读取订单骑士数据 34 | RawData rawData = new RawData(orderPath, courierPath); 35 | 36 | SequentialJudge sequentialJudge = new SequentialJudge(dispatchClient, rawData); 37 | sequentialJudge.doDispatch(); 38 | 39 | Score score = sequentialJudge.getScore(); 40 | log.error(String.format("AreaId %s overtimeCount: %f", dataFile.getName(), score.getOvertimeCount())); 41 | log.error(String.format("AreaId %s avgDeliveryTime: %f", dataFile.getName(), score.getAvgServiceTime())); 42 | if (score.getIllegalMsg().isIllegal()) { 43 | log.error(String.format("AreaId %s error Msg %s", dataFile.getName(), score.getIllegalMsg().getMsg())); 44 | } 45 | } 46 | //Merge result 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/DispatchLog.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import dispatch.api.dto.DispatchRequest; 4 | import dispatch.api.dto.DispatchSolution; 5 | import lombok.Getter; 6 | 7 | @Getter 8 | public class DispatchLog { 9 | private DispatchRequest request; 10 | private DispatchSolution solution; 11 | 12 | public DispatchLog(DispatchRequest request, DispatchSolution solution) { 13 | this.request = request; 14 | this.solution = solution; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/IllegalMsg.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class IllegalMsg { 7 | private boolean illegal; 8 | private String msg = ""; 9 | 10 | public IllegalMsg(String msg) { 11 | this.illegal = true; 12 | this.msg = msg; 13 | } 14 | 15 | public IllegalMsg() { 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/JudgeUtil.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import dispatch.api.dto.Location; 4 | import org.joda.time.DateTime; 5 | 6 | public class JudgeUtil { 7 | /** 8 | * 地球半径 9 | */ 10 | private static final double RADIUS = 6367000.0; 11 | 12 | /** 13 | * 导航距离/路面距离 经验系数 14 | */ 15 | private static final double COEFFICIENT = 1.4; 16 | 17 | /** 经验路面距离 = 球面距离 * 经验系数(1.4) */ 18 | public static double getDistance(Location from, Location to) { 19 | return greatCircleDistance(from.getLongitude(), from.getLatitude(), to.getLongitude(), to.getLatitude()) * COEFFICIENT; 20 | } 21 | 22 | /** 简化版球面距离 */ 23 | public static double greatCircleDistance(double lng1, double lat1, double lng2, double lat2) { 24 | // 经度差值 25 | double deltaLng = lng2 - lng1; 26 | // 纬度差值 27 | double deltaLat = lat2 - lat1; 28 | // 平均纬度 29 | double b = (lat1 + lat2) / 2.0; 30 | // 东西距离 31 | double x = Math.toRadians(deltaLng) * RADIUS * Math.cos(Math.toRadians(b)); 32 | // 南北距离 33 | double y = RADIUS * Math.toRadians(deltaLat); 34 | // 用平面的矩形对角距离公式计算总距离 35 | return Math.sqrt(x * x + y * y); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/OrderRecord.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import dispatch.api.dto.Order; 4 | import lombok.Data; 5 | 6 | @Data 7 | public class OrderRecord { 8 | private Order order; 9 | private int status; 10 | private boolean overTime; 11 | private Long deliveryTime; 12 | 13 | public OrderRecord(Order order) { 14 | this.order = order; 15 | this.status = 0; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/RawData.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.google.common.collect.Maps; 5 | import dispatch.api.dto.Courier; 6 | import dispatch.api.dto.Location; 7 | import dispatch.api.dto.Order; 8 | import lombok.Getter; 9 | 10 | import java.io.File; 11 | import java.util.*; 12 | 13 | @Getter 14 | public class RawData { 15 | 16 | private String areaId; 17 | private List orders; 18 | private List couriers; 19 | private Map courierOnlineTime; 20 | 21 | public RawData(String orderFilePath, String courierFilePath) { 22 | this.orders = Lists.newArrayList(); 23 | this.couriers = Lists.newArrayList(); 24 | this.courierOnlineTime = Maps.newHashMap(); 25 | 26 | try { 27 | Scanner orderScanner = new Scanner(new File(orderFilePath)); 28 | orderScanner.nextLine(); 29 | while (orderScanner.hasNextLine()) { 30 | this.orders.add(orderLine2Order(getRecordFromLine(orderScanner.nextLine()))); 31 | } 32 | Scanner courierScanner = new Scanner(new File(courierFilePath)); 33 | courierScanner.nextLine(); 34 | while (courierScanner.hasNextLine()) { 35 | List courierLine = getRecordFromLine(courierScanner.nextLine()); 36 | this.courierOnlineTime.put(courierLine.get(1), Long.parseLong(courierLine.get(2))); 37 | this.couriers.add(courierLine2Courier(courierLine)); 38 | } 39 | } catch (Exception e) { 40 | e.printStackTrace(); 41 | } 42 | this.orders.sort(Comparator.comparingLong(Order::getCreateTime)); 43 | this.couriers.sort(Comparator.comparingLong(c -> courierOnlineTime.get(c.getId()))); 44 | this.areaId = orders.get(0).getAreaId(); 45 | } 46 | 47 | 48 | private static final String COMMA_DELIMITER = "\t"; 49 | 50 | private static List getRecordFromLine(String line) { 51 | List values = new ArrayList<>(); 52 | try (Scanner rowScanner = new Scanner(line)) { 53 | rowScanner.useDelimiter(COMMA_DELIMITER); 54 | while (rowScanner.hasNext()) { 55 | values.add(rowScanner.next()); 56 | } 57 | } 58 | return values; 59 | } 60 | 61 | private static Order orderLine2Order(List orderLine) { 62 | return new Order().setAreaId(orderLine.get(0)) 63 | .setId(orderLine.get(1)) 64 | .setCreateTime(Long.parseLong(orderLine.get(2))) 65 | .setEstimatedPrepareCompletedTime(Long.parseLong(orderLine.get(3))) 66 | .setPromiseDeliverTime(Long.parseLong(orderLine.get(4))) 67 | .setSrcLoc(new Location(Double.parseDouble(orderLine.get(5)), Double.parseDouble(orderLine.get(6)))) 68 | .setDstLoc(new Location(Double.parseDouble(orderLine.get(7)), Double.parseDouble(orderLine.get(8)))); 69 | } 70 | 71 | private static Courier courierLine2Courier(List courierLine) { 72 | return new Courier().setAreaId(courierLine.get(0)) 73 | .setId(courierLine.get(1)) 74 | .setMaxLoads(Integer.parseInt(courierLine.get(3))) 75 | .setSpeed(Double.parseDouble(courierLine.get(4))) 76 | .setLoc(new Location(Double.parseDouble(courierLine.get(5)), Double.parseDouble(courierLine.get(6)))); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/Score.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Score { 7 | private IllegalMsg illegalMsg = new IllegalMsg(); 8 | private double avgServiceTime; 9 | private double overtimeCount; 10 | private long serviceTimeSum; 11 | private long orderSum; 12 | 13 | public void setIllegalMsg(IllegalMsg illegalMsg) { 14 | this.illegalMsg = illegalMsg; 15 | } 16 | 17 | public void setIllegalMsg(String illegalMsg) { 18 | this.illegalMsg = new IllegalMsg(illegalMsg); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/main/java/dispatch/judge/SequentialJudge.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import com.google.common.collect.Iterables; 4 | import com.google.common.collect.Lists; 5 | import com.google.common.collect.Queues; 6 | import dispatch.api.DispatchClient; 7 | import dispatch.api.dto.*; 8 | import lombok.Getter; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Queue; 13 | 14 | public class SequentialJudge { 15 | private DispatchClient dispatchClient; 16 | private int intervalSecond; 17 | 18 | private RawData rawData; 19 | private Queue orderQueue; 20 | private Queue courierQueue; 21 | 22 | private long currentTime; 23 | private long endTime; 24 | 25 | @Getter 26 | private Score score; 27 | private List dispatchLogs = new ArrayList<>(0); 28 | 29 | 30 | public SequentialJudge(DispatchClient client, RawData rawData) { 31 | this(client, rawData, 60); 32 | } 33 | 34 | public SequentialJudge(DispatchClient client, RawData rawData, int intervalSecond) { 35 | this.dispatchClient = client; 36 | this.rawData = rawData; 37 | this.intervalSecond = intervalSecond; 38 | this.orderQueue = Queues.newArrayDeque(rawData.getOrders()); 39 | this.courierQueue = Queues.newArrayDeque(rawData.getCouriers()); 40 | this.score = new Score(); 41 | 42 | this.currentTime = orderQueue.element().getCreateTime() + intervalSecond; 43 | this.endTime = Iterables.getLast(rawData.getOrders()).getCreateTime(); 44 | 45 | } 46 | 47 | public void doDispatch() { 48 | DispatchContext dispatchContext = new DispatchContext(); 49 | boolean isFirstRound = true; 50 | while (currentTime <= endTime) { 51 | DispatchRequest request = new DispatchRequest() 52 | .setAreaId(rawData.getAreaId()) 53 | .setRequestTime(currentTime); 54 | 55 | List dispatchingOrders = Lists.newArrayList(); 56 | List onlineCourier = Lists.newArrayList(); 57 | while (!orderQueue.isEmpty() && orderQueue.element().getCreateTime() <= currentTime) { 58 | dispatchingOrders.add(orderQueue.remove()); 59 | } 60 | while (!courierQueue.isEmpty() && 61 | rawData.getCourierOnlineTime().get(courierQueue.element().getId()) <= currentTime) { 62 | onlineCourier.add(courierQueue.remove()); 63 | } 64 | 65 | request.setCouriers(onlineCourier); 66 | request.setOrders(dispatchingOrders); 67 | 68 | currentTime += intervalSecond; 69 | request.setFirstRound(isFirstRound); 70 | request.setLastRound(currentTime > endTime); 71 | 72 | if (isFirstRound) { 73 | isFirstRound = false; 74 | } 75 | 76 | Response solutionResponse; 77 | try { 78 | solutionResponse = dispatchClient.dispatch(request); 79 | } catch (Exception e) { 80 | score.setIllegalMsg(e.getMessage()); 81 | return; 82 | } 83 | 84 | if (null == solutionResponse) { 85 | score.setIllegalMsg("no response"); 86 | return; 87 | } else if (solutionResponse.getCode() != 200) { 88 | score.setIllegalMsg(solutionResponse.getMessage()); 89 | return; 90 | } else { 91 | DispatchLog dispatchLog = new DispatchLog(request, solutionResponse.getResult()); 92 | this.dispatchLogs.add(dispatchLog); 93 | IllegalMsg illegalMsg = dispatchContext.allocate(dispatchLog); 94 | if (illegalMsg.isIllegal()) { 95 | score.setIllegalMsg(illegalMsg.getMsg()); 96 | return; 97 | } 98 | } 99 | } 100 | this.score = dispatchContext.checkAndScore(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-api/src/test/java/dispatch/api/impl/HttpDispatchClientImplTest.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.impl; 2 | 3 | import dispatch.api.DispatchClient; 4 | import dispatch.api.exception.DispatchException; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.junit.AfterClass; 7 | import org.junit.BeforeClass; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | 14 | @Slf4j 15 | public class HttpDispatchClientImplTest { 16 | private static DispatchClient dispatchClient; 17 | 18 | @BeforeClass 19 | public static void init() { 20 | dispatchClient = new HttpDispatchClientImpl(); 21 | } 22 | 23 | @AfterClass 24 | public static void destroy() throws IOException { 25 | dispatchClient.close(); 26 | } 27 | 28 | @Test 29 | public void testPing() throws DispatchException, InterruptedException { 30 | assertEquals(dispatchClient.ping().getResult(), "PONG"); 31 | Thread.sleep(100); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo-go/dispatch/cmd.go: -------------------------------------------------------------------------------- 1 | package dispatch 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | "os" 7 | "os/signal" 8 | "syscall" 9 | ) 10 | 11 | var ( 12 | debug bool 13 | clientId string 14 | shutdownWaitSecs int 15 | ) 16 | 17 | func init() { 18 | Cmd.PersistentFlags().BoolVar(&debug, "debug", true, "debug mode") 19 | Cmd.PersistentFlags().StringVar(&clientId, "clientId", "", "Id of your tianchi account") 20 | Cmd.PersistentFlags().IntVar(&shutdownWaitSecs, "shutdownWait", 10, "shutdown wait seconds") 21 | } 22 | 23 | var ( 24 | // Cmd is the sub command for running as an api server 25 | Cmd = &cobra.Command{ 26 | Use: "run", 27 | Short: "Start player's dispatching http server at port 8080.", 28 | Long: "Start player's dispatching http server at port 8080.", 29 | Run: func(cmd *cobra.Command, args []string) { 30 | if debug { 31 | logrus.SetLevel(logrus.DebugLevel) 32 | } 33 | 34 | server, err := NewServer(shutdownWaitSecs, debug, clientId) 35 | if err != nil { 36 | logrus.Fatalf("Starting player's server failed: %v\n", err) 37 | } 38 | 39 | err = server.Start() 40 | if err != nil { 41 | logrus.Fatalf("Starting player's server failed: %v\n", err) 42 | } 43 | 44 | signals := make(chan os.Signal) 45 | signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT) 46 | <-signals 47 | err = server.Shutdown() 48 | if err != nil { 49 | logrus.Fatalf("Shutdown client server failed: %v\n", err) 50 | } 51 | }, 52 | } 53 | ) 54 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo-go/dispatch/dispatcher.go: -------------------------------------------------------------------------------- 1 | package dispatch 2 | 3 | type Dispatcher interface { 4 | Ping() string 5 | Dispatch(request *DispatchRequest) ([]DispatchSolution, error) 6 | } 7 | 8 | type GreedyDispatcher struct { 9 | routes []DispatchSolution 10 | } 11 | 12 | func NewGreedyDispatcher() *GreedyDispatcher { 13 | return &GreedyDispatcher{} 14 | } 15 | 16 | func (*GreedyDispatcher) Ping() string { 17 | return "PONG" 18 | } 19 | 20 | func (*GreedyDispatcher) Dispatch(request *DispatchRequest) ([]DispatchSolution, error) { 21 | return nil, nil 22 | } 23 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo-go/dispatch/dto.go: -------------------------------------------------------------------------------- 1 | package dispatch 2 | 3 | const ( 4 | Status_OK = 200 5 | Status_BAD_REQUEST = 400 6 | Status_UNKNOWN = 500 7 | Status_TIMEOUT = 510 8 | ) 9 | 10 | type ActionNode struct { 11 | OrderId string `json:"orderId"` 12 | ActionType int `json:"actionType"` 13 | ActionTimestamp int64 `json:"ActionTimestamp"` 14 | } 15 | 16 | type Location struct { 17 | Latitude float64 `json:"latitude"` 18 | Longitude float64 `json:"longitude"` 19 | } 20 | 21 | type Courier struct { 22 | AreaId string `json:"areaId"` 23 | Id string `json:"id"` 24 | Loc *Location `json:"loc"` 25 | Speed float64 `json:speed` 26 | MaxLoads int `json:"maxLoads"` 27 | } 28 | 29 | type CourierPlan struct { 30 | CourierId string `json:"courierId"` 31 | PlanRoutes []ActionNode `json:planRoutes` 32 | } 33 | 34 | type Order struct { 35 | AreaId string `json:"areaId"` 36 | Id string `json:"id"` 37 | SrcLoc *Location `json:"srcLoc"` 38 | DstLoc *Location `json:"dstLoc"` 39 | Status int `json:"status"` 40 | CreateTimestamp int64 `json:"createTimestamp"` 41 | PromiseDeliverTime int64 `json:"promiseDeliverTime"` 42 | EstimatedPrepareCompletedTimestamp int64 `json:"estimatedPrepareCompletedTimestamp"` 43 | } 44 | 45 | type DispatchRequest struct { 46 | RequestTimestamp int64 `json:"requestTimestamp"` 47 | AreaId string `json:"areaId"` 48 | IsFirstRound bool `json:"isFirstRound"` 49 | IsLastRound bool `json:"isLastRound"` 50 | Couriers []Courier `json:"couriers"` 51 | Orders []Order `json:"orders"` 52 | } 53 | 54 | type DispatchSolution struct { 55 | CourierPlans []CourierPlan `json:"courierPlans"` 56 | } 57 | 58 | type Response struct { 59 | Code int `json:"code"` 60 | Result interface{} `json:"result"` 61 | Message string `json:"message"` 62 | } 63 | 64 | func NewResponse(v interface{}) *Response { 65 | return &Response{ 66 | Code: Status_OK, 67 | Result: v, 68 | Message: "", 69 | } 70 | } 71 | 72 | func NewErrorResponse(code int, message string) *Response { 73 | return &Response{ 74 | Code: code, 75 | Message: message, 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo-go/dispatch/log.go: -------------------------------------------------------------------------------- 1 | package dispatch 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/sirupsen/logrus" 6 | "io" 7 | "time" 8 | ) 9 | 10 | func Logger(writer io.Writer, debug bool) *logrus.Logger { 11 | logger := logrus.New() 12 | logger.Out = writer 13 | if debug { 14 | logger.SetLevel(logrus.DebugLevel) 15 | } 16 | return logger 17 | } 18 | 19 | func NewLogger(writer io.Writer, debug bool) gin.HandlerFunc { 20 | logger := Logger(writer, debug) 21 | return func(c *gin.Context) { 22 | // 开始时间 23 | startTime := time.Now() 24 | 25 | // 处理请求 26 | c.Next() 27 | 28 | // 结束时间 29 | endTime := time.Now() 30 | 31 | // 执行时间 32 | latencyTime := endTime.Sub(startTime) 33 | 34 | // 请求方式 35 | reqMethod := c.Request.Method 36 | 37 | // 请求路由 38 | reqUri := c.Request.RequestURI 39 | 40 | // 状态码 41 | statusCode := c.Writer.Status() 42 | 43 | // 请求IP 44 | clientIP := c.ClientIP() 45 | 46 | //日志格式 47 | logger.Infof("| %3d | %13v | %15s | %s | %s |", 48 | statusCode, 49 | latencyTime, 50 | clientIP, 51 | reqMethod, 52 | reqUri, 53 | 54 | ) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo-go/dispatch/server.go: -------------------------------------------------------------------------------- 1 | package dispatch 2 | 3 | import ( 4 | "context" 5 | "github.com/gin-gonic/gin" 6 | "github.com/pkg/errors" 7 | "github.com/sirupsen/logrus" 8 | "net/http" 9 | "os" 10 | "sync" 11 | "time" 12 | ) 13 | 14 | type Server struct { 15 | closeMux *sync.Mutex 16 | port int 17 | debug bool 18 | shutdownWait int 19 | closed bool 20 | logger *logrus.Entry 21 | srv *http.Server 22 | dispatcher Dispatcher 23 | } 24 | 25 | func NewServer(shutdownWait int, debug bool, clientId string) (*Server, error) { 26 | server := &Server{ 27 | closeMux: &sync.Mutex{}, 28 | debug: debug, 29 | shutdownWait: shutdownWait, 30 | closed: false, 31 | logger: logrus.WithField("client", clientId).WithField("time", time.Now().String()), 32 | dispatcher: NewGreedyDispatcher(), 33 | } 34 | return server, nil 35 | } 36 | 37 | func (server *Server) Start() error { 38 | server.closeMux.Lock() 39 | defer server.closeMux.Unlock() 40 | if server.closed { 41 | return errors.New("Server is closed") 42 | } 43 | r := gin.New() 44 | // Add Log 45 | r.Use(NewLogger(os.Stdout, server.debug)) 46 | //Add Recovery 47 | r.Use(gin.Recovery()) 48 | 49 | v1 := r.Group("/api/v1") 50 | v1.GET("/ping", func(c *gin.Context) { 51 | server.logger.Info("") 52 | c.JSON(http.StatusOK, server.dispatcher.Ping()) 53 | }) 54 | 55 | v1.POST("/dispatch", func(c *gin.Context) { 56 | request := &DispatchRequest{} 57 | if err := c.ShouldBind(&request); err == nil { 58 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 59 | defer cancel() 60 | ch := make(chan *Response) 61 | go func() { 62 | response, errs := server.dispatcher.Dispatch(request) 63 | if errs == nil { 64 | ch <- NewResponse(response) 65 | } else { 66 | ch <- NewErrorResponse(Status_UNKNOWN, errs.Error()) 67 | } 68 | }() 69 | var response *Response 70 | for { 71 | select { 72 | case <-ctx.Done(): 73 | server.logger.Errorf("Request timeout %v",*request) 74 | c.JSON(http.StatusOK, NewErrorResponse(Status_TIMEOUT, "Dispatcher timeout")) 75 | return 76 | case response = <-ch: 77 | server.logger.Infof("Request:%s,Response:%s", *request, *response) 78 | c.JSON(http.StatusOK, response) 79 | return 80 | } 81 | } 82 | } else { 83 | response := NewErrorResponse( 84 | Status_BAD_REQUEST, "Could not resolve request body.", 85 | ) 86 | server.logger.Infof("Request:%s,Response:%s", &request, &response) 87 | c.JSON(http.StatusOK, &response) 88 | } 89 | }) 90 | srv := &http.Server{ 91 | Addr: ":8080", 92 | Handler: r, 93 | } 94 | server.srv = srv 95 | go func() { 96 | if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { 97 | server.logger.Fatalf("listen: %s\n", err) 98 | } 99 | }() 100 | return nil 101 | } 102 | 103 | func (server *Server) Shutdown() error { 104 | server.closeMux.Lock() 105 | defer server.closeMux.Unlock() 106 | if server.closed { 107 | return nil 108 | } 109 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(server.shutdownWait)) 110 | defer cancel() 111 | if err := server.srv.Shutdown(ctx); err != nil { 112 | server.logger.Fatal("Server shutdown error:", err) 113 | return err 114 | } 115 | server.closed = true 116 | server.logger.Info("Server exited") 117 | return nil 118 | } 119 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo-go/go.mod: -------------------------------------------------------------------------------- 1 | module gitlab.alibaba-inc.com/fangyu.ffy/tianchi-dispatch/dispatch-demo-go 2 | 3 | require ( 4 | github.com/gin-gonic/gin v1.4.0 5 | github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect 6 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect 7 | github.com/pkg/errors v0.8.0 8 | github.com/sirupsen/logrus v1.5.0 9 | github.com/spf13/cobra v0.0.7 10 | github.com/stretchr/objx v0.1.1 // indirect 11 | github.com/stretchr/testify v1.5.1 // indirect 12 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d // indirect 13 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect 14 | gopkg.in/yaml.v2 v2.2.8 // indirect 15 | ) 16 | 17 | go 1.12 18 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo-go/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | "gitlab.alibaba-inc.com/fangyu.ffy/tianchi-dispatch/dispatch-demo-go/dispatch" 7 | ) 8 | 9 | var rootCmd = &cobra.Command{ 10 | Use: "run", 11 | Short: "Tianchi&Eleme Delivery Order Dispatching Contest 2020", 12 | Long: "Tianchi&Eleme Delivery Order Dispatching Contest 2020", 13 | Run: func(cmd *cobra.Command, args []string) { 14 | cmd.Usage() 15 | }, 16 | } 17 | 18 | func init() { 19 | rootCmd.AddCommand(dispatch.Cmd) 20 | } 21 | func main() { 22 | logrus.New().Info("demo") 23 | if err := rootCmd.Execute(); err != nil { 24 | logrus.Fatalf("%v", err) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo-py/app.py: -------------------------------------------------------------------------------- 1 | import http 2 | 3 | from flask import Flask, jsonify, request 4 | 5 | import json 6 | 7 | from demo.dto import Response 8 | 9 | app = Flask(__name__) 10 | 11 | 12 | @app.route('/api/v1/ping', methods=['GET']) 13 | def ping(): 14 | return json.dumps(dict(Response(200, "Pong", ""))) 15 | 16 | 17 | @app.route('/api/v1/dispatch', methods=['POST']) 18 | def dispatch(): 19 | data = request.json 20 | # data is in format of demo.dto.DispatchRequest 21 | print(data) 22 | return '', http.HTTPStatus.OK 23 | 24 | 25 | if __name__ == "__main__": 26 | app.run(debug=True, port=8080) 27 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo-py/demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/dispatch-demo-py/demo/__init__.py -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo-py/demo/dto.py: -------------------------------------------------------------------------------- 1 | class Location(object): 2 | def __init__(self, _latitude, _longitude): 3 | self.latitude = _latitude 4 | self.longitude = _longitude 5 | 6 | def keys(self): 7 | return ['latitude', 'longitude'] 8 | 9 | def __getitem__(self, item): 10 | return getattr(self, item) 11 | 12 | 13 | class Courier(object): 14 | def __init__(self, _id, _areaId, _loc, _speed, __maxLoads): 15 | self.id = _id 16 | self.areaId = _areaId 17 | self.loc = _loc 18 | self.speed = _speed 19 | self.maxLoads = __maxLoads 20 | 21 | def keys(self): 22 | return ['id', 'areaId', 'loc', 'speed', 'maxLoads'] 23 | 24 | def __getitem__(self, item): 25 | return getattr(self, item) 26 | 27 | 28 | class Order(object): 29 | def __init__(self, _areaId, _id, _srcLoc, _dstLoc, _status, _createTimestamp, _promiseDeliverTime, 30 | _estimatedPrepareCompletedTimestamp): 31 | self.areaId = _areaId 32 | self.id = _id 33 | self.srcLoc = _srcLoc 34 | self.dstLoc = _dstLoc 35 | self.status = _status 36 | self.createTimestamp = _createTimestamp 37 | self.promiseDeliverTime = _promiseDeliverTime 38 | self.estimatedPrepareCompletedTimestamp = _estimatedPrepareCompletedTimestamp 39 | 40 | def keys(self): 41 | return ['id', 'areaId', 'srcLoc', 'dstLoc', 'status', 42 | 'createTimestamp', 'promiseDeliverTime', 'estimatedPrepareCompletedTimestamp'] 43 | 44 | def __getitem__(self, item): 45 | return getattr(self, item) 46 | 47 | 48 | class ActionNode(object): 49 | def __init__(self, _actionType, _orderId, _actionTimestamp): 50 | self.actionType = _actionType 51 | self.orderId = _orderId 52 | self.actionTimestamp = _actionTimestamp 53 | 54 | def keys(self): 55 | return ['actionType', 'orderId', 'actionTimestamp'] 56 | 57 | def __getitem__(self, item): 58 | return getattr(self, item) 59 | 60 | 61 | class CourierPlan(object): 62 | def __init__(self, _courierId, _planRoutes): 63 | self.courierId = _courierId 64 | self.planRoutes = _planRoutes 65 | 66 | def keys(self): 67 | return ['courierId', 'planRoutes'] 68 | 69 | def __getitem__(self, item): 70 | return getattr(self, item) 71 | 72 | 73 | class DispatchRequest(object): 74 | def __init__(self, _requestTimestamp, _areaId, _isFirstRound, _isLastRound, _couriers, _orders): 75 | self.requestTimestamp = _requestTimestamp 76 | self.areaId = _areaId 77 | self.isFirstRound = _isFirstRound 78 | self.isLastRound = _isLastRound 79 | self.couriers = _couriers 80 | self.orders = _orders 81 | 82 | def keys(self): 83 | return ['requestTimestamp', 'areaId', 'isFirstRound', 'isLastRound', 84 | 'couriers', 'orders'] 85 | 86 | def __getitem__(self, item): 87 | return getattr(self, item) 88 | 89 | 90 | class Response(object): 91 | def __init__(self, _code, _result, _message): 92 | self.code = _code 93 | self.result = _result 94 | self.message = _message 95 | 96 | def keys(self): 97 | return ['code', 'result', 'message'] 98 | 99 | def __getitem__(self, item): 100 | return getattr(self, item) 101 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo-py/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name="dispatch-demo-py", 5 | version="0.0.1", 6 | author="fangyu.ffy", 7 | author_email="fangyu.ffy@alibaba-inc.com", 8 | description="Tianchi-Eleme delivery order dispatch contest.", 9 | keywords="Tianchi,Eleme,Delivery,Dispatch", 10 | install_requires=['flask>=1.1.1'] 11 | 12 | ) 13 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/dispatch-demo/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.13.RELEASE 9 | 10 | 11 | dispatch 12 | dispatch-demo 13 | 0.0.1-SNAPSHOT 14 | dispatch-demo 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.projectlombok 24 | lombok 25 | 26 | 27 | 28 | 29 | com.alibaba 30 | fastjson 31 | 1.2.68 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-web 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-devtools 42 | runtime 43 | true 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-test 48 | test 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-maven-plugin 59 | 60 | 61 | dispatch-demo 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/.DS_Store -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/.DS_Store -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/.DS_Store -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/DispatchDemoApplication.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author eleme.demo 8 | */ 9 | @SpringBootApplication 10 | public class DispatchDemoApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(DispatchDemoApplication.class, args); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/controller/DispatchController.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.controller; 2 | 3 | 4 | import com.alibaba.fastjson.JSON; 5 | import dispatch.demo.core.DispatchService; 6 | import dispatch.demo.dto.DispatchRequest; 7 | import dispatch.demo.dto.DispatchSolution; 8 | import dispatch.demo.dto.Response; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | import java.util.concurrent.ArrayBlockingQueue; 12 | import java.util.concurrent.Future; 13 | import java.util.concurrent.ThreadPoolExecutor; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | 17 | /** 18 | * @author eleme.demo 19 | */ 20 | @RestController() 21 | @RequestMapping("/api/v1") 22 | public class DispatchController { 23 | 24 | 25 | ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 26 | Runtime.getRuntime().availableProcessors(), 27 | Runtime.getRuntime().availableProcessors(), 28 | 30, 29 | TimeUnit.SECONDS, 30 | new ArrayBlockingQueue<>(100) 31 | ); 32 | 33 | DispatchService dispatchService = new DispatchService(); 34 | 35 | 36 | @RequestMapping(value = "/ping", method = RequestMethod.GET) 37 | public Response ping() { 38 | System.out.println("ping"); 39 | return new Response<>("PONG"); 40 | } 41 | 42 | @RequestMapping(value = "/dispatch", method = RequestMethod.POST, produces = "application/json") 43 | public String dispatch(@RequestBody String jsonRequest) { 44 | System.out.println(jsonRequest); 45 | DispatchRequest request = JSON.parseObject(jsonRequest, DispatchRequest.class); 46 | DispatchSolution result = null; 47 | Future f = threadPoolExecutor.submit(() -> { 48 | return dispatchService.dispatch(request); 49 | }); 50 | try { 51 | //wait maximum 4s 52 | result = f.get(4, TimeUnit.SECONDS); 53 | } catch (Exception e) { 54 | System.out.println(e.getMessage()); 55 | //downgrade solution here, downgrade solution must finish within 1s so that total request processing will be finished within 5s. 56 | return JSON.toJSONString(Response.NewErrResponse(e.getMessage())); 57 | } 58 | if (null != result) { 59 | System.out.println(JSON.toJSONString(result)); 60 | } 61 | Response r = new Response(200, result); 62 | return JSON.toJSONString(r); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/core/DispatchService.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.core; 2 | 3 | import dispatch.demo.core.context.DispatchContext; 4 | import dispatch.demo.core.solver.BaseSolver; 5 | import dispatch.demo.dto.CourierPlan; 6 | import dispatch.demo.dto.DispatchRequest; 7 | import dispatch.demo.dto.DispatchSolution; 8 | 9 | import java.util.Collections; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | /** 15 | * @author eleme.demo 16 | */ 17 | public class DispatchService { 18 | 19 | Map serviceContext = new HashMap<>(0); 20 | 21 | public DispatchSolution dispatch(DispatchRequest request) { 22 | String areaId = request.getAreaId(); 23 | DispatchContext context; 24 | if (request.isFirstRound()) { 25 | context = new DispatchContext(); 26 | context.setAreaId(areaId); 27 | context.setTimeStamp(request.getRequestTime()); 28 | serviceContext.put(areaId, context); 29 | } else { 30 | context = serviceContext.get(areaId); 31 | if (null == context) { 32 | DispatchSolution emptySolution = new DispatchSolution(); 33 | emptySolution.setCourierPlans(Collections.emptyList()); 34 | return emptySolution; 35 | } else { 36 | if (request.isLastRound()) { 37 | context.setEndOfTest(true); 38 | } 39 | } 40 | context.refresh(request.getRequestTime()); 41 | } 42 | context.addOnlineCouriers(request.getCouriers()); 43 | context.addDispatchingOrders(request.getOrders()); 44 | BaseSolver solver = getSolver(context); 45 | List courierPlans = solver.solve(); 46 | courierPlans.forEach(cp -> { 47 | cp.getPlanRoutes().forEach(a -> a.setSubmitted(true)); 48 | }); 49 | List assignedIds = solver.getAssignedOrderIds(); 50 | context.markAllocatedOrders(assignedIds); 51 | while (!context.getOrderPool().getDispatchingOrders().isEmpty() && context.isEndOfTest()) { 52 | long aheadTime = 10 * 60; 53 | context.setTimeStamp(context.getTimeStamp() + aheadTime); 54 | BaseSolver lastRoundSolver = getSolver(context); 55 | List tmpPlans = lastRoundSolver.solve(); 56 | courierPlans.addAll(tmpPlans); 57 | tmpPlans.forEach(cp -> { 58 | cp.getPlanRoutes().forEach(a -> a.setSubmitted(true)); 59 | }); 60 | context.markAllocatedOrders(lastRoundSolver.getAssignedOrderIds()); 61 | } 62 | DispatchSolution solution = new DispatchSolution(); 63 | solution.setCourierPlans(courierPlans); 64 | return solution; 65 | } 66 | 67 | BaseSolver getSolver(DispatchContext context) { 68 | return new BaseSolver(context); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/core/context/DispatchContext.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.core.context; 2 | 3 | import dispatch.demo.core.pool.CourierPool; 4 | import dispatch.demo.core.pool.OrderPool; 5 | import dispatch.demo.dto.ActionNode; 6 | import dispatch.demo.dto.Courier; 7 | import dispatch.demo.dto.Location; 8 | import dispatch.demo.dto.Order; 9 | import lombok.Data; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | /** 16 | * @author eleme.demo 17 | */ 18 | @Data 19 | public class DispatchContext { 20 | private String areaId; 21 | private CourierPool courierPool = new CourierPool(); 22 | private OrderPool orderPool = new OrderPool(); 23 | private long timeStamp; 24 | private boolean isEndOfTest = false; 25 | 26 | public void addOnlineCouriers(List courierList) { 27 | courierPool.getCouriers().addAll(courierList); 28 | } 29 | 30 | public void addDispatchingOrders(List orders) { 31 | orderPool.addDispatchingOrders(orders); 32 | } 33 | 34 | public void markAllocatedOrders(List orderIds) { 35 | orderIds.forEach(id -> orderPool.markAssignedOrder(id)); 36 | } 37 | 38 | public void refresh(long refreshTime) { 39 | this.timeStamp = refreshTime; 40 | courierPool.getCouriers().forEach(c -> { 41 | refreshCourier(c, refreshTime); 42 | }); 43 | } 44 | 45 | private void refreshCourier(Courier courier, long refreshTime) { 46 | List actionNodeList = courier.getPlanRoutes(); 47 | List refreshNodeList = new ArrayList<>(0); 48 | for (ActionNode node : actionNodeList) { 49 | if (node.isSubmitted() && node.getActionTime() <= refreshTime) { 50 | if (node.getActionType() == 1) { 51 | //到店完成 52 | orderPool.markArrivalCompleteOrder(node.getOrderId()); 53 | } 54 | if (node.getActionType() == 2) { 55 | //取餐完成 56 | orderPool.markPickCompleteOrder(node.getOrderId()); 57 | } 58 | if (node.getActionType() == 3) { 59 | //送达 60 | orderPool.markDeliverCompleteOrder(node.getOrderId()); 61 | } 62 | } else { 63 | refreshNodeList.add(node); 64 | } 65 | } 66 | List loadOrders = courier.getOrders().stream() 67 | .filter(o -> o.getStatus() != 4) 68 | .collect(Collectors.toList()); 69 | courier.setOrders(loadOrders); 70 | courier.setPlanRoutes(refreshNodeList); 71 | if(refreshNodeList.isEmpty() && !actionNodeList.isEmpty()){ 72 | Location latestLoc = orderPool.getOrderMap().get(actionNodeList.get(actionNodeList.size()-1).getOrderId()).getDstLoc(); 73 | courier.setLoc(latestLoc); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/core/pool/CourierPool.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.core.pool; 2 | 3 | import dispatch.demo.dto.Courier; 4 | import lombok.Data; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * @author eleme.demo 11 | */ 12 | @Data 13 | public class CourierPool { 14 | private List couriers = new ArrayList<>(0); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/core/pool/OrderPool.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.core.pool; 2 | 3 | import dispatch.demo.dto.Order; 4 | import lombok.Getter; 5 | 6 | import java.util.ArrayList; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | /** 12 | * @author eleme.demo 13 | */ 14 | 15 | public class OrderPool { 16 | 17 | private List orders; 18 | 19 | @Getter 20 | private HashMap orderMap; 21 | 22 | public OrderPool() { 23 | orders = new ArrayList<>(0); 24 | orderMap = new HashMap<>(0); 25 | } 26 | 27 | public void addDispatchingOrders(List dispatchingOrders) { 28 | this.orders.addAll(dispatchingOrders); 29 | for (Order order : orders) { 30 | orderMap.put(order.getId(), order); 31 | } 32 | } 33 | 34 | public List getDispatchingOrders() { 35 | return orders.stream().filter(o -> o.getStatus() == 0).collect(Collectors.toList()); 36 | } 37 | 38 | public void markAssignedOrder(String orderId){ 39 | orderMap.get(orderId).setStatus(1); 40 | } 41 | 42 | public void markArrivalCompleteOrder(String orderId){ 43 | orderMap.get(orderId).setStatus(2); 44 | } 45 | 46 | public void markPickCompleteOrder(String orderId){ 47 | orderMap.get(orderId).setStatus(3); 48 | } 49 | 50 | public void markDeliverCompleteOrder(String orderId){ 51 | orderMap.get(orderId).setStatus(4); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/core/route/Planner.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.core.route; 2 | 3 | import dispatch.demo.core.context.DispatchContext; 4 | import dispatch.demo.dto.ActionNode; 5 | import dispatch.demo.dto.Courier; 6 | import dispatch.demo.dto.Order; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author eleme.demo 12 | * route planner interface 13 | */ 14 | public interface Planner { 15 | 16 | /** 17 | * 路径规划 18 | * 19 | * @param courier 给定骑手 20 | * @param order 待规划的单 21 | * @param context 上下文信息 22 | * @return 骑手路径 23 | */ 24 | public List plan(Courier courier, Order order, DispatchContext context); 25 | } 26 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/core/route/TailAppendPlan.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.core.route; 2 | 3 | import dispatch.demo.core.context.DispatchContext; 4 | import dispatch.demo.dto.ActionNode; 5 | import dispatch.demo.dto.Courier; 6 | import dispatch.demo.dto.Location; 7 | import dispatch.demo.dto.Order; 8 | import dispatch.demo.utils.DistanceUtils; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | /** 15 | * @author eleme.demo 16 | * the courier always append new order to tail 17 | */ 18 | public class TailAppendPlan implements Planner { 19 | 20 | @Override 21 | public List plan(Courier courier, Order order, DispatchContext context) { 22 | Location loc; 23 | long planTime; 24 | if (courier.getOrders().isEmpty()) { 25 | loc = courier.getLoc(); 26 | planTime = context.getTimeStamp(); 27 | } else { 28 | int size = courier.getPlanRoutes().size(); 29 | ActionNode lastNode = courier.getPlanRoutes().get(size - 1); 30 | Order lastOrder = context.getOrderPool().getOrderMap().get(lastNode.getOrderId()); 31 | loc = lastOrder.getDstLoc(); 32 | planTime = lastNode.getActionTime(); 33 | } 34 | List tailPlans = planOneOrder(courier, loc, planTime, order); 35 | List appendPlans = new ArrayList<>(courier.getPlanRoutes().size() + tailPlans.size()); 36 | appendPlans.addAll(courier.getPlanRoutes()); 37 | appendPlans.addAll(tailPlans); 38 | return appendPlans; 39 | } 40 | 41 | private List planOneOrder(Courier courier, Location loc, long planTime, Order order) { 42 | long arrivalTime = planTime + DistanceUtils.timeConsuming(loc, order.getSrcLoc(), courier.getSpeed()); 43 | long pickTime = Math.max(order.getEstimatedPrepareCompletedTime(), arrivalTime); 44 | long deliverTime = pickTime + DistanceUtils.timeConsuming(order.getSrcLoc(), order.getDstLoc(), courier.getSpeed()); 45 | ActionNode arrivalNode = new ActionNode(order.getId(), 1, arrivalTime, false, planTime); 46 | ActionNode pickNode = new ActionNode(order.getId(), 2, pickTime, false, arrivalTime); 47 | ActionNode deliveryNode = new ActionNode(order.getId(), 3, deliverTime, false, pickTime); 48 | return Arrays.asList(arrivalNode, pickNode, deliveryNode); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/ActionNode.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * @author eleme.demo 10 | */ 11 | @Data 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class ActionNode { 15 | 16 | /** 运单ID */ 17 | private String orderId; 18 | 19 | /** 20 | * 1 到店完成 21 | * 2 取完成 22 | * 3 送完成 23 | */ 24 | private int actionType; 25 | 26 | /** 预计发生时刻 */ 27 | private long actionTime; 28 | 29 | /** 是否已提交 */ 30 | @JSONField(serialize = false) 31 | private boolean isSubmitted = false; 32 | 33 | /** 该动作需提交的时间,如果晚于该时间提交,可能造成评测系统判断骑手无法到达该点 */ 34 | @JSONField(serialize = false) 35 | private long needSubmitTime = -1L; 36 | 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/Courier.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.Data; 5 | import lombok.experimental.Accessors; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * @author eleme.demo 12 | */ 13 | @Data 14 | public class Courier { 15 | private String areaId; 16 | private String id; 17 | private Location loc; 18 | private Double speed; 19 | private Integer maxLoads; 20 | 21 | @JSONField(serialize = false) 22 | private List planRoutes = new ArrayList<>(0); 23 | 24 | @JSONField(serialize = false) 25 | private List orders = new ArrayList<>(0); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/CourierPlan.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | /** 10 | * @author eleme.demo 11 | */ 12 | @Data 13 | public class CourierPlan { 14 | private String courierId; 15 | private List planRoutes; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/DispatchRequest.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.Accessors; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author eleme.demo 10 | */ 11 | @Data 12 | public class DispatchRequest { 13 | private long requestTime; 14 | private String areaId; 15 | private boolean isFirstRound; 16 | private boolean isLastRound; 17 | private List couriers; 18 | private List orders; 19 | } 20 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/DispatchSolution.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author eleme.demo 9 | */ 10 | @Data 11 | public class DispatchSolution { 12 | private List courierPlans; 13 | } 14 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/Location.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author eleme.demo 7 | */ 8 | @Data 9 | public class Location { 10 | private Double latitude; 11 | private Double longitude; 12 | } 13 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/Order.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.Data; 5 | 6 | /** 7 | * @author eleme.demo 8 | */ 9 | 10 | @Data 11 | public class Order { 12 | private String areaId; 13 | private String id; 14 | private Location srcLoc; 15 | private Location dstLoc; 16 | private long createTime; 17 | private long promiseDeliverTime; 18 | private long estimatedPrepareCompletedTime; 19 | 20 | /** 21 | * 0 dispatching 22 | * 1 goingRst 23 | * 2 picking 24 | * 3 delivering 25 | * 4 complete 26 | */ 27 | @JSONField(serialize = false) 28 | int status = 0; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/dto/Response.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | 6 | /** 7 | * @author eleme.demo 8 | */ 9 | @Data 10 | public class Response { 11 | 12 | private int code; 13 | private T result; 14 | private String message; 15 | 16 | 17 | public Response(T result) { 18 | this.code = 200; 19 | this.result = result; 20 | } 21 | 22 | public Response(int code, T result, String message) { 23 | this.code = code; 24 | this.result = result; 25 | this.message = message; 26 | } 27 | 28 | public Response(int code, T result) { 29 | this.code = code; 30 | this.result = result; 31 | } 32 | 33 | public static Response NewErrResponse(String message) { 34 | return new Response(500, message); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/java/dispatch/demo/utils/DistanceUtils.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.utils; 2 | 3 | 4 | import dispatch.demo.dto.Location; 5 | 6 | /** 7 | * @author eleme.demo 8 | */ 9 | public class DistanceUtils { 10 | 11 | /** 12 | * 地球半径 13 | */ 14 | private static final double RADIUS = 6367000.0; 15 | 16 | /** 17 | * 导航距离/路面距离 经验系数 18 | */ 19 | private static final double COEFFICIENT = 1.4; 20 | 21 | 22 | public static int timeConsuming(Location from, Location to, double speed) { 23 | return (int) Math.ceil(getDistance(from, to) / speed); 24 | } 25 | 26 | /** 经验路面距离 = 球面距离 * 经验系数(1.4) */ 27 | public static double getDistance(Location from, Location to) { 28 | return greatCircleDistance(from.getLongitude(), from.getLatitude(), to.getLongitude(), to.getLatitude()) * COEFFICIENT; 29 | } 30 | 31 | /** 简化版球面距离 */ 32 | private static double greatCircleDistance(double lng1, double lat1, double lng2, double lat2) { 33 | // 经度差值 34 | double deltaLng = lng2 - lng1; 35 | // 纬度差值 36 | double deltaLat = lat2 - lat1; 37 | // 平均纬度 38 | double b = (lat1 + lat2) / 2.0; 39 | // 东西距离 40 | double x = Math.toRadians(deltaLng) * RADIUS * Math.cos(Math.toRadians(b)); 41 | // 南北距离 42 | double y = RADIUS * Math.toRadians(deltaLat); 43 | // 用平面的矩形对角距离公式计算总距离 44 | return Math.sqrt(x * x + y * y); 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/src/test/java/dispatch/dispatchdemo/DispatchDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package dispatch.dispatchdemo; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class DispatchDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/dispatch-demo/target/dispatch-demo.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200420/dispatch-demo/target/dispatch-demo.jar -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/open_test/680507/courier: -------------------------------------------------------------------------------- 1 | areaid id onlinetime maxload speed latitude longitude 2 | 680507 1715967914 1575683827 7 3.0127931733222635 40.435078000000004 102.702186 3 | 680507 1715967744 1575683767 8 2.3722593906366103 40.434919 102.702315 4 | 680507 1661678771 1575684188 10 2.5547650060659755 40.445004 102.72063 5 | 680507 116196748 1575682207 10 2.882425169609414 40.468836 102.712515 6 | 680507 1721147512 1575683407 8 2.5916427730250637 40.474717 102.700103 7 | 680507 1655005209 1575682987 8 3.3505052352121614 40.450897999999995 102.713833 8 | 680507 1691425423 1575681487 8 2.9210809228426444 40.452519 102.709094 9 | 680507 1703206249 1575681667 8 3.2195737276107717 40.452171 102.708752 10 | 680507 1334312509 1575680467 8 2.1847396267162402 40.463032 102.681313 11 | 680507 1208264316 1575684848 11 3.026112456289089 40.451155 102.707619 12 | 680507 1222639031 1575683467 8 3.546382437049226 40.450959000000005 102.713936 13 | 680507 1734975658 1575684248 3 3.704858788960522 40.438719 102.709014 14 | 680507 116322334 1575685027 11 3.13533821514342 40.451766 102.708254 15 | 680507 1672528308 1575681727 9 2.9713525964966485 40.452513 102.708735 16 | 680507 112845496 1575679027 3 3.8483245919491025 40.477753 102.69838299999999 17 | 680507 117879616 1575682507 12 2.951266669813286 40.471816 102.706665 18 | 680507 1498386500 1575684067 9 2.9499812409610935 40.450167 102.721127 19 | 680507 1641767011 1575681487 9 2.2825539266226222 40.451039 102.713886 20 | 680507 1403535350 1575682507 14 2.8481381075161396 40.476379 102.7112 21 | 680507 1691267820 1575682267 8 3.248321005542984 40.452329 102.708221 22 | 680507 115919319 1575677706 11 2.79297577504939 40.445732 102.719816 23 | 680507 1501461921 1575682807 10 3.336964136657864 40.451084 102.707528 24 | 680507 119056946 1575683347 9 2.4996290528183382 40.451015000000005 102.707634 25 | 680507 1739955571 1575683407 2 2.034439127338177 40.437531 102.71731199999999 26 | 680507 1739635429 1575680767 1 3.565758995409262 40.44531 102.72065699999999 27 | 680507 1704858710 1575678667 7 2.6817540792350334 40.445347 102.719949 28 | 680507 1260738882 1575682687 10 2.716981986023813 40.469231 102.711462 29 | 680507 118350282 1575683347 9 3.1410202954437145 40.450942 102.713872 30 | 680507 1100384890 1575678247 12 3.1739785164893477 40.432919 102.695546 31 | 680507 1243561117 1575681487 8 3.670216712496116 40.452275 102.708763 32 | 680507 1561488920 1575682987 10 2.970246575553227 40.443556 102.69686899999999 33 | 680507 1390049525 1575684367 10 2.729634861374282 40.45082 102.707702 34 | 680507 1604576185 1575677167 10 3.068057263223962 40.468577 102.721584 35 | 680507 1734008360 1575684608 5 2.8149660796620615 40.444188 102.719844 36 | 680507 1340930725 1575677647 8 3.0853481200407105 40.449676000000004 102.718729 37 | 680507 1680551613 1575684067 9 3.5419144511514684 40.467838 102.72192199999999 38 | 680507 1742712882 1575681187 1 2.469981468674661 40.445187 102.72061 39 | 680507 1663491750 1575682387 9 2.91739756865818 40.450008000000004 102.707255 40 | 680507 1646693599 1575678307 9 3.0540291748278556 40.451739 102.71054 41 | 680507 1353313828 1575679927 10 3.1144211901270675 40.422092 102.684789 42 | 680507 1724835943 1575683587 6 2.527793854772829 40.440612 102.696155 43 | 680507 1669429740 1575684308 9 2.3571432025488197 40.447069 102.706948 44 | 680507 1479565240 1575681727 10 3.8045368692139583 40.451286 102.707625 45 | 680507 1625244485 1575684067 10 3.1205103631990765 40.468387 102.72151099999999 46 | 680507 1536359470 1575681067 10 2.949029183367058 40.445296 102.720787 47 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/open_test/725011/courier: -------------------------------------------------------------------------------- 1 | areaid id onlinetime maxload speed latitude longitude 2 | 725011 1221280480 1575597549 11 3.0745467228136714 45.525371 103.662065 3 | 725011 113495157 1575591308 9 3.167722576151949 45.525573 103.648644 4 | 725011 1177503829 1575591308 12 3.6814195786682338 45.507856 103.662758 5 | 725011 1418952335 1575592808 10 3.8148912684766367 45.508578 103.648323 6 | 725011 1479538753 1575597129 11 2.832166129898812 45.54217 103.765009 7 | 725011 1622320859 1575592028 10 2.7767326358596005 45.543176 103.664697 8 | 725011 1307048619 1575594788 12 2.8811465775570624 45.507928 103.662966 9 | 725011 1657676623 1575594668 10 2.5084512136962984 45.554701 103.657823 10 | 725011 1646283965 1575591308 10 3.0709960737781836 45.517871 103.65811 11 | 725011 1246670853 1575594608 14 3.4073109270143678 45.5041 103.656093 12 | 725011 1307083020 1575591308 6 3.104167614990719 45.513523 103.646522 13 | 725011 1477839296 1575597609 11 3.1340188990585176 45.512018 103.645563 14 | 725011 1687180658 1575591308 9 3.379602154676791 45.496864 103.656408 15 | 725011 1500903736 1575591308 8 3.109008402113315 45.519959 103.637448 16 | 725011 1353832676 1575591668 12 2.9546278702091184 45.511084999999994 103.644226 17 | 725011 1469955904 1575591308 11 3.0431526726710088 45.50816 103.64672 18 | 725011 1250625037 1575591308 11 3.661297496606512 45.551017 103.658541 19 | 725011 1708425173 1575594128 7 2.8936645508515455 45.504822 103.64859100000001 20 | 725011 117244729 1575591548 8 3.745552874657883 45.507824 103.645524 21 | 725011 1622630002 1575595388 9 2.963381002287524 45.504607 103.652491 22 | 725011 1718265946 1575591908 8 3.2081500612724017 45.505793 103.648939 23 | 725011 1428083383 1575597309 13 3.4342418182588115 45.507699 103.661904 24 | 725011 1740484365 1575591308 1 3.1094414507277928 45.503514 103.663348 25 | 725011 1322529855 1575598449 9 3.4050049348521942 45.531061 103.647813 26 | 725011 1439011135 1575596649 10 3.170385812345891 45.50482 103.64859 27 | 725011 1734801322 1575591308 1 3.592799987069256 45.523335 103.648163 28 | 725011 1306666525 1575592568 11 3.059979859801288 45.531393 103.646792 29 | 725011 1584116537 1575591308 11 3.2326875812877685 45.507525 103.66171999999999 30 | 725011 114861767 1575598329 11 2.475249549190708 45.530645 103.648613 31 | 725011 1374788376 1575596349 12 3.377776328431921 45.507581 103.662041 32 | 725011 1287988348 1575602530 9 2.9140317765060852 45.527784000000004 103.661967 33 | 725011 1229044106 1575596169 6 2.261752965694964 45.512402 103.646282 34 | 725011 1680584174 1575591308 11 3.3716508780335053 45.521201 103.735459 35 | 725011 1137142537 1575598689 13 2.5892511698971408 45.541044 103.764013 36 | 725011 1642469864 1575591308 10 2.9722152944598874 45.523423 103.647972 37 | 725011 1254126910 1575591308 12 3.5647529504247255 45.507671 103.662028 38 | 725011 1237370576 1575596829 11 2.2297466450026837 45.513449 103.64869499999999 39 | 725011 1483094823 1575594908 11 3.7245840037730424 45.531253 103.64790500000001 40 | 725011 116287873 1575596349 11 2.41609808281589 45.501467 103.649249 41 | 725011 1603283203 1575595088 11 2.4171289591815524 45.508598 103.64837 42 | 725011 116752187 1575593288 11 2.856048911631838 45.520815 103.672229 43 | 725011 1495968351 1575591308 7 2.62466373517706 45.519472 103.638761 44 | 725011 1465546313 1575593828 11 2.908179066810375 45.511649 103.64427 45 | 725011 1642502425 1575600490 10 2.476718914322433 45.508105 103.646757 46 | 725011 1488524697 1575591308 7 3.1676446655060837 45.519224 103.641553 47 | 725011 115798791 1575599770 11 3.3014032247058434 45.514319 103.657326 48 | 725011 1287312067 1575591308 11 3.327427169310638 45.503823 103.66471 49 | 725011 1455084424 1575591308 11 3.1779898636537602 45.509151 103.64779 50 | 725011 1578881944 1575591308 10 3.6704894172748053 45.504233 103.655686 51 | 725011 1225769277 1575591308 11 3.242736489317296 45.530623 103.64749300000001 52 | 725011 1369995808 1575594368 9 3.0851662723791407 45.522729 103.643674 53 | 725011 1351295452 1575591308 10 3.344949353729399 45.514637 103.640763 54 | 725011 9028621 1575591308 7 3.350064118615471 45.499027000000005 103.654729 55 | 725011 1288750515 1575594548 9 2.706344400464836 45.50639 103.652383 56 | 725011 1360505717 1575594668 10 2.4994046906154845 45.554599 103.660969 57 | 725011 1387554021 1575595028 10 3.862021614383592 45.502163 103.65689300000001 58 | 725011 1244300839 1575591308 11 3.72014055841659 45.522973 103.664045 59 | 725011 115409365 1575591308 11 3.2135177692361996 45.530241 103.647946 60 | 725011 1501232069 1575591308 10 2.815186434932678 45.503602 103.656244 61 | 725011 1727665226 1575591308 4 3.050129780749418 45.527034 103.647473 62 | 725011 1307188096 1575591308 11 3.1440525066088196 45.514282 103.641467 63 | 725011 7960820 1575591728 7 3.2582422818676298 45.517493 103.665589 64 | 725011 1397564024 1575591308 13 3.4927502613980366 45.50346 103.66055 65 | 725011 1656032959 1575594428 10 3.0853410337771607 45.509891 103.647035 66 | 725011 113560243 1575594128 10 3.4392512368587513 45.509642 103.647185 67 | 725011 1718794740 1575600850 7 2.6709509184430917 45.51397 103.661188 68 | 725011 1131552518 1575597369 10 2.654692060202425 45.523501 103.657944 69 | 725011 1421636152 1575596049 10 2.3117626821830846 45.504822999999995 103.64858000000001 70 | 725011 111460869 1575591308 8 2.759435631046959 45.525423 103.648512 71 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/open_test/730221/courier: -------------------------------------------------------------------------------- 1 | areaid id onlinetime maxload speed latitude longitude 2 | 730221 1374270581 1575507758 9 3.0855756624075665 47.846135 103.45929100000001 3 | 730221 1219549877 1575511179 8 2.735835929651148 47.826640000000005 103.463714 4 | 730221 10362332 1575508418 8 3.3254622249269596 47.844551 103.393856 5 | 730221 1542508376 1575507518 10 3.1019804970568075 47.823334 103.471177 6 | 730221 1255986534 1575504878 9 2.756974127718802 47.828238 103.47454599999999 7 | 730221 116232492 1575508118 12 2.8297521465887914 47.82338 103.471088 8 | 730221 1438422421 1575509919 9 3.272551333258363 47.824993000000006 103.474819 9 | 730221 1719029443 1575507518 7 3.136633049048524 47.82363599999999 103.471125 10 | 730221 117392228 1575508778 9 3.4669860107852886 47.844689 103.459914 11 | 730221 1101190254 1575507338 10 3.8612638902439116 47.788332000000004 103.490189 12 | 730221 1533383487 1575508478 9 2.937137118458426 47.846368 103.459956 13 | 730221 116794113 1575505778 10 2.884703152256932 47.82363700000001 103.473532 14 | 730221 1303854304 1575508478 9 2.160099560075172 47.826007 103.463852 15 | 730221 1247414713 1575507578 9 2.788878708059746 47.823733 103.470837 16 | 730221 1531451263 1575509558 7 2.6897679187876915 47.823212 103.472229 17 | 730221 111342785 1575507878 9 2.957880472090308 47.836821 103.46289 18 | 730221 1682849560 1575509018 9 3.241013777926264 47.844787 103.45992 19 | 730221 1303878770 1575508598 10 3.3466503598224784 47.84734 103.461474 20 | 730221 1120065698 1575509138 9 2.7014314447421595 47.82511 103.463588 21 | 730221 10792789 1575508838 9 3.0827844146835695 47.844640000000005 103.45992 22 | 730221 117381435 1575505958 9 3.7629232745587236 47.823979 103.459474 23 | 730221 1303865484 1575506318 9 2.808289608338827 47.819551 103.465743 24 | 730221 110925020 1575509018 10 3.1668466386711596 47.84747900000001 103.460404 25 | 730221 1651978273 1575507518 8 2.4506182303580224 47.85174000000001 103.441963 26 | 730221 1164400013 1575506078 11 2.964001712330374 47.741595 103.468632 27 | 730221 1408109501 1575507158 9 3.2041788375567806 47.845499 103.459825 28 | 730221 118079460 1575509018 10 2.799603052382247 47.828739 103.47914200000001 29 | 730221 1311564690 1575504878 5 3.417007067974616 47.819253 103.4647 30 | 730221 1246047812 1575506738 11 2.958634651537811 47.84433799999999 103.394124 31 | 730221 1405204799 1575507878 9 3.036288073194167 47.837857 103.462714 32 | 730221 112555471 1575504878 11 3.058366006647499 47.821502 103.475454 33 | 730221 1519023207 1575504998 8 3.2949759474592866 47.844191 103.45954 34 | 730221 118896621 1575508538 9 2.6746718243901983 47.824197 103.47114300000001 35 | 730221 1243531992 1575504878 10 2.227462886485577 47.823415000000004 103.474312 36 | 730221 1225017311 1575509858 9 3.1169436831693504 47.824902 103.463851 37 | 730221 1150409328 1575504878 12 3.271827101878319 47.824758 103.471802 38 | 730221 117547592 1575508478 9 3.3856157294826255 47.823253 103.471598 39 | 730221 1233874607 1575504878 9 2.7118212357395577 47.823877 103.465486 40 | 730221 113850365 1575508658 10 2.189624388590529 47.843824 103.39528100000001 41 | 730221 1288945870 1575508898 11 3.098248949321933 47.824986 103.464715 42 | 730221 1303855272 1575506018 9 2.724410324420489 47.82703600000001 103.462849 43 | 730221 1436529449 1575508238 8 3.1714894832694034 47.823324 103.471049 44 | 730221 1303888099 1575508058 8 3.417693007938824 47.825124 103.486324 45 | 730221 116307064 1575508598 9 3.1963192009026438 47.824628 103.471935 46 | 730221 1300728100 1575505958 9 2.1140643596565374 47.825008000000004 103.465214 47 | 730221 7974530 1575505358 10 2.8990507440059408 47.822896 103.474005 48 | 730221 1360627504 1575508298 8 2.819111820894523 47.82342 103.470958 49 | 730221 1273313638 1575509078 8 2.5975482704031503 47.822659 103.468022 50 | 730221 1223524751 1575507638 9 3.527847028865668 47.823756 103.470972 51 | 730221 1703976777 1575504878 7 4.025214851828238 47.825114 103.46357900000001 52 | 730221 10669200 1575504878 9 3.7352047673609468 47.823370000000004 103.47205799999999 53 | 730221 1158047816 1575505598 10 2.8880841553476055 47.823678 103.475251 54 | 730221 7971553 1575506618 10 3.0950750096727178 47.825406 103.465599 55 | 730221 1118702233 1575507518 11 2.9743917491841323 47.827329999999996 103.459721 56 | 730221 116251331 1575508478 10 2.391277502357789 47.843587 103.395451 57 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | dispatch 8 | dispatch 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | dispatch-api 13 | 14 | 15 | 16 | 17 | 18 | org.projectlombok 19 | lombok 20 | 1.18.12 21 | 22 | 23 | 24 | com.alibaba 25 | fastjson 26 | 1.2.68 27 | 28 | 29 | 30 | org.slf4j 31 | slf4j-api 32 | 1.7.30 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | maven-compiler-plugin 43 | 3.1 44 | 45 | 1.8 46 | 1.8 47 | -Xlint:all 48 | -parameters 49 | true 50 | true 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Specify $JAVA_HOME as you need. 4 | if [ -z "$JAVA_HOME" ] ; then 5 | JAVA_HOME="/data/jdk11.0.2" 6 | fi 7 | 8 | echo $JAVA_HOME 9 | 10 | cd /data 11 | 12 | cpu=8 13 | GC_PARALLEL_THREAD=`expr $((cpu*5/8))` 14 | GC_CONC_THREAD=`expr $((cpu*5/8/4+1))` 15 | 16 | MEM_OPTS="-server -Xms12g -Xmx12g -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m" 17 | 18 | G1_OPTS="-XX:+UnlockExperimentalVMOptions -XX:G1RSetUpdatingPauseTimePercent=5 -XX:InitiatingHeapOccupancyPercent=33 -XX:G1NewSizePercent=35 -XX:G1MaxNewSizePercent=50 -XX:+AlwaysPreTouch -XX:-ParallelRefProcEnabled" 19 | G1_OPTS="$G1_OPTS -XX:ParallelGCThreads=$GC_PARALLEL_THREAD -XX:ConcGCThreads=$GC_CONC_THREAD" 20 | G1_OPTS="$G1_OPTS -XX:ReservedCodeCacheSize=128m -XX:+PrintCodeCache" 21 | 22 | $JAVA_HOME/bin/java $MEM_OPTS $G1_OPTS -jar dispatch-demo.jar 2>&1 & 23 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200420/start_judge.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ## Specify $JAVA_HOME as you need. 3 | if [ -z "$JAVA_HOME" ] ; then 4 | JAVA_HOME="/data/jdk11.0.2" 5 | fi 6 | 7 | echo $JAVA_HOME 8 | 9 | $JAVA_HOME/bin/java -server -Xms1g -Xmx1g -jar dispatch-judge-jar-with-dependencies.jar "$MOCK_DATA_DIR" "$API_SERVER" 10 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | __pycache__ 3 | dispatch-demo/dispatch-demo.iml 4 | dispatch-server/dispatchserver.iml 5 | dispatch-demo-py/dispatch-demo-py.iml 6 | dispatch-demo-py/venv 7 | dispatch-demo-go/dispatch-demo-go.iml 8 | target/ 9 | dispatch-api/target 10 | dispatch-demo/target 11 | dispatch-server/target 12 | *.iml 13 | dispatch-demo-go/go.sum 14 | 15 | .DS_Store 16 | dispatch-demo-py/demo/__init__.pyc 17 | dispatch-demo-py/demo/dto.pyc 18 | jdk11.tar.gz 19 | go1.14.1.linux-amd64.tar.gz 20 | dispatch-demo-py/build/ 21 | dispatch-demo-go/dispatch-demo-go 22 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-shanghai.aliyuncs.com/tcc-public/python:3 2 | #FROM registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2 3 | MAINTAINER annoymous 4 | 5 | WORKDIR / 6 | 7 | # 根据需要打包,如果你依赖的base image自身没有带jdk,需要你手动打包进去,并且在start.sh中指定$JAVA_HOME 8 | # ADD jdk11.tar.gz /data 9 | # 根据需要打包 10 | #ADD go1.14.1.linux-amd64.tar.gz /data 11 | 12 | # 安装JDK13 13 | 14 | ENV LANG=en_US.UTF-8 15 | ENV JAVA_HOME=/usr/java/openjdk-13 16 | ENV PATH=/usr/java/openjdk-13/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 17 | ENV JAVA_VERSION=13.0.2 18 | # ENV JAVA_URL=https://download.java.net/java/GA/jdk13.0.2/d4173c853231432d94f001e99d882ca7/8/GPL/openjdk-13.0.2_linux-x64_bin.tar.gz 19 | ENV JAVA_SHA256=acc7a6aabced44e62ec3b83e3b5959df2b1aa6b3d610d58ee45f0c21a7821a71 20 | COPY openjdk.tgz / 21 | RUN echo "$JAVA_SHA256 */openjdk.tgz" | sha256sum -c -; mkdir -p "$JAVA_HOME"; tar --extract --file /openjdk.tgz --directory "$JAVA_HOME" --strip-components 1; rm /openjdk.tgz; ln -sfT "$JAVA_HOME" /usr/java/default; ln -sfT "$JAVA_HOME" /usr/java/latest; java -Xshare:dump; java --version; javac --version 22 | 23 | 24 | # 根据需要编译你自己的代码,如果是java/python代码,可以本地编译之后copy进image,否则的话, 25 | # 需要在相关linux环境下编译之后copy进运行image,或者直接在下面RUN编译指令 26 | COPY dispatch-demo-py /dispatch-demo-py 27 | 28 | # 按照start.sh文件中说明,提供start.sh 脚本 29 | COPY run_py.sh / 30 | 31 | RUN cp /run_py.sh /run.sh && pip3 install flask jinja2 32 | 33 | EXPOSE 8080 34 | 35 | RUN chmod u+x /run.sh 36 | 37 | CMD ["/bin/bash","/run.sh", "jshell"] 38 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/DockerfileJ: -------------------------------------------------------------------------------- 1 | FROM registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2 2 | MAINTAINER annoymous 3 | 4 | WORKDIR / 5 | 6 | # 根据需要打包,如果你依赖的base image自身没有带jdk,需要你手动打包进去,并且在start.sh中指定$JAVA_HOME 7 | #ADD jdk11.tar.gz /data 8 | # 根据需要打包 9 | #ADD go1.14.1.linux-amd64.tar.gz /data 10 | 11 | # 根据需要编译你自己的代码,如果是java/python代码,可以本地编译之后copy进image,否则的话, 12 | # 需要在相关linux环境下编译之后copy进运行image,或者直接在下面RUN编译指令 13 | COPY dispatch-demo/target/dispatch-demo.jar / 14 | 15 | # 按照start.sh文件中说明,提供start.sh 脚本 16 | COPY run.sh / 17 | 18 | EXPOSE 8080 19 | 20 | RUN chmod u+x /run.sh 21 | 22 | CMD ["/bin/bash","/run.sh"] 23 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all build build-java build-py build-go build-image build-image-judge clean clean-java clean-py clean-go 2 | 3 | NOW=$(shell date '+%Y-%m-%d_%H:%M:%S') 4 | USER=${shell whoami} 5 | 6 | all: build 7 | 8 | build: build-java build-py build-go build-image build-image-judge 9 | 10 | clean: clean-java clean-py clean-go 11 | 12 | build-java: 13 | echo "start build java" && \ 14 | mvn -f pom.xml clean package install -DskipTests && mvn -f dispatch-demo/pom.xml clean package -DskipTests 15 | 16 | build-py: 17 | echo "start build python" && \ 18 | cd dispatch-demo-py && python setup.py build 19 | 20 | build-go: 21 | echo "start build go" && \ 22 | cd dispatch-demo-go && go build 23 | 24 | build-image: 25 | docker build -t registry.cn-shanghai.aliyuncs.com/tcc-public/${USER}:v${NOW} . 26 | 27 | build-image-judge: 28 | docker build -t registry.cn-shanghai.aliyuncs.com/tcc-public/${USER}:v${NOW} -f DockerfileJudge 29 | 30 | clean-java: 31 | mvn clean && mvn clean -f dispatch-demo/pom.xml 32 | 33 | clean-py: 34 | cd dispatch-demo-py && python setup.py clean && rm -rf dispatch_demo_py.egg-info 35 | 36 | clean-go: 37 | cd dispatch-demo-go && go mod tidy && rm -rf dispatch-demo-go 38 | 39 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200421/deploy.png -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | dispatch 7 | dispatch 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | tianchi-dispatch-api 13 | 14 | 15 | 16 | org.projectlombok 17 | lombok 18 | 19 | 20 | 21 | com.alibaba 22 | fastjson 23 | 24 | 25 | com.google.guava 26 | guava 27 | 28.1-jre 28 | 29 | 30 | org.apache.commons 31 | commons-lang3 32 | 3.9 33 | 34 | 35 | joda-time 36 | joda-time 37 | 2.10.3 38 | 39 | 40 | org.apache.httpcomponents 41 | httpclient 42 | 4.5.12 43 | 44 | 45 | org.slf4j 46 | slf4j-api 47 | 48 | 49 | ch.qos.logback 50 | logback-classic 51 | 1.2.3 52 | 53 | 54 | 55 | ch.qos.logback 56 | logback-core 57 | 1.2.3 58 | 59 | 60 | 61 | junit 62 | junit 63 | 4.12 64 | test 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.apache.maven.plugins 73 | maven-assembly-plugin 74 | 2.5.5 75 | 76 | 77 | 78 | dispatch.judge.DispatchJudge 79 | 80 | 81 | 82 | jar-with-dependencies 83 | 84 | 85 | 86 | 87 | make-assembly 88 | package 89 | 90 | single 91 | 92 | 93 | 94 | 95 | 96 | dispatch-judge 97 | 98 | 99 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/DispatchClient.java: -------------------------------------------------------------------------------- 1 | package dispatch.api; 2 | 3 | import dispatch.api.dto.DispatchRequest; 4 | import dispatch.api.dto.DispatchSolution; 5 | import dispatch.api.dto.Response; 6 | import dispatch.api.exception.DispatchException; 7 | 8 | import java.io.Closeable; 9 | 10 | /** 11 | * @author fangyu.fu 12 | */ 13 | public interface DispatchClient extends Closeable { 14 | Response dispatch(DispatchRequest dispatchRequest) throws DispatchException; 15 | 16 | Response ping() throws DispatchException; 17 | } 18 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/ActionNode.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ActionNode { 7 | private String orderId; 8 | private int actionType; 9 | private long actionTime; 10 | } 11 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/Courier.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.Accessors; 5 | 6 | 7 | @Data 8 | @Accessors(chain = true) 9 | public class Courier { 10 | private String areaId; 11 | private String id; 12 | private Location loc; 13 | private Double speed; 14 | private Integer maxLoads; 15 | } 16 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/CourierPlan.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | @Data 8 | public class CourierPlan { 9 | private String courierId; 10 | private List planRoutes; 11 | } 12 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/DispatchRequest.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.Accessors; 5 | 6 | import java.util.List; 7 | 8 | @Data 9 | @Accessors(chain = true) 10 | public class DispatchRequest { 11 | private long requestTime; 12 | private String areaId; 13 | private boolean isFirstRound; 14 | private boolean isLastRound; 15 | private List couriers; 16 | private List orders; 17 | } 18 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/DispatchSolution.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | @Data 8 | public class DispatchSolution { 9 | private List courierPlans; 10 | } 11 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/Location.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Location { 7 | private Double latitude; 8 | private Double longitude; 9 | 10 | public Location(Double latitude, Double longitude) { 11 | this.latitude = latitude; 12 | this.longitude = longitude; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/Order.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.Accessors; 5 | 6 | @Data 7 | @Accessors(chain = true) 8 | public class Order { 9 | private String areaId; 10 | private String id; 11 | private Location srcLoc; 12 | private Location dstLoc; 13 | private long createTime; 14 | private long promiseDeliverTime; 15 | private long estimatedPrepareCompletedTime; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/dto/Response.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.dto; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | 6 | @Data 7 | @NoArgsConstructor 8 | public class Response { 9 | 10 | private int code; 11 | private T result; 12 | private String message; 13 | 14 | 15 | public Response(T result) { 16 | this.code = 200; 17 | this.result = result; 18 | } 19 | 20 | public Response(int code, T result, String message) { 21 | this.code = code; 22 | this.result = result; 23 | this.message = message; 24 | } 25 | 26 | public Response(int code, T result) { 27 | this.code = code; 28 | this.result = result; 29 | } 30 | 31 | public static Response NewErrResponse(String message) { 32 | return new Response(500, message); 33 | } 34 | 35 | public static Response NewErrResponse(int code, String message) { 36 | return new Response(500, message); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/exception/DispatchException.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.exception; 2 | 3 | public class DispatchException extends Exception { 4 | public DispatchException(int code, String message) { 5 | super(message); 6 | } 7 | 8 | public DispatchException(int code, String message, Throwable t) { 9 | super(message, t); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/api/impl/HttpDispatchClientImpl.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.impl; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.TypeReference; 5 | import dispatch.api.DispatchClient; 6 | import dispatch.api.dto.DispatchRequest; 7 | import dispatch.api.dto.DispatchSolution; 8 | import dispatch.api.dto.Response; 9 | import dispatch.api.exception.DispatchException; 10 | import lombok.Data; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.apache.http.HttpStatus; 13 | import org.apache.http.client.config.RequestConfig; 14 | 15 | import java.io.Closeable; 16 | import java.io.IOException; 17 | 18 | /** 19 | * @author fangyu.fu 20 | */ 21 | @Data 22 | @Slf4j 23 | public class HttpDispatchClientImpl implements DispatchClient, Closeable { 24 | 25 | private static final String DISPATCH_PATH_V1 = "/api/v1/dispatch"; 26 | private static final String PING_PATH_V1 = "/api/v1/ping"; 27 | private static String DEFAULT_URL = "http://localhost:8080"; 28 | private HttpClientManager httpClientManager; 29 | 30 | public HttpDispatchClientImpl(String url) { 31 | httpClientManager = new HttpClientManager(url, 5000, 5000,5000,0); 32 | } 33 | 34 | public HttpDispatchClientImpl() { 35 | httpClientManager = new HttpClientManager(DEFAULT_URL, 5000, 5000, 5000, 0); 36 | } 37 | 38 | public HttpDispatchClientImpl(String url, RequestConfig requestConfig, int retry) { 39 | httpClientManager = new HttpClientManager(url, requestConfig, retry); 40 | } 41 | 42 | @Override 43 | public Response dispatch(DispatchRequest dispatchRequest) throws DispatchException { 44 | try { 45 | return httpClientManager.post(DISPATCH_PATH_V1, JSON.toJSONString(dispatchRequest), (body) -> 46 | JSON.parseObject(body, new TypeReference>() { 47 | }) 48 | ); 49 | } catch (Exception e) { 50 | log.error("", e); 51 | throw new DispatchException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e); 52 | } 53 | } 54 | 55 | @Override 56 | public Response ping() throws DispatchException { 57 | try { 58 | return httpClientManager.get(PING_PATH_V1, (body) -> 59 | JSON.parseObject(body, new TypeReference>() { 60 | }) 61 | ); 62 | } catch (Exception e) { 63 | log.error("", e); 64 | throw new DispatchException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e); 65 | } 66 | } 67 | 68 | @Override 69 | public void close() throws IOException { 70 | httpClientManager.close(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/CourierRecord.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import com.google.common.collect.Lists; 4 | import dispatch.api.dto.Courier; 5 | import dispatch.api.dto.CourierPlan; 6 | import dispatch.api.dto.Location; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | 10 | import java.util.List; 11 | 12 | @Getter 13 | public class CourierRecord { 14 | private Courier courier; 15 | @Setter 16 | private Location location; 17 | private Long courierTime; 18 | private List courierPlans; 19 | 20 | public CourierRecord(Courier courier, Long courierTime) { 21 | this.courier = courier; 22 | this.location = courier.getLoc(); 23 | this.courierTime = courierTime; 24 | this.courierPlans = Lists.newArrayList(); 25 | } 26 | 27 | public void timeChange(Long time) { 28 | if (time > courierTime) { 29 | courierTime = time; 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/DispatchJudge.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import dispatch.api.DispatchClient; 5 | import dispatch.api.impl.HttpDispatchClientImpl; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import java.io.File; 9 | import java.util.HashMap; 10 | 11 | @Slf4j 12 | public class DispatchJudge { 13 | 14 | public static void main(String[] args) { 15 | 16 | String directory = ""; 17 | String api = "http://localhost:8080"; 18 | if (args.length > 0) { 19 | directory = args[0]; 20 | log.error(String.format("Data directory is %s", directory)); 21 | } 22 | if (args.length > 1) { 23 | api = args[1]; 24 | log.error(String.format("Api is %s", api)); 25 | } 26 | File rootDirectory = new File(directory); 27 | if(!rootDirectory.isDirectory()){ 28 | log.error("Input path must be a directory."); 29 | System.exit(1); 30 | } 31 | File[] dataFiles = rootDirectory.listFiles((f)->f.isDirectory() && f.getName().matches("\\d+")); 32 | for(File dataFile:dataFiles){ 33 | String orderPath = String.format("%s/%s",dataFile.getAbsolutePath(),"order"); 34 | String courierPath = String.format("%s/%s",dataFile.getAbsolutePath(), "courier"); 35 | DispatchClient dispatchClient = new HttpDispatchClientImpl(api); 36 | // 从文件读取订单骑士数据 37 | RawData rawData = new RawData(orderPath, courierPath); 38 | 39 | SequentialJudge sequentialJudge = new SequentialJudge(dispatchClient, rawData); 40 | sequentialJudge.doDispatch(); 41 | 42 | Score score = sequentialJudge.getScore(); 43 | log.error(String.format("AreaId %s overtimeCount: %f", dataFile.getName(), score.getOvertimeCount())); 44 | log.error(String.format("AreaId %s avgDeliveryTime: %f", dataFile.getName(), score.getAvgServiceTime())); 45 | if (score.getIllegalMsg().isIllegal()) { 46 | log.error(String.format("AreaId %s error Msg %s", dataFile.getName(), score.getIllegalMsg().getMsg())); 47 | } 48 | } 49 | //Merge result 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/DispatchLog.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import dispatch.api.dto.DispatchRequest; 4 | import dispatch.api.dto.DispatchSolution; 5 | import lombok.Getter; 6 | 7 | @Getter 8 | public class DispatchLog { 9 | private DispatchRequest request; 10 | private DispatchSolution solution; 11 | 12 | public DispatchLog(DispatchRequest request, DispatchSolution solution) { 13 | this.request = request; 14 | this.solution = solution; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/IllegalMsg.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class IllegalMsg { 7 | private boolean illegal; 8 | private String msg = ""; 9 | 10 | public IllegalMsg(String msg) { 11 | this.illegal = true; 12 | this.msg = msg; 13 | } 14 | 15 | public IllegalMsg() { 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/JudgeUtil.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import dispatch.api.dto.Location; 4 | import org.joda.time.DateTime; 5 | 6 | public class JudgeUtil { 7 | /** 8 | * 地球半径 9 | */ 10 | private static final double RADIUS = 6367000.0; 11 | 12 | /** 13 | * 导航距离/路面距离 经验系数 14 | */ 15 | private static final double COEFFICIENT = 1.4; 16 | 17 | /** 经验路面距离 = 球面距离 * 经验系数(1.4) */ 18 | public static double getDistance(Location from, Location to) { 19 | return greatCircleDistance(from.getLongitude(), from.getLatitude(), to.getLongitude(), to.getLatitude()) * COEFFICIENT; 20 | } 21 | 22 | /** 简化版球面距离 */ 23 | public static double greatCircleDistance(double lng1, double lat1, double lng2, double lat2) { 24 | // 经度差值 25 | double deltaLng = lng2 - lng1; 26 | // 纬度差值 27 | double deltaLat = lat2 - lat1; 28 | // 平均纬度 29 | double b = (lat1 + lat2) / 2.0; 30 | // 东西距离 31 | double x = Math.toRadians(deltaLng) * RADIUS * Math.cos(Math.toRadians(b)); 32 | // 南北距离 33 | double y = RADIUS * Math.toRadians(deltaLat); 34 | // 用平面的矩形对角距离公式计算总距离 35 | return Math.sqrt(x * x + y * y); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/OrderRecord.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import dispatch.api.dto.Order; 4 | import lombok.Data; 5 | 6 | @Data 7 | public class OrderRecord { 8 | private Order order; 9 | private int status; 10 | private boolean overTime; 11 | private Long deliveryTime; 12 | 13 | public OrderRecord(Order order) { 14 | this.order = order; 15 | this.status = 0; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/RawData.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.google.common.collect.Maps; 5 | import dispatch.api.dto.Courier; 6 | import dispatch.api.dto.Location; 7 | import dispatch.api.dto.Order; 8 | import lombok.Getter; 9 | 10 | import java.io.File; 11 | import java.util.*; 12 | 13 | @Getter 14 | public class RawData { 15 | 16 | private String areaId; 17 | private List orders; 18 | private List couriers; 19 | private Map courierOnlineTime; 20 | 21 | public RawData(String orderFilePath, String courierFilePath) { 22 | this.orders = Lists.newArrayList(); 23 | this.couriers = Lists.newArrayList(); 24 | this.courierOnlineTime = Maps.newHashMap(); 25 | 26 | try { 27 | Scanner orderScanner = new Scanner(new File(orderFilePath)); 28 | orderScanner.nextLine(); 29 | while (orderScanner.hasNextLine()) { 30 | this.orders.add(orderLine2Order(getRecordFromLine(orderScanner.nextLine()))); 31 | } 32 | Scanner courierScanner = new Scanner(new File(courierFilePath)); 33 | courierScanner.nextLine(); 34 | while (courierScanner.hasNextLine()) { 35 | List courierLine = getRecordFromLine(courierScanner.nextLine()); 36 | this.courierOnlineTime.put(courierLine.get(1), Long.parseLong(courierLine.get(2))); 37 | this.couriers.add(courierLine2Courier(courierLine)); 38 | } 39 | } catch (Exception e) { 40 | e.printStackTrace(); 41 | } 42 | this.orders.sort(Comparator.comparingLong(Order::getCreateTime)); 43 | this.couriers.sort(Comparator.comparingLong(c -> courierOnlineTime.get(c.getId()))); 44 | this.areaId = orders.get(0).getAreaId(); 45 | } 46 | 47 | 48 | private static final String COMMA_DELIMITER = "\t"; 49 | 50 | private static List getRecordFromLine(String line) { 51 | List values = new ArrayList<>(); 52 | try (Scanner rowScanner = new Scanner(line)) { 53 | rowScanner.useDelimiter(COMMA_DELIMITER); 54 | while (rowScanner.hasNext()) { 55 | values.add(rowScanner.next()); 56 | } 57 | } 58 | return values; 59 | } 60 | 61 | private static Order orderLine2Order(List orderLine) { 62 | return new Order().setAreaId(orderLine.get(0)) 63 | .setId(orderLine.get(1)) 64 | .setCreateTime(Long.parseLong(orderLine.get(2))) 65 | .setEstimatedPrepareCompletedTime(Long.parseLong(orderLine.get(3))) 66 | .setPromiseDeliverTime(Long.parseLong(orderLine.get(4))) 67 | .setSrcLoc(new Location(Double.parseDouble(orderLine.get(5)), Double.parseDouble(orderLine.get(6)))) 68 | .setDstLoc(new Location(Double.parseDouble(orderLine.get(7)), Double.parseDouble(orderLine.get(8)))); 69 | } 70 | 71 | private static Courier courierLine2Courier(List courierLine) { 72 | return new Courier().setAreaId(courierLine.get(0)) 73 | .setId(courierLine.get(1)) 74 | .setMaxLoads(Integer.parseInt(courierLine.get(3))) 75 | .setSpeed(Double.parseDouble(courierLine.get(4))) 76 | .setLoc(new Location(Double.parseDouble(courierLine.get(5)), Double.parseDouble(courierLine.get(6)))); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/Score.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Score { 7 | private IllegalMsg illegalMsg = new IllegalMsg(); 8 | private double avgServiceTime; 9 | private double overtimeCount; 10 | private long serviceTimeSum; 11 | private long orderSum; 12 | 13 | public void setIllegalMsg(IllegalMsg illegalMsg) { 14 | this.illegalMsg = illegalMsg; 15 | } 16 | 17 | public void setIllegalMsg(String illegalMsg) { 18 | this.illegalMsg = new IllegalMsg(illegalMsg); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/main/java/dispatch/judge/SequentialJudge.java: -------------------------------------------------------------------------------- 1 | package dispatch.judge; 2 | 3 | import com.google.common.collect.Iterables; 4 | import com.google.common.collect.Lists; 5 | import com.google.common.collect.Queues; 6 | import dispatch.api.DispatchClient; 7 | import dispatch.api.dto.*; 8 | import lombok.Getter; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Queue; 13 | 14 | public class SequentialJudge { 15 | private DispatchClient dispatchClient; 16 | private int intervalSecond; 17 | 18 | private RawData rawData; 19 | private Queue orderQueue; 20 | private Queue courierQueue; 21 | 22 | private long currentTime; 23 | private long endTime; 24 | 25 | @Getter 26 | private Score score; 27 | private List dispatchLogs = new ArrayList<>(0); 28 | 29 | 30 | public SequentialJudge(DispatchClient client, RawData rawData) { 31 | this(client, rawData, 60); 32 | } 33 | 34 | public SequentialJudge(DispatchClient client, RawData rawData, int intervalSecond) { 35 | this.dispatchClient = client; 36 | this.rawData = rawData; 37 | this.intervalSecond = intervalSecond; 38 | this.orderQueue = Queues.newArrayDeque(rawData.getOrders()); 39 | this.courierQueue = Queues.newArrayDeque(rawData.getCouriers()); 40 | this.score = new Score(); 41 | 42 | this.currentTime = orderQueue.element().getCreateTime() + intervalSecond; 43 | this.endTime = Iterables.getLast(rawData.getOrders()).getCreateTime(); 44 | 45 | } 46 | 47 | public void doDispatch() { 48 | DispatchContext dispatchContext = new DispatchContext(); 49 | boolean isFirstRound = true; 50 | while (currentTime <= endTime) { 51 | DispatchRequest request = new DispatchRequest() 52 | .setAreaId(rawData.getAreaId()) 53 | .setRequestTime(currentTime); 54 | 55 | List dispatchingOrders = Lists.newArrayList(); 56 | List onlineCourier = Lists.newArrayList(); 57 | while (!orderQueue.isEmpty() && orderQueue.element().getCreateTime() <= currentTime) { 58 | dispatchingOrders.add(orderQueue.remove()); 59 | } 60 | while (!courierQueue.isEmpty() && 61 | rawData.getCourierOnlineTime().get(courierQueue.element().getId()) <= currentTime) { 62 | onlineCourier.add(courierQueue.remove()); 63 | } 64 | 65 | request.setCouriers(onlineCourier); 66 | request.setOrders(dispatchingOrders); 67 | 68 | currentTime += intervalSecond; 69 | request.setFirstRound(isFirstRound); 70 | request.setLastRound(currentTime > endTime); 71 | 72 | if (isFirstRound) { 73 | isFirstRound = false; 74 | } 75 | 76 | Response solutionResponse; 77 | try { 78 | solutionResponse = dispatchClient.dispatch(request); 79 | } catch (Exception e) { 80 | score.setIllegalMsg(e.getMessage()); 81 | return; 82 | } 83 | 84 | if (null == solutionResponse) { 85 | score.setIllegalMsg("no response"); 86 | return; 87 | } else if (solutionResponse.getCode() != 200) { 88 | score.setIllegalMsg(solutionResponse.getMessage()); 89 | return; 90 | } else { 91 | DispatchLog dispatchLog = new DispatchLog(request, solutionResponse.getResult()); 92 | this.dispatchLogs.add(dispatchLog); 93 | IllegalMsg illegalMsg = dispatchContext.allocate(dispatchLog); 94 | if (illegalMsg.isIllegal()) { 95 | score.setIllegalMsg(illegalMsg.getMsg()); 96 | return; 97 | } 98 | } 99 | } 100 | this.score = dispatchContext.checkAndScore(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-api/src/test/java/dispatch/api/impl/HttpDispatchClientImplTest.java: -------------------------------------------------------------------------------- 1 | package dispatch.api.impl; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import dispatch.api.DispatchClient; 5 | import dispatch.api.exception.DispatchException; 6 | import dispatch.judge.DispatchJudge; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.junit.AfterClass; 9 | import org.junit.BeforeClass; 10 | import org.junit.Test; 11 | 12 | import java.io.IOException; 13 | import java.util.HashMap; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | 17 | @Slf4j 18 | public class HttpDispatchClientImplTest { 19 | private static DispatchClient dispatchClient; 20 | 21 | @BeforeClass 22 | public static void init() { 23 | dispatchClient = new HttpDispatchClientImpl(); 24 | } 25 | 26 | @AfterClass 27 | public static void destroy() throws IOException { 28 | dispatchClient.close(); 29 | } 30 | 31 | @Test 32 | public void testPing() throws DispatchException, InterruptedException { 33 | log.error(String.format("%s", JSON.toJSON(new DispatchJudge()))); 34 | assertEquals(dispatchClient.ping().getResult(), "PONG"); 35 | Thread.sleep(100); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-go/dispatch/cmd.go: -------------------------------------------------------------------------------- 1 | package dispatch 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | "os" 7 | "os/signal" 8 | "syscall" 9 | ) 10 | 11 | var ( 12 | debug bool 13 | clientId string 14 | shutdownWaitSecs int 15 | ) 16 | 17 | func init() { 18 | Cmd.PersistentFlags().BoolVar(&debug, "debug", true, "debug mode") 19 | Cmd.PersistentFlags().StringVar(&clientId, "clientId", "", "Id of your tianchi account") 20 | Cmd.PersistentFlags().IntVar(&shutdownWaitSecs, "shutdownWait", 10, "shutdown wait seconds") 21 | } 22 | 23 | var ( 24 | // Cmd is the sub command for running as an api server 25 | Cmd = &cobra.Command{ 26 | Use: "run", 27 | Short: "Start player's dispatching http server at port 8080.", 28 | Long: "Start player's dispatching http server at port 8080.", 29 | Run: func(cmd *cobra.Command, args []string) { 30 | if debug { 31 | logrus.SetLevel(logrus.DebugLevel) 32 | } 33 | 34 | server, err := NewServer(shutdownWaitSecs, debug, clientId) 35 | if err != nil { 36 | logrus.Fatalf("Starting player's server failed: %v\n", err) 37 | } 38 | 39 | err = server.Start() 40 | if err != nil { 41 | logrus.Fatalf("Starting player's server failed: %v\n", err) 42 | } 43 | 44 | signals := make(chan os.Signal) 45 | signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT) 46 | <-signals 47 | err = server.Shutdown() 48 | if err != nil { 49 | logrus.Fatalf("Shutdown client server failed: %v\n", err) 50 | } 51 | }, 52 | } 53 | ) 54 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-go/dispatch/dispatcher.go: -------------------------------------------------------------------------------- 1 | package dispatch 2 | 3 | type Dispatcher interface { 4 | Ping() string 5 | Dispatch(request *DispatchRequest) ([]DispatchSolution, error) 6 | } 7 | 8 | type GreedyDispatcher struct { 9 | routes []DispatchSolution 10 | } 11 | 12 | func NewGreedyDispatcher() *GreedyDispatcher { 13 | return &GreedyDispatcher{} 14 | } 15 | 16 | func (*GreedyDispatcher) Ping() string { 17 | return "PONG" 18 | } 19 | 20 | func (*GreedyDispatcher) Dispatch(request *DispatchRequest) ([]DispatchSolution, error) { 21 | return nil, nil 22 | } 23 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-go/dispatch/dto.go: -------------------------------------------------------------------------------- 1 | package dispatch 2 | 3 | const ( 4 | Status_OK = 200 5 | Status_BAD_REQUEST = 400 6 | Status_UNKNOWN = 500 7 | Status_TIMEOUT = 510 8 | ) 9 | 10 | type ActionNode struct { 11 | OrderId string `json:"orderId"` 12 | ActionType int `json:"actionType"` 13 | ActionTimestamp int64 `json:"ActionTimestamp"` 14 | } 15 | 16 | type Location struct { 17 | Latitude float64 `json:"latitude"` 18 | Longitude float64 `json:"longitude"` 19 | } 20 | 21 | type Courier struct { 22 | AreaId string `json:"areaId"` 23 | Id string `json:"id"` 24 | Loc *Location `json:"loc"` 25 | Speed float64 `json:speed` 26 | MaxLoads int `json:"maxLoads"` 27 | } 28 | 29 | type CourierPlan struct { 30 | CourierId string `json:"courierId"` 31 | PlanRoutes []ActionNode `json:planRoutes` 32 | } 33 | 34 | type Order struct { 35 | AreaId string `json:"areaId"` 36 | Id string `json:"id"` 37 | SrcLoc *Location `json:"srcLoc"` 38 | DstLoc *Location `json:"dstLoc"` 39 | Status int `json:"status"` 40 | CreateTimestamp int64 `json:"createTimestamp"` 41 | PromiseDeliverTime int64 `json:"promiseDeliverTime"` 42 | EstimatedPrepareCompletedTimestamp int64 `json:"estimatedPrepareCompletedTimestamp"` 43 | } 44 | 45 | type DispatchRequest struct { 46 | RequestTimestamp int64 `json:"requestTimestamp"` 47 | AreaId string `json:"areaId"` 48 | IsFirstRound bool `json:"isFirstRound"` 49 | IsLastRound bool `json:"isLastRound"` 50 | Couriers []Courier `json:"couriers"` 51 | Orders []Order `json:"orders"` 52 | } 53 | 54 | type DispatchSolution struct { 55 | CourierPlans []CourierPlan `json:"courierPlans"` 56 | } 57 | 58 | type Response struct { 59 | Code int `json:"code"` 60 | Result interface{} `json:"result"` 61 | Message string `json:"message"` 62 | } 63 | 64 | func NewResponse(v interface{}) *Response { 65 | return &Response{ 66 | Code: Status_OK, 67 | Result: v, 68 | Message: "", 69 | } 70 | } 71 | 72 | func NewErrorResponse(code int, message string) *Response { 73 | return &Response{ 74 | Code: code, 75 | Message: message, 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-go/dispatch/log.go: -------------------------------------------------------------------------------- 1 | package dispatch 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/sirupsen/logrus" 6 | "io" 7 | "time" 8 | ) 9 | 10 | func Logger(writer io.Writer, debug bool) *logrus.Logger { 11 | logger := logrus.New() 12 | logger.Out = writer 13 | if debug { 14 | logger.SetLevel(logrus.DebugLevel) 15 | } 16 | return logger 17 | } 18 | 19 | func NewLogger(writer io.Writer, debug bool) gin.HandlerFunc { 20 | logger := Logger(writer, debug) 21 | return func(c *gin.Context) { 22 | // 开始时间 23 | startTime := time.Now() 24 | 25 | // 处理请求 26 | c.Next() 27 | 28 | // 结束时间 29 | endTime := time.Now() 30 | 31 | // 执行时间 32 | latencyTime := endTime.Sub(startTime) 33 | 34 | // 请求方式 35 | reqMethod := c.Request.Method 36 | 37 | // 请求路由 38 | reqUri := c.Request.RequestURI 39 | 40 | // 状态码 41 | statusCode := c.Writer.Status() 42 | 43 | // 请求IP 44 | clientIP := c.ClientIP() 45 | 46 | //日志格式 47 | logger.Infof("| %3d | %13v | %15s | %s | %s |", 48 | statusCode, 49 | latencyTime, 50 | clientIP, 51 | reqMethod, 52 | reqUri, 53 | 54 | ) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-go/dispatch/server.go: -------------------------------------------------------------------------------- 1 | package dispatch 2 | 3 | import ( 4 | "context" 5 | "github.com/gin-gonic/gin" 6 | "github.com/pkg/errors" 7 | "github.com/sirupsen/logrus" 8 | "net/http" 9 | "os" 10 | "sync" 11 | "time" 12 | ) 13 | 14 | type Server struct { 15 | closeMux *sync.Mutex 16 | port int 17 | debug bool 18 | shutdownWait int 19 | closed bool 20 | logger *logrus.Entry 21 | srv *http.Server 22 | dispatcher Dispatcher 23 | } 24 | 25 | func NewServer(shutdownWait int, debug bool, clientId string) (*Server, error) { 26 | server := &Server{ 27 | closeMux: &sync.Mutex{}, 28 | debug: debug, 29 | shutdownWait: shutdownWait, 30 | closed: false, 31 | logger: logrus.WithField("client", clientId).WithField("time", time.Now().String()), 32 | dispatcher: NewGreedyDispatcher(), 33 | } 34 | return server, nil 35 | } 36 | 37 | func (server *Server) Start() error { 38 | server.closeMux.Lock() 39 | defer server.closeMux.Unlock() 40 | if server.closed { 41 | return errors.New("Server is closed") 42 | } 43 | r := gin.New() 44 | // Add Log 45 | r.Use(NewLogger(os.Stdout, server.debug)) 46 | //Add Recovery 47 | r.Use(gin.Recovery()) 48 | 49 | v1 := r.Group("/api/v1") 50 | v1.GET("/ping", func(c *gin.Context) { 51 | server.logger.Info("") 52 | c.JSON(http.StatusOK, server.dispatcher.Ping()) 53 | }) 54 | 55 | v1.POST("/dispatch", func(c *gin.Context) { 56 | request := &DispatchRequest{} 57 | if err := c.ShouldBind(&request); err == nil { 58 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 59 | defer cancel() 60 | ch := make(chan *Response) 61 | go func() { 62 | response, errs := server.dispatcher.Dispatch(request) 63 | if errs == nil { 64 | ch <- NewResponse(response) 65 | } else { 66 | ch <- NewErrorResponse(Status_UNKNOWN, errs.Error()) 67 | } 68 | }() 69 | var response *Response 70 | for { 71 | select { 72 | case <-ctx.Done(): 73 | server.logger.Errorf("Request timeout %v",*request) 74 | c.JSON(http.StatusOK, NewErrorResponse(Status_TIMEOUT, "Dispatcher timeout")) 75 | return 76 | case response = <-ch: 77 | server.logger.Infof("Request:%s,Response:%s", *request, *response) 78 | c.JSON(http.StatusOK, response) 79 | return 80 | } 81 | } 82 | } else { 83 | response := NewErrorResponse( 84 | Status_BAD_REQUEST, "Could not resolve request body.", 85 | ) 86 | server.logger.Infof("Request:%s,Response:%s", &request, &response) 87 | c.JSON(http.StatusOK, &response) 88 | } 89 | }) 90 | srv := &http.Server{ 91 | Addr: ":8080", 92 | Handler: r, 93 | } 94 | server.srv = srv 95 | go func() { 96 | if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { 97 | server.logger.Fatalf("listen: %s\n", err) 98 | } 99 | }() 100 | return nil 101 | } 102 | 103 | func (server *Server) Shutdown() error { 104 | server.closeMux.Lock() 105 | defer server.closeMux.Unlock() 106 | if server.closed { 107 | return nil 108 | } 109 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(server.shutdownWait)) 110 | defer cancel() 111 | if err := server.srv.Shutdown(ctx); err != nil { 112 | server.logger.Fatal("Server shutdown error:", err) 113 | return err 114 | } 115 | server.closed = true 116 | server.logger.Info("Server exited") 117 | return nil 118 | } 119 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-go/go.mod: -------------------------------------------------------------------------------- 1 | module gitlab.alibaba-inc.com/fangyu.ffy/tianchi-dispatch/dispatch-demo-go 2 | 3 | require ( 4 | github.com/gin-gonic/gin v1.4.0 5 | github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect 6 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect 7 | github.com/pkg/errors v0.8.0 8 | github.com/sirupsen/logrus v1.5.0 9 | github.com/spf13/cobra v0.0.7 10 | github.com/stretchr/objx v0.1.1 // indirect 11 | github.com/stretchr/testify v1.5.1 // indirect 12 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d // indirect 13 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect 14 | gopkg.in/yaml.v2 v2.2.8 // indirect 15 | ) 16 | 17 | go 1.12 18 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-go/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | "gitlab.alibaba-inc.com/fangyu.ffy/tianchi-dispatch/dispatch-demo-go/dispatch" 7 | ) 8 | 9 | var rootCmd = &cobra.Command{ 10 | Use: "run", 11 | Short: "Tianchi&Eleme Delivery Order Dispatching Contest 2020", 12 | Long: "Tianchi&Eleme Delivery Order Dispatching Contest 2020", 13 | Run: func(cmd *cobra.Command, args []string) { 14 | cmd.Usage() 15 | }, 16 | } 17 | 18 | func init() { 19 | rootCmd.AddCommand(dispatch.Cmd) 20 | } 21 | func main() { 22 | logrus.New().Info("demo") 23 | if err := rootCmd.Execute(); err != nil { 24 | logrus.Fatalf("%v", err) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from flask import Flask, jsonify, request 4 | from demo.service import DispatchService 5 | from demo.dto import DispatchRequest, Location, Order, Courier, Response 6 | import json 7 | 8 | app = Flask(__name__) 9 | 10 | 11 | @app.route('/api/v1/ping', methods=['GET']) 12 | def ping(): 13 | pong_result = '{"code":200,"result":"PONG"}' 14 | return pong_result 15 | 16 | 17 | @app.route('/api/v1/score', methods=['GET']) 18 | def score(): 19 | score_result = '{"code":200,"result":"PONG"}' 20 | return score_result 21 | 22 | 23 | def toLocation(dct): 24 | latitude = dct['latitude'] 25 | longitude = dct['longitude'] 26 | return Location(float(latitude), float(longitude)) 27 | 28 | 29 | def toDispatchRequest(dct): 30 | courierList = dct['couriers'] 31 | courierobjs = [] 32 | for courier in courierList: 33 | areaId = courier['areaId'] 34 | id = courier['id'] 35 | loc = courier['loc'] 36 | maxLoads = courier['maxLoads'] 37 | speed = courier['speed'] 38 | courierobj = Courier(id, areaId, toLocation(loc), float(speed), int(maxLoads)) 39 | courierobjs.append(courierobj) 40 | orderList = dct['orders'] 41 | orderobjs = [] 42 | for order in orderList: 43 | areaId = order['areaId'] 44 | createTime = order['createTime'] 45 | dstLoc = order['dstLoc'] 46 | estimatedPrepareCompletedTime = order['estimatedPrepareCompletedTime'] 47 | id = order['id'] 48 | promiseDeliverTime = order['promiseDeliverTime'] 49 | srcLoc = order['srcLoc'] 50 | orderobj = Order(areaId, id, toLocation(srcLoc), toLocation(dstLoc), 0, int(createTime), 51 | int(promiseDeliverTime), int(estimatedPrepareCompletedTime)) 52 | orderobjs.append(orderobj) 53 | request = DispatchRequest(int(dct['requestTime']), dct['areaId'], bool(dct['firstRound']), bool(dct['lastRound']), 54 | courierobjs, orderobjs) 55 | return request 56 | 57 | 58 | dispatchService = DispatchService() 59 | 60 | 61 | @app.route('/api/v1/dispatch', methods=['POST']) 62 | def dispatch(): 63 | data = request.json 64 | # data is in format of demo.dto.DispatchRequest 65 | # print(data) 66 | # empty_result = """{ 67 | # "code":200, 68 | # "result":{ 69 | # "courierPlans":[] 70 | # } 71 | # }""" 72 | resultobj = dispatchService.dispatch(toDispatchRequest(data)) 73 | 74 | def outputFilter(o): 75 | is_find = False 76 | res: dict = o.__dict__ 77 | res = res.copy() 78 | for k in res.keys(): 79 | if k == "isSubmitted" or k == "needSubmitTime": 80 | is_find = True 81 | break 82 | if is_find: 83 | del res["isSubmitted"] 84 | del res["needSubmitTime"] 85 | return res 86 | 87 | result = json.dumps(resultobj.__dict__, default=outputFilter, sort_keys=False) 88 | # if result is not None: 89 | # print(result.replace(" ", "")) 90 | responseobj = Response(200, resultobj, "") 91 | response = json.dumps(responseobj.__dict__, default=outputFilter, sort_keys=False) 92 | 93 | return response.replace(" ", "") 94 | 95 | 96 | def local_start(port=8080): 97 | app.run(debug=False, port=port) 98 | 99 | 100 | if __name__ == "__main__": 101 | app.run(debug=False, port=8080) 102 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/__init__.py -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/context.py: -------------------------------------------------------------------------------- 1 | from .dto import Order, Courier, ActionNode 2 | from .pool import OrderPool, CourierPool 3 | from typing import Dict, List 4 | 5 | 6 | class DispatchContext: 7 | def __init__(self, areaId, timeStamp, isEndOfTest=False): 8 | self.areaId = areaId 9 | self.timeStamp = timeStamp 10 | self.isEndOfTest = isEndOfTest 11 | 12 | self.courierPool = CourierPool() 13 | self.orderPool = OrderPool() 14 | 15 | def setTimeStamp(self, timeStamp): 16 | self.timeStamp = timeStamp 17 | 18 | def setIsEndOfTest(self, isEndOfTest): 19 | self.isEndOfTest = isEndOfTest 20 | 21 | def addOnlineCouriers(self, courierList): 22 | self.courierPool.addOnlineCouriers(courierList) 23 | 24 | def addDispatchingOrders(self, orders): 25 | self.orderPool.addDispatchingOrders(orders) 26 | 27 | def markAllocatedOrders(self, orderIds): 28 | for orderId in orderIds: 29 | self.orderPool.markAssignedOrder(orderId) 30 | 31 | def refresh(self, refreshTime): 32 | self.timeStamp = refreshTime 33 | for courier in self.courierPool.couriers: 34 | self.refreshCourier(courier, refreshTime) 35 | 36 | def refreshCourier(self, courier: Courier, refreshTime): 37 | actionNodeList = courier.planRoutes 38 | refreshNodeList: List[ActionNode] = [] 39 | for node in actionNodeList: 40 | if node.isSubmitted and node.actionTime <= refreshTime: 41 | if node.actionType == 1: 42 | self.orderPool.markArrivalCompleteOrder(node.orderId) 43 | elif node.actionType == 2: 44 | self.orderPool.markPickCompleteOrder(node.orderId) 45 | elif node.actionType == 3: 46 | self.orderPool.markDeliverCompleteOrder(node.orderId) 47 | else: 48 | refreshNodeList.append(node) 49 | loadOrders = [order for order in courier.orders if order.status != 4] 50 | courier.orders = loadOrders 51 | courier.planRoutes = refreshNodeList 52 | if len(refreshNodeList) == 0 and len(actionNodeList) != 0: 53 | latestOrder: Order = self.orderPool.getOrder(actionNodeList[-1].orderId) 54 | courier.setLoc(latestOrder.dstLoc) 55 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/dto.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List 2 | 3 | class Location(object): 4 | def __init__(self, _latitude, _longitude): 5 | self.latitude = _latitude 6 | self.longitude = _longitude 7 | 8 | def keys(self): 9 | return ['latitude', 'longitude'] 10 | 11 | def __getitem__(self, item): 12 | return getattr(self, item) 13 | 14 | 15 | class Courier(object): 16 | def __init__(self, _id, _areaId, _loc, _speed, __maxLoads): 17 | self.id = _id 18 | self.areaId = _areaId 19 | self.loc = _loc 20 | self.speed = _speed 21 | self.maxLoads = __maxLoads 22 | 23 | self.planRoutes: List[ActionNode] = [] 24 | self.orders: List[Order] = [] 25 | 26 | def keys(self): 27 | return ['id', 'areaId', 'loc', 'speed', 'maxLoads'] 28 | 29 | def __getitem__(self, item): 30 | return getattr(self, item) 31 | 32 | def setLoc(self, loc): 33 | self.loc = loc 34 | 35 | def setsetPlanRoutes(self, _planRoutes): 36 | self.planRoutes = _planRoutes 37 | 38 | 39 | class Order(object): 40 | def __init__(self, _areaId, _id, _srcLoc, _dstLoc, _status, _createTimestamp, _promiseDeliverTime, 41 | _estimatedPrepareCompletedTime): 42 | self.areaId = _areaId 43 | self.id = _id 44 | self.srcLoc = _srcLoc 45 | self.dstLoc = _dstLoc 46 | self.status = _status 47 | self.createTimestamp = _createTimestamp 48 | self.promiseDeliverTime = _promiseDeliverTime 49 | self.estimatedPrepareCompletedTime = _estimatedPrepareCompletedTime 50 | 51 | def keys(self): 52 | return ['id', 'areaId', 'srcLoc', 'dstLoc', 'status', 53 | 'createTimestamp', 'promiseDeliverTime', 'estimatedPrepareCompletedTime'] 54 | 55 | def __getitem__(self, item): 56 | return getattr(self, item) 57 | 58 | def setStatus(self, status): 59 | self.status = status 60 | 61 | 62 | class ActionNode(object): 63 | def __init__(self, _actionType, _orderId, _actionTimestamp, _isSubmitted, _needSubmitTime): 64 | self.actionTime = _actionTimestamp 65 | self.actionType = _actionType 66 | self.orderId = _orderId 67 | if _isSubmitted is None: 68 | self.isSubmitted = False 69 | else: 70 | self.isSubmitted = _isSubmitted 71 | if _needSubmitTime is None: 72 | self.needSubmitTime = -1 73 | else: 74 | self.needSubmitTime = _needSubmitTime 75 | 76 | def keys(self): 77 | return ['actionType', 'orderId', 'actionTimestamp', 'isSubmitted', 'needSubmitTime'] 78 | 79 | def __getitem__(self, item): 80 | return getattr(self, item) 81 | 82 | def setSubmitted(self, _isSubmitted): 83 | self.isSubmitted = _isSubmitted 84 | 85 | 86 | class CourierPlan(object): 87 | def __init__(self, _courierId, _planRoutes): 88 | self.courierId = _courierId 89 | self.planRoutes: List[ActionNode] = _planRoutes 90 | 91 | def keys(self): 92 | return ['courierId', 'planRoutes'] 93 | 94 | def __getitem__(self, item): 95 | return getattr(self, item) 96 | 97 | 98 | class DispatchRequest(object): 99 | def __init__(self, _requestTimestamp, _areaId, _isFirstRound, _isLastRound, _couriers, _orders): 100 | self.requestTimestamp = _requestTimestamp 101 | self.areaId = _areaId 102 | self.isFirstRound = _isFirstRound 103 | self.isLastRound = _isLastRound 104 | self.couriers = _couriers 105 | self.orders = _orders 106 | 107 | def keys(self): 108 | return ['requestTimestamp', 'areaId', 'isFirstRound', 'isLastRound', 109 | 'couriers', 'orders'] 110 | 111 | def __getitem__(self, item): 112 | return getattr(self, item) 113 | 114 | 115 | class DispatchSolution(object): 116 | def __init__(self, _courierPlans): 117 | self.courierPlans = _courierPlans 118 | 119 | def keys(self): 120 | return ['courierPlans'] 121 | 122 | def __getitem__(self, item): 123 | return getattr(self, item) 124 | 125 | 126 | class Response(object): 127 | def __init__(self, _code, _result, _message): 128 | self.code = _code 129 | self.result = _result 130 | self.message = _message 131 | 132 | def keys(self): 133 | return ['code', 'result', 'message'] 134 | 135 | def __getitem__(self, item): 136 | return getattr(self, item) 137 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/plan.py: -------------------------------------------------------------------------------- 1 | from .dto import ActionNode, Courier, Order, Location 2 | from .context import DispatchContext 3 | from .util import DistanceUtils 4 | from typing import Dict, List 5 | 6 | 7 | class TailAppendPlan(): 8 | def plan(self, courier: Courier, order: Order, context: DispatchContext) -> List[ActionNode]: 9 | if len(courier.orders) == 0: 10 | loc = courier.loc 11 | planTime = context.timeStamp 12 | else: 13 | lastNode = courier.planRoutes[-1] 14 | lastOrder = context.orderPool.orderMap[lastNode.orderId] 15 | loc = lastOrder.dstLoc 16 | planTime = lastNode.actionTime 17 | tailPlans = self.planOneOrder(courier, loc, planTime, order) 18 | appendPlans = [] 19 | appendPlans += courier.planRoutes 20 | appendPlans += tailPlans 21 | return appendPlans 22 | 23 | def planOneOrder(self, courier: Courier, loc: Location, planTime, order: Order): 24 | distanceUtils = DistanceUtils() 25 | arrivalTime = planTime + distanceUtils.timeConsuming(loc, order.srcLoc, courier.speed) 26 | pickTime = max(order.estimatedPrepareCompletedTime, arrivalTime) 27 | deliverTime = pickTime + distanceUtils.timeConsuming(order.srcLoc, order.dstLoc, courier.speed) 28 | arrivalNode = ActionNode(1, order.id, arrivalTime, False, planTime) 29 | pickNode = ActionNode(2, order.id, pickTime, False, arrivalTime) 30 | deliveryNode = ActionNode(3, order.id, deliverTime, False, pickTime) 31 | return [arrivalNode, pickNode, deliveryNode] -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/pool.py: -------------------------------------------------------------------------------- 1 | from .dto import Order, Courier 2 | from typing import Dict, List 3 | 4 | 5 | class OrderPool: 6 | def __init__(self): 7 | self.orders: List[Order] = [] 8 | self.orderMap: Dict[str, Order] = {} 9 | 10 | def addDispatchingOrders(self, dispatchingOrders: List[Order]): 11 | self.orders = self.orders + dispatchingOrders 12 | for order in dispatchingOrders: 13 | self.orderMap[order.id] = order 14 | 15 | def getDispatchingOrders(self): 16 | return [order for order in self.orders if order.status == 0] 17 | 18 | def markAssignedOrder(self, orderId): 19 | self.orderMap.get(orderId).setStatus(1) 20 | 21 | def markArrivalCompleteOrder(self, orderId): 22 | self.orderMap.get(orderId).setStatus(2) 23 | 24 | def markPickCompleteOrder(self, orderId): 25 | self.orderMap.get(orderId).setStatus(3) 26 | 27 | def markDeliverCompleteOrder(self, orderId): 28 | self.orderMap.get(orderId).setStatus(4) 29 | 30 | def getOrder(self, orderId) -> Order: 31 | return self.orderMap.get(orderId) 32 | 33 | 34 | class CourierPool: 35 | def __init__(self): 36 | self.couriers: List[Courier] = [] 37 | 38 | def addOnlineCouriers(self, courierList: List[Courier]): 39 | self.couriers = self.couriers + courierList 40 | 41 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/service.py: -------------------------------------------------------------------------------- 1 | from .dto import DispatchRequest, DispatchSolution, ActionNode, CourierPlan 2 | from .context import DispatchContext 3 | from typing import Dict, List 4 | from .solver import BaseSolver 5 | 6 | class DispatchService: 7 | def __init__(self): 8 | self.serviceContext: Dict[str, DispatchContext] = {} 9 | 10 | def dispatch(self, request: DispatchRequest): 11 | areaId = request.areaId 12 | if request.isFirstRound: 13 | context = DispatchContext(areaId, request.requestTimestamp) 14 | self.serviceContext[areaId] = context 15 | else: 16 | context = self.serviceContext.get(areaId) 17 | if context is None: 18 | emptySolution = DispatchSolution([]) 19 | return emptySolution 20 | else: 21 | if request.isLastRound: 22 | context.setIsEndOfTest(True) 23 | context.refresh(request.requestTimestamp) 24 | 25 | context.addOnlineCouriers(request.couriers) 26 | context.addDispatchingOrders(request.orders) 27 | solver = self.getSolver(context) 28 | courierPlans = solver.solve() 29 | for cp in courierPlans: 30 | for a in cp.planRoutes: 31 | a.setSubmitted(True) 32 | assignedIds = solver.getAssignedOrderIds() 33 | context.markAllocatedOrders(assignedIds) 34 | while len(context.orderPool.getDispatchingOrders()) != 0 and context.isEndOfTest: 35 | aheadTime = 10 * 60 36 | context.setTimeStamp(context.timeStamp + aheadTime) 37 | lastRoundSolver = self.getSolver(context) 38 | tmpPlans = lastRoundSolver.solve() 39 | for cp in tmpPlans: 40 | for a in cp.planRoutes: 41 | a.setSubmitted(True) 42 | context.markAllocatedOrders(lastRoundSolver.getAssignedOrderIds()) 43 | solution = DispatchSolution(courierPlans) 44 | return solution 45 | 46 | def getSolver(self, context: DispatchContext) -> BaseSolver: 47 | return BaseSolver(context) 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/solver.py: -------------------------------------------------------------------------------- 1 | from .context import DispatchContext 2 | from .dto import Courier, Order, CourierPlan 3 | from typing import Dict, List 4 | from .plan import TailAppendPlan 5 | import sys 6 | 7 | 8 | class Cost: 9 | def __init__(self, i, j, couriers: List[Courier], orders: List[Order], context: DispatchContext): 10 | self.i = i 11 | self.j = j 12 | self.courier = couriers[i] 13 | self.order = orders[j] 14 | tailAppendPlan = TailAppendPlan() 15 | self.planActionNodes = tailAppendPlan.plan(self.courier, self.order, context) 16 | self.cost = self.calCost() 17 | 18 | def isValid(self): 19 | maxLoad = self.courier.maxLoads 20 | cr = sum([1 for order in self.courier.orders if order.status == 3]) 21 | for node in self.planActionNodes: 22 | if node.actionType == 2: 23 | cr += 1 24 | if cr > maxLoad: 25 | return False 26 | if node.actionType == 3: 27 | cr -= 1 28 | return True 29 | 30 | def calCost(self): 31 | cost = sys.float_info.max 32 | if not self.isValid(): 33 | return sys.float_info.max 34 | for node in self.planActionNodes: 35 | if node.actionType == 3 and node.orderId == self.order.id: 36 | cost = node.actionTime 37 | break 38 | return cost 39 | 40 | 41 | class BaseSolver: 42 | def __init__(self, context: DispatchContext): 43 | self.context = context 44 | self.orders = self.getCandidateOrders(context) 45 | self.couriers = self.getCandidateCouriers(context) 46 | self.ordersAssigned = [False for i in self.orders] 47 | self.costTable = [] 48 | self.MINIMUM_INTERVAL_SECONDS = 60 49 | 50 | def getCandidateCouriers(self, dispatchContext: DispatchContext): 51 | return dispatchContext.courierPool.couriers 52 | 53 | def getCandidateOrders(self, dispatchContext: DispatchContext): 54 | return dispatchContext.orderPool.getDispatchingOrders() 55 | 56 | def getAssignedOrderIds(self): 57 | return [order.id for i, order in enumerate(self.orders) if self.ordersAssigned[i]] 58 | 59 | def initTable(self): 60 | courierSize = len(self.couriers) 61 | orderSize = len(self.orders) 62 | for i in range(courierSize): 63 | costTableRow = [] 64 | for j in range(orderSize): 65 | costTableRow.append(self.getCost(i, j)) 66 | self.costTable.append(costTableRow) 67 | 68 | def solve(self) -> List[CourierPlan]: 69 | self.initTable() 70 | while True: 71 | cost = self.getBest() 72 | if cost is None: 73 | break 74 | self.dealWithCost(cost) 75 | results: List[CourierPlan] = [] 76 | for courier in self.couriers: 77 | submitPlan = self.getSubmitPlan(courier) 78 | if len(submitPlan.planRoutes) != 0: 79 | results.append(submitPlan) 80 | return results 81 | 82 | def getSubmitPlan(self, courier: Courier): 83 | submitThresholdTime = self.context.timeStamp + self.MINIMUM_INTERVAL_SECONDS 84 | submittedNodes = [node for node in courier.planRoutes if (not node.isSubmitted) and (node.needSubmitTime <= submitThresholdTime or self.context.isEndOfTest)] 85 | plan = CourierPlan(courier.id, submittedNodes) 86 | return plan 87 | 88 | def dealWithCost(self, cost: Cost): 89 | cost.courier.setsetPlanRoutes(cost.planActionNodes) 90 | cost.courier.orders.append(cost.order) 91 | self.ordersAssigned[cost.j] = True 92 | self.updateWeightRow(cost.i) 93 | self.updateWeightCol(cost.j) 94 | 95 | def updateWeightRow(self, i): 96 | for j in range(len(self.orders)): 97 | self.costTable[i][j] = self.getCost(i, j) 98 | 99 | def updateWeightCol(self, j): 100 | for i in range(len(self.couriers)): 101 | self.costTable[i][j] = self.getCost(i, j) 102 | 103 | def getBest(self): 104 | best = None 105 | courierSize = len(self.couriers) 106 | orderSize = len(self.orders) 107 | for i in range(courierSize): 108 | for j in range(orderSize): 109 | tmpC = self.costTable[i][j] 110 | if tmpC is None: 111 | continue 112 | if best is None: 113 | best = tmpC 114 | continue 115 | if self.costLess(tmpC, best): 116 | best = tmpC 117 | return best 118 | 119 | def costLess(self, c1: Cost, c2: Cost): 120 | return c1.cost <= c2.cost 121 | 122 | def getCost(self, i, j): 123 | if self.ordersAssigned[j]: 124 | return None 125 | cost = Cost(i, j, self.couriers, self.orders, self.context) 126 | if not cost.isValid(): 127 | return None 128 | return cost 129 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/demo/util.py: -------------------------------------------------------------------------------- 1 | from .dto import Location 2 | import math 3 | 4 | 5 | class DistanceUtils: 6 | def __init__(self): 7 | # 地球半径 8 | self.RADIUS = 6367000.0 9 | # 导航距离/路面距离 经验系数 10 | self.COEFFICIENT = 1.4 11 | 12 | def timeConsuming(self, fromL: Location, toL: Location, speed): 13 | return math.ceil(self.getDistance(fromL, toL) / speed) 14 | 15 | # 经验路面距离 = 球面距离 * 经验系数(1.4) 16 | def getDistance(self, fromL: Location, toL: Location): 17 | return self.greatCircleDistance(fromL.longitude, fromL.latitude, toL.longitude, toL.latitude) * self.COEFFICIENT 18 | 19 | # 简化版球面距离 20 | def greatCircleDistance(self, lng1, lat1, lng2, lat2): 21 | # 经度差值 22 | deltaLng = lng2 - lng1 23 | # 纬度差值 24 | deltaLat = lat2 - lat1 25 | # 平均纬度 26 | b = (lat1 + lat2) / 2.0 27 | # 东西距离 28 | x = math.radians(deltaLng) * self.RADIUS * math.cos(math.radians(b)) 29 | # 南北距离 30 | y = self.RADIUS * math.radians(deltaLat) 31 | # 用平面的矩形对角距离公式计算总距离 32 | return math.sqrt(x * x + y * y) -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200421/dispatch-demo-py/dispatch-judge-jar-with-dependencies.jar -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/local_judge.py: -------------------------------------------------------------------------------- 1 | import os 2 | import multiprocessing 3 | import app 4 | 5 | 6 | def run_judge(jar_path, class_path, date_path): 7 | cmd = "java -cp .:{} {} {}".format(jar_path, class_path, date_path) 8 | print(cmd) 9 | os.system(cmd) 10 | print("end judge.") 11 | 12 | 13 | if __name__ == '__main__': 14 | p = multiprocessing.Process(target=app.local_start, kwargs={'port': 8080}) 15 | p.start() 16 | run_judge("./dispatch-judge-jar-with-dependencies.jar", "dispatch.judge.DispatchJudge", "./open_test") 17 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test/680507/courier: -------------------------------------------------------------------------------- 1 | areaid id onlinetime maxload speed latitude longitude 2 | 680507 1715967914 1575683827 7 3.0127931733222635 40.435078000000004 102.702186 3 | 680507 1715967744 1575683767 8 2.3722593906366103 40.434919 102.702315 4 | 680507 1661678771 1575684188 10 2.5547650060659755 40.445004 102.72063 5 | 680507 116196748 1575682207 10 2.882425169609414 40.468836 102.712515 6 | 680507 1721147512 1575683407 8 2.5916427730250637 40.474717 102.700103 7 | 680507 1655005209 1575682987 8 3.3505052352121614 40.450897999999995 102.713833 8 | 680507 1691425423 1575681487 8 2.9210809228426444 40.452519 102.709094 9 | 680507 1703206249 1575681667 8 3.2195737276107717 40.452171 102.708752 10 | 680507 1334312509 1575680467 8 2.1847396267162402 40.463032 102.681313 11 | 680507 1208264316 1575684848 11 3.026112456289089 40.451155 102.707619 12 | 680507 1222639031 1575683467 8 3.546382437049226 40.450959000000005 102.713936 13 | 680507 1734975658 1575684248 3 3.704858788960522 40.438719 102.709014 14 | 680507 116322334 1575685027 11 3.13533821514342 40.451766 102.708254 15 | 680507 1672528308 1575681727 9 2.9713525964966485 40.452513 102.708735 16 | 680507 112845496 1575679027 3 3.8483245919491025 40.477753 102.69838299999999 17 | 680507 117879616 1575682507 12 2.951266669813286 40.471816 102.706665 18 | 680507 1498386500 1575684067 9 2.9499812409610935 40.450167 102.721127 19 | 680507 1641767011 1575681487 9 2.2825539266226222 40.451039 102.713886 20 | 680507 1403535350 1575682507 14 2.8481381075161396 40.476379 102.7112 21 | 680507 1691267820 1575682267 8 3.248321005542984 40.452329 102.708221 22 | 680507 115919319 1575677706 11 2.79297577504939 40.445732 102.719816 23 | 680507 1501461921 1575682807 10 3.336964136657864 40.451084 102.707528 24 | 680507 119056946 1575683347 9 2.4996290528183382 40.451015000000005 102.707634 25 | 680507 1739955571 1575683407 2 2.034439127338177 40.437531 102.71731199999999 26 | 680507 1739635429 1575680767 1 3.565758995409262 40.44531 102.72065699999999 27 | 680507 1704858710 1575678667 7 2.6817540792350334 40.445347 102.719949 28 | 680507 1260738882 1575682687 10 2.716981986023813 40.469231 102.711462 29 | 680507 118350282 1575683347 9 3.1410202954437145 40.450942 102.713872 30 | 680507 1100384890 1575678247 12 3.1739785164893477 40.432919 102.695546 31 | 680507 1243561117 1575681487 8 3.670216712496116 40.452275 102.708763 32 | 680507 1561488920 1575682987 10 2.970246575553227 40.443556 102.69686899999999 33 | 680507 1390049525 1575684367 10 2.729634861374282 40.45082 102.707702 34 | 680507 1604576185 1575677167 10 3.068057263223962 40.468577 102.721584 35 | 680507 1734008360 1575684608 5 2.8149660796620615 40.444188 102.719844 36 | 680507 1340930725 1575677647 8 3.0853481200407105 40.449676000000004 102.718729 37 | 680507 1680551613 1575684067 9 3.5419144511514684 40.467838 102.72192199999999 38 | 680507 1742712882 1575681187 1 2.469981468674661 40.445187 102.72061 39 | 680507 1663491750 1575682387 9 2.91739756865818 40.450008000000004 102.707255 40 | 680507 1646693599 1575678307 9 3.0540291748278556 40.451739 102.71054 41 | 680507 1353313828 1575679927 10 3.1144211901270675 40.422092 102.684789 42 | 680507 1724835943 1575683587 6 2.527793854772829 40.440612 102.696155 43 | 680507 1669429740 1575684308 9 2.3571432025488197 40.447069 102.706948 44 | 680507 1479565240 1575681727 10 3.8045368692139583 40.451286 102.707625 45 | 680507 1625244485 1575684067 10 3.1205103631990765 40.468387 102.72151099999999 46 | 680507 1536359470 1575681067 10 2.949029183367058 40.445296 102.720787 47 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test/725011/courier: -------------------------------------------------------------------------------- 1 | areaid id onlinetime maxload speed latitude longitude 2 | 725011 1221280480 1575597549 11 3.0745467228136714 45.525371 103.662065 3 | 725011 113495157 1575591308 9 3.167722576151949 45.525573 103.648644 4 | 725011 1177503829 1575591308 12 3.6814195786682338 45.507856 103.662758 5 | 725011 1418952335 1575592808 10 3.8148912684766367 45.508578 103.648323 6 | 725011 1479538753 1575597129 11 2.832166129898812 45.54217 103.765009 7 | 725011 1622320859 1575592028 10 2.7767326358596005 45.543176 103.664697 8 | 725011 1307048619 1575594788 12 2.8811465775570624 45.507928 103.662966 9 | 725011 1657676623 1575594668 10 2.5084512136962984 45.554701 103.657823 10 | 725011 1646283965 1575591308 10 3.0709960737781836 45.517871 103.65811 11 | 725011 1246670853 1575594608 14 3.4073109270143678 45.5041 103.656093 12 | 725011 1307083020 1575591308 6 3.104167614990719 45.513523 103.646522 13 | 725011 1477839296 1575597609 11 3.1340188990585176 45.512018 103.645563 14 | 725011 1687180658 1575591308 9 3.379602154676791 45.496864 103.656408 15 | 725011 1500903736 1575591308 8 3.109008402113315 45.519959 103.637448 16 | 725011 1353832676 1575591668 12 2.9546278702091184 45.511084999999994 103.644226 17 | 725011 1469955904 1575591308 11 3.0431526726710088 45.50816 103.64672 18 | 725011 1250625037 1575591308 11 3.661297496606512 45.551017 103.658541 19 | 725011 1708425173 1575594128 7 2.8936645508515455 45.504822 103.64859100000001 20 | 725011 117244729 1575591548 8 3.745552874657883 45.507824 103.645524 21 | 725011 1622630002 1575595388 9 2.963381002287524 45.504607 103.652491 22 | 725011 1718265946 1575591908 8 3.2081500612724017 45.505793 103.648939 23 | 725011 1428083383 1575597309 13 3.4342418182588115 45.507699 103.661904 24 | 725011 1740484365 1575591308 1 3.1094414507277928 45.503514 103.663348 25 | 725011 1322529855 1575598449 9 3.4050049348521942 45.531061 103.647813 26 | 725011 1439011135 1575596649 10 3.170385812345891 45.50482 103.64859 27 | 725011 1734801322 1575591308 1 3.592799987069256 45.523335 103.648163 28 | 725011 1306666525 1575592568 11 3.059979859801288 45.531393 103.646792 29 | 725011 1584116537 1575591308 11 3.2326875812877685 45.507525 103.66171999999999 30 | 725011 114861767 1575598329 11 2.475249549190708 45.530645 103.648613 31 | 725011 1374788376 1575596349 12 3.377776328431921 45.507581 103.662041 32 | 725011 1287988348 1575602530 9 2.9140317765060852 45.527784000000004 103.661967 33 | 725011 1229044106 1575596169 6 2.261752965694964 45.512402 103.646282 34 | 725011 1680584174 1575591308 11 3.3716508780335053 45.521201 103.735459 35 | 725011 1137142537 1575598689 13 2.5892511698971408 45.541044 103.764013 36 | 725011 1642469864 1575591308 10 2.9722152944598874 45.523423 103.647972 37 | 725011 1254126910 1575591308 12 3.5647529504247255 45.507671 103.662028 38 | 725011 1237370576 1575596829 11 2.2297466450026837 45.513449 103.64869499999999 39 | 725011 1483094823 1575594908 11 3.7245840037730424 45.531253 103.64790500000001 40 | 725011 116287873 1575596349 11 2.41609808281589 45.501467 103.649249 41 | 725011 1603283203 1575595088 11 2.4171289591815524 45.508598 103.64837 42 | 725011 116752187 1575593288 11 2.856048911631838 45.520815 103.672229 43 | 725011 1495968351 1575591308 7 2.62466373517706 45.519472 103.638761 44 | 725011 1465546313 1575593828 11 2.908179066810375 45.511649 103.64427 45 | 725011 1642502425 1575600490 10 2.476718914322433 45.508105 103.646757 46 | 725011 1488524697 1575591308 7 3.1676446655060837 45.519224 103.641553 47 | 725011 115798791 1575599770 11 3.3014032247058434 45.514319 103.657326 48 | 725011 1287312067 1575591308 11 3.327427169310638 45.503823 103.66471 49 | 725011 1455084424 1575591308 11 3.1779898636537602 45.509151 103.64779 50 | 725011 1578881944 1575591308 10 3.6704894172748053 45.504233 103.655686 51 | 725011 1225769277 1575591308 11 3.242736489317296 45.530623 103.64749300000001 52 | 725011 1369995808 1575594368 9 3.0851662723791407 45.522729 103.643674 53 | 725011 1351295452 1575591308 10 3.344949353729399 45.514637 103.640763 54 | 725011 9028621 1575591308 7 3.350064118615471 45.499027000000005 103.654729 55 | 725011 1288750515 1575594548 9 2.706344400464836 45.50639 103.652383 56 | 725011 1360505717 1575594668 10 2.4994046906154845 45.554599 103.660969 57 | 725011 1387554021 1575595028 10 3.862021614383592 45.502163 103.65689300000001 58 | 725011 1244300839 1575591308 11 3.72014055841659 45.522973 103.664045 59 | 725011 115409365 1575591308 11 3.2135177692361996 45.530241 103.647946 60 | 725011 1501232069 1575591308 10 2.815186434932678 45.503602 103.656244 61 | 725011 1727665226 1575591308 4 3.050129780749418 45.527034 103.647473 62 | 725011 1307188096 1575591308 11 3.1440525066088196 45.514282 103.641467 63 | 725011 7960820 1575591728 7 3.2582422818676298 45.517493 103.665589 64 | 725011 1397564024 1575591308 13 3.4927502613980366 45.50346 103.66055 65 | 725011 1656032959 1575594428 10 3.0853410337771607 45.509891 103.647035 66 | 725011 113560243 1575594128 10 3.4392512368587513 45.509642 103.647185 67 | 725011 1718794740 1575600850 7 2.6709509184430917 45.51397 103.661188 68 | 725011 1131552518 1575597369 10 2.654692060202425 45.523501 103.657944 69 | 725011 1421636152 1575596049 10 2.3117626821830846 45.504822999999995 103.64858000000001 70 | 725011 111460869 1575591308 8 2.759435631046959 45.525423 103.648512 71 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test/730221/courier: -------------------------------------------------------------------------------- 1 | areaid id onlinetime maxload speed latitude longitude 2 | 730221 1374270581 1575507758 9 3.0855756624075665 47.846135 103.45929100000001 3 | 730221 1219549877 1575511179 8 2.735835929651148 47.826640000000005 103.463714 4 | 730221 10362332 1575508418 8 3.3254622249269596 47.844551 103.393856 5 | 730221 1542508376 1575507518 10 3.1019804970568075 47.823334 103.471177 6 | 730221 1255986534 1575504878 9 2.756974127718802 47.828238 103.47454599999999 7 | 730221 116232492 1575508118 12 2.8297521465887914 47.82338 103.471088 8 | 730221 1438422421 1575509919 9 3.272551333258363 47.824993000000006 103.474819 9 | 730221 1719029443 1575507518 7 3.136633049048524 47.82363599999999 103.471125 10 | 730221 117392228 1575508778 9 3.4669860107852886 47.844689 103.459914 11 | 730221 1101190254 1575507338 10 3.8612638902439116 47.788332000000004 103.490189 12 | 730221 1533383487 1575508478 9 2.937137118458426 47.846368 103.459956 13 | 730221 116794113 1575505778 10 2.884703152256932 47.82363700000001 103.473532 14 | 730221 1303854304 1575508478 9 2.160099560075172 47.826007 103.463852 15 | 730221 1247414713 1575507578 9 2.788878708059746 47.823733 103.470837 16 | 730221 1531451263 1575509558 7 2.6897679187876915 47.823212 103.472229 17 | 730221 111342785 1575507878 9 2.957880472090308 47.836821 103.46289 18 | 730221 1682849560 1575509018 9 3.241013777926264 47.844787 103.45992 19 | 730221 1303878770 1575508598 10 3.3466503598224784 47.84734 103.461474 20 | 730221 1120065698 1575509138 9 2.7014314447421595 47.82511 103.463588 21 | 730221 10792789 1575508838 9 3.0827844146835695 47.844640000000005 103.45992 22 | 730221 117381435 1575505958 9 3.7629232745587236 47.823979 103.459474 23 | 730221 1303865484 1575506318 9 2.808289608338827 47.819551 103.465743 24 | 730221 110925020 1575509018 10 3.1668466386711596 47.84747900000001 103.460404 25 | 730221 1651978273 1575507518 8 2.4506182303580224 47.85174000000001 103.441963 26 | 730221 1164400013 1575506078 11 2.964001712330374 47.741595 103.468632 27 | 730221 1408109501 1575507158 9 3.2041788375567806 47.845499 103.459825 28 | 730221 118079460 1575509018 10 2.799603052382247 47.828739 103.47914200000001 29 | 730221 1311564690 1575504878 5 3.417007067974616 47.819253 103.4647 30 | 730221 1246047812 1575506738 11 2.958634651537811 47.84433799999999 103.394124 31 | 730221 1405204799 1575507878 9 3.036288073194167 47.837857 103.462714 32 | 730221 112555471 1575504878 11 3.058366006647499 47.821502 103.475454 33 | 730221 1519023207 1575504998 8 3.2949759474592866 47.844191 103.45954 34 | 730221 118896621 1575508538 9 2.6746718243901983 47.824197 103.47114300000001 35 | 730221 1243531992 1575504878 10 2.227462886485577 47.823415000000004 103.474312 36 | 730221 1225017311 1575509858 9 3.1169436831693504 47.824902 103.463851 37 | 730221 1150409328 1575504878 12 3.271827101878319 47.824758 103.471802 38 | 730221 117547592 1575508478 9 3.3856157294826255 47.823253 103.471598 39 | 730221 1233874607 1575504878 9 2.7118212357395577 47.823877 103.465486 40 | 730221 113850365 1575508658 10 2.189624388590529 47.843824 103.39528100000001 41 | 730221 1288945870 1575508898 11 3.098248949321933 47.824986 103.464715 42 | 730221 1303855272 1575506018 9 2.724410324420489 47.82703600000001 103.462849 43 | 730221 1436529449 1575508238 8 3.1714894832694034 47.823324 103.471049 44 | 730221 1303888099 1575508058 8 3.417693007938824 47.825124 103.486324 45 | 730221 116307064 1575508598 9 3.1963192009026438 47.824628 103.471935 46 | 730221 1300728100 1575505958 9 2.1140643596565374 47.825008000000004 103.465214 47 | 730221 7974530 1575505358 10 2.8990507440059408 47.822896 103.474005 48 | 730221 1360627504 1575508298 8 2.819111820894523 47.82342 103.470958 49 | 730221 1273313638 1575509078 8 2.5975482704031503 47.822659 103.468022 50 | 730221 1223524751 1575507638 9 3.527847028865668 47.823756 103.470972 51 | 730221 1703976777 1575504878 7 4.025214851828238 47.825114 103.46357900000001 52 | 730221 10669200 1575504878 9 3.7352047673609468 47.823370000000004 103.47205799999999 53 | 730221 1158047816 1575505598 10 2.8880841553476055 47.823678 103.475251 54 | 730221 7971553 1575506618 10 3.0950750096727178 47.825406 103.465599 55 | 730221 1118702233 1575507518 11 2.9743917491841323 47.827329999999996 103.459721 56 | 730221 116251331 1575508478 10 2.391277502357789 47.843587 103.395451 57 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/open_test_small/680507/courier: -------------------------------------------------------------------------------- 1 | areaid id onlinetime maxload speed latitude longitude 2 | 680507 1715967914 1575683827 7 3.0127931733222635 40.435078000000004 102.702186 3 | 680507 1715967744 1575683767 8 2.3722593906366103 40.434919 102.702315 4 | 680507 1661678771 1575684188 10 2.5547650060659755 40.445004 102.72063 5 | 680507 116196748 1575682207 10 2.882425169609414 40.468836 102.712515 6 | 680507 1721147512 1575683407 8 2.5916427730250637 40.474717 102.700103 7 | 680507 1655005209 1575682987 8 3.3505052352121614 40.450897999999995 102.713833 8 | 680507 1691425423 1575681487 8 2.9210809228426444 40.452519 102.709094 9 | 680507 1703206249 1575681667 8 3.2195737276107717 40.452171 102.708752 10 | 680507 1334312509 1575680467 8 2.1847396267162402 40.463032 102.681313 11 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo-py/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name="dispatch_demo_py", 5 | version="0.0.1", 6 | author="fangyu.ffy", 7 | author_email="fangyu.ffy@alibaba-inc.com", 8 | description="Tianchi-Eleme delivery order dispatch contest.", 9 | keywords="Tianchi,Eleme,Delivery,Dispatch", 10 | install_requires=['flask>=1.1.1'] 11 | 12 | ) 13 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/eleme_round2_dispatch_master_20200421/dispatch-demo/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.13.RELEASE 9 | 10 | 11 | dispatch 12 | dispatch-demo 13 | 0.0.1-SNAPSHOT 14 | dispatch-demo 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.projectlombok 24 | lombok 25 | 26 | 27 | 28 | 29 | com.alibaba 30 | fastjson 31 | 1.2.68 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-web 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-devtools 42 | runtime 43 | true 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-test 48 | test 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-maven-plugin 59 | 60 | 61 | dispatch-demo 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/DispatchDemoApplication.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author eleme.demo 8 | */ 9 | @SpringBootApplication 10 | public class DispatchDemoApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(DispatchDemoApplication.class, args); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/controller/DispatchController.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.controller; 2 | 3 | 4 | import com.alibaba.fastjson.JSON; 5 | import dispatch.demo.core.DispatchService; 6 | import dispatch.demo.dto.DispatchRequest; 7 | import dispatch.demo.dto.DispatchSolution; 8 | import dispatch.demo.dto.Response; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | import java.util.concurrent.ArrayBlockingQueue; 13 | import java.util.concurrent.Future; 14 | import java.util.concurrent.ThreadPoolExecutor; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | 18 | /** 19 | * @author eleme.demo 20 | */ 21 | @RestController() 22 | @RequestMapping("/api/v1") 23 | public class DispatchController { 24 | 25 | 26 | ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 27 | Runtime.getRuntime().availableProcessors(), 28 | Runtime.getRuntime().availableProcessors(), 29 | 30, 30 | TimeUnit.SECONDS, 31 | new ArrayBlockingQueue<>(100) 32 | ); 33 | 34 | DispatchService dispatchService = new DispatchService(); 35 | 36 | 37 | @RequestMapping(value = "/ping", method = RequestMethod.GET) 38 | public Response ping() { 39 | System.out.println("ping"); 40 | return new Response<>("PONG"); 41 | } 42 | 43 | @RequestMapping(value = "/score", method = RequestMethod.POST) 44 | public Response score(HttpServletRequest request) { 45 | System.out.println("ping"); 46 | return new Response<>("PONG"); 47 | } 48 | 49 | @RequestMapping(value = "/dispatch", method = RequestMethod.POST, produces = "application/json") 50 | public String dispatch(@RequestBody String jsonRequest) { 51 | System.out.println(jsonRequest); 52 | DispatchRequest request = JSON.parseObject(jsonRequest, DispatchRequest.class); 53 | DispatchSolution result = null; 54 | Future f = threadPoolExecutor.submit(() -> { 55 | return dispatchService.dispatch(request); 56 | }); 57 | try { 58 | //wait maximum 4s 59 | result = f.get(4, TimeUnit.SECONDS); 60 | } catch (Exception e) { 61 | System.out.println(e.getMessage()); 62 | //downgrade solution here, downgrade solution must finish within 1s so that total request processing will be finished within 5s. 63 | return JSON.toJSONString(Response.NewErrResponse(e.getMessage())); 64 | } 65 | if (null != result) { 66 | System.out.println(JSON.toJSONString(result)); 67 | } 68 | Response r = new Response(200, result); 69 | return JSON.toJSONString(r); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/core/DispatchService.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.core; 2 | 3 | import dispatch.demo.core.context.DispatchContext; 4 | import dispatch.demo.core.solver.BaseSolver; 5 | import dispatch.demo.dto.CourierPlan; 6 | import dispatch.demo.dto.DispatchRequest; 7 | import dispatch.demo.dto.DispatchSolution; 8 | 9 | import java.util.Collections; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | /** 15 | * @author eleme.demo 16 | */ 17 | public class DispatchService { 18 | 19 | Map serviceContext = new HashMap<>(0); 20 | 21 | public DispatchSolution dispatch(DispatchRequest request) { 22 | String areaId = request.getAreaId(); 23 | DispatchContext context; 24 | if (request.isFirstRound()) { 25 | context = new DispatchContext(); 26 | context.setAreaId(areaId); 27 | context.setTimeStamp(request.getRequestTime()); 28 | serviceContext.put(areaId, context); 29 | } else { 30 | context = serviceContext.get(areaId); 31 | if (null == context) { 32 | DispatchSolution emptySolution = new DispatchSolution(); 33 | emptySolution.setCourierPlans(Collections.emptyList()); 34 | return emptySolution; 35 | } else { 36 | if (request.isLastRound()) { 37 | context.setEndOfTest(true); 38 | } 39 | } 40 | context.refresh(request.getRequestTime()); 41 | } 42 | context.addOnlineCouriers(request.getCouriers()); 43 | context.addDispatchingOrders(request.getOrders()); 44 | BaseSolver solver = getSolver(context); 45 | List courierPlans = solver.solve(); 46 | courierPlans.forEach(cp -> { 47 | cp.getPlanRoutes().forEach(a -> a.setSubmitted(true)); 48 | }); 49 | List assignedIds = solver.getAssignedOrderIds(); 50 | context.markAllocatedOrders(assignedIds); 51 | while (!context.getOrderPool().getDispatchingOrders().isEmpty() && context.isEndOfTest()) { 52 | long aheadTime = 10 * 60; 53 | context.setTimeStamp(context.getTimeStamp() + aheadTime); 54 | BaseSolver lastRoundSolver = getSolver(context); 55 | List tmpPlans = lastRoundSolver.solve(); 56 | courierPlans.addAll(tmpPlans); 57 | tmpPlans.forEach(cp -> { 58 | cp.getPlanRoutes().forEach(a -> a.setSubmitted(true)); 59 | }); 60 | context.markAllocatedOrders(lastRoundSolver.getAssignedOrderIds()); 61 | } 62 | DispatchSolution solution = new DispatchSolution(); 63 | solution.setCourierPlans(courierPlans); 64 | return solution; 65 | } 66 | 67 | BaseSolver getSolver(DispatchContext context) { 68 | return new BaseSolver(context); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/core/context/DispatchContext.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.core.context; 2 | 3 | import dispatch.demo.core.pool.CourierPool; 4 | import dispatch.demo.core.pool.OrderPool; 5 | import dispatch.demo.dto.ActionNode; 6 | import dispatch.demo.dto.Courier; 7 | import dispatch.demo.dto.Location; 8 | import dispatch.demo.dto.Order; 9 | import lombok.Data; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | /** 16 | * @author eleme.demo 17 | */ 18 | @Data 19 | public class DispatchContext { 20 | private String areaId; 21 | private CourierPool courierPool = new CourierPool(); 22 | private OrderPool orderPool = new OrderPool(); 23 | private long timeStamp; 24 | private boolean isEndOfTest = false; 25 | 26 | public void addOnlineCouriers(List courierList) { 27 | courierPool.getCouriers().addAll(courierList); 28 | } 29 | 30 | public void addDispatchingOrders(List orders) { 31 | orderPool.addDispatchingOrders(orders); 32 | } 33 | 34 | public void markAllocatedOrders(List orderIds) { 35 | orderIds.forEach(id -> orderPool.markAssignedOrder(id)); 36 | } 37 | 38 | public void refresh(long refreshTime) { 39 | this.timeStamp = refreshTime; 40 | courierPool.getCouriers().forEach(c -> { 41 | refreshCourier(c, refreshTime); 42 | }); 43 | } 44 | 45 | private void refreshCourier(Courier courier, long refreshTime) { 46 | List actionNodeList = courier.getPlanRoutes(); 47 | List refreshNodeList = new ArrayList<>(0); 48 | for (ActionNode node : actionNodeList) { 49 | if (node.isSubmitted() && node.getActionTime() <= refreshTime) { 50 | if (node.getActionType() == 1) { 51 | //到店完成 52 | orderPool.markArrivalCompleteOrder(node.getOrderId()); 53 | } 54 | if (node.getActionType() == 2) { 55 | //取餐完成 56 | orderPool.markPickCompleteOrder(node.getOrderId()); 57 | } 58 | if (node.getActionType() == 3) { 59 | //送达 60 | orderPool.markDeliverCompleteOrder(node.getOrderId()); 61 | } 62 | } else { 63 | refreshNodeList.add(node); 64 | } 65 | } 66 | List loadOrders = courier.getOrders().stream() 67 | .filter(o -> o.getStatus() != 4) 68 | .collect(Collectors.toList()); 69 | courier.setOrders(loadOrders); 70 | courier.setPlanRoutes(refreshNodeList); 71 | if(refreshNodeList.isEmpty() && !actionNodeList.isEmpty()){ 72 | Location latestLoc = orderPool.getOrderMap().get(actionNodeList.get(actionNodeList.size()-1).getOrderId()).getDstLoc(); 73 | courier.setLoc(latestLoc); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/core/pool/CourierPool.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.core.pool; 2 | 3 | import dispatch.demo.dto.Courier; 4 | import lombok.Data; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * @author eleme.demo 11 | */ 12 | @Data 13 | public class CourierPool { 14 | private List couriers = new ArrayList<>(0); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/core/pool/OrderPool.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.core.pool; 2 | 3 | import dispatch.demo.dto.Order; 4 | import lombok.Getter; 5 | 6 | import java.util.ArrayList; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | /** 12 | * @author eleme.demo 13 | */ 14 | 15 | public class OrderPool { 16 | 17 | private List orders; 18 | 19 | @Getter 20 | private HashMap orderMap; 21 | 22 | public OrderPool() { 23 | orders = new ArrayList<>(0); 24 | orderMap = new HashMap<>(0); 25 | } 26 | 27 | public void addDispatchingOrders(List dispatchingOrders) { 28 | this.orders.addAll(dispatchingOrders); 29 | for (Order order : orders) { 30 | orderMap.put(order.getId(), order); 31 | } 32 | } 33 | 34 | public List getDispatchingOrders() { 35 | return orders.stream().filter(o -> o.getStatus() == 0).collect(Collectors.toList()); 36 | } 37 | 38 | public void markAssignedOrder(String orderId){ 39 | orderMap.get(orderId).setStatus(1); 40 | } 41 | 42 | public void markArrivalCompleteOrder(String orderId){ 43 | orderMap.get(orderId).setStatus(2); 44 | } 45 | 46 | public void markPickCompleteOrder(String orderId){ 47 | orderMap.get(orderId).setStatus(3); 48 | } 49 | 50 | public void markDeliverCompleteOrder(String orderId){ 51 | orderMap.get(orderId).setStatus(4); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/core/route/Planner.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.core.route; 2 | 3 | import dispatch.demo.core.context.DispatchContext; 4 | import dispatch.demo.dto.ActionNode; 5 | import dispatch.demo.dto.Courier; 6 | import dispatch.demo.dto.Order; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author eleme.demo 12 | * route planner interface 13 | */ 14 | public interface Planner { 15 | 16 | /** 17 | * 路径规划 18 | * 19 | * @param courier 给定骑手 20 | * @param order 待规划的单 21 | * @param context 上下文信息 22 | * @return 骑手路径 23 | */ 24 | public List plan(Courier courier, Order order, DispatchContext context); 25 | } 26 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/core/route/TailAppendPlan.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.core.route; 2 | 3 | import dispatch.demo.core.context.DispatchContext; 4 | import dispatch.demo.dto.ActionNode; 5 | import dispatch.demo.dto.Courier; 6 | import dispatch.demo.dto.Location; 7 | import dispatch.demo.dto.Order; 8 | import dispatch.demo.utils.DistanceUtils; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | /** 15 | * @author eleme.demo 16 | * the courier always append new order to tail 17 | */ 18 | public class TailAppendPlan implements Planner { 19 | 20 | @Override 21 | public List plan(Courier courier, Order order, DispatchContext context) { 22 | Location loc; 23 | long planTime; 24 | if (courier.getOrders().isEmpty()) { 25 | loc = courier.getLoc(); 26 | planTime = context.getTimeStamp(); 27 | } else { 28 | int size = courier.getPlanRoutes().size(); 29 | ActionNode lastNode = courier.getPlanRoutes().get(size - 1); 30 | Order lastOrder = context.getOrderPool().getOrderMap().get(lastNode.getOrderId()); 31 | loc = lastOrder.getDstLoc(); 32 | planTime = lastNode.getActionTime(); 33 | } 34 | List tailPlans = planOneOrder(courier, loc, planTime, order); 35 | List appendPlans = new ArrayList<>(courier.getPlanRoutes().size() + tailPlans.size()); 36 | appendPlans.addAll(courier.getPlanRoutes()); 37 | appendPlans.addAll(tailPlans); 38 | return appendPlans; 39 | } 40 | 41 | private List planOneOrder(Courier courier, Location loc, long planTime, Order order) { 42 | long arrivalTime = planTime + DistanceUtils.timeConsuming(loc, order.getSrcLoc(), courier.getSpeed()); 43 | long pickTime = Math.max(order.getEstimatedPrepareCompletedTime(), arrivalTime); 44 | long deliverTime = pickTime + DistanceUtils.timeConsuming(order.getSrcLoc(), order.getDstLoc(), courier.getSpeed()); 45 | ActionNode arrivalNode = new ActionNode(order.getId(), 1, arrivalTime, false, planTime); 46 | ActionNode pickNode = new ActionNode(order.getId(), 2, pickTime, false, arrivalTime); 47 | ActionNode deliveryNode = new ActionNode(order.getId(), 3, deliverTime, false, pickTime); 48 | return Arrays.asList(arrivalNode, pickNode, deliveryNode); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/ActionNode.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * @author eleme.demo 10 | */ 11 | @Data 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class ActionNode { 15 | 16 | /** 运单ID */ 17 | private String orderId; 18 | 19 | /** 20 | * 1 到店完成 21 | * 2 取完成 22 | * 3 送完成 23 | */ 24 | private int actionType; 25 | 26 | /** 预计发生时刻 */ 27 | private long actionTime; 28 | 29 | /** 是否已提交 */ 30 | @JSONField(serialize = false) 31 | private boolean isSubmitted = false; 32 | 33 | /** 该动作需提交的时间,如果晚于该时间提交,可能造成评测系统判断骑手无法到达该点 */ 34 | @JSONField(serialize = false) 35 | private long needSubmitTime = -1L; 36 | 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/Courier.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.Data; 5 | import lombok.experimental.Accessors; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * @author eleme.demo 12 | */ 13 | @Data 14 | public class Courier { 15 | private String areaId; 16 | private String id; 17 | private Location loc; 18 | private Double speed; 19 | private Integer maxLoads; 20 | 21 | @JSONField(serialize = false) 22 | private List planRoutes = new ArrayList<>(0); 23 | 24 | @JSONField(serialize = false) 25 | private List orders = new ArrayList<>(0); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/CourierPlan.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | /** 10 | * @author eleme.demo 11 | */ 12 | @Data 13 | public class CourierPlan { 14 | private String courierId; 15 | private List planRoutes; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/DispatchRequest.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.Accessors; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author eleme.demo 10 | */ 11 | @Data 12 | public class DispatchRequest { 13 | private long requestTime; 14 | private String areaId; 15 | private boolean isFirstRound; 16 | private boolean isLastRound; 17 | private List couriers; 18 | private List orders; 19 | } 20 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/DispatchSolution.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author eleme.demo 9 | */ 10 | @Data 11 | public class DispatchSolution { 12 | private List courierPlans; 13 | } 14 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/Location.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author eleme.demo 7 | */ 8 | @Data 9 | public class Location { 10 | private Double latitude; 11 | private Double longitude; 12 | } 13 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/Order.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.Data; 5 | 6 | /** 7 | * @author eleme.demo 8 | */ 9 | 10 | @Data 11 | public class Order { 12 | private String areaId; 13 | private String id; 14 | private Location srcLoc; 15 | private Location dstLoc; 16 | private long createTime; 17 | private long promiseDeliverTime; 18 | private long estimatedPrepareCompletedTime; 19 | 20 | /** 21 | * 0 dispatching 22 | * 1 goingRst 23 | * 2 picking 24 | * 3 delivering 25 | * 4 complete 26 | */ 27 | @JSONField(serialize = false) 28 | int status = 0; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/dto/Response.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.dto; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | 6 | /** 7 | * @author eleme.demo 8 | */ 9 | @Data 10 | public class Response { 11 | 12 | private int code; 13 | private T result; 14 | private String message; 15 | 16 | 17 | public Response(T result) { 18 | this.code = 200; 19 | this.result = result; 20 | } 21 | 22 | public Response(int code, T result, String message) { 23 | this.code = code; 24 | this.result = result; 25 | this.message = message; 26 | } 27 | 28 | public Response(int code, T result) { 29 | this.code = code; 30 | this.result = result; 31 | } 32 | 33 | public static Response NewErrResponse(String message) { 34 | return new Response(500, message); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/java/dispatch/demo/utils/DistanceUtils.java: -------------------------------------------------------------------------------- 1 | package dispatch.demo.utils; 2 | 3 | 4 | import dispatch.demo.dto.Location; 5 | 6 | /** 7 | * @author eleme.demo 8 | */ 9 | public class DistanceUtils { 10 | 11 | /** 12 | * 地球半径 13 | */ 14 | private static final double RADIUS = 6367000.0; 15 | 16 | /** 17 | * 导航距离/路面距离 经验系数 18 | */ 19 | private static final double COEFFICIENT = 1.4; 20 | 21 | 22 | public static int timeConsuming(Location from, Location to, double speed) { 23 | return (int) Math.ceil(getDistance(from, to) / speed); 24 | } 25 | 26 | /** 经验路面距离 = 球面距离 * 经验系数(1.4) */ 27 | public static double getDistance(Location from, Location to) { 28 | return greatCircleDistance(from.getLongitude(), from.getLatitude(), to.getLongitude(), to.getLatitude()) * COEFFICIENT; 29 | } 30 | 31 | /** 简化版球面距离 */ 32 | private static double greatCircleDistance(double lng1, double lat1, double lng2, double lat2) { 33 | // 经度差值 34 | double deltaLng = lng2 - lng1; 35 | // 纬度差值 36 | double deltaLat = lat2 - lat1; 37 | // 平均纬度 38 | double b = (lat1 + lat2) / 2.0; 39 | // 东西距离 40 | double x = Math.toRadians(deltaLng) * RADIUS * Math.cos(Math.toRadians(b)); 41 | // 南北距离 42 | double y = RADIUS * Math.toRadians(deltaLat); 43 | // 用平面的矩形对角距离公式计算总距离 44 | return Math.sqrt(x * x + y * y); 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/dispatch-demo/src/test/java/dispatch/dispatchdemo/DispatchDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package dispatch.dispatchdemo; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class DispatchDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | dispatch 8 | dispatch 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | dispatch-api 13 | tianchi-dispatch-evaluate 14 | 15 | 16 | 17 | 18 | 19 | org.projectlombok 20 | lombok 21 | 1.18.12 22 | 23 | 24 | 25 | com.alibaba 26 | fastjson 27 | 1.2.68 28 | 29 | 30 | 31 | org.slf4j 32 | slf4j-api 33 | 1.7.30 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | maven-compiler-plugin 44 | 3.1 45 | 46 | 1.8 47 | 1.8 48 | -Xlint:all 49 | -parameters 50 | true 51 | true 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Specify $JAVA_HOME as you need. 4 | if [ -z "$JAVA_HOME" ] ; then 5 | JAVA_HOME="/data/jdk11.0.2" 6 | fi 7 | 8 | echo $JAVA_HOME 9 | 10 | cd /data 11 | 12 | cpu=8 13 | GC_PARALLEL_THREAD=`expr $((cpu*5/8))` 14 | GC_CONC_THREAD=`expr $((cpu*5/8/4+1))` 15 | 16 | MEM_OPTS="-server" 17 | 18 | G1_OPTS="-XX:+UnlockExperimentalVMOptions -XX:G1RSetUpdatingPauseTimePercent=5 -XX:InitiatingHeapOccupancyPercent=33 -XX:G1NewSizePercent=35 -XX:G1MaxNewSizePercent=50 -XX:+AlwaysPreTouch -XX:-ParallelRefProcEnabled" 19 | G1_OPTS="$G1_OPTS -XX:ParallelGCThreads=$GC_PARALLEL_THREAD -XX:ConcGCThreads=$GC_CONC_THREAD" 20 | G1_OPTS="$G1_OPTS -XX:ReservedCodeCacheSize=128m -XX:+PrintCodeCache" 21 | 22 | $JAVA_HOME/bin/java $MEM_OPTS $G1_OPTS -jar dispatch-demo.jar 2>&1 & 23 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/run_py.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Specify $JAVA_HOME as you need. 4 | if [ -z "$JAVA_HOME" ] ; then 5 | JAVA_HOME="/data/jdk-11.0.2" 6 | fi 7 | export JAVA_HOME 8 | cd dispatch-demo-py 9 | 10 | export FLASK_APP=app.py 11 | flask run -p 8080 & 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/run_py_dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Specify $JAVA_HOME as you need. 4 | if [ -z "$JAVA_HOME" ] ; then 5 | JAVA_HOME="/data/jdk-11.0.2" 6 | fi 7 | export JAVA_HOME 8 | cd dispatch-demo-py 9 | 10 | export FLASK_APP=app.py 11 | flask run -p 8080 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /eleme_round2_dispatch_master_20200421/start_judge.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ## Specify $JAVA_HOME as you need. 3 | if [ -z "$JAVA_HOME" ] ; then 4 | JAVA_HOME="/data/jdk11.0.2" 5 | fi 6 | 7 | echo $JAVA_HOME 8 | 9 | $JAVA_HOME/bin/java -server -Xms1g -Xmx1g -jar dispatch-judge-jar-with-dependencies.jar "$MOCK_DATA_DIR" "$API_SERVER" 10 | -------------------------------------------------------------------------------- /复赛 Baseline 流程部署分享/Screen Shot 2020-04-21 at 6.06.29 AM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/复赛 Baseline 流程部署分享/Screen Shot 2020-04-21 at 6.06.29 AM.png -------------------------------------------------------------------------------- /复赛 Baseline 流程部署分享/Screen Shot 2020-04-21 at 6.55.34 AM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/复赛 Baseline 流程部署分享/Screen Shot 2020-04-21 at 6.55.34 AM.png -------------------------------------------------------------------------------- /复赛 Baseline 流程部署分享/deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NorwinYu/eleme_round2_baseline_py/a202cefd8266668d50619b7c98a8956ad112d014/复赛 Baseline 流程部署分享/deploy.png --------------------------------------------------------------------------------