机器学习与模式识别大作业

import plane
# import dense
import numpy as np
from sklearn.cluster import KMeans


# 注意行列和xy的转换 应该只用行列 向上为行-1 向左为列-1
# 如果在xy图像里面会上下颠倒,左右不变
# 地图上有三个信息来源,一个是字符地图,一个是带有信息的二维数组,一个是两个基地列表,如果要更新都需要进行修改
# 聚类出来坐标为float64,使用时注意取整
class Data:
    def __init__(self, filename):#初始化,保存各类信息
        self.base = []
        self.basexy = []
        self.enemybase = []
        self.enemybasexy = []
        self.plane = []
        self.map = []
        self.mapinfo = []
        with open(filename, "r") as file:
            # 第一行保存行列大小信息
            content = file.readline()
            sp = content.split()
            self.row = int(sp[0])
            self.column = int(sp[1])
            # 接下来row行保存地图信息
            for i in range(self.row):
                self.map.append(file.readline().rstrip("\n"))
            # 有多少己方基地
            content = file.readline()
            self.base_num = int(content)
            # 己方基地信息
            for i in range(self.base_num):
                content = file.readline()
                sp = content.split()
                # 分别保存xy坐标
                self.basexy.append([int(sp[0]), int(sp[1])])
                content = file.readline()
                sp = content.split()
                # 分别保存燃油、导弹、防御、价值
                self.base.append([int(sp[0]), int(sp[1]), int(sp[2]), int(sp[3])])
            # 有多少敌方基地
            content = file.readline()
            self.enemybase_num = int(content)
            # 敌方基地信息
            for i in range(self.enemybase_num):
                content = file.readline()
                sp = content.split()
                # 分别保存xy坐标
                self.enemybasexy.append([int(sp[0]), int(sp[1])])
                content = file.readline()
                sp = content.split()
                # 分别保存燃油、导弹、防御、价值
                self.enemybase.append([int(sp[0]), int(sp[1]), int(sp[2]), int(sp[3])])
            # 有多少架飞机
            content = file.readline()
            self.plane_num = int(content)
            for i in range(self.plane_num):
                content = file.readline()
                sp = content.split()
                # 分别保存xy坐标、油箱容量、最大载弹量
                self.plane.append([int(sp[0]), int(sp[1]), int(sp[2]), int(sp[3])])
        #遍历二维数组进行更新操作。
        hang = 0
        lie = 0
        for i in self.map:
            add = []
            for j in i:
                if j == '.':
                    add.append(None)
                elif j == '*':#己方基地的更新操作
                    for selfbase in range(self.base_num):
                        if self.basexy[selfbase][0] == hang and self.basexy[selfbase][1] == lie:
                            add.append(self.base[selfbase])
                            break
                elif j == '#':#地方基地的更新操作
                    for enemybase in range(self.enemybase_num):
                        if self.enemybasexy[enemybase][0] == hang and self.enemybasexy[enemybase][1] == lie:
                            add.append(self.enemybase[enemybase])
                            break
                lie += 1
            lie = 0
            hang += 1
            self.mapinfo.append(add)


class InstrManager:
    def __init__(self, filepath):
        self.filepath = filepath
        with open(self.filepath, 'w') as file:  # 清空文件内容
            file.write("")
        self.instrs = []

    # 移动Id飞机,0,1,2,3代表上下左右
    def move(self, Id, direction):
        self.instrs.append(" ".join(["move", str(Id), str(direction), "\n"]))

    # Id飞机攻击方向和次数
    def attack(self, Id, direction, count):
        self.instrs.append(" ".join(["attack", str(Id), str(direction), str(count), "\n"]))

    # Id飞机补充燃油counts
    def fuel(self, Id, count):
        self.instrs.append(" ".join(["fuel", str(Id), str(count), "\n"]))

    # Id飞机补充导弹count
    def missile(self, Id, count):
        self.instrs.append(" ".join(["missile", str(Id), str(count), "\n"]))

    def writeinstr(self):
        with open(self.filepath, 'a') as file:
            file.writelines(self.instrs)
            file.write("OK\n")
        self.instrs = []

# 计算聚类中心附近的燃油和导弹储备
def count_resource(data: Data, center, radius):
    radius = int(radius)
    fuel_total = 0
    missile_total = 0
    # 在半径范围内进行搜索
    for i in range(max(0, int(center[0]) - radius), min(data.row, int(center[0]) + radius)):
        for j in range(max(0, int(center[1]) - radius), min(data.column, int(center[1]) + radius)):
            if abs(i - int(center[0])) + abs(j - int(center[1])) > radius:
                continue  # 在圆圈范围以外
            if data.map[i][j] == '*':  # 己方基地
                fuel_total += data.mapinfo[i][j][0]
                missile_total += data.mapinfo[i][j][1]
    return [fuel_total, missile_total]

# 进行聚类返回聚类中心以及每架飞机适应的聚类点,想法为聚类中心点的基地更加集中,但还需要各聚类点的燃油和导弹等信息。
#我们使用的是一半燃油。
# 聚类中心油量在减去距离才能得到净油量
def Clustering(data: Data, plane_arr):
    points = np.array(data.basexy)
    # 设置聚类的数量
    # k = data.plane_num
    k = int(np.log(data.row*data.column))
    print("分成", k, "类")
    print("识别距离为:", (data.row+data.column)/k)
    # 执行k均值聚类
    kmeans = KMeans(n_clusters=k)
    kmeans.fit(points)
    # 获取聚类中心和标签
    centers = kmeans.cluster_centers_  # 聚类中心点
    centers = centers.astype(int)
    labels = kmeans.labels_  # 对应的标签
    for i in plane_arr:  # 对每架飞机找到最佳加油点和导弹补给点
        fuel_points = []
        missile_points = []
        for j in centers:
            fuel, missile = count_resource(data, j, (data.row+data.column)/k)
            fuel -= (abs(j[0]-i.position[0])+abs(j[1]-i.position[1]))
            fuel_points.append(fuel)
            missile_points.append(missile)
        # 为每架飞机找到燃油点和导弹点,注意取整
        i.fuel_positions = centers[fuel_points.index(max(fuel_points))]
        i.missile_positions = centers[missile_points.index(max(missile_points))]
    print("聚类中心:",centers)
    return centers


# 删除无用基地信息
def delete_base(data, position):
    if data.map[position[0]][position[1]] == '*':  # 己方基地
        for i in range(data.base_num):  # 遍历己方基地
            if data.basexy[i][0]==position[0] and data.basexy[i][1]==position[1]:
                data.basexy.pop(i)
                data.base.pop(i)
                data.base_num -= 1
                break
    if data.map[position[0]][position[1]] == '#' or data.map[position[0]][position[1]] == 's':  # 敌方基地
        for i in range(data.enemybase_num):  # 遍历敌方基地
            if data.enemybasexy[i][0]==position[0] and data.enemybasexy[i][1]==position[1]:
                data.enemybasexy.pop(i)
                data.enemybase.pop(i)
                data.enemybase_num -= 1
                break
    str2list = list(data.map[position[0]])
    str2list[position[1]] = '.'
    data.map[position[0]] = ''.join(str2list)



if __name__ == "__main__":
    data = Data("data/testcase2.in")
    sum = 0
    for i in data.enemybase:
        sum += i[3]
    print("总分为:", sum)
    instr = InstrManager("data/testcase2.out")
    directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]  # 上下左右
    # print(data.mapinfo, data.enemybasexy)
    # 不能飞的飞机
    can_fly = []
    # 飞机数组
    plane_arr = []
    # 路径数组
    way = []
    # 行动数组,0,1,2,3分别为四个方向攻击,4为补给
    action = []
    # 记录发射导弹数量
    missile = []
    # 记录加燃油和导弹的数量
    fuel_and_missile = []
    # 用于删除的临时坐标
    temp_position = [0, 0]
    # 删除无用的己方基地和
    for i in range(data.base_num-1, -1, -1):  # 倒序遍历,防止删除时出现波动
        if data.base[i][0] == 0 and data.base[i][1] == 0:
            print("初始删除己方基地:", data.basexy[i])
            delete_base(data, data.basexy[i])
    for i in range(data.plane_num):
        plane_arr.append(plane.plane(data, instr, i))
        way.append([])
        action.append([-1])
        can_fly.append(1)
        missile.append(0)
        fuel_and_missile.append([0, 0])
    fly_index = 0
    for i in plane_arr:
        i.add_fuel(min(data.mapinfo[i.position[0]][i.position[1]][0], i.max_fuel))
        i.add_missile(min(data.mapinfo[i.position[0]][i.position[1]][1], i.max_missile))
        # print(i.position)
        # print(i.DFS())
        nearest_base, base_way, nearest_enemy, enemy_way = i.DFS()
        if data.mapinfo[nearest_enemy[0]][nearest_enemy[1]][2] > i.missile or 2 * (len(enemy_way) - 1) + len(
                base_way) > i.fuel:
            action[fly_index] = 4  # 进行补给
            way[fly_index] = base_way
            supply_fuel = min(data.mapinfo[nearest_base[0]][nearest_base[1]][0], i.max_fuel - i.fuel + len(base_way))
            supply_missile = min(data.mapinfo[nearest_base[0]][nearest_base[1]][1], i.max_missile - i.missile)
            fuel_and_missile[fly_index] = [supply_fuel, supply_missile]  # 提前记录补充的燃油和导弹
            print(f"飞机{i.number}选择补给,寻路:", base_way, "     该基地信息:",
                  data.mapinfo[nearest_base[0]][nearest_base[1]])
            data.mapinfo[nearest_base[0]][nearest_base[1]][0] -= supply_fuel
            data.mapinfo[nearest_base[0]][nearest_base[1]][1] -= supply_missile
            if data.mapinfo[nearest_base[0]][nearest_base[1]][0] == 0 and \
                    data.mapinfo[nearest_base[0]][nearest_base[1]][1] == 0:
                # 删除己方基地
                delete_base(data, nearest_base)
                print("资源耗尽,删除己方基地:", nearest_base)
                # str_list = list(data.map[nearest_base[0]])  # 字符串不能改,先列表化
                # str_list[nearest_base[1]] = '.'  # 基地已空
                # data.map[nearest_base[0]] = ''.join(str_list)  # 修改成功

        else:  # 能击毁,能回基地
            action[fly_index] = enemy_way[0]  # 进行攻击
            # 更新地图,但是要防止寻路出错
            missile[fly_index] = data.mapinfo[nearest_enemy[0]][nearest_enemy[1]][2]  # 记录需要发射的导弹数
            str_list = list(data.map[nearest_enemy[0]])  # 字符串不能改,先列表化
            str_list[nearest_enemy[1]] = 's'  # 防止两个飞机攻击同一目标
            data.enemybase_num -= 1  # 敌方基地数量减一
            data.map[nearest_enemy[0]] = ''.join(str_list)  # 修改成功
            data.mapinfo[nearest_enemy[0]][nearest_enemy[1]] = []  # 击毁,只更新了这两个,别用别的数据
            del (enemy_way[0])
            way[fly_index] = enemy_way
            print(f"飞机{i.number}选择攻击,寻路:", enemy_way, f"锁定敌方基地{nearest_enemy}")
            # print("修改后地图为:")
            # print(data.map)
            # print(data.mapinfo)
        fly_index += 1
    print("寻路:", way)
    flag = 1  # 判断是否该结束
    frame = 1  # 只能15000帧
    while flag == 1 and frame <= 15000:
        print("frame====>>>", frame)
        flag = 0
        # 对每个飞机执行命令,若没有命令则创造命令
        for j in range(data.plane_num):
            if can_fly[j] == 0:
                continue
            i = plane_arr[j]
            if not way[j]:  # 已经到达
                if action[j] == 4:  # 补给
                    i.add_fuel(fuel_and_missile[j][0])
                    i.add_missile(fuel_and_missile[j][1])
                    flag = 1
                else:  # 攻击
                    i.attack_missiles(action[j], missile[j])
                    temp_position[0] = i.position[0] + directions[action[j]][0]
                    temp_position[1] = i.position[1] + directions[action[j]][1]
                    delete_base(data, temp_position)
                    # str_list = list(data.map[i.position[0] + directions[action[j]][0]])  # 字符串不能改,先列表化
                    # str_list[i.position[1] + directions[action[j]][1]] = '.'  # 防止两个飞机攻击同一目标
                    # data.map[i.position[0] + directions[action[j]][0]] = ''.join(str_list)  # 基地已经被击毁
                    # print(f"{i.number}飞机位置:{i.position}")
                    # print(f"修改了:{i.position[0]+directions[action[j]][0],i.position[1]+directions[action[j]][1]}")
                    # print("当前地图为:")
                    # print(data.map)
                    # print(data.mapinfo)
                    flag = 1
                nearest_base, base_way, nearest_enemy, enemy_way = i.DFS()  # 重新检索
                if nearest_enemy is None or nearest_base is None:
                    print(f"{i.number}飞机已经不能飞了")
                    can_fly[j] = 0
                    continue
                print("最近的己方基地:", nearest_base, "                      最近的敌方基地:", nearest_enemy)
                if data.mapinfo[nearest_enemy[0]][nearest_enemy[1]][2] > i.missile or 2 * (len(enemy_way) - 1) + len(
                        base_way) > i.fuel:
                    action[j] = 4  # 进行补给
                    way[j] = base_way
                    supply_fuel = min(data.mapinfo[nearest_base[0]][nearest_base[1]][0],
                                      i.max_fuel - i.fuel + len(base_way))
                    supply_missile = min(data.mapinfo[nearest_base[0]][nearest_base[1]][1], i.max_missile - i.missile)
                    fuel_and_missile[j] = [supply_fuel, supply_missile]  # 提前记录补充的燃油和导弹
                    print(f"飞机{i.number}选择补给,寻路:", base_way, "     该基地信息:",
                          data.mapinfo[nearest_base[0]][nearest_base[1]])
                    data.mapinfo[nearest_base[0]][nearest_base[1]][0] -= supply_fuel
                    data.mapinfo[nearest_base[0]][nearest_base[1]][1] -= supply_missile
                    if data.mapinfo[nearest_base[0]][nearest_base[1]][0] == 0 and \
                            data.mapinfo[nearest_base[0]][nearest_base[1]][1] == 0:
                        # 删除己方基地
                        delete_base(data, nearest_base)
                        print("资源耗尽,删除己方基地:", nearest_base)
                        # str_list = list(data.map[nearest_base[0]])  # 字符串不能改,先列表化
                        # str_list[nearest_base[1]] = '.'  # 基地已空
                        # data.map[nearest_base[0]] = ''.join(str_list)  # 修改成功
                else:  # 能击毁,能回基地
                    action[j] = enemy_way[0]  # 进行攻击
                    # 更新地图,但是要防止寻路出错
                    missile[j] = data.mapinfo[nearest_enemy[0]][nearest_enemy[1]][2]  # 记录需要发射的导弹数
                    str_list = list(data.map[nearest_enemy[0]])  # 字符串不能改,先列表化
                    str_list[nearest_enemy[1]] = 's'  # 防止两个飞机攻击同一目标
                    data.enemybase_num -= 1  # 敌方基地数量减一
                    data.map[nearest_enemy[0]] = ''.join(str_list)  # 修改成功
                    data.mapinfo[nearest_enemy[0]][nearest_enemy[1]] = []  # 击毁,只更新了这两个,别用别的数据
                    del (enemy_way[0])
                    way[j] = enemy_way
                    print(f"飞机{i.number}选择攻击,寻路:", enemy_way, f"锁定敌方基地{nearest_enemy}")
            else:
                i.move(way[j].pop())  # 移动
                flag = 1
        instr.writeinstr()
        frame += 1
        if frame == 3000:
            print("3000帧地图为:")
            for i in range(data.row):
                print(data.map[i])
            break

这段代码是初始化的代码,在data类中,主要内容是解析游戏相关配置,从指定文件中读取并解析游戏相关配置信息,包括地图尺寸,地图内容,玩家信息,敌方基地和飞机信息,并将这些信息组织成易于处理的数据结构。

第二个类用于管理飞行器的各种指令操作,并将这些指令写到指定的文件中。

下面是count_resource函数,作用是计算并返回在给定半径范围内所有的己方基地的总燃油量和总导弹量。通过遍历地图信息,累加基地的燃油和导弹资源。

然后是Clustering函数,功能是聚类作用,计算出聚类中心和识别距离。
对己方基地进行聚类是为了确定潜在补给中心点,。对于每架飞机遍历所有聚类点,利用count_resource函数计算出每个中心点周围的资源总量,并减去到达该点的距离成本(直线距离)的一半燃油消耗,以评估收益,收益大的优先。为每架飞机分配最佳的加油点和导弹补给点,即在啊所有聚类中心中选择燃油和导弹资源净收益最大的点。返回聚类中心点列表,同时修改飞机对象的属性(fuel_positions和missile_positions)指定每架飞机的最优补给点。

下面的delete_base函数目的是从给定的游戏数据结构data中删除位于特定position的基地,更新相关数据结构以反映这一变化。
删除无用的己方基地的原则是检查基地的资源是否是0,如果是进行删除,删除无用的敌方基地同理,如果被摧毁,删除敌方基地。

实现过程中,循环创建飞机对象,添加到plane_arr中,并为每架飞机计算最近的己方基地,敌方基地的路径。根据飞机状态决定是攻击敌方基地还是返回己方基地进行补给,并更新相关的变量。

飞机执行行动,对于每一帧都进行状态的更新。同时进行地图的管理,当飞机攻击敌方基地时,更新地图信息表示基地被摧毁,并减少敌方基地总数。
若飞机补给耗尽,同样删除该基地信息。


import numpy as np
import queue
import heapq


class Node:
    def __init__(self, x, y, g=0, h=0, f=0, com_dir=None, parent=None):
        self.x = x
        self.y = y
        self.g = g  # 从起点到该结点
        self.h = h  # 从该节点到终点
        self.f = f  # 总花费
        self.com_dir = com_dir  # 上一个结点到该结点选择的前进方向
        self.parent = parent  # 上一个结点

    def __lt__(self, other):  # 用于最小堆的计算
        return self.f < other.f


def heuristic(node, end):
    return abs(node.x - end.x) + abs(node.y - end.y)  # 启发函数计算曼哈顿距离


class plane:
    def __init__(self, Data, InstrManager, number):
        self.Data = Data
        self.number = number
        self.InstrManager = InstrManager
        self.position = self.Data.plane[number][:2]  # 同样是行列而不是xy
        self.max_fuel = self.Data.plane[number][2]
        self.max_missile = self.Data.plane[number][3]
        self.fuel = 0
        self.missile = 0
        self.fuel_positions = None  # 补充燃油地点
        self.missile_positions = None  # 补充导弹地点
        self.fuel_base_arr = []  # 记录加油的节点,防止来回跑,传进来己方基地的位置

    # 广度优先算法,寻找最进敌方基地和己方基地,并返回路径
    def DFS(self):
        DFS_map = [[-1 for i in range(self.Data.column)] for i in range(self.Data.row)]
        open_list = queue.Queue()
        open_list.put(self.position)
        direction = [[-1, 0], [1, 0], [0, -1], [0, 1]]  # 上下左右
        visited = [self.position]
        DFS_map[self.position[0]][self.position[1]] = -2  # 起点为-2
        flag = 0

        nearest_enemy = None
        enemy_way = []
        nearest_base = None
        base_way = []

        while not open_list.empty():
            node = open_list.get()
            for i in range(len(direction)):
                x, y = [node[0] + direction[i][0], node[1] + direction[i][1]]
                if 0 <= x < self.Data.row and 0 <= y < self.Data.column and [x, y] not in visited:
                    if self.Data.map[x][y] == 's':
                        continue
                    elif self.Data.map[x][y] == '#':
                        if nearest_enemy is None:
                            nearest_enemy = [x, y]
                            flag += 1
                            xx, yy, ii = x, y, i
                            while DFS_map[xx][yy] != -2:
                                enemy_way.append(ii)
                                xx = xx - direction[ii][0]
                                yy = yy - direction[ii][1]
                                ii = DFS_map[xx][yy]
                    else:
                        if self.Data.map[x][y] == '*' and nearest_base is None:
                            nearest_base = [x, y]
                            flag += 1
                            xx, yy, ii = x, y, i
                            while DFS_map[xx][yy] != -2:
                                base_way.append(ii)
                                xx = xx - direction[ii][0]
                                yy = yy - direction[ii][1]
                                ii = DFS_map[xx][yy]
                        DFS_map[x][y] = i
                        visited.append([x, y])
                        open_list.put([x, y])

                    if flag == 2:
                        return nearest_base, base_way, nearest_enemy, enemy_way
        if nearest_enemy:
            return None, None, nearest_enemy, enemy_way
        elif nearest_base:
            return nearest_base, base_way, None, None
        else:
            return None, None, None, None

    # 广搜找燃油,返回有到达后有燃油盈余的那个基地,返回最近的基地坐标以及路径
    def WFS_for_fuel(self):
        DFS_map = [[-1 for i in range(self.Data.column)] for i in range(self.Data.row)]
        open_list = queue.Queue()
        open_list.put(self.position)
        direction = [[-1, 0], [1, 0], [0, -1], [0, 1]]  # 上下左右
        visited = [self.position]
        DFS_map[self.position[0]][self.position[1]] = -2  # 起点为-2
        base_way = []
        while not open_list.empty():
            node = open_list.get()
            for i in range(len(direction)):
                x, y = [node[0] + direction[i][0], node[1] + direction[i][1]]
                if 0 <= x < self.Data.row and 0 <= y < self.Data.column and [x, y] not in visited:
                    if self.Data.map[x][y] == 's' or self.Data.map[x][y] == '#':  # 碰到敌方基地直接跳过
                        continue
                    elif self.Data.map[x][y] == '*' and self.Data.mapinfo[x][y][0] > 0:  # 燃油不为空
                        if self.Data.mapinfo[x][y][0]-abs(x-self.position[0])-abs(y-self.position[1]) > 0:  # 有燃油盈余
                            nearest_base = [x, y]
                            xx, yy, ii = x, y, i
                            while DFS_map[xx][yy] != -2:
                                base_way.append(ii)
                                xx = xx - direction[ii][0]
                                yy = yy - direction[ii][1]
                                ii = DFS_map[xx][yy]
                            return nearest_base, base_way
                    DFS_map[x][y] = i
                    visited.append([x, y])
                    open_list.put([x, y])
        return None

    # 广搜找导弹,返回最近有导弹的那个基地,返回最近的基地坐标以及路径
    def WFS_for_missile(self):
        DFS_map = [[-1 for i in range(self.Data.column)] for i in range(self.Data.row)]
        open_list = queue.Queue()
        open_list.put(self.position)
        direction = [[-1, 0], [1, 0], [0, -1], [0, 1]]  # 上下左右
        visited = [self.position]
        DFS_map[self.position[0]][self.position[1]] = -2  # 起点为-2
        base_way = []
        while not open_list.empty():
            node = open_list.get()
            for i in range(len(direction)):
                x, y = [node[0] + direction[i][0], node[1] + direction[i][1]]
                if 0 <= x < self.Data.row and 0 <= y < self.Data.column and [x, y] not in visited:
                    if self.Data.map[x][y] == 's' or self.Data.map[x][y] == '#':  # 碰到敌方基地直接跳过
                        continue
                    elif self.Data.map[x][y] == '*' and self.Data.mapinfo[x][y][1] > 0:  # 导弹不为空
                        nearest_base = [x, y]
                        xx, yy, ii = x, y, i
                        while DFS_map[xx][yy] != -2:
                            base_way.append(ii)
                            xx = xx - direction[ii][0]
                            yy = yy - direction[ii][1]
                            ii = DFS_map[xx][yy]
                        return nearest_base, base_way
                    DFS_map[x][y] = i
                    visited.append([x, y])
                    open_list.put([x, y])
        return None

    # A*算法,找到到达目标的最近路径
    def A_star(self, target):
        start_node = Node(self.position[0], self.position[1])  # 生成起点和终点
        end_node = Node(target[0], target[1])
        direction = [[-1, 0], [1, 0], [0, -1], [0, 1]]  # 上下左右
        visited = [self.position]  # 元素为二维坐标
        open_list = []
        heapq.heappush(open_list, start_node)
        path = []
        while open_list:
            current_node = heapq.heappop(open_list)
            visited.append([current_node.x, current_node.y])
            if current_node.x == end_node.x and current_node.y == end_node.y:  # 到达终点
                while current_node != start_node:  # python中的等号比较的是内存地址
                    path.append(current_node.com_dir)  # 记录路径
                    current_node = current_node.parent  # 到上一个结点
                return path
            else:  # 未到达终点
                for i in range(len(direction)):
                    neighbor_x = current_node.x + direction[i][0]
                    neighbor_y = current_node.y + direction[i][1]
                    if 0 <= neighbor_x < self.Data.row and 0 <= neighbor_y < self.Data.column and [neighbor_x, neighbor_y] not in visited and (self.Data.map[neighbor_x][neighbor_y]=='*' or self.Data.map[neighbor_x][neighbor_y]=='.'):
                        neighbor_node = Node(neighbor_x, neighbor_y, g=current_node.g+1, com_dir=i, parent=current_node)
                        neighbor_node.h = heuristic(neighbor_node, end_node)
                        neighbor_node.f = neighbor_node.g+neighbor_node.h  # 计算距离
                        heapq.heappush(open_list, neighbor_node)
        return None


    # 返回离position最近的敌方基地的位置以及距离,重载
    def search_nearest_enemy(self, position):
        dist = []
        for i in self.Data.enemybasexy:
            dist.append(abs(i[0] - position[0]) + abs(i[1] - position[1]))
        return [self.Data.enemybasexy[np.argmin(dist)], min(dist)]

    # 返回离position最近的基地的位置以及距离
    def serch_nearest_base(self, position):
        dist = []
        for i in self.Data.basexy:
            dist.append(abs(i[0] - position[0]) + abs(i[1] - position[1]))
        return [self.Data.basexy[np.argmin(dist)], min(dist)]

    # 判断是否可继续飞,若可以则返回加油最多的地方和净加油数
    def able2fly(self):
        dist = []
        index = 0
        for i in self.Data.basexy:
            # 计算去基地加油后的燃油余额
            dist.append(self.Data.base[index] + self.fuel - (i[0] - self.position[0]) + abs(i[1] - self.position[1]))
            index += 1
        return [self.Data.basexy[np.argmax(dist)], max(dist)]

    # 向目标前进一步,优先向上或向下移动,没有进行碰撞检测,没有将飞机变化赋值给Data
    def target_one_step(self, position):
        if self.position[0] > position[0]:
            # 向上走一步
            self.InstrManager.move(self.number, 0)
            self.position[0] = self.position[0] - 1
        elif self.position[0] < position[0]:
            # 向下走一步
            self.InstrManager.move(self.number, 1)
            self.position[0] = self.position[0] + 1
        else:
            if self.position[1] > position[1]:
                # 向左一步
                self.InstrManager.move(self.number, 2)
                self.position[1] = self.position[1] - 1
            elif self.position[1] < position[1]:
                # 向右一步
                self.InstrManager.move(self.number, 3)
                self.position[1] = self.position[1] + 1
        self.fuel = self.fuel - 1

    # 向某个方向移动,燃料减少
    def move(self, direction):
        print(self.number, "飞机移动,方向:", direction)
        self.InstrManager.move(self.number, direction)
        directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]  # 上下左右
        self.position[0] += directions[direction][0]
        self.position[1] += directions[direction][1]
        self.fuel -= 1

    # 向某方向发射导弹,在外面进行数量检测,没有更新地图,在外面进行更新
    def attack_missiles(self, direction, missiles):
        print(self.number, "飞机发射导弹,方向:", direction, "  导弹数量:", missiles)
        self.InstrManager.attack(self.number, direction, missiles)
        self.missile = self.missile - missiles

    # 补充燃油
    def add_fuel(self, fuels):
        print(self.number, "飞机补充燃油", fuels)
        self.InstrManager.fuel(self.number, fuels)
        self.fuel = self.fuel + fuels

    # 补充导弹
    def add_missile(self, missiles):
        print(self.number, "飞机补充导弹", missiles)
        self.InstrManager.missile(self.number, missiles)
        self.missile = self.missile + missiles


# if __name__ == "__main__":
#     data = pythonIn.Data("testcase1.in")
#     instr = pythonIn.InstrManager("testcase1.out")
#     plane_arr = []
#     for i in range(data.plane_num):
#         plane_arr.append(plane(data, instr, i))
#     print("plane[0]的坐标为:", plane_arr[0].position)
#     for i in data.enemybasexy:
#         print("当前敌方基地:", i)
#         print("寻路为:",plane_arr[0].A_star(i))

Node类,一个典型的A*算法。

启发式函数计算曼哈顿距离。

plane类初始化时将信息实例化。
使用深度优先搜索实现寻找最近的地方基地和己方基地,并返回实现这两个目标的路径。

深度优先搜用到的是栈结构。

过程是:从当前飞机位置开始,按照上下左右四个方向递归搜索地图,遇到障碍物(被摧毁的地方基地)跳过,遇到敌方基地或者己方基地记录并构建新的路径。
使用DFS_map记录每个位置的访问顺序,以便回溯生成路径。

当地方基地和己方基地都找到的时候返回结果。如果循环结束或者未找到二者之一,则根据找到的目标返回响应的结果。
说是BFS也没错,因为使用了队列来进行层次遍历。但是回溯更像是DFS。

进行 燃油和导弹搜索同理,以燃油搜索为例,创建一个二维数组DFS_map来记录地图状态,base_way用于存储到达最近基地的路径指示。
当队列非空时,从队列中取出一个节点进行处理,遍历当前节点的四个相邻位置,针对每个相邻位置,进行越界检查,检查是否有充分的燃油供给(计算当前位置到基地的距离,确保基地燃油减去当前位置之后仍然》0)。

进行导弹检查类似,但是可用导弹数量>0即可。满足条件加入访问队列。

A*算法实现路径查找功能,在给定地图上找到从当前位置到目标位置的最短路径。判断当前节点的坐标和目标节点的坐标是否相同,如果相同,通过回溯构建路径path,记录每个结点的移动方向。返回找到的路径path,如果未到达终点,创建一个邻居节点。如果open_list为空,说明已探索所有可能路径但是没有找到目标,返回None。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丘小羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值