Python: get all active states

Hi,

How can I get all active states on the player object? I tried it with this:

print (own.state, 'State')

But all I get is a number sth like this: 657898

Should I get smart out of this numbers???

All I want get is like in the debug: Player_Logic.state = 3, 5, 8

Hope there is a way to get that? Thanks in advance

I believe those are bit values that you’re looking at, but I’m not 100% sure.


>>> a = 5
>>> a & 2
0
>>> a & 1
1
>>> a & 4
4

A quick tooling around in the Python interpreter helped me out here. In the above example, I assign a value of 5 to the variable a. In a computer, the number 5 which is comprised of four individual switches, or bits: 1, 0, 0, and 1. You add up bits to get individual numbers. For the number 5, the left-most 1 represents a 4, and the right-most one represents 1. 0’s are ignored, so to speak. Bits go up from right to left, and rise in order of magnitude as they go up, i.e.

Bit Position: _0____0____0____0___0___0___0___0
Bit Value: __128__64___32___16___8___4___2___1

Ignore the underscores, that’s just the way that could get them in columns. As an example, a byte is made up of eight bits, and can represent a number between 0 and 255, like above. When all eight bits are set to 1, the value adds up to 255. Higher numbers require more bits.

Anyway, we can do a bit operation with the & operator that compares the bits between two numbers. The & operator in particular compares the bits to see if they match.

In the above example, I do ‘a & 2’ to compare the two numbers - a with a value of 5, and the number 2. Since the variable a has a value of 5, its ‘bit representation’ is 1001. 2’s representation is 10 (or 0010). There are no common bits between those, so the value returned is 0 - no bits match.

On the other hand, both ‘a & 1’ and ‘a & 4’ work because both share bits (the returned value is a number that’s composed of the matching bits, if I am correct). 5 and 1 only share one bit, the right-most one that represents a 1, and so that’s the result. With ‘a & 4’, both numbers (5 and 4) share the left-most bit, which is a 4. That’s the result of that operation.

All of that is to say that the state variable is a single number that represents the currently active states. You can use the ‘&’ operator to compare the state bit number to the object’s state variable and see which ones are active. Note, though, that the state numbers increase in magnitude, not in order.

What this means is that state 1, 2, and 3 aren’t ‘1, 2, 3’, but rather are ‘2^0, 2^1, 2^2,’ and so on. In other words, if you want to check if state 3 is on, use

obj.state & 4

As that will check the 3rd bit, which corresponds to the third state.

EDIT: P.S. This is good, though, because it allows you to check multiple states at a time. For example, you can see if the 1st, 2nd, and 3rd states are enabled:



states = 1 + 2 + 4 # 1st, 2nd, 3rd bits = 1, 2, 4

print (obj.state & states) # see if they're on


I’m not super knowledgeable about this, though.

You can use this function to get a list of states:


def printStates(cont):
    print( str(stateToList(cont.owner.state)) )
    
def stateToList(state): 
    '''Creates a list of states''' 
    states = []
    i = 0    
    while True:
        stateToCheck = 2**i
        i += 1
                
        if state & stateToCheck != 0:
            states.append(i)
            
        if stateToCheck > state:
            return states

This should not be used to check for states as it is too inefficient to do such things. Better use the method as described by SolarLune.

Hey thanks SolarLune and Monster for the nice explanation and example.

But I don’t understand the bits thing. No matter what I do I don’t get the correct active states.

This is one of many tries:

def States(cont):
    own = cont.owner
    
    
    s_space = cont.sensors['s_space']
    
    
    
    active_states = []
            
    if s_space.positive:
        
        available_states = range(31)
        
        
        
        for i in range(1,31):
            
            each_state = own.state & i
            
            if each_state == 1:
            
            
                active_states.append(i)
        
        print (active_states, 'active_states')

Seems not work though.

As a quick “might not work, use at your own caution” try:

def States(cont):
    own = cont.owner
   
    s_space = cont.sensors['s_space']
       
    active_states = []
            
    if s_space.positive:
                
        for i in range(0,31):
            
            each_state = own.state & (i ^ 2)
            
            if each_state > 0:
                      
                active_states.append(i)
        
        print (active_states, 'active_states')

I took out the available_states variable since you weren’t using it.

I changed it from range(1, 31) to range(0, 31) because we’re going to need the first 0. This is because, like I mentioned before, it goes up in magnitude in powers of 2. You can’t just use own.state & i, because that’s just going to compare the bits to numbers, which won’t give you the correct response. You have to compare the bits in own.state to the state number (which is a magnitude). So, it should be own.state & (i ^ 2).

0 ^ 2 = 1, 1 ^ 2 = 2, 2 ^ 2 = 4, and so on. This will give you the magnitude number. The first number also corresponds to the state number (0, 1, 2, 3, 4, 5, etc).

I changed it from each_state == 1 to each_state > 0 because a bitwise operation returns the number of matching bits. So, each_state would only be 1 if there was a common 1 in the two numbers (own.state and the number you’re comparing it to). What you want to know is if there’s a match at all (> 0).

Again, I’m not 100% positive on this. If it works fine for you, I would recommend really learning why it works so that you come out of this with something.

Thanks a lot again SolarLune. Didn’t work though this way. I found out that in YoFrankie they used such a thing for debugging. So a quick look at the frankie.blend file brought me the solution.

def States(cont):
    own = cont.owner
   
    s_space = cont.sensors['s_space']
       
    active_states = []
            
    if s_space.positive:
                
        for i in range(0,31):
            
            each_state = own.state & 1<<i
           
            if each_state > 0:
                new_state = i + 1
                active_states.append(new_state)
        
        print (active_states, 'active_states')

If it works fine for you, I would recommend really learning why it works so that you come out of this with something.
That is what I always do. But in this case there is not that much resources to learn from.

Here is a example file:
states.blend (425 KB)

these are bit operations. This is common practice in hardware-near programming (e.g. with C, C++).

1 << i
is a left shift of the bits
this is finally a very fast
2**i
operation

& is a bit-wise AND (1&1 = 1, 0&1=0 etc.)

These operations allow an efficient way to store multiple boolean values in one number. From high-level perspective you do not want to care about:

isFirstState(): True

Thanks Monster for the nice explanation. These operations get me to my limit though. :slight_smile: