Im working on a game that creates Procedurally generated dungeons, I found an example that uses bit masking to retrieve things like room number and type of door.
In the example he uses a bitmask to pull details from the integer for each tile. and the integer is broken down like this
0xLLSDRRET
L - is the Level Number
S - Denotes a special tile(Like Stairs)
D - is if its a door, and what type(Door, Arch, Trapped)
R - Room number
E - Flags an entrance to a room
T - Names the type of tile(Floor, Cooridor, Blocked)
In this He uses a bit mask to get, for instance, the room number like:
int[][] map = new int[40][40]
int $ROOM_ID = 0x0000FF00;
System.out.println(map[x][y] & $ROOM_ID);
Now with this if map[x][y] was for instance 0x00001200 the output would be 1200. This part of Masks I understand.
But in the source $ROOM_ID is ACTUALLY 0x0000FFC0 and I dont understand what the C does,because I tried diferent values and I cant seem to grab what the C does, for example
0x00001200 output-> 1200
0x00001210 output-> 1200
0x00001220 output-> 1200
0x00001230 output-> 1200
0x00001240 output-> 1240
0x00001250 output-> 1240
0x00001260 output-> 1240
0x00001270 output-> 1240
0x00001280 output-> 1280
0x00001290 output-> 1280
0x000012A0 output-> 1280
0x000012B0 output-> 1280
0x000012C0 output-> 12C0
0x000012D0 output-> 12C0
0x000012E0 output-> 12C0
0x000012F0 output-> 12C0
Can Someone with more knowledge of bitmasks explain why 0x0000FFC0 & 0x000012F0 = 12C0?
What you are doing is bitwise arithmetic. Ignore the high-order bits for now (since they are all 0's) and simply consider the two hexadecimal values 0xFFC0
and 0x12F0
. Then a bitwise and
works exactly like multiplication in base 10. It will look like this on the bit level:
0xFFC0 = 1111111111100000
&
0x12F0 = 0001001011110000
This then equals 0001001011100000 = 0x12F0
A trick to converting to and from hex-binary is this. Every two hex digits is a byte (i.e. 8 bits). For instance, 0xFF
is a single byte. Thus you can convert this to its binary representation by simply writing the bit-value for each hex digit (i.e. 0xF (base-16) = 1111 (base-2) = 15 (base-10)
). Since we know each byte is always exactly 8-bits, each hex digit converts to its own 4-bit binary representation. Then you only need to memorize binary representations for hexadecimal values 0000
(0) to 1111
(F) and replace them appropriately. The trick works in both directions.
As far as bitmasks go, this is simply useful for extracting values from a bitvector. A bitvector is (usually) a simple data type (i.e. int
, char
, etc.). Then, each particular bit signifies a type of value to enable or disable. So if I have a bitvector (char = single byte, so consider this data type for bitvector, for example) of 0x01
and my lowest-order bit signifies a door is enabled, then this bitvector has a door. If my bitvector's value is 0x02
, then there is no door enabled (but in 0x03
there is a door). Why is this? You need to always look at the underlying binary representation to fully understand a bitvector/bitmask.
0x01 = 00000001
, 0x02 = 00000010
, 0x03 = 00000011
As you can see, in the first and third values, the lowest-order bit is set. However, in the second value, the second lowest-order bit is set, but not the lowest-order. You can use this second value to signify another property, however (although for the purpose of example there is no door in the second value).
Then note, the corresponding bitmask (coincidentally) to retrieve a door from the bitvector formatted as above would be 0x01
since 0x01 & 0x01 = 1
, 0x02 & 0x01 = 0
, and 0x03 & 0x01 = 1
(again, return to the binary representation and multiply)