001/*
002 * Trident - A Multithreaded Server Alternative
003 * Copyright 2014 The TridentSDK Team
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package net.tridentsdk.server.entity.ai.pathfind;
019
020import net.tridentsdk.base.Position;
021
022import javax.annotation.concurrent.NotThreadSafe;
023
024@NotThreadSafe
025public class Node {
026    private Node parent;
027    private final int x;
028    private final int y;
029    private final int z;
030
031    private double h = -1;
032    private double g = -1;
033    private double f = -1;
034
035    public Node(Node parent, Position position) {
036        this(parent, position.x(), position.y(), position.z());
037    }
038
039    public Node(Node parent, double x, double y, double z) {
040        this(parent, (int) x, (int) y, (int) z);
041    }
042
043    public Node(Node parent, int x, int y, int z) {
044        this.parent = parent;
045        this.x = x;
046        this.y = y;
047        this.z = z;
048    }
049
050    /**
051     * Get f value of node.
052     *
053     * @return F value
054     */
055    public double getF() {
056        return f;
057    }
058
059    /**
060     * Get node relative to current.
061     *
062     * @param dx relative x
063     * @param dy relative y
064     * @param dz relative z
065     * @return Relative node with current as parent
066     */
067    public Node getRelative(int dx, int dy, int dz) {
068        return new Node(this, x + dx, y + dy, z + dz);
069    }
070
071    /**
072     * Get the node x coord.
073     *
074     * @return X coord of node
075     */
076    public int x() {
077        return x;
078    }
079
080    /**
081     * Get the node y coord
082     *
083     * @return Y coord of node
084     */
085    public int y() {
086        return y;
087    }
088
089    /**
090     * Get the node z coord
091     *
092     * @return Z coord of node
093     */
094    public int z() {
095        return z;
096    }
097
098    /**
099     * Set the node's parent.
100     *
101     * @param parent New parent of node
102     */
103    public void setParent(Node parent) {
104        this.parent = parent;
105    }
106
107    /**
108     * Get the current node parent.
109     *
110     * @return Parent of node
111     */
112    public Node parent() {
113        return parent;
114    }
115
116    /**
117     * Calculate distance cost based on euclidean distance.
118     *
119     * @param target Final tile in path
120     */
121    public void calculateH(Node target) {
122        this.h = distance(target);
123    }
124
125    /**
126     * Calculate movement cost, we dislike jumping and moving diagonally.
127     */
128    public void calculateG() {
129        double dx = Math.abs(x - parent.x);
130        double dy = Math.abs(y - parent.y);
131        double dz = Math.abs(z - parent.z);
132        this.g = parent.g; // Append to G value of parent
133
134        // We dislike jumping because we are lazy
135        if(dx == 1 && dy == 1 && dz == 1) {
136            g += 1.7;
137        } else if((dx == 1 && dz == 1) || dy == 1) {
138            g += 1.4;
139        } else {
140            g += 1.0;
141        }
142    }
143
144    /**
145     * Calculate F value, basically H + G.
146     */
147    public void calculateF() {
148        this.f = h + g;
149    }
150
151    /**
152     * Calculate all movement values in one go.
153     *
154     * @param target Final tile in path
155     */
156    public void calculateHGF(Node target) {
157        calculateH(target);
158        calculateG();
159        calculateF();
160    }
161
162    /**
163     * Distance squared between this node and another
164     *
165     * @param with Node to compare with
166     * @return Squared distance
167     */
168    public double distance(Node with) {
169        int dx = with.x - x;
170        int dy = with.y - y;
171        int dz = with.z - z;
172        return dx * dx + dy * dy + dz * dz;
173    }
174
175    @Override
176    public boolean equals(Object o) {
177        if (this == o) return true;
178        if (o == null || getClass() != o.getClass()) return false;
179
180        Node node = (Node) o;
181
182        return x == node.x && y == node.y && z == node.z;
183    }
184
185    @Override
186    public int hashCode() {
187        int result = x;
188        result = 31 * result + y;
189        result = 31 * result + z;
190        return result;
191    }
192
193    @Override
194    public String toString() {
195        return "Tile{" +
196                "parent=" + parent +
197                ", x=" + x +
198                ", y=" + y +
199                ", z=" + z +
200                '}';
201    }
202}