Bit flags

Blitz3D Forums/Blitz3D Tutorials/Bit flags

_33(Posted 2007) [#1]
Bit flags/indicators are extra practicle in many ways:
- They take little space (1 bit as opposed to 4 bytes for an INT)
- Stacking bit indicators in a file is just like compressing, you're saving 32 times the space that you'd usually take with INT values.
- Bit indicators are harder to hack into, as they are hidden in bytes and ints.
- grouping them in an INT makes it for easy maintenance of all those indicators

With using the bits that are located within an int value, all you need to define is your flip indicator values by using simple boolean and/or math calculations. This way, a full row of flip indicators can be stored within each int value, making them (1)very small, (2) practical for writing into files, (3) easy to maintain.

How does it work? Here is a simple look at how you get/set bit values from a "32 bit" int:
mask%  = %11111111111111111111111111111111 ; this is very useful for And operations
value% = %11010101110101110001010101110100 ; here's the starting value
Print "the full 32bits:" + Bin$(value)
Print ""
pos = 2
Print "looking at position " + pos
Print "what we find   :" + Bin$(value And (1 Shl pos))
Print ""
Print "Setting bit " + pos + " to false"
value = value And (mask - (1 Shl pos))
Print "the full 32bits:" + Bin$(value)
Print ""
pos = 9
value = value Or (1 Shl pos)
Print "Setting bit " + pos + " to true"
Print "the full 32bits:" + Bin$(value)
WaitKey()


An example of bit flipping:

Let's say that you're making a game that involves flipping tiles. But, at some point, your game needs to be informed about which tiles have been flipped. Let's presume that you have a grid of 25 tiles by 25 tiles. All there is to store/retrieve is this singular value of 'true' or 'false'.

The usual common method would be to define a table with the DIM instruction, such as 'Dim tiles%(25, 25)'. Let's say that we need to write this into a file. Basically, what we will do would be to create a routine containing two embedded "For...Next" loops. And within that loop, we put a write instruction of the int values (containing simply 1's and 0's) down to a file.

-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

Now, here is a more efficient way. For our tile example, we will initiallize our table in the following manner:
Dim tile_row%(25)
For i = 1 to 25
   tile_row(i) = %0000000000000000000000000
Next

The reason we put % is to see the bits that we're initializing. That way, we know what bits are equal to what values. If we put some bits to 1 (True) or 0 (False), it becomes quite easier and more accessible this way.

Next, how to look at the bits: As seen on the first code snippet, we can interrogate the int values and see what they contain. It's always good to make some small functions that helps us perform modifications tasks to our table or to interrogate their contents. Here is an example code:
Function Get_tile_flipped(col%, row%)
; returns 0 if tile is not flipped
; > 0 (or true) if tile is flipped
   Return tile_row(row) And (1 Shl col)
End Function


Finally, we make a function to permit tile flipping!
Function Flip_tile(col%, row%, flipped% = True)
; flipped = 0 to unflip the tile
; flipped = 1 to flip the tile (default)
Local mask%
   If flipped then
      mask = (1 Shl col)
      tile_row(row) = tile_row(row) Or mask
   Else
      mask = %1111111111111111111111111 - (1 Shl col)
      tile_row(row) = tile_row(row) And mask
   EndIf
End Function


Thanks for reading! Hope this was helpful and easy to learn.


Danny(Posted 2007) [#2]
Very usefull, thanks for sharing!


Leto(Posted 2007) [#3]
That's a great explanation--thanks, _33!


_33(Posted 2007) [#4]
Here's another use for bit flags: state modes

State modes are always used in programs, for thousands of reasons. For example, you want to know if the game is started, or you want to know if the trace mode is activated, or say you want to know if your game is in the menu or in pause or IN GAME or whatever...

Usually, what you'll find is the following:

Type Game_Info
   Field game_started%
   Field game_paused%
   Field game_over%
   Field game_menu%
   Field debug_mode%
   Field ...
End Type


...Or, you sometimes find stuff like this:
Global game_state%
...
game_state = 1 ; Set the flag to game started
...
game_state = 2 ; the game is in the menu
...

Note here, that the coder actually had to explain what the code is doing, as 1 or 2 are just numeric values that, by themselves, don't mean anything.

Most of the time, you'll be searching for the field, and you'll have to maintain all those fields, which is usually one of the headaches of managing your game, because it seems so sloppy...

-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

Here's the example I've tought for everyone interested in the topic:

You want to have a game_state that contains all your possible game states. First you'll define your bit constants as follows........
; Game state modes
Const GMSTA_RESET         = %00000000
Const GMSTA_INITIALIZED   = %00000001
Const GMSTA_MENU          = %00000010
Const GMSTA_IN_GAME       = %00000100
Const GMSTA_PAUSE         = %00001000
Const GMSTA_GAME_OVER     = %00010000
Const GMSTA_DEBUG         = %10000000
Const GMSTA_NO_MENU       = %11111101
Const GMSTA_NOT_IN_GAME   = %11111011
Const GMSTA_NOT_PAUSED    = %11110111
Const GMSTA_NOT_GAME_OVER = %11101111
Const GMSTA_NO_DEBUG      = %01111111


Then, in your game type:
; main game information
Type game_info
   Field mode%
...
End Type

Global game.game_info = New game_info


Next, you can do the following:
game\mode = game\mode Or GMSTA_INITIALIZED ; set the game mode as initialized


If you want to know if the game is initialized:
If game\mode And GMSTA_INITIALIZED Then


Let's say you were in the menu, but now you have left that and started a new game, you'll set the mode as following:
game\mode = game\mode And GMSTA_NO_MENU Or GMSTA_IN_GAME


So, in essence, you have a mode, and in that, you can set a number of bits to whatever you wish. Of course it has to be consistent to what it means and how it is used.

Cheers.