game.pathfinding.AStar.java Source code

Java tutorial

Introduction

Here is the source code for game.pathfinding.AStar.java

Source

// Copyright (C) 2002-2010 StackFrame, LLC http://www.stackframe.com/
// This software is provided under the GNU General Public License, version 2.
package game.pathfinding;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import com.google.common.collect.Ordering;

/**
 * An implementation of the A* path finding algorithm.
 *
 * @author Gene McCulley
 */
public class AStar<T extends Node<T>> extends AbstractPathFinder<T> {

    private class State extends NodeState<T> implements Comparable<State> {

        private final double costFromStart;
        private final double costToGoal;

        private State(final T node, final double costFromStart, final State parent, final Collection<T> goals) {
            super(node, parent);
            this.costFromStart = costFromStart;
            costToGoal = minimumPathCostEstimate(node, goals);
        }

        private double minimumPathCostEstimate(final T node, final Collection<T> goals) {
            double min = Double.MAX_VALUE;
            for (final T goal : goals) {
                final double cost = node.pathCostEstimate(goal);
                if (cost < min) {
                    min = cost;
                }
            }

            return min;
        }

        private double totalCost() {
            return costFromStart + costToGoal;
        }

        @Override
        public int compareTo(final State other) {
            return (int) (totalCost() - other.totalCost());
        }

    }

    @Override
    public Optional<List<T>> findPath(final Collection<T> graph, final T start, final T goal) {
        return findPath(graph, start, Collections.singleton(goal));
    }

    @Override
    public Optional<List<T>> findPath(final Collection<T> graph, final T start, final Collection<T> goals) {
        canceled = false;
        final Map<T, State> open = new HashMap<T, State>();
        final Map<T, State> closed = new HashMap<T, State>();
        final State startState = new State(start, 0, null, goals);
        open.put(start, startState);
        final Ordering<Map.Entry<T, State>> orderByEntryValue = orderByEntryValue();
        while (!(open.isEmpty() || canceled)) {
            final State state = open.remove(orderByEntryValue.min(open.entrySet()).getKey());
            fireConsidered(new PathEvent<T>(this) {

                private static final long serialVersionUID = 1L;

                @Override
                public List<T> getPath() {
                    return state.makePath();
                }

            });
            if (goals.contains(state.node))
                return Optional.of(state.makePath());
            else {
                for (final T newNode : state.node.neighbors()) {
                    final double newCost = state.costFromStart + state.node.traverseCost(newNode);
                    final State openNode = open.get(newNode);
                    if (openNode != null && openNode.costFromStart <= newCost) {
                        continue;
                    }

                    final State closedNode = closed.get(newNode);
                    if (closedNode != null && closedNode.costFromStart <= newCost) {
                        continue;
                    }

                    if (closedNode != null) {
                        closed.remove(newNode);
                    }

                    if (openNode != null) {
                        open.remove(newNode);
                    }

                    final State newState = new State(newNode, newCost, state, goals);
                    open.put(newNode, newState);
                }
            }

            closed.put(state.node, state);
        }

        return Optional.empty();
    }

    static private <K, V extends Comparable<V>> Ordering<Map.Entry<K, V>> orderByEntryValue() {
        return new Ordering<Map.Entry<K, V>>() {

            @Override
            public int compare(final Map.Entry<K, V> o1, final Map.Entry<K, V> o2) {
                return o1.getValue().compareTo(o2.getValue());
            }

        };
    }

}