How to use "conditionals" without using IF statements? - java

I have this project that we can't use IF statements for. For example, if something is connected this needs to happen. So I made a variable connected and initialised it to 0. To say, if something is connected then it's 1 and if it's not its 0. But i cant figure out how to write the statements to say that without using if statements.
public void removeBattery(){
connected = 0;
cameraCharge = cameraCharge * connected;
}
But this isn't working in the tests when I call the method. Even though, its multiplied by 0 its still showing a different value.
public double drain(double minutes) {
double drain = Math.min((cameraPowerConsumption * minutes),
batteryCharge);
batteryCharge = Math.max(batteryCharge - drain, 0);
totalDrain += drain;
return drain;
}
And here if its connected this is how you calculate drain, but when you call the removeBattery method it shouldnt be connected anymore and the drain should be 0. Im so confused.

The logical AND operator && can be included in your code to examine the status of the declared variable 'connected'. When the value of 'connected' is 1, the expression 'connected == 1 &&' will evaluate to true, while it will return a false result if the value is something else. This can be incorporated in the 'drain' method to control the calculation of the drain in response to the status of 'connected'. For example, it can be written as such:
public double drain(double minutes) {
double drain = connected == 1 ? Math.min((cameraPowerConsumption * minutes),
batteryCharge) : 0;
batteryCharge = Math.max(batteryCharge - drain, 0);
totalDrain += drain;
return drain;
}
If the connection is established, the amount of drain will be determined as normal. On the other hand, if the connection is not made, the drain value will be set to zero.

Related

How is codahale metrics Meter mark() method threadsafe?

I have recently begun to learn CodaHale/DropWizard metrics library. I cannot understand how is the Meter class thread-safe (it is according to the documentation), especially mark() and tickIfNecessary() methods here:
https://github.com/dropwizard/metrics/blob/3.2-development/metrics-core/src/main/java/com/codahale/metrics/Meter.java#L54-L77
public void mark(long n) {
tickIfNecessary();
count.add(n);
m1Rate.update(n);
m5Rate.update(n);
m15Rate.update(n);
}
private void tickIfNecessary() {
final long oldTick = lastTick.get();
final long newTick = clock.getTick();
final long age = newTick - oldTick;
if (age > TICK_INTERVAL) {
final long newIntervalStartTick = newTick - age % TICK_INTERVAL;
if (lastTick.compareAndSet(oldTick, newIntervalStartTick)) {
final long requiredTicks = age / TICK_INTERVAL;
for (long i = 0; i < requiredTicks; i++) {
m1Rate.tick();
m5Rate.tick();
m15Rate.tick();
}
}
}
}
I can see that there is a lastTick of type AtomicLong, but still there can be a situation that m1-m15 rates are ticking a little bit longer so another thread can invoke those ticks as well as a part of next TICK_INTERVAL. Wouldn't that be a race condition since tick() method of Rates is not synchronized at all? https://github.com/dropwizard/metrics/blob/3.2-development/metrics-core/src/main/java/com/codahale/metrics/EWMA.java#L86-L95
public void tick() {
final long count = uncounted.sumThenReset();
final double instantRate = count / interval;
if (initialized) {
rate += (alpha * (instantRate - rate));
} else {
rate = instantRate;
initialized = true;
}
}
Thanks,
Marian
It is thread safe because this line from tickIfNecessary() returns true only once per newIntervalStartTick
if (lastTick.compareAndSet(oldTick, newIntervalStartTick))
What happens if two threads enter tickIfNecessary() at almost the same time?
Both threads read the same value from oldTick, decide that at least TICK_INTERVAL nanoseconds have passed and calculate a newIntervalStartTick.
Now both threads try to do lastTick.compareAndSet(oldTick, newIntervalStartTick). As the name compareAndSet implies, this method compares to current value of lastTick to oldTick and only if the value is equal to oldTick it gets atomically replaced with newIntervalStartTick and returns true.
Since this is an atomic instruction (at the hardware level!), only one thread can succeed. When the other thread executes this method it will already see newIntervalStartTick as the current value of lastTick. Since this value no longer matches oldTick the update fails and the method returns false and therefore this thread does not call m1Rate.tick() to m15Rate.tick().
The EWMA.update(n) method uses a java.util.concurrent.atomic.LongAdder to accumulate the event counts that gives similar thread safety guarantees.
As far as I can see you are right. If tickIfNecessary() is called such that age > TICK_INTERVAL while another call is still running, it is possible that m1Rate.tick() and the other tick() methods are called at the same time from multiple threads. So it boils down to wether tick() and its called routines/operations are safe.
Let's dissect tick():
public void tick() {
final long count = uncounted.sumThenReset();
final double instantRate = count / interval;
if (initialized) {
rate += (alpha * (instantRate - rate));
} else {
rate = instantRate;
initialized = true;
}
}
alpha and interval are set only on instance initialization and marked final those thread-safe since read-only. count and instantRate are local and those not visible to other threads anyway. rate and initialized are marked volatile and those writes should always be visible for following reads.
If I'm not wrong, pretty much from the first read of initialized to the last write on either initialized or rate this is open for races but some are without effect like when 2 threads race for the switch of initialized to true.
It seems the majority of effective races can happen in rate += (alpha * (instantRate - rate)); especially dropped or mixed calculations like:
Assumed: initialized is true
Thread1: calculates count, instantRate, checks initialized, does the first read of rate which we call previous_rate and for whatever reason stalls
Thread2: calculates count, instantRate, checks initialized, and calculates rate += (alpha * (instantRate - rate));
Thread1: continues its operation and calculates rate += (alpha * (instantRate - previous_rate));
A drop would occur if the reads and writes somehow get ordered such that rate is read on all threads and then written on all threads, effectively dropping one or more calculations.
But the probability for such races, meaning that both age > TICK_INTERVAL matches such that 2 Threads run into the same tick() method and especially the rate += (alpha * (instantRate - rate)) may be extremely low and depending on the values not noticeable.
The mark() method seems to be thread-safe as long as the LongAdderProxy uses a thread-safe Data-structure for update/add and for the tick() method in sumThenReset.
I think the only ones who can answer the Questions left open - wether the races are without noticeable effect or otherwise mitigated - are the project authors or people who have in depth knowledge of these parts of the project and the values calculated.

LibGDX Android: Lag with 25+ sprites despite use of TimeKeeping

The Problem I have ArrayList of "pellets". I'm pushing around 25 of them and they all bounce. However, for some reason they seem to go faster while render() is slower / takes more time (wut?) Please help me make it so that the 25 sprites smoothly glide about at a constant speed. It also jerks when only 5 sprites are onScreen.
Tried this stuff:
Reading around SO. They recommended getDeltaTime
Gdx.graphics.getDeltaTime() multiplying by pelletSpeed (no Change)
In the current code the pellets hop, jerk, and inconsistently sputter about almost unpredictably. I am assuming that it's going constant speed underneath the hood but honestly it's hard to tell
For Loop in Render:
String currentDir = pelletList.get(i).getDir();
String currentColor = pelletList.get(i).getColor6();
pelletSpeedElapsedTime = TimeUtils.nanoTime();
if(currentDir.equals("Up")) {
pelletList.get(i).y -= pelletSpeed * TimeUtils.timeSinceNanos(pelletSpeedElapsedTime);
if(pelletList.get(i).y < 0 ) {
pelletList.get(i).setDir("Down");
}
} else if (currentDir.equals("Down")) {
pelletList.get(i).y += pelletSpeed * TimeUtils.timeSinceNanos(pelletSpeedElapsedTime);
if(pelletList.get(i).y > screenHeight) {
pelletList.get(i).setDir("Up");
}
} else if (currentDir.equals("Left")) {
pelletList.get(i).x -= pelletSpeed * TimeUtils.timeSinceNanos(pelletSpeedElapsedTime);
if(pelletList.get(i).x < 0) {
pelletList.get(i).setDir("Right");
}
} else if (currentDir.equals("Right")) {
pelletList.get(i).x += pelletSpeed * TimeUtils.timeSinceNanos(pelletSpeedElapsedTime);
if(pelletList.get(i).x > screenWidth) {
pelletList.get(i).setDir("Left");
}
}
Thanks
The pelletSpeedElapsedTime = TimeUtils.nanoTime(); looks suspicious to me - you're getting this time, and then calculating elapsed time for bullets immediately afterward. Almost no time will have elapsed by then, and you won't be accounting at all for whatever time passes before the next call to whatever method this is.
I think (guessing at what the rest of your code is like) that you want to move that pelletSpeedElapsedTime assignment to the end of this method. The idea here is that you want to capture the time where you finished this update, so that the next time you update you know how much time has passed between updates (e.g. time spent rendering, sleeping, whatever.)
Doing this would mean that you'd have to handle the case where pelletSpeedElapsedTime hasn't been initialized, as well (maybe initialize it in the constructor? again, not sure of the broader context.) Also, I don't think all those TimeUtils.timeSinceNanos calls or necessary - I would call that once at the start of this section of code and use the value (to make sure the moving entities all get a consistent time delta, and to avoid the redundant call/calculation.)

AtomicInteger: keep non-negative

Is there a way to perform a "decrement if result is positive or zero" operation with an AtomicInteger?
To clarify the desired behavior:
if the current value is greater than zero, decrement
if the current value is equal to zero, do nothing
(negative current value is not handled)
In Java 8, yes:
atomicInteger.updateAndGet(i -> i > 0 ? i - 1 : i);
Before Java 8, no.
I suppose you could do something like this pre-Java 8:
int val = atomicInt.get();
boolean success = false;
while(val > 0 && !success) {
success = atomicInt.compareAndSet(val, val - 1);
if(!success) {
// Try again if the value is still > 0
val = atomicInt.get();
}
}
// Check 'success' to see if it worked
Not the most elegant code, but I think it does the trick.
Informal proof of correctness (by #Stephen C)
In the case where there is no other thread modifying the AtomicInteger, success will be set to true on the first compareAndSet call. So the code will be equivalent to
int val = atomicInt.get();
if (val > 0) {
atomicInt.compareAndSet(val, val - 1);
}
which is clearly correct.
In the case where some other thread modifies the AtomicInteger, between the get and the compareAndSet then the latter call will fail because the current value is no longer equal to val. So what happens then is that we call atomicInt.get() again to get the updated value ... and repeat. We keep repeating until either we succeeded in the compareAndSet OR the current val is less zero or less.
The net effect is that this thread EITHER decrements the AtomicInteger once, OR it gives up because it sees that the value is zero.
Note the following caveats:
The retry loop may result in another thread "overtaking" and getting its decrement in before our thread. (Another way of saying that is to say the algorithm is not "fair".)
If you immediately observed the value of the AtomicInteger after this sequence, you may observe that its value has changed ... again.
It is theoretically possible for the code to loop indefinitely. But that requires other threads to be continually updating the AtomicInteger.
However, none of these caveats is a violation of the (assumed) requirements.
Credit goes to #JB Nizet.
To know update is successful or not:
AtomicBoolean isUpdateSuccessful = new AtomicBoolean(false);
atomicInteger.updateAndGet( i -> {
if( i > 0 ) {
isUpdateSuccessful.getAndSet(true);
return i - 1;
} else {
isUpdateSuccessful.getAndSet(false);
return i;
}
});

How to check if a body has almost stopped moving in libgdx + box2d

So, I have a player body + fixture etc, it is essentially a ball that bounces around.
I want to detect when it is 'pretty much' finished moving.
At the moment I do this:
public Boolean isStopped() {
return body.getLinearVelocity().x <= 0.3f && body.getLinearVelocity().y <= 0.3f;
}
This mostly works, the problem being when the player hits something, there's a split second where its velocity is 0, so this returns true. What I really wanted is to just return true when it is basically finished. Preferably within a range that I can set to whatever I like as I tweak the physics of my game world.
I can't use a check on whether it is sleeping or not as that comes too late, it doesn't sleep until after it has stopped having forces act upon it, I need just before.
I could just store how long it has been stopped/a count of stopped steps, but I was hoping there would be a nice pre existing method that I missed.
Any ideas?
You can keep track of recent movement and update it by mixing in a little of the current speed each time step:
float speedNow = body.getLinearVelocity().len();
recentSpeed = 0.1 * speedNow + 0.9 * recentSpeed;
if ( recentSpeed < someThreshold )
... do something ...
You would need to set recentSpeed to a suitably high value to begin with, otherwise it might be below the threshold in the first time step.
Seeing how you've determined that your false positives are caused by the body making contact with another, why not add a couple of lines in your ContactListener's beginContact method, storing the body's current speed in its user data? Then you can check that speed in your isStopped method. If there is a stored speed and the current speed isn't greater, this means the body is in the process of bouncing off whatever it hit: ignore. If there is a stored speed and the current speed is greater, the ball has bounced and is proceeding in some new direction: clear the stored speed. If there is no stored speed and the current speed is below your threshold, you've detected the sought situation.
In your ContactListener:
public void beginContact(Contact contact) {
Body a = contact.getFixtureA().getBody();
Body b = contact.getFixtureB().getBody();
if (a == mBall) {
a.setUserData(a.getLinearVelocity().len());
} else if (b == mBall) {
b.setUserData(b.getLinearVelocity().len());
}
}
And in your isStopped check:
public Boolean isStopped() {
float storedSpd = (Float) body.getUserData();
float currentSpd = body.getLinearVelocity().len();
if ((storedSpd > Float.MIN_VALUE) && (currentSpd > storedSpd)) {
body.setUserData(Float.MIN_VALUE);
return false;
} else {
return (currentSpd < THRESHOLD);
}
}
This is untested, but you get the idea. Also, remember to initially set the user data to Float.MIN_VALUE.
In the end I have simply passed the delta from each render call to the isStopped() method.
public Boolean isStopped(float delta) {
boolean isMoving = (
Math.abs(body.getLinearVelocity().x) >= 0.25f || Math.abs(body.getLinearVelocity().y) >= 0.25f);
if(isMoving) {
timeStopped = 0f;
return false;
} else {
timeStopped += delta;
return timeStopped >= 0.3f;
}
}
timeStopped is just a class property that starts off as zero. This does return true for the beginning of the game (before the user has made a move) but in my application that is absolutely fine. Besides which, it is true to say it has stopped in that circumstance.
I'd still love to see a way to do this without storing extra crap, since I'm guessing box2d must have this information somewhere in order to figure out if a body with zero velocity has no force acting upon or if it is just changing direction after an impact.

Increasing value by 1 continues forever

So, I have been working on this code for way to long for one day. I am sure there has to be a simple way to solve this but I can't think anything right now. First a small section of the code:
if(Settings.totalHits >= 50 && Settings.totalHits <= 99)
{
Settings.medal1 = true;
Settings.save(game.getFileIO());
totalMedals = totalMedals + 1;
}
This is a very basic achievement/medal system. Basically, once the user has done a total of 50 hits, it sets the value of "medal1" to true, which will remove the "lock" image which only displays when medal1 = false.
The issue deals with the totalMedals section. Basically, there is a total of 32 medals a user can earn, and after one is unlocked, it needs to update the totalMedals by 1. So in this case, the output would be "1/32". Except, now after the medal is unlocked (by hitting 50), the lock image is removed correctly, but the totalMedals keeps increasing by 1 extremely fast instead of just increasing to "1" and stopping.
Like I said, there has to be something small that I am overlooking here. I tried tossing into a for loop but that didn't work (or I did it wrong). Any idea what I can change to fix this?
Instead of
if(Settings.totalHits >= 50 && Settings.totalHits <= 99)
Try:
if(Settings.totalHits >= 50 && Settings.totalHits <= 99 && !Settings.medal1)
This way, once the medal has been triggered, it cannot be triggered again. Thus, totalMedals is only incremented once.
You only want to unlock the medal if you've reached the threshold and you haven't already unlocked it (the upper limit is irrelevant here), so you can use:
if (Settings.totalHits >= 50 && !Settings.medal1) {
Settings.medal1 = true;
Settings.save(game.getFileIO());
totalMedals++;
}
if (Settings.totalHits >= 100 && !Settings.medal2) {
Settings.medal2 = true;
Settings.save(game.getFileIO());
totalMedals++;
}
// and so on.
Though of course, this positively calls out for refactoring so as to efficiently use arrays, something like:
for (i = 1; i < 33; i++) {
if (Settings.totalHits >= 50 * i && !Settings.medal[i-1]) {
Settings.medal[i-1] = true;
Settings.save(game.getFileIO());
totalMedals++;
}
}
And, if the thresholds aren't a direct multiple of 50, you can easily place an arbitrarily complex function (or array lookup) into the if statement to match your needs.

Categories