Finding the closest value in a collection in a game-server plugin implementation I have an array of a instances of an enum type. A random double variable is initialized with a value between 0.... to 1, and should be used to get the closest value's enum instance to that randomly set double value.
The enum looks like this:
public enum TargetScope {

    CLEAN(1, 5040),
    FIRST(.888, 5046),
    SECOND(.777,5052),
    THIRD(.666,5058),
    FOURTH(.555, 5064),
    FIFTH(.444, 5070),
    SIXTH(.333, 5076),
    SEVENTH(.222, 5082),
    EIGHTH(.001, 5088);
    
    private int interfaceBase;
    private double time;
    
    TargetScope(double time,int interfaceIdBase) {
        this.time = time;
        this.interfaceBase = interfaceIdBase;
    }
    
    public int getTime() {
        return (int) this.time * TargetManager.TARGET_SEARCH_WAIT;
    }
    
    public int getInterfaceBase() {
        return this.interfaceBase;
    }
    
    public double getPercent() {
        return this.time;
    }
}

I have implemented an algorithm which does that, using the array and few temp variables:
public TargetScope getInterfaceScopeByTime() {
    double alpha = (double) this.time / TargetManager.TARGET_SEARCH_WAIT;

    TargetScope[] scopes = TargetScope.values();
    
    double delta = 1;
    TargetScope scope = null;
    
    for (int i = 0; i &lt; scopes.length; i++) {
        double distance = Math.abs(scopes[i].getPercent() - alpha);
        if (distance &lt; delta) {
            delta = distance;
            scope = scopes[i];
        }
    }
    
    return scope;
}

Basically it gets the closest Enum.getPercent() value in the list to alpha, and then returns the final closest TargetScope instance.
But I really feel bad about using this, where Java has an advanced collection API, which can be used better for this case, but I am not really as experienced with Collections API to use them for that.
Is there really a shorter way to perform this?
The idea behind this
I am working on a game-server plugin, which basically makes two players targets and have them fight each other. For a player to get a target, he needs his target-timer to hit 0, in order to let the system search for a target. Originally, the default target timer is 1000, each system cycle is 600ms, so 1000 is 10 minutes.
Each player has an interface that looks like a sliced circle to 8 pieces, something like this:

I need to let the interface know, what slices should be filled with colour, to let the player know when he can get his target. a fully coloured scope (circle) means that the timer hit 0.
Each interface slice has it's own id, as you see in the enum, int interfaceBase.
I need to update the player's interface, by using the player's current left time.
So if his time is 800, I do 800 / 1000, I get 0.8, now from the enums list, the closest enum is called SECOND because the closest value to 0.8 out of the list is 0.777, therefore when the server updates player's interface exactly when the timer is 800, then the interface will display one slice out of 8.
The interface updates every 10 seconds, per player (as in each player has its executor).
This problem can be solved mathematically much better than it can with a list, or collection.

What you have is 9 states, and a timer that counts down. The timer can be expressed as a proportion of 1. Because the states are all equally spaced on 1/9 intervals, you can just do math....

So, if the time is \$x\$ and the total time is \$y\$, then the current portion is \$\frac{x}{y}\$ If you multiply this value by 9, you get something on the scale of 0 to 9 inclusive. you really want:



public int tileID(int currentTime, int totalTime, int tileCount) {
    // we want the shift to happen at less than half-the-time (in the middle of the period).
    double shift = (1.0 / tileCount) / 2;
    double progress = (double)currentTime / (double)(totalTime);
    int tile = (int)(progress * tileCount + shift);
    return tile;
}




shift is needed to make the (int) truncation work. Your comment has made me think, and, in reality, it is not the most readable/understandable code. In fact it is broken, and shift should just be 0.5 always... Let me re-do it in the form of a round() instead of a truncation:

public int tileID(int currentTime, int totalTime, int tileCount) {
    double progress = (double)currentTime / (double)totalTime;
    int tile = (int)Math.round(progress * tileCount + 0.3);
    // because your tiles are in the opposite order: tileCount - 1 - tile
    return tileCount - 1 - tile;
}


Then, you can use this with:

TargetScope tile = TargetScope.values[tileId(this.time,
              TargetManager.TARGET_SEARCH_WAIT, TargetScope.values[].length)];