001/*
002 * This file is part of Baritone.
003 *
004 * Baritone is free software: you can redistribute it and/or modify
005 * it under the terms of the GNU Lesser General Public License as published by
006 * the Free Software Foundation, either version 3 of the License, or
007 * (at your option) any later version.
008 *
009 * Baritone is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012 * GNU Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public License
015 * along with Baritone.  If not, see <https://www.gnu.org/licenses/>.
016 */
017
018package baritone.api.pathing.goals;
019
020import baritone.api.utils.SettingsUtil;
021import baritone.api.utils.interfaces.IGoalRenderPos;
022import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet;
023import it.unimi.dsi.fastutil.doubles.DoubleIterator;
024import net.minecraft.util.math.BlockPos;
025
026public class GoalNear implements Goal, IGoalRenderPos {
027
028    private final int x;
029    private final int y;
030    private final int z;
031    private final int rangeSq;
032
033    public GoalNear(BlockPos pos, int range) {
034        this.x = pos.getX();
035        this.y = pos.getY();
036        this.z = pos.getZ();
037        this.rangeSq = range * range;
038    }
039
040    @Override
041    public boolean isInGoal(int x, int y, int z) {
042        int xDiff = x - this.x;
043        int yDiff = y - this.y;
044        int zDiff = z - this.z;
045        return xDiff * xDiff + yDiff * yDiff + zDiff * zDiff <= rangeSq;
046    }
047
048    @Override
049    public double heuristic(int x, int y, int z) {
050        int xDiff = x - this.x;
051        int yDiff = y - this.y;
052        int zDiff = z - this.z;
053        return GoalBlock.calculate(xDiff, yDiff, zDiff);
054    }
055
056    @Override
057    public double heuristic() {// TODO less hacky solution
058        int range = (int) Math.ceil(Math.sqrt(rangeSq));
059        DoubleOpenHashSet maybeAlwaysInside = new DoubleOpenHashSet(); // see pull request #1978
060        double minOutside = Double.POSITIVE_INFINITY;
061        for (int dx = -range; dx <= range; dx++) {
062            for (int dy = -range; dy <= range; dy++) {
063                for (int dz = -range; dz <= range; dz++) {
064                    double h = heuristic(x + dx, y + dy, z + dz);
065                    if (h < minOutside && isInGoal(x + dx, y + dy, z + dz)) {
066                        maybeAlwaysInside.add(h);
067                    } else {
068                        minOutside = Math.min(minOutside, h);
069                    }
070                }
071            }
072        }
073        double maxInside = Double.NEGATIVE_INFINITY;
074        DoubleIterator it = maybeAlwaysInside.iterator();
075        while (it.hasNext()) {
076            double inside = it.nextDouble();
077            if (inside < minOutside) {
078                maxInside = Math.max(maxInside, inside);
079            }
080        }
081        return maxInside;
082    }
083
084    @Override
085    public BlockPos getGoalPos() {
086        return new BlockPos(x, y, z);
087    }
088
089    @Override
090    public String toString() {
091        return String.format(
092                "GoalNear{x=%s, y=%s, z=%s, rangeSq=%d}",
093                SettingsUtil.maybeCensor(x),
094                SettingsUtil.maybeCensor(y),
095                SettingsUtil.maybeCensor(z),
096                rangeSq
097        );
098    }
099}