示例#1
0
    // Função Start() do Unity, executada ao iniciar a execução do programa
    void Start()
    {
        // Obtendo a Referência do Agente
        player = HyruleMapManager.getInstance().getPlayerReference();

        // Comentários auxiliares durante a implementação

        // 1. add to stack -> lost woods, dungeons 1, 2, 3 and house, dungeons are the travelling salesman problem
        // 2. on the begginig the stack will be: lostWoords | link's house | dungeon | dungeon | dungeon
        // 3. remove first on the stack and A* to it
        // 4. when reach dungeon, will go inside it, add to stack -> exit | get pendant
        // 5. go to 3.

        // sample execution:
        // Init stack.     -> stack: lost woods | house | dungeon a | dungeon b | dungeon c
        // go to dungeon c -> stack: lost woods | house | dungeon a | dungeon b | exit dungeon c | get pendant c
        // get pendant c   -> stack: lost woods | house | dungeon a | dungeon b | exit dungeon c
        // exit dungeon c  -> stack: lost woods | house | dungeon a | dungeon b
        // go to dungeon b -> stack: lost woods | house | dungeon a | exit dungeon b | get pendant b
        // get pendant b   -> stack: lost woods | house | dungeon a | exit dungeon b
        // exit dungeon b  -> stack: lost woods | house | dungeon a
        // go to dungeon a -> stack: lost woods | house | exit dungeon a | get pendant a
        // get pendant a   -> stack: lost woods | house | exit dungeon a
        // exit dungeon a  -> stack: lost woods | house
        // go to house     -> stack: lost woods
        // go to lost woods
        // the end

        // for each iteration -> remove objective from stack, A* until reach it, when accomplished, get next objective

        /*   ALGORITHM:
         * while(objectivesStack is not empty)
         *
         *   if(!objective)
         *      objective = objectivesStack.pop();
         *
         *  while(!reached_object)
         *      calculate_path_to_objective_using_A*()
         *      execute_commands_and_go_to_objective()
         *      delete(objective)
         *
         *
         *
         * calculate_path_to_objective_using_A*():
         *    calculate_heuristics_on_map()
         *
         *    evaluated_node = current_node
         *    while(evaluting_node != goal_node)
         *        foreach(neighbour_tiles)
         *            select_nodes_to_evaluate()
         *            get(f(n))
         *            push them into the queue()
         *            evaluating_node = queueNext
         *
         */

        // Função que dará inicio aos planejamentos e ações do agente
        //saveHyrule ();
    }
示例#2
0
    /*
     *
     * Função de inserir movimentos na lista de movimentos do agente
     *
     * Recebe o nodo objetivo que foi atingido através da busca
     *
     * Através da informação do nodo e de seu pai é possivel obter o movimento que o agente
     * deve realizar para ir do nodo pai para o filho.
     *
     * É executado um laço percorrendo os pais dos nodos até que seja encontrada a raiz (pai nulo)
     */
    private void insertMovement(Tile goal)
    {
        //Debug.Log ("found goal!");

        // temos o objetivo, agora podemos atualizar os custos dos caminhos!
        custoCaminho   = goal.getG();
        custoAcumulado = custoAcumulado + custoCaminho;
        UserInterface.getInstance().setCaminhoParcial(custoCaminho);
        UserInterface.getInstance().setCaminhoTotal(custoAcumulado);

        Tile    p = goal;
        Vector2 pos;

        while (p.getParent() != null)
        {
            // Marca na interface que essa posição faz parte do caminho final
                        #if VISUALIZE_ASTAR_STEPS
            HyruleMapManager.getInstance().markPath((int)p.getPosition().x, (int)p.getPosition().y);
                        #endif

            // obtém a diferença entre a posição atual e do pai
            pos = new Vector2(p.getPosition().x - p.getParent().getPosition().x,
                              p.getPosition().y - p.getParent().getPosition().y);

            //Debug.Log ("p position: " + p.getPosition());
            //Debug.Log ("p parent position: " + p.getParent ().getPosition ());
            //Debug.Log ("pos: " + pos);

            // de acordo com a posição obtida calcula o movimento que o agente terá que fazer
            // e empilha esse movimento
            if (pos == Vector2.up)
            {
                //Debug.Log ("up: " + pos);
                movements.Insert(0, 'R');
            }
            else if (pos == Vector2.down)
            {
                //Debug.Log ("down: " + pos);
                movements.Insert(0, 'L');
            }
            else if (pos == Vector2.left)
            {
                //Debug.Log ("left: " + pos);
                movements.Insert(0, 'U');
            }
            else if (pos == Vector2.right)
            {
                //Debug.Log ("right:" + pos);
                movements.Insert(0, 'D');
            }

            p = p.getParent();
        }
    }
示例#3
0
    /*
     * Função que movimenta o agente, recebe uma lista de movimentos
     *
     * Para cada movemento da lista de movimentos, o agente efetivamente realiza o movimento
     * É a função que transforma todo o planejamento em ação
     *
     */
    private IEnumerator move_to(List <char> moveSequence)
    {
        //Debug.Log ("movimentos: " + moveSequence.Count);
        for (int i = 0; i < moveSequence.Count; i++)
        {
            switch (moveSequence [i])
            {
            case 'U':
                player.GetComponent <Player> ().goUp();
                break;

            case 'D':
                player.GetComponent <Player> ().goDown();
                break;

            case 'L':
                player.GetComponent <Player> ().goLeft();
                break;

            case 'R':
                player.GetComponent <Player> ().goRight();
                break;
            }

            UserInterface.getInstance().setActualTileCost(HyruleMapManager.getInstance().getCostForTile((int)player.transform.position.x, (int)player.transform.position.y));
            yield return(new WaitForSeconds(0.1f));
        }

        //yield return new WaitForSeconds (1.0f);
        movements.Clear();

        string objective = HyruleMapManager.getInstance().reachedObjectiveAction((int)player.transform.position.x, (int)player.transform.position.y);

        if (objective == "pendant0" || objective == "pendant1" || objective == "pendant2")
        {
            player.GetComponent <Player>().gotPendant();
        }

        agentBusy = false;
        saveHyrule();
    }
示例#4
0
    /*
     * Aqui tem o inicio o Algoritmo de Busca Heurística A*
     *
     * Algoritmo:
     *
     * calcula os valores de heurística no mapa para o objetivo
     * marca todos as posições do mapa como não visitadas
     *
     * coloca a posição inicial do agente na fila
     * escolhe para expandir o nodo com menor valor de f(n) = g(n) + h(n)
     * expande o nodo, adicionando os resultados na fila
     * repete essas ações até encontrar um nodo que corresponde ao objetivo
     *
     */
    private IEnumerator astar_search(Vector2 goal)
    {
        //Debug.Log ("goal: " + goal);

        // Calculando as Heurísticas no Mapa
        HyruleMapManager.getInstance().setHeuristicBoard((int)goal.x, (int)goal.y);
        // Marcando todas as posições do mapa como não visitadas
        HyruleMapManager.getInstance().unvisit();

        //Debug.Log("player current position: " + player.transform.position);

        // Caso haja alguma posição resquiciosa de outras execuções limpa a fila
        if (evaluationQueue.Count > 0)
        {
            evaluationQueue.Clear();
        }

        // Colocando posição atual na fila de avaliação
        evaluationQueue.Add(new Tile(player.transform.position, 0, 0, null));

        Tile evaluating;

        // Escolhe o nodo a ser expandido de menor valor f(n)
        // Remove-o da fila de nodos a serem avaliados e adiciona na lista de nodos avaliados
        evaluating = evaluationQueue [0];
        for (int i = 1; i < evaluationQueue.Count; i++)
        {
            if (evaluating.getF() > evaluationQueue [i].getF())
            {
                evaluating = evaluationQueue [i];
            }
        }
        evaluationQueue.Remove(evaluating);
        //Debug.Log("evaluating position " + evaluating.getPosition());
        closeEvaluations.Add(evaluating);

        // Marca na interface gráfica que o nodo foi expandido
                #if VISUALIZE_ASTAR_STEPS
        HyruleMapManager.getInstance().markClosed((int)evaluating.getPosition().x, (int)evaluating.getPosition().y);
                #endif

        // Faz a expansão do nodo
        expandNode(evaluating);

                #if VISUALIZE_ASTAR_STEPS
        yield return(new WaitForSeconds(delayTime));
                #endif

        // Prepara o próximo nodo para ser avaliado pelo mesmo próximo feito anteriormente
        evaluating = evaluationQueue [0];
        for (int i = 1; i < evaluationQueue.Count; i++)
        {
            if (evaluating.getF() > evaluationQueue [i].getF())
            {
                evaluating = evaluationQueue [i];
            }
        }
        evaluationQueue.Remove(evaluating);
        closeEvaluations.Add(evaluating);

                #if VISUALIZE_ASTAR_STEPS
        HyruleMapManager.getInstance().markClosed((int)evaluating.getPosition().x, (int)evaluating.getPosition().y);
                #endif

        // Executa essas ações já descritas acima enquanto houverem elementos a serem avaliados
        while (evaluationQueue.Count > 0)
        {
            expandNode(evaluating);
                        #if VISUALIZE_ASTAR_STEPS
            yield return(new WaitForSeconds(delayTime));
                        #endif

            // Caso o nodo atual seja o objetivo
            if (evaluating.getPosition() == goal)
            {
                // São calculados os movimentos gerados pelo algoritmo
                insertMovement(evaluating);
                // O Agente então se movimenta
                StartCoroutine(move_to(movements));
                                #if VISUALIZE_ASTAR_STEPS
                yield break;
                                #else
                yield return(new WaitForSeconds(delayTime));
                                #endif
            }

            evaluating = evaluationQueue [0];
            for (int i = 1; i < evaluationQueue.Count; i++)
            {
                if (evaluating.getF() > evaluationQueue [i].getF())
                {
                    evaluating = evaluationQueue [i];
                }
            }
            evaluationQueue.Remove(evaluating);
            closeEvaluations.Add(evaluating);
                        #if VISUALIZE_ASTAR_STEPS
            HyruleMapManager.getInstance().markClosed((int)evaluating.getPosition().x, (int)evaluating.getPosition().y);
                        #endif
        }
    }
示例#5
0
    /*
     *
     * Função para expandir nodo, recebe um nodo.
     *
     * A função recebe um nodo e coloca na fila os 4 nodos adjacentes, cada um com
     * seus custos de g(n) e f(n)
     *
     * Nessa função, os nodos expandidos são marcados como visitados e são mostrados na interface
     * na lista de proximos a serem expandidos
     *
     */
    private void expandNode(Tile node)
    {
        //Debug.Log ("expanding node");
        Vector2 pos;
        int     h;
        int     g_value;


        // obtendo a posição do nodo resultado da expansão para cima
        pos = node.getPosition() + Vector2.up;
        // obtendo o valor de g(n) para esse nodo
        g_value = node.getG() + (HyruleMapManager.getInstance().getCostForTile((int)pos.x, (int)pos.y));
        // calculando o valor de h(n)
        h = (g_value +
             (HyruleMapManager.getInstance().getHeuristicValue((int)pos.x, (int)pos.y)));

        // Verificando se o nodo é possível de ser visitado (h >= 0) e se ele não foi visitado
        if (h >= 0 && HyruleMapManager.getInstance().visit((int)pos.x, (int)pos.y))
        {
            this.insertOnQueueList(new Tile(pos, h, g_value, node));

            // Marca na interface gráfica que o nodo foi aberto para expansão
                        #if VISUALIZE_ASTAR_STEPS
            HyruleMapManager.getInstance().markOpen((int)pos.x, (int)pos.y);
                        #endif
        }

        // obtendo a posição do nodo resultado da expansão para baixo
        pos     = node.getPosition() + Vector2.down;
        g_value = node.getG() + (HyruleMapManager.getInstance().getCostForTile((int)pos.x, (int)pos.y));
        h       = (g_value +
                   (HyruleMapManager.getInstance().getHeuristicValue((int)pos.x, (int)pos.y)));
        if (h >= 0 && HyruleMapManager.getInstance().visit((int)pos.x, (int)pos.y))
        {
            this.insertOnQueueList(new Tile(pos, h, g_value, node));

                        #if VISUALIZE_ASTAR_STEPS
            HyruleMapManager.getInstance().markOpen((int)pos.x, (int)pos.y);
                        #endif
        }

        // obtendo a posição do nodo resultado da expansão para a esquerda
        pos     = node.getPosition() + Vector2.left;
        g_value = node.getG() + (HyruleMapManager.getInstance().getCostForTile((int)pos.x, (int)pos.y));
        h       = (g_value +
                   (HyruleMapManager.getInstance().getHeuristicValue((int)pos.x, (int)pos.y)));
        if (h >= 0 && HyruleMapManager.getInstance().visit((int)pos.x, (int)pos.y))
        {
            this.insertOnQueueList(new Tile(pos, h, g_value, node));

                        #if VISUALIZE_ASTAR_STEPS
            HyruleMapManager.getInstance().markOpen((int)pos.x, (int)pos.y);
                        #endif
        }

        // obtendo a posição do nodo resultado da expansão para a direita
        pos     = node.getPosition() + Vector2.right;
        g_value = node.getG() + (HyruleMapManager.getInstance().getCostForTile((int)pos.x, (int)pos.y));
        h       = (g_value +
                   (HyruleMapManager.getInstance().getHeuristicValue((int)pos.x, (int)pos.y)));
        if (h >= 0 && HyruleMapManager.getInstance().visit((int)pos.x, (int)pos.y))
        {
            this.insertOnQueueList(new Tile(pos, h, g_value, node));

                        #if VISUALIZE_ASTAR_STEPS
            HyruleMapManager.getInstance().markOpen((int)pos.x, (int)pos.y);
                        #endif
        }
    }
    /*
     * Função Awake() pertence ao escopo de funções do Unity
     * A função Awake é executada antes da função Start()
     */
    void Awake()
    {
        // Referentes ao Padrão Singleton
        if (instance == null)
        {
            instance = this;
        }
        else if (instance != this)
        {
            Destroy(gameObject);
        }

        DontDestroyOnLoad(this);

        hyruleMap.createHeuristicBoard();
        dungeon1Map.createHeuristicBoard();
        dungeon2Map.createHeuristicBoard();
        dungeon3Map.createHeuristicBoard();
        map.createHeuristicBoard();

        // Criando os vetores de referências
        dungeonsReference     = new GameObject[dungeons.Length];
        pendantsReference     = new GameObject[pendants.Length];
        dungeonsExitReference = new GameObject[dungeonsExitPosition.Length];

        // Informando que nenhum pingente ainda foi coletado
        pendantsTaken = new bool[pendantsPositions.Length];
        for (int i = 0; i < pendantsTaken.Length; i++)
        {
            pendantsTaken [i] = false;
        }


        // Link deve voltar à sua casa antes de partir?
        //GameManager.getInstance ().push (new Vector2(playerStartingPosition.y - map.getCount() / 2, playerStartingPosition.x - map.getCount() / 2);

        /*
         *
         * TO DO
         *
         * Para encontrar a melhor ordem para pegar os pingentes é necessário
         * resolver o problema do caixeiro viajante (travelling salesman).
         *
         * Para isto considere que antes do agente chegar à entrada de Lost Woods ele deverá iniciar a
         * jornada na casa de Link e voltar a esta casa com todos os pingentes coletados.
         *
         * Resolva tal problema usando alguma das técnicas de busca especificadas na disciplina.
         *
         * O caixeiro viajante é feito na posição das dungeons, a posição das dungeons são então empilhadas
         * na pilha de objetivos
         */

        //GameManager.getInstance ().push (new Vector2(dungeonPositions [1].y - (map.getCount()/2), dungeonPositions[1].x - (map.getCount()/2)));
        //GameManager.getInstance ().push (new Vector2(dungeonPositions [2].y - (map.getCount()/2), dungeonPositions[2].x - (map.getCount()/2)));
        //GameManager.getInstance ().push (new Vector2(dungeonPositions [0].y - (map.getCount()/2), dungeonPositions[0].x - (map.getCount()/2)));

        // Criando os Holders dos tiles referentes ao A*
        openTilesHolder   = new GameObject("Open Tiles Holder");
        closedTilesHolder = new GameObject("Closed Tiles Holder");
        pathTilesHolder   = new GameObject("Path Tiles Holder");

        // Instanciando o Agente e guardando sua referência
        playerRef = Instantiate(player, new Vector3(playerStartingPosition.y - (map.getCount() / 2), playerStartingPosition.x - (map.getCount() / 2), -9), Quaternion.identity) as GameObject;
        playerRef.transform.eulerAngles = new Vector3(playerRef.transform.eulerAngles.x, playerRef.transform.eulerAngles.y, playerRef.transform.eulerAngles.z + 90);
    }