Алгоритм AStar в Python - PullRequest
       20

Алгоритм AStar в Python

0 голосов
/ 01 декабря 2019

Проблема, которую необходимо решить, - это склад, на который прибывает ряд ящиков, у этих ящиков есть день входа и день выхода. Ящики хранятся в кучах, которые имеют не более MAXSIZE ящиков. Необходимо убедиться, что невозможно хранить коробку с выходным днем ​​после даты, указанной ниже. Я попытался решить эту проблему в python, выполнив следующие функции:

class Bcolors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'

class Caja:
    def __init__ (self, id, entrada, salida):
        self.id = id
        self.entrada = entrada
        self.salida = salida

    def to_string (self):
        return "Caja(" + str(self.id) + "," + str(self.entrada) + "," + str(self.salida) + ")"

class Pila:
    def __init__ (self, cajas, disponible, total):
        self.cajas = cajas
        self.disponible = disponible
        self.total = total

class Estado:
    def __init__ (self, pilas, cajaColocada):
        self.pilas = pilas
        self.cajaColocada = cajaColocada

class Nodo:
    def __init__ (self, estado, posibilidades, visitado, coste):
        self.estado = estado
        self.posibilidades = posibilidades
        self.visitado = visitado
        self.coste = coste

    def __lt__(self, other):
        return self.coste < other.coste

def crea_cajas():
    cajas = []

    cajas.append(Caja(9,1,17))
    cajas.append(Caja(10,1,17))
    cajas.append(Caja(11,1,17))
    cajas.append(Caja(12,1,17))
    cajas.append(Caja(13,1,17))
    cajas.append(Caja(14,1,17))
    cajas.append(Caja(15,1,17))
    cajas.append(Caja(16,1,17))
    cajas.append(Caja(17,1,17))
    cajas.append(Caja(18,1,17))
    cajas.append(Caja(19,1,17))
    cajas.append(Caja(20,1,17))
    cajas.append(Caja(3,1,18))
    cajas.append(Caja(4,1,18))
    cajas.append(Caja(5,1,18))
    cajas.append(Caja(6,1,18))
    cajas.append(Caja(7,1,18))
    cajas.append(Caja(8,1,18))
    cajas.append(Caja(1,1,19))
    cajas.append(Caja(2,1,19))

    return cajas

Эта функция отвечает за создание списка ящиков в соответствии с порядком прибытия на склад.

def imprime_estado(estado, type):
    global MAXSIZE, MAXPILAS;

    if type == 1:
        print(Bcolors.OKGREEN + "#####################################################################")
    else:
        print(Bcolors.WARNING + "#####################################################################")
    print("# Caja colocada en este estado:" + str(estado.cajaColocada))
    print("# Coste del estado:" + str(calcula_coste(estado)))
    for i in range(MAXPILAS):
        disponible = estado.pilas[i].disponible
        if disponible == MAXSIZE:
            print("# PILA " + str(i))
            print("# - NONE")
        else:
            print("# PILA " + str(i))
            for j in range(MAXSIZE - estado.pilas[i].disponible):
                print("# - " + estado.pilas[i].cajas[j].to_string())
    print("#####################################################################" + Bcolors.ENDC)

Эта функция используется в качестве отладки, печатая последнее состояние в качестве аргумента и имея возможность выбирать между зеленым цветом или выводом предупреждения со вторым аргументом функции.

def calcula_coste(estado):
    global MAXSIZE, MAXPILAS;
    coste = 0

    for i in range(MAXPILAS):
        if estado.pilas[i].disponible == MAXSIZE:
            continue
        coste = coste + 1 + (MAXSIZE/(MAXSIZE - estado.pilas[i].disponible))

    return coste

Эта функция рассчитывает стоимость узла в соответствии с его состоянием, чтобы алгоритм AStar мог выбрать следующий узел с наименьшей стоимостью. Цель состоит в том, чтобы использовать как можно меньше батарей, следовательно, используется функция расчета стоимости.

def genera_nodos(estados):
    numero_estados = len(estados)
    nodos = []

    for i in range(numero_estados):
        nodos.append(Nodo(estados[i],None,0,calcula_coste(estados[i])))

    return nodos

Эта функция получает в качестве входных данных список состояний и возвращает список узлов, новый узел для каждого состояния доставляется какаргумент.

def genera_estados(nodo_actual, cajas_entrada):
    global MAXSIZE, MAXPILAS;
    estados_posibles = []
    caja_actual = None
    caja_siguiente = None

    if nodo_actual.estado == None:
        pilas_estado = []
        for i in range(MAXPILAS):
            cajas_pila = []
            if i == 0:
                cajas_pila.append(cajas_entrada[0])
                pilas_estado.append(Pila(cajas_pila,MAXSIZE-1,MAXSIZE))
            else:
                pilas_estado.append(Pila([],MAXSIZE,MAXSIZE))
        estados_posibles.append(Estado(pilas_estado,0))
    else:
        pilas_actual = nodo_actual.estado.pilas
        caja_actual = nodo_actual.estado.cajaColocada
        caja_siguiente = caja_actual + 1
        for i in range(MAXPILAS):
            if pilas_actual[i].disponible == 0:
                continue
            elif pilas_actual[i].disponible == MAXSIZE:
                nuevo_estado = Estado(pilas_actual,caja_siguiente)
                nuevo_estado.pilas[i].cajas.append(cajas_entrada[caja_siguiente])
                nuevo_estado.pilas[i].disponible = MAXSIZE - 1
                estados_posibles.append(nuevo_estado)
                break
            else:
                if pilas_actual[i].cajas[MAXSIZE-1-pilas_actual[i].disponible].salida < cajas_entrada[caja_siguiente].salida:
                    continue
                else:
                    nuevo_estado = Estado(pilas_actual,caja_siguiente)
                    nuevo_estado.pilas[i].disponible = pilas_actual[i].disponible - 1
                    nuevo_estado.pilas[i].cajas.append(cajas_entrada[caja_siguiente])
                    estados_posibles.append(nuevo_estado)

    for estado in estados_posibles:
        imprime_estado(estado, 2)
    return estados_posibles

Эта функция отвечает за создание всех возможных состояний для размещения следующего блока в соответствии с прошлым текущим узлом в качестве аргумента. Проблема заключается в том, что, например, при получении в качестве входных данных узла, состояние которого следующее:

#####################################################################
# box in this state en:0
# cost :5.0
# PILE 0
# - Caja(9,1,17)
# PILE 1
# - NONE
# PILE 2
# - NONE
# PILE 3
# - NONE
# PILE 4
# - NONE
#####################################################################

Я надеюсь получить в качестве выходных данных два состояния в списке, соответствующих двум возможным состояниям размещенияполе в стеке 1 над уже расположенным или помещающим его в стек 2:

#####################################################################
# box in this state en:1
# cost :3
# - Caja(9,1,17)
# - Caja(10,1,17)
# PILA 1
# - NONE
# PILA 2
# - NONE
# PILA 3
# - NONE
# PILA 4
# - NONE
#####################################################################
#####################################################################
# box in this state en:1
# cost :10
# - Caja(9,1,17)
# PILA 1
# - Caja(10,1,17)
# PILA 2
# - NONE
# PILA 3
# - NONE
# PILA 4
# - NONE
#####################################################################

Но вместо этого я получаю следующий список функций:

#####################################################################
# box in this state:1
# cost:8.0
# PILA 0
# - Caja(9,1,17)
# - Caja(10,1,17)
# PILA 1
# - Caja(10,1,17)
# PILA 2
# - NONE
# PILA 3
# - NONE
# PILA 4
# - NONE
#####################################################################
#####################################################################
# box in this state en:1
# cost:8.0
# PILA 0
# - Caja(9,1,17)
# - Caja(10,1,17)
# PILA 1
# - Caja(10,1,17)
# PILA 2
# - NONE
# PILA 3
# - NONE
# PILA 4
# - NONE
#####################################################################

Тело выполнения файлавыглядит следующим образом:

#Se declaran las dos listas de nodos
nodos_posibles = []
nodos_visitados = []
estado_final = None

#Se caragan las cajas de entrada
cajas_entrada = crea_cajas()

#Se crea el nodo inicial
nodo_inicial = Nodo(None,None,1,0)
nodos_visitados.append(nodo_inicial)

#Se crean los estados desde los que se puede ir del nodo inicial
estados_posibles = genera_estados(nodo_inicial, cajas_entrada)
nodos_posibles = genera_nodos(estados_posibles)
nodo_inicial.posibilidades = nodos_posibles

#Comienza el algoritmo
while True:
    if len(nodos_posibles) == 0:
        break
    nodo_actual = nodos_posibles[0]
    imprime_estado(nodo_actual.estado, 1)
    nodos_posibles.pop(0)
    nodo_actual.visitado = 1
    if (nodo_actual.estado.cajaColocada == len(cajas_entrada)-1):
        estado_final = nodo_actual.estado
        break
    estados_posibles = genera_estados(nodo_actual, cajas_entrada)
    if len(estados_posibles) == 0:
        nodo_actual.posibilidades = None
        nodos_visitados.append(nodo_actual)
        continue
    nodos_alcanzables = genera_nodos(estados_posibles)
    for i in range(len(nodos_alcanzables)):
        #imprime_estado(nodos_alcanzables[i].estado,2)
        nodos_posibles.append(nodos_alcanzables[i])
    nodo_actual.posibilidades = nodos_alcanzables
    nodos_visitados.append(nodo_actual)

if estado_final == None:
    print("NO SE PUEDEN COLOCAR LAS PILAS CON ESA ENTRADA DE CAJAS")
else:
    print(Bcolors.OKBLUE + "ESTADO FINAL ENCONTRADO")
    imprime_estado(estado_final)

Я хотел бы знать, как решить проблему функции, отвечающей за создание возможных состояний, на основе узла, полученного в качестве параметра, который соответствует узлу, посещаемому алгоритмом AStar.

...