Ejemplo n.º 1
0
    IEnumerator Work(Node origin, Node destiny, int capacity, bool precission, bool manhattan, Unidad solicitante, Node[,] copiaNodo)
    {
        PriorityQueue abiertos = new PriorityQueue(capacity);
        List <Node>   cerrados = new List <Node>();
        bool          final = false;
        Node          actualNode, oldNode, nodoOrigen, nodoDestino;

        nodoOrigen       = origin;
        nodoDestino      = destiny;
        nodoOrigen.Cost  = 0;
        nodoOrigen.Route = null;
        abiertos.Encolar(nodoOrigen, nodoOrigen.Cost);
        actualNode = null;

        int contador     = 0;
        int fragmentador = 0;

        while (!final)
        {
            //para evitar bucles (nunca se sabe...)
            if (contador > 10000)
            {
                yield break;
            }

            contador++;
            fragmentador++;
            oldNode    = actualNode;
            actualNode = abiertos.Desencolar();
            if (actualNode == null) //si el monticulo se vaica
            {
                actualNode = oldNode;
                break;
            }

            foreach (Pareja value in actualNode.ArrayVecinos)
            {
                //si el nodo esta ocupado, se descarta
                if (/*value.nodo.unidad != null || */ value.nodo.resourceType != TipoRecurso.NullResourceType)
                {
                    continue;
                }


                //si se llega al nodo con un coste mejor
                if (actualNode.Cost + value.distancia < value.nodo.Cost)
                {
                    //se actualiza el coste
                    value.nodo.Cost = actualNode.Cost + value.distancia;

                    //calculamos nueva prioridad del nodo
                    if (manhattan)
                    {
                        value.nodo.Estimated = value.nodo.Cost + heuristicaManhattan(value.nodo.position, destiny.position);
                    }
                    else//euclideana
                    {
                        value.nodo.Estimated = value.nodo.Cost + Vector3.Distance(value.nodo.position, destiny.position);
                    }

                    //actualizar ruta hasta el nodo
                    value.nodo.Route = actualNode;


                    if (value.nodo.QueuePosition == Node.EN_LISTA_CERRADOS) //Si esta en la lista de cerrados, lo sacamos de la lista
                    {
                        cerrados.Remove(value.nodo);
                    }

                    //comprobamos si ya esta en abiertos
                    if (abiertos.Contiene(value.nodo))
                    {
                        //si esta en la lista, reducimos su prioridad
                        abiertos.ActualizarPrioridad(value.nodo, value.nodo.Estimated);
                    }
                    else
                    {
                        //si no esta, se encola
                        abiertos.Encolar(value.nodo, value.nodo.Estimated);
                    }
                }
            }

            //el nodo que hemos recorrido entra en cerrado
            cerrados.Add(actualNode);
            //Debug.Log("Metido " + actualNode.gameObject.name + " en cerrados");
            actualNode.QueuePosition = Node.EN_LISTA_CERRADOS;
            //Debug.Log("Peek = " + abiertos.Peek().gameObject.name);


            if (abiertos.NumElementos() == 0 || (precission == false && abiertos.Primero == nodoDestino))
            {
                final = true;
            }
            else if (abiertos.NumElementos() == 0 || abiertos.Primero.Cost > nodoDestino.Cost)
            {
                final = true;
            }

            if (fragmentador >= 50000 /*100*/)
            {
                //print(solicitante.gameObject.name + " fragmentando A*");
                fragmentador = 0;
                yield return(null);
            }
        }

        abiertos = null;
        cerrados.Clear();

        List <Vector3> path = new List <Vector3>();

        actualNode = destiny;                   //Reciclamos actualNode para usarlo como auxiliar
        while (actualNode != null)
        {
            path.Add(actualNode.position);
            actualNode = actualNode.Route;
        }

        StageData.currentInstance.LimpiarGrafo(StageData.currentInstance.CG.nodeMap);
        solicitante.ResultadoAEstrella(path);
    }