From 2fa19599467263dcf582bb12906e03328e03b4a4 Mon Sep 17 00:00:00 2001 From: zhang <zc857179121@qq.com> Date: 星期三, 02 七月 2025 13:12:26 +0800 Subject: [PATCH] 初版提交 --- config/environment.py | 360 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 360 insertions(+), 0 deletions(-) diff --git a/config/environment.py b/config/environment.py new file mode 100644 index 0000000..47f42d0 --- /dev/null +++ b/config/environment.py @@ -0,0 +1,360 @@ +""" +鐜閰嶇疆妯″潡 - 璐熻矗瀹氫箟鍔犺浇浠撳簱鐜閰嶇疆 +""" +import json +from enum import Enum, auto +import numpy as np +from typing import Dict, List, Tuple, Optional, Union + + +class CellType(Enum): + """鍗曞厓鏍肩被鍨嬫灇涓�""" + EMPTY = auto() # 绌哄崟鍏冩牸 + STATION = auto() # 绔欑偣 + PATH = auto() # 璺緞 + STORAGE = auto() # 浠撳偍鍖哄煙 + OBSTACLE = auto() # 闅滅鐗� + LOADING = auto() # 瑁呰浇鍖� + UNLOADING = auto() # 鍗歌浇鍖� + + +class EnvironmentConfig: + """鐜閰嶇疆绫�""" + + def __init__(self, width: int, height: int): + """鍒濆鍖栫幆澧冮厤缃�""" + self.width = width + self.height = height + # 鍒濆鍖栨墍鏈夊崟鍏冩牸涓虹┖ + self.grid = np.full((height, width), CellType.EMPTY) + # 绔欑偣浣嶇疆鍙婂叾閰嶇疆 + self.stations = {} # 鏍煎紡: {(x, y): {"capacity": 4, "load_position": (x-1, y), "unload_position": (x+1, y)}} + # 璺緞鐐逛綅缃� + self.paths = set() # 鏍煎紡: {(x1, y1), (x2, y2), ...} + # 浠撳偍鍖哄煙浣嶇疆 + self.storage_areas = set() # 鏍煎紡: {(x1, y1), (x2, y2), ...} + # 瑁呭嵏鍖轰綅缃� + self.loading_areas = set() # 鏍煎紡: {(x1, y1), (x2, y2), ...} + self.unloading_areas = set() # 鏍煎紡: {(x1, y1), (x2, y2), ...} + # 闅滅鐗╀綅缃� + self.obstacles = set() # 鏍煎紡: {(x1, y1), (x2, y2), ...} + # 缃戞牸鐐归偦鎺ヨ〃锛堢敤浜庤矾寰勮鍒掞級 + self.adjacency_list = {} # 鏍煎紡: {(x1, y1): {(x2, y2): distance, ...}, ...} + + def set_cell_type(self, x: int, y: int, cell_type: CellType) -> bool: + """ + 璁剧疆鍗曞厓鏍肩被鍨� + + Args: + x: x鍧愭爣 + y: y鍧愭爣 + cell_type: 鍗曞厓鏍肩被鍨� + + Returns: + bool: 璁剧疆鏄惁鎴愬姛 + """ + if 0 <= x < self.width and 0 <= y < self.height: + self.grid[y, x] = cell_type + + # 鏍规嵁鍗曞厓鏍肩被鍨嬫洿鏂扮浉搴旂殑闆嗗悎 + pos = (x, y) + if cell_type == CellType.PATH: + self.paths.add(pos) + elif cell_type == CellType.STATION: + if pos not in self.stations: + self.stations[pos] = { + "capacity": 4, # 榛樿瀹归噺 + "load_position": (x-1, y), # 榛樿鍔犺浇浣嶇疆 + "unload_position": (x+1, y) # 榛樿鍗歌浇浣嶇疆 + } + elif cell_type == CellType.STORAGE: + self.storage_areas.add(pos) + elif cell_type == CellType.LOADING: + self.loading_areas.add(pos) + elif cell_type == CellType.UNLOADING: + self.unloading_areas.add(pos) + elif cell_type == CellType.OBSTACLE: + self.obstacles.add(pos) + + return True + return False + + def add_station(self, x: int, y: int, capacity: int = 4, + load_position: Tuple[int, int] = None, + unload_position: Tuple[int, int] = None) -> bool: + """ + 娣诲姞绔欑偣 + + Args: + x: 绔欑偣x鍧愭爣 + y: 绔欑偣y鍧愭爣 + capacity: 绔欑偣瀹归噺 + load_position: 鍔犺浇浣嶇疆 + unload_position: 鍗歌浇浣嶇疆 + + Returns: + bool: 娣诲姞鏄惁鎴愬姛 + """ + if 0 <= x < self.width and 0 <= y < self.height: + # 璁剧疆榛樿鐨勮鍗镐綅缃� + if load_position is None: + load_position = (x-1, y) # 宸︿晶涓哄嵏鏂欑浣嶇疆 + if unload_position is None: + unload_position = (x+1, y) # 鍙充晶涓哄彇鏂欑浣嶇疆 + + # 鏇存柊缃戞牸鍜岀珯鐐逛俊鎭� + self.grid[y, x] = CellType.STATION + self.stations[(x, y)] = { + "capacity": capacity, + "load_position": load_position, + "unload_position": unload_position + } + + # 纭繚瑁呭嵏浣嶇疆涔熻鏍囪 + self.set_cell_type(load_position[0], load_position[1], CellType.LOADING) + self.set_cell_type(unload_position[0], unload_position[1], CellType.UNLOADING) + + return True + return False + + def add_path(self, x: int, y: int) -> bool: + """ + 娣诲姞璺緞鐐� + + Args: + x: x鍧愭爣 + y: y鍧愭爣 + + Returns: + bool: 娣诲姞鏄惁鎴愬姛 + """ + return self.set_cell_type(x, y, CellType.PATH) + + def add_storage_area(self, x: int, y: int) -> bool: + """ + 娣诲姞浠撳偍鍖哄煙 + + Args: + x: x鍧愭爣 + y: y鍧愭爣 + + Returns: + bool: 娣诲姞鏄惁鎴愬姛 + """ + return self.set_cell_type(x, y, CellType.STORAGE) + + def add_obstacle(self, x: int, y: int) -> bool: + """ + 娣诲姞闅滅鐗� + + Args: + x: x鍧愭爣 + y: y鍧愭爣 + + Returns: + bool: 娣诲姞鏄惁鎴愬姛 + """ + return self.set_cell_type(x, y, CellType.OBSTACLE) + + def is_valid_position(self, x: int, y: int) -> bool: + """ + 妫�鏌ヤ綅缃槸鍚﹀悎娉曪紙鍦ㄧ綉鏍煎唴涓旈潪闅滅鐗╋級 + + Args: + x: x鍧愭爣 + y: y鍧愭爣 + + Returns: + bool: 浣嶇疆鏄惁鍚堟硶 + """ + return (0 <= x < self.width and + 0 <= y < self.height and + self.grid[y, x] != CellType.OBSTACLE) + + def build_adjacency_list(self): + """鏋勫缓缃戞牸鐐归偦鎺ヨ〃锛堢敤浜庤矾寰勮鍒掞級""" + # 娓呯┖鐜版湁閭绘帴琛� + self.adjacency_list = {} + + # AGV杩涜鍥涙柟鍚戠Щ鍔� + directions = [ + (0, 1), # 涓� + (1, 0), # 鍙� + (0, -1), # 涓� + (-1, 0) # 宸� + ] + + # 涓烘瘡涓矾寰勭偣鏋勫缓閭绘帴琛� + for x, y in self.paths: + if (x, y) not in self.adjacency_list: + self.adjacency_list[(x, y)] = {} + + # 妫�鏌ュ洓涓柟鍚戠殑閭诲眳 + for dx, dy in directions: + nx, ny = x + dx, y + dy + # 妫�鏌ョ浉閭荤偣鏄惁涓烘湁鏁堣矾寰勭偣 + if (nx, ny) in self.paths: + # 绉诲姩璺濈缁熶竴涓�1.0 + distance = 1.0 + self.adjacency_list[(x, y)][(nx, ny)] = distance + + # 娣诲姞绔欑偣鐨勮鍗哥偣鍒伴偦鎺ヨ〃 + for station_pos, station_info in self.stations.items(): + load_pos = station_info["load_position"] + unload_pos = station_info["unload_position"] + + # 纭繚瑁呭嵏鐐瑰凡娣诲姞鍒伴偦鎺ヨ〃 + if load_pos not in self.adjacency_list: + self.adjacency_list[load_pos] = {} + if unload_pos not in self.adjacency_list: + self.adjacency_list[unload_pos] = {} + + # 杩炴帴瑁呭嵏鐐瑰埌鏈�杩戠殑璺緞鐐� + for pos in [load_pos, unload_pos]: + # 鎵惧埌鏈�杩戠殑璺緞鐐瑰苟杩炴帴 + min_dist = float('inf') + nearest_path = None + + for path_pos in self.paths: + dist = ((pos[0] - path_pos[0]) ** 2 + (pos[1] - path_pos[1]) ** 2) ** 0.5 + if dist < min_dist: + min_dist = dist + nearest_path = path_pos + + if nearest_path: + self.adjacency_list[pos][nearest_path] = min_dist + self.adjacency_list[nearest_path][pos] = min_dist + + def save_to_file(self, filepath: str): + """ + 灏嗙幆澧冮厤缃繚瀛樺埌鏂囦欢 + + Args: + filepath: 鏂囦欢璺緞 + """ + config_data = { + "width": self.width, + "height": self.height, + "stations": {f"{x},{y}": info for (x, y), info in self.stations.items()}, + "paths": [{"x": x, "y": y} for x, y in self.paths], + "storage_areas": [{"x": x, "y": y} for x, y in self.storage_areas], + "loading_areas": [{"x": x, "y": y} for x, y in self.loading_areas], + "unloading_areas": [{"x": x, "y": y} for x, y in self.unloading_areas], + "obstacles": [{"x": x, "y": y} for x, y in self.obstacles] + } + + with open(filepath, 'w') as f: + json.dump(config_data, f, indent=2) + + @classmethod + def load_from_file(cls, filepath: str) -> 'EnvironmentConfig': + """ + 浠庢枃浠跺姞杞界幆澧冮厤缃� + + Args: + filepath: 鏂囦欢璺緞 + + Returns: + EnvironmentConfig: 鐜閰嶇疆瀵硅薄 + """ + with open(filepath, 'r') as f: + config_data = json.load(f) + + env_config = cls(config_data["width"], config_data["height"]) + + # 鍔犺浇绔欑偣 + for pos_str, info in config_data["stations"].items(): + x, y = map(int, pos_str.split(',')) + load_x, load_y = info["load_position"] + unload_x, unload_y = info["unload_position"] + env_config.add_station(x, y, info["capacity"], + (load_x, load_y), (unload_x, unload_y)) + + # 鍔犺浇璺緞 + for path in config_data["paths"]: + env_config.add_path(path["x"], path["y"]) + + # 鍔犺浇浠撳偍鍖哄煙 + for area in config_data["storage_areas"]: + env_config.add_storage_area(area["x"], area["y"]) + + # 鍔犺浇闅滅鐗� + for obstacle in config_data["obstacles"]: + env_config.add_obstacle(obstacle["x"], obstacle["y"]) + + # 鏋勫缓閭绘帴琛� + env_config.build_adjacency_list() + + return env_config + + def create_default_environment(self) -> 'EnvironmentConfig': + """ + 鍒涘缓榛樿鐜閰嶇疆锛堟寜鐓ч渶姹傛弿杩伴厤缃珯鐐瑰拰璺緞锛� + + Returns: + EnvironmentConfig: 鐜閰嶇疆瀵硅薄 + """ + # 娓呯┖褰撳墠閰嶇疆 + self.grid = np.full((self.height, self.width), CellType.EMPTY) + self.stations = {} + self.paths = set() + self.storage_areas = set() + self.loading_areas = set() + self.unloading_areas = set() + self.obstacles = set() + + # 閰嶇疆20涓珯鐐� + station_y = self.height - 5 + station_spacing = self.width // 25 # 绔欑偣闂磋窛 + + for i in range(20): + station_x = (i + 1) * station_spacing + self.add_station(station_x, station_y) + + # 浠撳偍鍖哄煙 + storage_start_y = 5 + storage_end_y = station_y - 10 + + for col in range(5): + col_x = (col + 1) * (self.width // 6) + + for row_y in range(storage_start_y, storage_end_y, 5): + for dx in range(-1, 2): + for dy in range(-1, 2): + self.add_storage_area(col_x + dx, row_y + dy) + + # 閰嶇疆璺緞 + # 姘村钩涓昏矾寰� + for x in range(5, self.width - 5): + # 绔欑偣鍓嶆按骞宠矾寰� + self.add_path(x, station_y - 5) + # 璐ф灦鍖哄煙姘村钩璺緞 + for path_y in range(10, storage_end_y, 10): + self.add_path(x, path_y) + + # 鍨傜洿杩炴帴璺緞 + for col in range(7): + path_x = col * (self.width // 7) + for y in range(5, station_y): + self.add_path(path_x, y) + + # 鏋勫缓閭绘帴琛� + self.build_adjacency_list() + + return self + + +# 鍒涘缓鍜屽垵濮嬪寲榛樿鐜鐨勮緟鍔╁嚱鏁� +def create_default_environment(width=100, height=100) -> EnvironmentConfig: + """ + 鍒涘缓榛樿鐜閰嶇疆 + + Args: + width: 鐜瀹藉害 + height: 鐜楂樺害 + + Returns: + EnvironmentConfig: 榛樿鐜閰嶇疆 + """ + env_config = EnvironmentConfig(width, height) + return env_config.create_default_environment() \ No newline at end of file -- Gitblit v1.9.1