patternjavaMinor
Finding the closest value in a collection in a game-server plugin implementation
Viewed 0 times
thecollectionfindingvalueplugingameclosestserverimplementation
Problem
I have an array of a instances of an
The
I have implemented an algorithm which does that, using the array and few temp variables:
Basically it gets the closest
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
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 < scopes.length; i++) {
double distance = Math.abs(scopes[i].getPercent() - alpha);
if (distance < 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
Solution
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:
Then, you can use this with:
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)];Code Snippets
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;
}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;
}TargetScope tile = TargetScope.values[tileId(this.time,
TargetManager.TARGET_SEARCH_WAIT, TargetScope.values[].length)];Context
StackExchange Code Review Q#61944, answer score: 3
Revisions (0)
No revisions yet.