001/*
002MIT License
003
004Copyright (c) 2020 earlygrey
005
006Permission is hereby granted, free of charge, to any person obtaining a copy
007of this software and associated documentation files (the "Software"), to deal
008in the Software without restriction, including without limitation the rights
009to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010copies of the Software, and to permit persons to whom the Software is
011furnished to do so, subject to the following conditions:
012
013The above copyright notice and this permission notice shall be included in all
014copies or substantial portions of the Software.
015
016THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
022SOFTWARE.
023 */
024package squidpony.squidai.graph;
025
026import squidpony.squidmath.BinaryHeap;
027
028import java.io.Serializable;
029import java.util.ArrayList;
030import java.util.Collection;
031import java.util.HashMap;
032
033/**
034 * An extended version of {@link squidpony.squidmath.BinaryHeap.Node} that also stores a reference to the parent Graph,
035 * a vertex object of type {@code V}, a Map of neighbor Nodes to the appropriate {@link Connection} per Node, an extra
036 * List of those same Connections for faster iteration, and a lot of internal data used by algorithms in this package.
037 * @param <V> the vertex type; often {@link squidpony.squidmath.Coord}
038 * @author earlygrey
039 */
040public class Node<V> extends BinaryHeap.Node implements Serializable {
041    private static final long serialVersionUID = 1L;
042
043
044    //================================================================================
045    // Graph structure related members
046    //================================================================================
047
048    protected final Graph<V> graph;
049    protected final int idHash;
050    protected final V object;
051    protected HashMap<Node<V>, Connection<V>> neighbors = new HashMap<>();
052    protected ArrayList<Connection<V>> outEdges = new ArrayList<>(); // List for fast iteration
053
054    //================================================================================
055    // Constructor
056    //================================================================================
057
058    protected Node(V v, Graph<V> graph) {
059        super(0.0);
060        this.object = v;
061        this.graph = graph;
062        idHash = System.identityHashCode(this);
063    }
064
065    //================================================================================
066    // Internal methods
067    //================================================================================
068
069    protected Connection<V> getEdge(Node<V> v) {
070        return neighbors.get(v);
071    }
072
073    protected Connection<V> addEdge(Node<V> v, float weight) {
074        Connection<V> edge = neighbors.get(v);
075        if (edge == null) {
076            edge = graph.obtainEdge();
077            edge.set(this, v, weight);
078            neighbors.put(v, edge);
079            outEdges.add(edge);
080            return edge;
081        } else {
082            edge.setWeight(weight);
083        }
084        return edge;
085    }
086    protected Connection<V> removeEdge(Node<V> v) {
087        Connection<V> edge = neighbors.remove(v);
088        if (edge == null) return null;
089        // loop backwards to make Graph#removeNode faster
090        for (int j = outEdges.size()-1; j >= 0; j--) {
091            Connection<V> connection = outEdges.get(j);
092            if (connection.equals(edge)) {
093                outEdges.remove(j);
094                break;
095            }
096        }
097        return edge;
098    }
099
100    protected void disconnect() {
101        neighbors.clear();
102        outEdges.clear();
103    }
104
105    //================================================================================
106    // Public Methods
107    //================================================================================
108
109    public Collection<Connection<V>> getConnections() {
110        return outEdges;
111    }
112
113    public V getObject() {
114        return object;
115    }
116
117    //================================================================================
118    // Algorithm fields and methods
119    //================================================================================
120
121    /**
122     * Internal; tracking bit for whether this Node has already been visited during the current algorithm.
123     */
124    protected boolean visited;
125    /**
126     * Internal; tracking bit for whether this Node has been checked during the current algorithm.
127     */
128    protected boolean seen;
129    /**
130     * Internal; confirmed distance so far to get to this Node from the start.
131     */
132    protected double distance;
133    /**
134     * Internal; estimated distance to get from this Node to the goal.
135     */
136    protected double estimate;
137    /**
138     * Internal; a reference to the previous Node in a BinaryHeap.
139     */
140    protected Node<V> prev;
141    /**
142     * Internal; a utility field used to store depth in some algorithms.
143     */
144    protected int i;
145    /**
146     * Internal; a utility field used to distinguish which algorithm last used this Node.
147     */
148    protected int lastRunID;
149
150    /**
151     * If {@code runID} is not equal to {@link #lastRunID}, this resets the internal fields {@link #visited},
152     * {@link #seen}, {@link #distance}, {@link #estimate}, {@link #prev}, and {@link #i}, then sets {@link #lastRunID}
153     * to {@code runID}.
154     * @param runID an int that identifies which run of an algorithm is currently active
155     * @return true if anything was reset, or false if {@code runID} is equal to {@link #lastRunID}
156     */
157    protected boolean resetAlgorithmAttributes(int runID) {
158        if (runID == this.lastRunID) return false;
159        visited = false;
160        prev = null;
161        distance = Float.MAX_VALUE;
162        estimate = 0;
163        i = 0;
164        seen = false;
165        this.lastRunID = runID;
166        return true;
167    }
168    
169    //================================================================================
170    // Misc
171    //================================================================================
172
173
174    @Override
175    public boolean equals(Object o) {
176        return o == this;
177    }
178
179
180    @Override
181    public int hashCode() {
182        return idHash;
183    }
184
185    @Override
186    public String toString() {
187        return "["+object+"]";
188    }
189}