How can I increment a variable without exceeding a maximum value?
Asked Answered
P

14

89

I am working on a simple video game program for school and I have created a method where the player gets 15 health points if that method is called. I have to keep the health at a max of 100 and with my limited programming ability at this point I am doing something like this.

public void getHealed(){
    if(health <= 85)
        health += 15;
    else if(health == 86)
        health += 14;
    else if(health == 87)
    health += 13; 
}// this would continue so that I would never go over 100

I understand my syntax about isn't perfect but my question is, what may be a better way to do it, because I also have to do a similar thing with the damage points and not go below 0.

This is called saturation arithmetic.

Precancel answered 5/9, 2013 at 22:53 Comment(1)
As a side note, I would choose a different name for this method. Per Java standard (and most other languages I know of), a method name starting with "get" should return a value, and not change anything. Likewise method names starting with "set" should change a value and usually not return anything.Idonah
C
225

I would just do this. It basically takes the minimum between 100 (the max health) and what the health would be with 15 extra points. It ensures that the user's health does not exceed 100.

public void getHealed() {
    health = Math.min(health + 15, 100);
}

To ensure that hitpoints do not drop below zero, you can use a similar function: Math.max.

public void takeDamage(int damage) {
    if(damage > 0) {
        health = Math.max(health - damage, 0);
    }
}
Christianly answered 5/9, 2013 at 22:54 Comment(0)
L
70

just add 15 to the health, so:

health += 15;
if(health > 100){
    health = 100;
}

However, as bland has noted, sometimes with multi-threading (multiple blocks of code executing at once) having the health go over 100 at any point can cause problems, and changing the health property multiple times can also be bad. In that case, you could do this, as mentioned in other answers.

if(health + 15 > 100) {
    health = 100;
} else {
    health += 15;
}
Layoff answered 5/9, 2013 at 22:54 Comment(5)
Should never allow it to go over, this could introduce new problems such as a race condition where character health is assumed to be at most the defined health max (100). Unlikely for this level project I'd guess but should enforce good practices early on.Keever
@Keever If one were to use this approach, a way of avoiding such a race condition would be to use a temporary variable to store the new health value, and then set health to this new health value in one place, with synchronisation if necessary.Goss
@bland: Race conditions are only relevant when multi-threading. And if he is doing multi-threading (which I highly doubt), the solution would be to lock on all accesses to health, or to make sure health is only accessed from one thread. The constraint "Should never allow health to go over 100" is not a realistic one.Eldreeda
@BlueRaja-DannyPflughoeft I stated it was unlikely for this project. In general locks are not going to always be in use and if you have a max value then it should be strictly adhered to, gaming or otherwise. Example: If an event is tied to a change of a property, and uses percentage then you've now skewed that processing immensely, as well as having it invoked twice. I'm trying to stay general here and ensure OP learns - I feel this answer, while it works, is too narrow and specific for a student as it will enforce him to not think of the big picture.Keever
@Goss i think thats unnecessary for something this simple.Waterrepellent
O
44

You don't need a separate case for each int above 85. Just have one else, so that if the health is already 86 or higher, then just set it directly to 100.

if(health <= 85)
    health += 15;
else
    health = 100;
Oratorical answered 5/9, 2013 at 22:54 Comment(1)
A bit too much magic numbers for me (even considering 100 allowed) - when changing 15 to 16 the 85 would need to be adjusted. Wouldn't changing 85 to at least 100 - 15 (or 100 -HEALED_HEALTH) be an improvement?Surefooted
E
36

I think an idiomatic, object oriented way of doing this is to have a setHealth on the Character class. The implementation of that method will look like this:

public void setHealth(int newValue) {
    health = Math.max(0, Math.min(100, newValue))
}

This prevents the health from going below 0 or higher than 100, regardless of what you set it to.


Your getHealed() implementation can just be this:

public void getHealed() {
    setHealth(getHealth() + 15);
}

Whether it makes sense for the Character to have-a getHealed() method is an exercise left up to the reader :)

Eggcup answered 5/9, 2013 at 23:3 Comment(10)
+1: This is a great way to do this in an object-oriented manner! The only thing I might suggest (and this would probably be left to the reader) is to possibly have two methods (heal(int hp) and damage(int hp)) which each call your setHealth(int newValue) method.Christianly
This is a very nice solution for this +1Layoff
Calling two library functions (min and max) to avoid a simple if is an overkill.Outherod
What is wrong with calling library functions? As named functions, they express intent more clearly than a bunch of conditional logic.Dandy
Also many library functions (and very likely these ones) are really built-in and won't perform any call at all.Mejias
@Outherod Wrong answer - most likely the library function does exactly the same thing internally, so why repeat yourself and pollute your code? NOT using library functions doesn't follow the basic principles of DRY.Unstrained
@Outherod Would you prefer newValue > 100 ? 100 : newValue < 0 ? 0 : newValue? That's a LOT less readable.Wanderlust
Not because of the internals, but with both max and min the statement is not really readable. Just my opinion but the if is more readable.Outherod
@Doorknob No I would find an if much more readable (but it's just my opinion I'm not saying that the solution is wrong)Outherod
@Outherod this is not to avoid an if. This is to prevent yourself from being able to shoot yourself in the foot. If it's too verbose, just use static imports. Then it looks like this: health = max(0, min(100, newValue)) If that's still unreadable to you, extract it to a method named clamp so the line looks like this: health = clamp(0, 100, newValue)Eggcup
N
14

I am just going to offer a more reusable slice of code, its not the smallest but you can use it with any amount so its still worthy to be said

health += amountToHeal;
if (health >= 100) 
{ 
    health = 100;
}

You could also change the 100 to a maxHealth variable if you want to add stats to the game your making, so the whole method could be something like this

private int maxHealth = 100;
public void heal(int amountToHeal)
{
    health += amountToHeal;
    if (health >= maxHealth) 
    { 
        health = maxHealth;
    }
}

EDIT

For extra information

You could do the same for when the player gets damaged, but you wouldn't need a minHealth because that would be 0 anyways. Doing it this way you would be able to damage and heal any amounts with the same code.

Needful answered 6/9, 2013 at 6:9 Comment(3)
minHealth might be negative, say for example, in D&D... :)Nobles
By far the best answer here.Lafond
@JYelton, yeah you'd just say (health <= 0) in the if statement. You could handle it however you want, if you want them to have lives you just minus 1 from lifeCount or just if they flat out lose then it can handle that. If you wanted to you could even make them start their new life with the amount of -HP they had. You can paste this code in pretty much anywhere and it'll do the job just fine, that was the point of this answer.Needful
E
10
health = health < 85 ? health + 15 : 100;
Exedra answered 8/9, 2013 at 17:6 Comment(0)
P
4

I would make a static method in a helper class. This way, rather than repeating code for every value which need to fit within some boundaries, you can have one all purpose method. It would accept two values defining the min and max, and a third value to be clamped within that range.

class HelperClass
{
    // Some other methods

    public static int clamp( int min, int max, int value )
    {
        if( value > max )
            return max;
        else if( value < min )
            return min;
        else
            return value;
    }
}

For your case, you would declare your minimum and maximum health somewhere.

final int HealthMin = 0;
final int HealthMax = 100;

Then call the function passing in your min, max, and adjusted health.

health = HelperClass.clamp( HealthMin, HealthMax, health + 15 );
Prepay answered 10/9, 2013 at 21:15 Comment(0)
S
3

I know this is a school project, but if you wanted to expand your game later on and be able to upgrade your healing power, write the function like so:

public void getHealed(healthPWR) {
    health = Math.min(health + healthPWR, 100);
}

and call out the function:

getHealed(15);
getHealed(25);

...etc...

Furthermore you can create your max HP by creating a variable that is not local to the function. Since I don't know what language you're using, I will not show an example because it might have the wrong syntax.

Sock answered 7/9, 2013 at 5:24 Comment(0)
M
2

Maybe this?

public void getHealed()
{
  if (health <= 85)
  {
    health += 15;
  } else
  {
    health = 100;
  }
}
Mothy answered 5/9, 2013 at 23:0 Comment(0)
C
2

If you want to be cheeky and fit your code on one line, you could use a ternary operator:

health += (health <= 85) ? 15 : (100 - health);

Note that some people will frown upon this syntax due to (arguably) bad readability!

Candie answered 6/9, 2013 at 4:48 Comment(1)
I find health = (health <= 85)?(health+15):100 more readable (if you really want to use a ternary operator)Outherod
J
1

I believe this will do

if (health >= 85) health = 100;
else health += 15;

Explanation:

  • If the gap for healing is 15 or less, health will become 100.

  • Otherwise if the gap is bigger than 15, it will add 15 to the health.

So for example: if the health is 83, it will become 98 but not 100.

Jud answered 6/9, 2013 at 4:32 Comment(4)
Can you expand on how this will works to resolve the requester's question?Ireneirenic
If the gap for healing is 15 or less health will become 100 else if the gap is bigger than 15 it will add 15 to the health. so for Example the health is 83 will become 98 but not 100. If any specific concern please let me know, thank you for comment.Jud
The && health < 100 condition is unnecessary. If it is 100, it will be set to 100, no change. The only reason you'd need that is if it were possible to get > 100 somehow and we don't want the healing to reduce you back down to 100.Idonah
@DarrelHoffman I think you are right if the game does not provide extra health 100+ then you are right, I have corrected my answer :) thank youJud
A
1

If I wanted to be thread safe I'd do it this way rather than using a synchronized block.

The atomic compareAndSet achieves the same outcome as synchronized without the overhead.

AtomicInteger health = new AtomicInteger();

public void addHealth(int value)
{
    int original = 0;
    int newValue = 0;
    do
    {
        original = health.get();
        newValue = Math.min(100, original + value);
    }
    while (!health.compareAndSet(original, newValue));
}
Allison answered 11/9, 2013 at 0:6 Comment(0)
C
1

Most simple way using the modulus operator.

health = (health + 50) % 100;

health will never equal or exceed 100.

Chit answered 16/11, 2015 at 22:20 Comment(1)
But if you do that operation when health is 100, you'd end with 50 health.Worsley
E
0
   private int health;
    public void Heal()
    {
        if (health > 85)
            health = 100;
        else
            health += 15;
    }
    public void Damage()
    {
        if (health < 15)
            health = 0;
        else
            health -= 15;
    }
Edana answered 6/9, 2013 at 9:5 Comment(2)
if you are going to make functions, you should at least make the 15 be a parameter :)Layoff
@Jordan: It depends on the context I am writing the code. :-)Edana

© 2022 - 2024 — McMap. All rights reserved.