def __init__(self, initial_time: int, time_interval: int,
                 id_to_order: dict, id_to_vehicle: dict, id_to_factory: dict,
                 route_map):
        """
        :param initial_time: unix timestamp, unit is second
        :param time_interval: unit is second
        :param id_to_order: 所有订单集合, total orders
        :param id_to_vehicle: 所有车辆, total vehicles
        :param id_to_factory: 工厂信息, total factories
        :param route_map: 路网信息
        """
        self.initial_time = initial_time
        self.time_interval = time_interval
        self.cur_time = initial_time
        self.pre_time = initial_time

        self.id_to_order = id_to_order
        # item list of total orders, used for order splitting
        self.id_to_order_item = get_item_dict_from_order_dict(id_to_order)
        self.id_to_vehicle = id_to_vehicle
        self.id_to_factory = id_to_factory
        self.route_map = route_map

        # 不同状态的订单, order with different status
        self.id_to_generated_order_item = {}  # state = 1
        self.id_to_ongoing_order_item = {}  # state = 2
        self.id_to_completed_order_item = {}  # state = 3

        # 车辆运行模拟器, simulate the vehicle status and order fulfillment in a given time interval [pre_time, cur_time]
        self.vehicle_simulator = VehicleSimulator(route_map, id_to_factory)

        # 每次派单结果的存档, save each dispatch result from the algorithm
        self.time_to_dispatch_result = {}

        # 历史记录保存, save the visited nodes of vehicles and different status of orders for evaluation
        self.history = self.__ini_history()

        # 目标函数值, objective
        self.total_score = sys.maxsize

        # 算法调用命令
        self.algorithm_calling_command = ''
class SimulateEnvironment(object):
    def __init__(self, initial_time: int, time_interval: int,
                 id_to_order: dict, id_to_vehicle: dict, id_to_factory: dict,
                 route_map):
        """
        :param initial_time: unix timestamp, unit is second
        :param time_interval: unit is second
        :param id_to_order: 所有订单集合, total orders
        :param id_to_vehicle: 所有车辆, total vehicles
        :param id_to_factory: 工厂信息, total factories
        :param route_map: 路网信息
        """
        self.initial_time = initial_time
        self.time_interval = time_interval
        self.cur_time = initial_time
        self.pre_time = initial_time

        self.id_to_order = id_to_order
        # item list of total orders, used for order splitting
        self.id_to_order_item = get_item_dict_from_order_dict(id_to_order)
        self.id_to_vehicle = id_to_vehicle
        self.id_to_factory = id_to_factory
        self.route_map = route_map

        # 不同状态的订单, order with different status
        self.id_to_generated_order_item = {}  # state = 1
        self.id_to_ongoing_order_item = {}  # state = 2
        self.id_to_completed_order_item = {}  # state = 3

        # 车辆运行模拟器, simulate the vehicle status and order fulfillment in a given time interval [pre_time, cur_time]
        self.vehicle_simulator = VehicleSimulator(route_map, id_to_factory)

        # 每次派单结果的存档, save each dispatch result from the algorithm
        self.time_to_dispatch_result = {}

        # 历史记录保存, save the visited nodes of vehicles and different status of orders for evaluation
        self.history = self.__ini_history()

        # 目标函数值, objective
        self.total_score = -1

    # 初始化历史记录
    def __ini_history(self):
        history = History()
        for vehicle_id, vehicle in self.id_to_vehicle.items():
            history.add_vehicle_position_history(vehicle_id,
                                                 vehicle.gps_update_time,
                                                 vehicle.cur_factory_id)
        for item_id, item in self.id_to_order_item.items():
            history.add_order_item_status_history(
                item.id, item.delivery_state, self.initial_time,
                item.committed_completion_time, item.order_id)
        return history

    # 模拟器仿真环节
    def run(self):
        used_seconds = 0
        # 迭代
        while True:
            logger.info(f"{'*' * 50}")

            # 确定当前时间, 取算法执行时间和模拟器的切片时间的大值
            self.cur_time = self.pre_time + (
                used_seconds // self.time_interval + 1) * self.time_interval
            logger.info(
                f"cur time: {datetime.datetime.fromtimestamp(self.cur_time)}, "
                f"pre time: {datetime.datetime.fromtimestamp(self.pre_time)}")

            # update the status of vehicles and orders in a given interval [self.pre_time, self.cur_time]
            updated_input_info = self.update_input()

            # 派单环节, 设计与算法交互
            used_seconds, dispatch_result = self.dispatch(updated_input_info)
            self.time_to_dispatch_result[self.cur_time] = dispatch_result

            # 校验, 车辆目的地不能改变
            if not Checker.check_dispatch_result(
                    dispatch_result, self.id_to_vehicle, self.id_to_order):
                logger.error("Dispatch result is infeasible")
                sys.exit(-1)

            # 根据派单指令更新车辆
            self.deliver_control_command_to_vehicles(dispatch_result)

            # 判断是否完成所有订单的派发
            if self.complete_the_dispatch_of_all_orders():
                break

            self.pre_time = self.cur_time

            # 若订单已经超时, 但是算法依旧未分配, 模拟终止
            if self.ignore_allocating_timeout_orders(dispatch_result):
                break

        # 模拟完成车辆剩下的订单
        self.simulate_the_left_ongoing_orders_of_vehicles(self.id_to_vehicle)

        # 根据self.history 计算指标
        self.total_score = Evaluator.calculate_total_score(
            self.history, self.route_map, len(self.id_to_vehicle))

    # 数据更新
    def update_input(self):
        logger.info(
            f"Start to update the input of {datetime.datetime.fromtimestamp(self.cur_time)}"
        )

        # 获取车辆的位置信息和订单状态
        # Get the updated status of vehicles and orders according to the simulator
        self.vehicle_simulator.run(self.id_to_vehicle, self.pre_time)
        self.vehicle_simulator.parse_simulation_result(self.id_to_vehicle,
                                                       self.pre_time,
                                                       self.cur_time)
        # 增加历史记录, add history
        self.history.add_history_of_vehicles(self.id_to_vehicle, self.cur_time)
        self.history.add_history_of_order_items(self.id_to_vehicle,
                                                self.cur_time)

        # 更新订单状态
        self.update_status_of_orders(self.vehicle_simulator.completed_item_ids,
                                     self.vehicle_simulator.ongoing_item_ids)

        # 更新车辆状态
        self.update_status_of_vehicles(
            self.vehicle_simulator.vehicle_id_to_cur_position_info,
            self.vehicle_simulator.vehicle_id_to_destination,
            self.vehicle_simulator.vehicle_id_to_carrying_items)

        # 根据当前时间选择待分配订单的物料集合
        # Select the item collection of the orders to be allocated according to the current time
        self.id_to_generated_order_item = get_order_items_to_be_dispatched_of_cur_time(
            self.id_to_order_item, self.cur_time)

        # 汇总车辆、订单和路网信息, 作为派单算法的输入
        # create the input of algorithm
        updated_input_info = InputInfo(self.id_to_generated_order_item,
                                       self.id_to_ongoing_order_item,
                                       self.id_to_vehicle, self.id_to_factory,
                                       self.route_map)
        logger.info(
            f"Get {len(self.id_to_generated_order_item)} unallocated order items, "
            f"{len(self.id_to_ongoing_order_item)} ongoing order items, "
            f"{len(self.id_to_completed_order_item)} completed order items")

        return updated_input_info

    # 更新订单状态
    def update_status_of_orders(self, completed_item_ids, ongoing_item_ids):
        for item_id in completed_item_ids:
            item = self.id_to_order_item.get(item_id)
            if item is not None:
                if item_id not in self.id_to_completed_order_item:
                    self.id_to_completed_order_item[item_id] = item
                    item.delivery_state = Configs.ORDER_STATUS_TO_CODE.get(
                        "COMPLETED")

        for item_id in ongoing_item_ids:
            item = self.id_to_order_item.get(item_id)
            if item is not None:
                if item_id not in self.id_to_ongoing_order_item:
                    self.id_to_ongoing_order_item[item_id] = item
                    item.delivery_state = Configs.ORDER_STATUS_TO_CODE.get(
                        "ONGOING")

        # remove expired items
        expired_item_id_list = []
        for item_id, item in self.id_to_ongoing_order_item.items():
            if item.delivery_state > Configs.ORDER_STATUS_TO_CODE.get(
                    "ONGOING"):
                expired_item_id_list.append(item_id)
        for item_id in expired_item_id_list:
            self.id_to_ongoing_order_item.pop(item_id)

    # 更新车辆状态
    def update_status_of_vehicles(self, vehicle_id_to_cur_position_info,
                                  vehicle_id_to_destination,
                                  vehicle_id_to_carry_items):
        for vehicle_id, vehicle in self.id_to_vehicle.items():
            if vehicle_id in vehicle_id_to_cur_position_info:
                cur_position_info = vehicle_id_to_cur_position_info.get(
                    vehicle_id)
                vehicle.set_cur_position_info(
                    cur_position_info.get("cur_factory_id"),
                    cur_position_info.get("update_time"),
                    cur_position_info.get("arrive_time_at_current_factory"),
                    cur_position_info.get("leave_time_at_current_factory"))
            else:
                logger.error(
                    f"Vehicle {vehicle_id} does not have updated position information"
                )

            if vehicle_id in vehicle_id_to_destination:
                vehicle.destination = vehicle_id_to_destination.get(vehicle_id)
            else:
                logger.error(
                    f"Vehicle {vehicle_id} does not have the destination information"
                )

            if vehicle_id in vehicle_id_to_carry_items:
                vehicle.carrying_items = vehicle_id_to_carry_items.get(
                    vehicle_id)
            else:
                logger.error(
                    f"Vehicle {vehicle_id} does not have the information of carrying items"
                )

            vehicle.planned_route = []

    # 派单环节
    def dispatch(self, input_info):
        # 1. Prepare the input json of the algorithm
        convert_input_info_to_json_files(input_info)

        # 2. Run the algorithm
        command = get_algorithm_calling_command()
        time_start_algorithm = time.time()
        used_seconds, message = subprocess_function(command)

        # 3. parse the output json of the algorithm
        if Configs.ALGORITHM_SUCCESS_FLAG in message:
            if (time_start_algorithm < os.stat(
                    Configs.algorithm_output_destination_path).st_mtime <
                    time.time() and time_start_algorithm < os.stat(
                        Configs.algorithm_output_planned_route_path).st_mtime <
                    time.time()):
                vehicle_id_to_destination, vehicle_id_to_planned_route = get_output_of_algorithm(
                    self.id_to_order_item)
                dispatch_result = DispatchResult(vehicle_id_to_destination,
                                                 vehicle_id_to_planned_route)
                return used_seconds, dispatch_result
            else:
                logger.error('output.json is not the newest')
                sys.exit(-1)
        else:
            logger.error(message)
            raise ValueError('未寻获算法输出成功标识SUCCESS')

    # 判断是否完成所有订单的派发
    def complete_the_dispatch_of_all_orders(self):
        for item in self.id_to_order_item.values():
            if item.delivery_state <= 1:
                logger.info(
                    f"{datetime.datetime.fromtimestamp(self.cur_time)}, Item {item.id}: "
                    f"state = {item.delivery_state} < 2, we can not finish the simulation"
                )
                return False
        logger.info(
            f"{datetime.datetime.fromtimestamp(self.cur_time)}, the status of all items is greater than 1, "
            f"we could finish the simulation")
        return True

    # 把车辆身上的剩余订单模拟掉
    def simulate_the_left_ongoing_orders_of_vehicles(self,
                                                     id_to_vehicle: dict):
        self.vehicle_simulator.run(id_to_vehicle, self.cur_time)
        self.history.add_history_of_vehicles(self.id_to_vehicle)
        self.history.add_history_of_order_items(self.id_to_vehicle)

    def deliver_control_command_to_vehicles(self, dispatch_result):
        vehicle_id_to_destination = dispatch_result.vehicle_id_to_destination
        vehicle_id_to_planned_route = dispatch_result.vehicle_id_to_planned_route

        for vehicle_id, vehicle in self.id_to_vehicle.items():
            if vehicle_id not in vehicle_id_to_destination:
                logger.error(
                    f"algorithm does not output the destination of vehicle {vehicle_id}"
                )
                continue
            if vehicle_id not in vehicle_id_to_planned_route:
                logger.error(
                    f"algorithm does not output the planned route of vehicle {vehicle_id}"
                )
                continue
            vehicle.destination = vehicle_id_to_destination.get(vehicle_id)
            if vehicle.destination is not None:
                vehicle.destination.update_service_time()
            vehicle.planned_route = vehicle_id_to_planned_route.get(vehicle_id)
            for node in vehicle.planned_route:
                if node is not None:
                    node.update_service_time()

    # 检查当前是否有订单已经超时却依旧未分配
    def ignore_allocating_timeout_orders(self, dispatch_result):
        vehicle_id_to_item_list = get_item_list_of_vehicles(
            dispatch_result, self.id_to_vehicle)
        total_item_ids_in_dispatch_result = []
        for vehicle_id, item_list in vehicle_id_to_item_list.items():
            for item in item_list:
                if item.id not in total_item_ids_in_dispatch_result:
                    total_item_ids_in_dispatch_result.append(item.id)

        for item_id, item in self.id_to_generated_order_item.items():
            if item_id not in total_item_ids_in_dispatch_result:
                if item.committed_completion_time < self.cur_time:
                    logger.error(
                        f"{datetime.datetime.fromtimestamp(self.cur_time)}, Item {item_id} has timed out, "
                        f"however it is still ignored in the dispatch result")
                    return True
        return False