Madmenyo
Madmenyo

Reputation: 8584

How to retrieve bits from number

Sometimes I come across the below code. I believe it is used to represent values as bits and they can be combined into a single number and retrieved later.

The number 34 consists of 01000000 and 00000100 or 2 and 32. How do I work this out in Java? Somehow I have to compare 2 to some variable to do X and 32 tot another variable to do Y.

The following is a example with some of my thoughts.

from the DotA modding wiki.

DOTA_ABILITY_BEHAVIOR_HIDDEN               = 1 << 0, //Can be owned by a unit but can't be cast and won't show up on the HUD.
DOTA_ABILITY_BEHAVIOR_PASSIVE              = 1 << 1, //Cannot be cast like above but this one shows up on the ability HUD.
DOTA_ABILITY_BEHAVIOR_NO_TARGET            = 1 << 2, //Doesn't need a target to be cast, ability fires off as soon as the button is pressed.
DOTA_ABILITY_BEHAVIOR_UNIT_TARGET          = 1 << 3, //Needs a target to be cast on.
DOTA_ABILITY_BEHAVIOR_POINT                = 1 << 4, //Can be cast anywhere the mouse cursor is (if a unit is clicked it will just be cast where the unit was standing).
DOTA_ABILITY_BEHAVIOR_AOE                  = 1 << 5, //Draws a radius where the ability will have effect. Kinda like POINT but with a an area of effect display.
//...

So these "behaviors" get stored as 1, 2, 4, 8, 16, 32, etc. But the whole idea of this seems to be able to store multiple types into a single number/bytes and retrieve these later. I see usages like this:

DOTA_ABILITY_BEHAVIOR_AOE | DOTA_ABILITY_BEHAVIOR_PASSIVE

Which seems to be 34. The only combination that would yield 34 would be this one DOTA_ABILITY_BEHAVIOR_AOE | DOTA_ABILITY_BEHAVIOR_PASSIVE and I believe that every combination made this way would be unique as long as you don't use the same value twice.

So how do I retrieve these two numbers from the number 34? And are there any limitations in the usage like this?

Upvotes: 3

Views: 612

Answers (4)

Debosmit Ray
Debosmit Ray

Reputation: 5403

About the part where you mentioned how to get back the bits used to obtain 34. I will post a 'solution' to give an idea about one way to achieve it. It is probably not the best way.

You have mentioned...

DOTA_ABILITY_BEHAVIOR_HIDDEN               = 1 << 0  # 0 0 0 0 0 0 0 1
DOTA_ABILITY_BEHAVIOR_PASSIVE              = 1 << 1  # 0 0 0 0 0 0 1 0
DOTA_ABILITY_BEHAVIOR_NO_TARGET            = 1 << 2  # 0 0 0 0 0 1 0 0
DOTA_ABILITY_BEHAVIOR_UNIT_TARGET          = 1 << 3  # 0 0 0 0 1 0 0 0
DOTA_ABILITY_BEHAVIOR_POINT                = 1 << 4  # 0 0 0 1 0 0 0 0
DOTA_ABILITY_BEHAVIOR_AOE                  = 1 << 5  # 0 0 1 0 0 0 0 0

And 34 in binary is 0 0 1 0 0 0 1 0.

If we keep shifting left and check to see if the bit at the 0th index is set.

List<Integer> indx = new ArrayList<Integer>();
int count = 0;
while(n != 0) { 
    if(n & 0x1 == 1)
        indx.add(count);
    n = n >> 1;
    count++;
}

For 34, indx will contain [1,5]. You can use this to recreate which bits were used to form it [DOTA_ABILITY_BEHAVIOR_PASSIVE, DOTA_ABILITY_BEHAVIOR_AOE].

Upvotes: 1

Jim Garrison
Jim Garrison

Reputation: 86754

Since nobody has answered your specific question:

Decimal 34 == Hex 0022 == Binary 0000 0000 0010 0010

Your values are

DOTA_ABILITY_BEHAVIOR_HIDDEN       = 1 << 0, // 0000 0000 0000 0001
DOTA_ABILITY_BEHAVIOR_PASSIVE      = 1 << 1, // 0000 0000 0000 0010
DOTA_ABILITY_BEHAVIOR_NO_TARGET    = 1 << 2, // 0000 0000 0000 0100
DOTA_ABILITY_BEHAVIOR_UNIT_TARGET  = 1 << 3, // 0000 0000 0000 1000
DOTA_ABILITY_BEHAVIOR_POINT        = 1 << 4, // 0000 0000 0001 0000
DOTA_ABILITY_BEHAVIOR_AOE          = 1 << 5, // 0000 0000 0010 0000

The two values that can be OR'ed together to make decimal 34 are

DOTA_ABILITY_BEHAVIOR_PASSIVE | DOTA_ABILITY_BEHAVIOR_AOE

Upvotes: -1

Peter Walser
Peter Walser

Reputation: 15706

Those special numbers are called bit masks, used to set and read out binary flags.
A byte, short, int or long value can thus hold multiple of those flags.

Example:

int flag1 = 0b0000001; // 1<<0, or 1
int flag2 = 0b0000010; // 1<<1, or 2
int flag3 = 0b0000100; // 1<<2, or 4

To combine flags:

int combined= flag1 | flag2;

To set a flag:

combined = combined | flag3;

To unset a flag:

combined = combined & ~flag;

To check if a flag is set:

boolean set3 = (combined & flag3) !=0;

Upvotes: 4

Steve Harris
Steve Harris

Reputation: 5109

int x = DOTA_ABILITY_BEHAVIOR_AOE | DOTA_ABILITY_BEHAVIOR_PASSIVE

if (x & DOTA_ABILITY_BEHAVIOR_AOE == DOTA_ABILITY_BEHAVIOR_AOE)
    // do stuff

You can add as many values represented by a single bit as the data type can store.

Upvotes: 1

Related Questions