华为软件精英挑战赛——普朗克计划
2024华为软件精英挑战赛——普朗克计划
赛题:https://bbs.huaweicloud.com/forum/thread-0209145106256505005-1-1.html
解题思路
题目概括:地图随机生成价值不等的货物,控制10个机器人收集货物到港口;地图中会有10个固定港口存储机器人的货物,控制5艘轮船前往港口搬运货物到销售处获得金额。
我们队伍的思路是设计多个模块,运动模块控制机器人运动,包括上下左右、搬运、放等动作;目标选择模块帮助机器人选择目标货物和目标港口;路径规划模块帮助机器人进行路径查找;初始化模块获取初始化地图信息,预先查找部分路径和获取机器人状态;运输模块控制船收集买卖货物;防碰撞模块避免多个机器人之间互相碰撞与撞死;
具体实现
一、初始化模块
与判题器交互采用标准输入输出,在初始化阶段,我们获取地图信息,包括:障碍物、船、机器人、港口、机器人状态等信息。
def Init():
for i in range(0, map_size):
line = sys.stdin.readline().strip()
ch.append(list(line))
# line = input()
# ch.append([c for c in line.split(sep=" ")]) # 读取地图
for i in range(berth_num):
line = input()
berth_list = [int(c) for c in line.split(sep=" ")]
id = berth_list[0]
berths[id].x = berth_list[1]
berths[id].y = berth_list[2]
berths[id].transport_time = berth_list[3]
if berths[id].transport_time > 1500:
berth_final.append(id)
berths[id].choose=1
# None
berths[id].loading_speed = berth_list[4] #初始化泊位
boat_capacity = int(input()) #初始化轮船容积
okk = input() #初始化完成,读取ok
#确定船的坐标
for i in range(berth_num):
berth_x=berths[i].x
berth_y=berths[i].y
berth_con=[(berth_x,berth_y),(berth_x,berth_y+3),(berth_x+3,berth_y),(berth_x+3,berth_y+3)]
berth_nums=[]
index = 0
for con in berth_con:
nums = 0
for x in range(-1,2):
for y in range(-1,2):
if x==0 and y==0:
continue
xx = con[0]+x;
yy = con[1]+y;
if min(xx,yy) >= 0 and max(xx,yy) <= 199 and ch[xx][yy] == '.':
nums = nums+1
berth_nums.append([index , nums])
index = index + 1
sorted_num = sorted(berth_nums, key=lambda x : x[1] , reverse=True)
point_1 = berth_con[sorted_num[0][0]]
point_2 = berth_con[sorted_num[1][0]]
berths[i].x = (point_1[0]+point_2[0])//2
berths[i].y = (point_1[1]+point_2[1])//2
obstacles=get_obstacles(ch)
# print(obstacles,file=sys.stderr)
for obstacle in obstacles:
obstacles_set.add(Node(obstacle[0],obstacle[1]))
return obstacles ,boat_capacity
二、目标选择模块
2.1 定义状态表
总共10个机器人,每个机器人有7个信息需要存储:目标货物的x坐标、目标货物的y坐标、目标港口的id、机器人此时的状态位(0表示闲置、1表示确定目标货物,需要寻找路径、2表示正在前往目标货物、3表示已经取到货物,需要搜索目标港口的路径、4表示正在前往目标港口)、目标货物的价格、该机器人是否是初始的机器人、上一次的目标港口。
target_table = np.zeros((10,7),dtype=int)
target_table[:,6] = -1 #最初所有机器人都是初始机器人,当机器人完成第一次寻路之后即不是初始机器人
2.2 定义策略
选择货物的衡量标准是单位时间获得的金额大小即:$p=\frac{货物价值}{初始点到货物的距离+货物到港口的距离}$
公式中的距离我们采用真实距离,即真实路径的长度。但是如果是初始化的机器人,我们不采用真实路径长短,初始的货物很少,只要是机器人可达货物,即可前往。需要注意的是,如果某一个货物已经成为机器人的目标,则其他机器热无法选择该货物,我们将该货物到其他机器人的距离设置成99999
def robot2goods(goods,robots,berths,paths,now_frame,robot_to_init_goods,boat_capacity,berth_final):
global target_table
index_good_choosen = []
if len(goods.available_goods) == 0:
return []
available_goods = np.array(goods.available_goods)
#第一步计算出船厂与所有good的距离
berth2good = np.zeros((10,len(goods.available_goods)),dtype=int)
for index_berth,berth in enumerate(berths):
for index_good in range(len(goods.available_goods)):
berth2good[index_berth][index_good] = paths[index_berth][(goods.available_goods[index_good][0],goods.available_goods[index_good][1])]
#当船厂号在最终不可达船厂号,设置为无限大
ber2good_final = berth2good.copy()
for i in range(10):
if i in berth_final:
ber2good_final[i,:] = 99999
#获得所有物品的死亡帧
death_good = np.array(available_goods[:,3]) + 1000
#获取所有物品价值
good_value = np.array(available_goods[:,2])
#获得good到其最近船厂的距离和对应船厂id
good2berth_id = np.argmin(ber2good_final,axis=0)#1*n
# print(good2berth_id,file=sys.stderr)
good2berth_value = np.amin(ber2good_final,axis=0)#1*n
for index_robot,robot in enumerate(robots):
#判断是否为初始机器人
if target_table[index_robot][5] == 1:
if target_table[index_robot][3] == 0 and robot.live and np.any(good2berth_value < 99999):
#获取机器人所在的berth号
berth_id = target_table[index_robot][2]
robot2good = berth2good[berth_id]
#确定机器人是否能拿到货物,不能拿到货的r2g距离设置成99999
RobotArriveTime = robot2good + now_frame + 10
CanNotReach = RobotArriveTime > death_good
robot2good[CanNotReach] = 99999
all_path_len = robot2good + good2berth_value
#当最后一轮时要考虑船厂死亡帧
if now_frame > 12500:
for ind in range(10):
list_berths = np.where(good2berth_id == ind)[0]
if len(list_berths) > 0:
need_to_op = all_path_len[list_berths] + now_frame + 5
CanNotReach = need_to_op > berth_death[ind]
cannot = list_berths[CanNotReach]
all_path_len[cannot] = 99999
m = np.divide(good_value, all_path_len)
Choose_good_id = np.argmax(m)
Choose_berth_id = good2berth_id[Choose_good_id]
#如果选择的还是大,那么不选
if robot2good[Choose_good_id]>=99999 or all_path_len[Choose_good_id]>=99999:
continue
index_good_choosen.append(Choose_good_id)
good2berth_value[Choose_good_id] = 99999
target_table[index_robot][0] = available_goods[Choose_good_id][0]
target_table[index_robot][1] = available_goods[Choose_good_id][1]
target_table[index_robot][2] = Choose_berth_id
target_table[index_robot][3] = 1
target_table[index_robot][4] = available_goods[Choose_good_id][2]
target_table[index_robot][6] = berth_id
else:
if target_table[index_robot][3] == 0 and robot.live and np.any(good2berth_value < 99999):
second_goods2robot=robot_to_init_goods[index_robot]
all_path_len = second_goods2robot + good2berth_value
m = np.divide(good_value, all_path_len)
Choose_good_id = np.argmax(m)
#如果选择的还是大,那么不选
if second_goods2robot[Choose_good_id]>=99999 or all_path_len[Choose_good_id]>=99999:
continue
Choose_berth_id = good2berth_id[Choose_good_id]
index_good_choosen.append(Choose_good_id)
good2berth_value[Choose_good_id] = 99999
target_table[index_robot][0] = available_goods[Choose_good_id][0]
target_table[index_robot][1] = available_goods[Choose_good_id][1]
target_table[index_robot][2] = Choose_berth_id
target_table[index_robot][3] = 1
target_table[index_robot][4] = available_goods[Choose_good_id][2]
return index_good_choosen
三、路径规划模块
3.1 A*算法寻找路径
机器人路径规划问题中,我们采用常见的A*算法来实现对机器人路径优化。在算法中,我们采用欧氏距离作为启发式函数:
# A*算法
def astar(start, goal, obstacles):
open_set = set()
closed_set = set()
current = start
open_set.add(current)
# counter = 1
while open_set:
# counter += 1
# if counter >= 10000:
# return None
current = min(open_set, key=lambda x: x.g + x.h)
open_set.remove(current)
closed_set.add(current)
if get_distance(current, goal) ==0:
path = []
while current:
path.append(current)
current = current.parent
return path[::-1]
for neighbor in get_neighbors(current, obstacles):
if neighbor in closed_set:
continue
# tentative_g = current.g+ 1/3*get_distance(current, neighbor)
tentative_g = get_distance(current, neighbor)
if neighbor not in open_set:
open_set.add(neighbor)
neighbor.h = get_distance(neighbor, goal)
elif tentative_g >= neighbor.g:
continue
neighbor.parent = current
neighbor.g = tentative_g
return None
# 获取当前点的邻居点
def get_neighbors(node, obstacles):
neighbors = []
for x in range(-1, 2):
for y in range(-1, 2):
if x == 0 and y == 0 or(x*y!=0):
continue
if node.x + x <0 or node.x + x >200 or node.y + y <0 or node.y + y > 200 or Node(
node.x + x , node.y + y ) in obstacles:
continue
neighbor = Node(node.x + x , node.y + y )
neighbors.append(neighbor)
return neighbors
def get_distance(node1, node2):
return math.sqrt((node1.x - node2.x) ** 2 + (node1.y - node2.y) ** 2)
def get_manhadundis(node1, node2):
return abs(node1.x - node2.x) + abs(node1.y - node2.y)
A*算法查找路径效果如下:
A可以很好的动态找到路径,但是经过多次优化,A\查找一次路径的时间还是很长:
考虑到机器人与判题器交互时间上限是15ms,如果多个机器人同时查找路径,那时间显然是不够的。考虑到除了初始化的机器人,即机器人在初始化之后每次运货都是从某个港口出发,再回到某个港口。因此很自然的想到,我们可以存储每个港口到所有位置的所有路径,机器人每次寻找路径只需要查表即可,于是改变思路,我们只在初始化阶段使用A*寻找路径。
3.2 广度优先搜索遍历,查找港口到所有点的路径。
def is_valid(x, y, rows, cols):
return 0 <= x < rows and 0 <= y < cols
def find_paths(initial_positions, obstacle_coordinates, rows, cols):
obstacles = set(obstacle_coordinates)
paths = {}
for start_x, start_y in initial_positions:
visited = set()
queue = deque([(start_x, start_y, [])])
while queue:
current_x, current_y, path = queue.popleft()
if (current_x, current_y) not in visited:
visited.add((current_x, current_y))
if (current_x, current_y) not in obstacles:
current_path = path + [(current_x, current_y)]
paths[(start_x, start_y, current_x, current_y)] = current_path
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
new_x, new_y = current_x + dx, current_y + dy
if is_valid(new_x, new_y, rows, cols) and (new_x, new_y) not in visited:
queue.append((new_x, new_y, current_path))
return paths
这样我们只需要在初始化阶段遍历10次地图(因为每个港口都需要遍历一次地图)即可查找10个港口到所有点的路径表。经过我们的计算,在200200的地图中,可达点大约有25000,也就是每个港口我们要存储25000个路径,每个路径是一个长度平局为100的列表,经过我们的计算,这个路径表会占用存储将近*3GB。担心比赛的提交系统有存储上限,因此这个方案我们没有使用。
3.2 路径表转换方向表
我们为每一个港口存储一个200*200的方向表,每个位置存储01234、0表示该位置无法到达该港口,1表示该位置到达港口则需要机器人向下移动,以此类推如下图:绿色表示港口,黑色表示障碍物:
这样我们只需要存储10个200*200的表格,然后需要路径时,根据方向表格遍历提取路径,这样存储仅为:
在表格中提取路径时间为:
同时,在广搜过程中,我们记录方向表和单通道。方向表为查找路径,单通道为防止机器人在单通道撞死。效果如下,红色表示从目标港口到目标货物提取的路径,黄色表示地图中的单通道:
四、运动模块
简单通过标准输出控制机器人和船运动:
def robots_movation(robot_num):
for i in range(robot_num):
print("move", i, 1)
sys.stdout.flush()
def robot_up(robot_id):
print("move", robot_id, 2)
def robot_down(robot_id):
print("move", robot_id, 3)
def robot_left(robot_id):
print("move", robot_id, 1)
def robot_right(robot_id):
print("move", robot_id, 0)
def robot_get_goods(robot_id):
print("get", robot_id)
def robot_pull_goods(robot_id):
print("pull",robot_id)
def boat_ship(boat_id,berth_id):
print("ship",boat_id,berth_id)
def boat_go_virtual(boat_id):
print("go",boat_id)
五、防碰撞模块
防碰撞策略为:单通道进行锁死,非单通道采用优先停止,其次左右最后后退的策略防止机器人碰撞:
def detect_collision_1(paths , robots , track_index, connected_points , connected_locks):
bot_num = 10
collision_flag = True
reback_status = [0] * 10
now_position = set()
robot_next_pos = [] # 存储机器人的位置信息
robot_flag = [0] * 10 # 标记机器人下一个执行位置是否合法
robot_next_pos_1 = set()
waits = [[] for _ in range(10)]
# nums = []
#初始化robot_pos
for index in range(bot_num):
now_position.add(Node(robots[index].x , robots[index].y))
if track_index[index] < len(paths[index]) and isinstance(paths[index][track_index[index]] , tuple) and len(paths[index][track_index[index]]) > 1:
robot_flag[index] = 1
robot_next_pos.append(Node(paths[index][track_index[index]][0],paths[index][track_index[index]][0]))
else:
robot_next_pos.append(Node(-1,-1))
robot_next_pos_1 = set(robot_next_pos)
if len(connected_locks) > 15:
#进行单通道的解锁
for index in range(len(connected_locks)):
if connected_locks[index] != 0:
pos = Node(robots[connected_locks[index]-1].x , robots[connected_locks[index]-1].y)
if pos not in connected_points[index]:
connected_locks[index] = 0
#进行单通道的上锁
for index in range(bot_num):
step = 0
index_1 = max(0 , min(len(paths[index])-1 , track_index[index]+step))
cancel_flag = True
if index_1 < len(paths[index]) and isinstance(paths[index][index_1] , tuple) and len(paths[index][index_1]) > 1:
pos = Node(paths[index][index_1][0] , paths[index][index_1][1])
for i in range(len(connected_points)):
if pos in connected_points[i]:
cancel_flag = False
if connected_locks[i] == index+1:
continue
elif connected_locks[i] == 0:
connected_locks[i] = index+1
else:
# track_index[index] = max(0 , track_index[index]-1)
# 单通道门口执行左右移动
if direction_flag[index] == 0:
reback_status[index] = 2
left_right_flag = False # 判断其他两个方向有没有空地
wait_pos = [] #构建可选点,长度为1或者2
for dict in direction:
pos = (robots[index].x+dict[0] , robots[index].y+dict[1])
pos_1 = Node(robots[index].x+dict[0],robots[index].y+dict[1])
if min(pos[0],pos[1]) >= 0 and max(pos[0] , pos[1]) <= 199 and pos != paths[index][track_index[index]] and pos_1 not in obstacles_set and pos_1 not in robot_next_pos_1 and pos_1 not in now_position: # 测试时修改为live_points_1,同时传入
if track_index[index] >= 2 and pos == paths[index][track_index[index]-2]:
continue
wait_pos.append(pos)
left_right_flag = True
if not left_right_flag: # 没有左右的执行回退
track_index[index] = max(0 , track_index[index]-2)
reback_status[index] = 3
else:
pos = wait_pos[0]
waits[index] = wait_pos
paths[index].insert(track_index[index] , pos)
paths[index].insert(track_index[index]+1 , (robots[index].x , robots[index].y))
reback_status[index] = 2 # 发生过左右的情况
direction_flag[index] = 1
else:
reback_status[index] = 3
track_index[index] = max(0 , track_index[index]-2)
break
if cancel_flag:
direction_flag[index] = 0
while(collision_flag):
collision_flag = False
bots = list(itertools.combinations(robots, 2))
random.shuffle(bots)
for bot in bots:
robot_1 = bot[0].id
robot_2 = bot[1].id
if len(paths[robot_1]) <= 1 or len(paths[robot_2]) <= 1 or track_index[robot_1] < 0 or track_index[robot_2] < 0 or track_index[robot_1] >= len(paths[robot_1]) or track_index[robot_2] >= len(paths[robot_2]):
continue
# 两种情况,直接冲突和交换冲突
if (paths[robot_1][track_index[robot_1]][0] == paths[robot_2][track_index[robot_2]][0] and paths[robot_1][track_index[robot_1]][1] == paths[robot_2][track_index[robot_2]][1]) or ((robots[robot_1].x == paths[robot_2][track_index[robot_2]][0] and robots[robot_1].y == paths[robot_2][track_index[robot_2]][1]) and (robots[robot_2].x == paths[robot_1][track_index[robot_1]][0] and robots[robot_2].y == paths[robot_1][track_index[robot_1]][1])):
target_robot = robot_1 if reback_status[robot_1] < reback_status[robot_2] else robot_2
#编号小的保持不变,编号大的进行处理,即robot_2,这里规定0代表未发生碰撞,1代表停止,2代表其他两个方向寻路,==3代表回退
reback_status[target_robot] = reback_status[target_robot] + 1
if reback_status[target_robot] >= 4:# 已经进行过所有避障操作
continue
elif reback_status[target_robot] == 3: # 已经产生了左右退的现象,弹出插入的点执行回退
if len(waits[target_robot]) == 2: # 如果还有备选位置,执行另一个躲避位置
paths[target_robot][track_index[target_robot]] = waits[target_robot][1]
waits[target_robot] = []
reback_status[target_robot] = 2
else:
del paths[target_robot][track_index[target_robot]]
track_index[target_robot] = max(0 , track_index[target_robot]-1)
elif reback_status[target_robot] == 1 and paths[robot_1][track_index[robot_1]] == paths[robot_2][track_index[robot_2]]: #产生相撞于一点
track_index[target_robot] = max(0 , track_index[target_robot]-1)
elif (reback_status[target_robot] == 1 and ((robots[robot_1].x , robots[robot_1].y) == paths[robot_2][track_index[robot_2]] and (robots[robot_2].x , robots[robot_2].y) == paths[robot_1][track_index[robot_1]])):
left_right_flag = False # 判断其他两个方向有没有空地
wait_pos = [] #构建可选点,长度为1或者2
for dict in direction:
pos = (robots[target_robot].x+dict[0] , robots[target_robot].y+dict[1])
pos_1 = Node(robots[target_robot].x+dict[0],robots[target_robot].y+dict[1])
if min(pos[0],pos[1]) >= 0 and max(pos[0] , pos[1]) <= 199 and pos != paths[target_robot][track_index[target_robot]] and pos_1 not in obstacles_set and pos_1 not in robot_next_pos_1 and pos_1 not in now_position: # 测试时修改为live_points_1,同时传入
if track_index[target_robot] >= 2 and pos == paths[target_robot][track_index[target_robot]-2]:
continue
wait_pos.append(pos)
left_right_flag = True
if not left_right_flag: # 没有左右的执行回退
track_index[target_robot] = max(0 , track_index[target_robot]-2)
reback_status[target_robot] = 3
else:
pos = wait_pos[0]
waits[target_robot] = wait_pos
paths[target_robot].insert(track_index[target_robot] , pos)
paths[target_robot].insert(track_index[target_robot]+1 , (robots[target_robot].x , robots[target_robot].y))
reback_status[target_robot] = 2 # 发生过左右的情况
elif reback_status[target_robot] == 2:# 这里是对之前相撞于一点的情况进行处理
left_right_flag = False # 判断其他两个方向有没有空地
wait_pos = [] #构建可选点,长度为1或者2
for dict in direction:
pos = (robots[target_robot].x+dict[0] , robots[target_robot].y+dict[1])
pos_1 = Node(robots[target_robot].x+dict[0] , robots[target_robot].y+dict[1])
if min(pos[0],pos[1]) >= 0 and max(pos[0] , pos[1]) <= 199 and pos != paths[target_robot][track_index[target_robot]+1] and pos not in obstacles and pos_1 not in robot_next_pos_1 and pos_1 not in now_position: # 测试时修改为live_points_1,同时传入
if track_index[target_robot] >= 1 and pos == paths[target_robot][track_index[target_robot]-1]:
continue
wait_pos.append(pos)
left_right_flag = True
if not left_right_flag: # 没有左右的执行回退
track_index[target_robot] = max(0 , track_index[target_robot]-1)
reback_status[target_robot] = 3
else:
pos = wait_pos[0]
waits[target_robot] = wait_pos
paths[target_robot].insert(track_index[target_robot] , pos)
reback_status[target_robot] = 2 # 发生过左右的情况
collision_flag = True
# # 更新robot_next_pos
if isinstance(paths[target_robot][track_index[target_robot]] , tuple) and len(paths[target_robot][track_index[target_robot]]) > 1:
robot_next_pos[target_robot] = Node(paths[target_robot][track_index[target_robot]][0] , paths[target_robot][track_index[target_robot]][0])
robot_next_pos_1 = set(robot_next_pos)
return track_index,paths,connected_locks
六、运输模块
五艘船选取港口的指标为:$p=\frac{船可以装的货物价值}{买卖点到港口的时间+装货时间+离开时间}$,五艘船轮流选择目标港口,到达港口之后如果可以装满,则装满离开,如果无法装满,则根据$p$考虑是否前往下一个港口继续装。
设置轮船的状态表,分别表示:目的港口id、轮船状态位(0表示闲置,1表示确定好港口,2表示在去港口的路上,3表示正在装货,4表示准备离开港口,5表示正在回买卖点)、轮次、船的转折次数:
target_table_boat_berth = np.zeros((5,4),dtype=int)
target_table_boat_berth[:,0] = -1
运输选择:
def update_BoatStatus(boats,berths,capacity,now_frame):
global target_table_boat_berth
global berth_final
global berth_death
global berth_death_num
for index_boat in range(5):
#(共用)
if target_table_boat_berth[index_boat][1] == 5 and boats[index_boat].update_status():
target_table_boat_berth[index_boat][1] = 0
target_table_boat_berth[index_boat][3] = 0
#第五轮直接设置为转移过一次了,不会再转了
# if target_table_boat_berth[index_boat][2] == 4:
# target_table_boat_berth[index_boat][3] = 1
boats[index_boat].idle()
#第一轮6000帧以内,涉及到它只回去一次,也可能回去两次。不管如何6000帧必须在虚拟点,并且前期就是要么装满走人,如果转移的话考虑船内装没装够0.9cap,装够的话去虚拟点卖就行。只有前两轮用这个
if now_frame < 12000 :
if target_table_boat_berth[index_boat][1] == 0:
#选取目标
berth_index = -1
#第一轮就正常选
if target_table_boat_berth[index_boat][2] == 0:
berth_index = select_first_two_first(berths,now_frame)
#只有能选的berth才会执行
if berth_index != -1:
target_table_boat_berth[index_boat][0] = berth_index
target_table_boat_berth[index_boat][1] = 1
berths[berth_index].choosen = 1
#如果没选到直接啥也不干轮次+1
# else:
# target_table_boat_berth[index_boat][2] += 1
#确定是否到船厂
if target_table_boat_berth[index_boat][1] == 2 and boats[index_boat].update_status():
target_table_boat_berth[index_boat][1] = 3
#装货状态判断
if target_table_boat_berth[index_boat][1] == 3:
index_berth = target_table_boat_berth[index_boat][0]
#判断是否可以继续装货
if len(berths[index_berth].GoodsOfBerth) > 0 and boats[index_boat].inventory < capacity:
boats[index_boat].load(berths[index_berth].unload(capacity - boats[index_boat].inventory))
#不能继续装货有两种情况,第一种是港口空了,第二种是船满了
else:
#先解锁
berths[index_berth].choosen = 0
#如果是装满了就直接回去
if boats[index_boat].inventory >= capacity:
target_table_boat_berth[index_boat][1] = 4
#没装满。
else:
#如果装够0.9个cap直接走人就行了
if boats[index_boat].inventory >= 0.9 * capacity:
target_table_boat_berth[index_boat][1] = 4
#如果没装够0.9
else:
berth_index = select_first_two_second(berths,capacity - boats[index_boat].inventory,now_frame)
if berth_index != -1:
target_table_boat_berth[index_boat][0] = berth_index
target_table_boat_berth[index_boat][1] = 1
berths[berth_index].choosen = 1
target_table_boat_berth[index_boat][3] += 1
if (12000 - now_frame) <= berths[index_berth].transport_time:
target_table_boat_berth[index_boat][1] = 4
else:
#全新改版
if 12000 <= now_frame <= 12005 :
if target_table_boat_berth[index_boat][1] == 0:
#只有最后一轮直接定
berth_index = select(berths,capacity)
target_table_boat_berth[index_boat][0] = berth_index
target_table_boat_berth[index_boat][1] = 1
berths[berth_index].choosen = 1
target_table_boat_berth[index_boat][2] = 4
#最后一轮直接加时间
if target_table_boat_berth[index_boat][2] == 4:
l_time = len(berths[berth_index].GoodsOfBerth) / berths[berth_index].loading_speed
#这样可以
berth_death[berth_index] = now_frame + berths[berth_index].transport_time + l_time + 5
berth_death_num += 1
#确定是否到船厂(共用)
if target_table_boat_berth[index_boat][1] == 2 and boats[index_boat].update_status():
target_table_boat_berth[index_boat][1] = 3
#装货状态
if target_table_boat_berth[index_boat][1] == 3:
index_berth = target_table_boat_berth[index_boat][0]
#判断是否可以继续装货
if len(berths[index_berth].GoodsOfBerth) > 0 and boats[index_boat].inventory < capacity:
boats[index_boat].load(berths[index_berth].unload(capacity - boats[index_boat].inventory))
else:
#先解锁
berths[index_berth].choosen = 0
#如果是倒数第二轮最后走的时候不解锁
# if target_table_boat_berth[index_boat][2] == 3 and target_table_boat_berth[index_boat][3] == 1:
# berths[index_berth].choosen = 1
#如果是装满了就直接回去(实际不会出现)
if boats[index_boat].inventory >= capacity:
target_table_boat_berth[index_boat][1] = 4
if target_table_boat_berth[index_boat][2] == 4:
if len(berth_final) == 9:
berth_final.clear()
berth_death[:] = 99999
# print('清空',file=sys.stderr)
#最多为4因此应该小于9,这样最后加完应该为9
if len(berth_final) < 9:
berth_final.append(target_table_boat_berth[index_boat][0])
# None
else:#没装满考虑怎么走
#如果没装满并且没有转移过,找下家
if target_table_boat_berth[index_boat][3] == 0:
if target_table_boat_berth[index_boat][2] == 4:
berth_final.append(target_table_boat_berth[index_boat][0])
#print(f'frame:{now_frame},boat_id:{index_boat},left:{boats[index_boat].inventory},boat_table:\n{target_table_boat_berth}',file=sys.stderr)
berth_index = select_two(berths,capacity - boats[index_boat].inventory,now_frame)
target_table_boat_berth[index_boat][0] = berth_index
target_table_boat_berth[index_boat][1] = 1
berths[berth_index].choosen = 1
target_table_boat_berth[index_boat][3] = 1
if target_table_boat_berth[index_boat][2] == 4:
#记录船厂被锁时间
berth_death[berth_index] = 15000 - berths[berth_index].transport_time
berth_death_num += 1
if berth_death_num == 10:
# 找到不是 999 的值的下标
indices = np.where(berth_death != 99999)[0]
# 通过下标获取对应的值
values = berth_death[indices]
# 找到最大值的下标
max_index = np.argmax(values)
# 在原始矩阵中找到最大值的位置
max_value_index = indices[max_index]
berth_death[max_value_index] = 99999
#如果转移过只有呆满才能走
else:
if (3000 - (now_frame % 3000)) <= berths[index_berth].transport_time:
target_table_boat_berth[index_boat][1] = 4
if target_table_boat_berth[index_boat][2] == 4:
if len(berth_final) == 9:
berth_final.clear()
berth_death[:] = 99999
#print('清空',file=sys.stderr)
#最多为4因此应该小于9,这样最后加完应该为9
if len(berth_final) < 9:
berth_final.append(target_table_boat_berth[index_boat][0])
七、总结
采用静态和贪心的策略进行货物的选择,可能导致机器人运货量达不到最优;、
防碰撞没有没有做到完美,机器人仍会出现卡死的情况