6

我正在开发一个创建程序生成的地牢的游戏,我发现了一个使用位掩码来检索房间号和门类型等内容的示例。

在示例中,他使用位掩码从每个图块的整数中提取详细信息。整数是这样分解的

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)

在此他使用位掩码来获取例如房间号,例如:

int[][] map = new int[40][40] 
int $ROOM_ID = 0x0000FF00;
System.out.println(map[x][y] & $ROOM_ID);

现在有了这个,如果 map[x][y] 是例如 0x00001200 输出将是 1200。我理解掩码的这一部分。

但是在源代码中 $ROOM_ID 是 ACTUALLY 0x0000FFC0 并且我不明白 C 做了什么,因为我尝试了不同的值,但我似乎无法抓住 C 的功能,例如

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

有更多位掩码知识的人可以解释为什么 0x0000FFC0 & 0x000012F0 = 12C0?

4

3 回答 3

10

你正在做的是按位算术。现在忽略高位(因为它们都是 0),只考虑两个十六进制值0xFFC00x12F0。然后 a 的bitwise and工作原理与以 10 为底的乘法完全一样。它在位级别上看起来像这样:

0xFFC0 = 1111111111100000

&

0x12F0 = 0001001011110000

这等于0001001011100000 = 0x12F0

与十六进制二进制相互转换的技巧就是这个。每两个十六进制数字是一个字节(即 8 位)。例如,0xFF是单个字节。0xF (base-16) = 1111 (base-2) = 15 (base-10)因此,您可以通过简单地为每个十六进制数字(即)写入位值来将其转换为二进制表示。因为我们知道每个字节总是正好是 8 位,所以每个十六进制数字都转换成它自己的 4 位二进制表示。然后你只需要记住十六进制值0000(0) 到1111(F) 的二进制表示并适当地替换它们。这个技巧在两个方向都有效。

就位掩码而言,这对于从位向量中提取值非常有用。位向量(通常)是一种简单的数据类型(即int,char等)。然后,每个特定位表示要启用或禁用的值类型。因此,如果我有一个位向量(例如,char = 单字节,因此请考虑这种位向量的数据类型),0x01并且我的最低位表示启用了一个门,那么这个位向量就有一个门。如果我的位向量的值为0x02,则没有启用门(但0x03里面有一扇门)。为什么是这样?您需要始终查看底层二进制表示以完全理解位向量/位掩码。

0x01 = 00000001, 0x02 = 00000010,0x03 = 00000011

如您所见,在第一个和第三个值中,设置了最低位。然而,在第二个值中,设置了第二个最低位,而不是最低位。但是,您可以使用第二个值来表示另一个属性(尽管出于示例的目的,第二个值中没有门)。

然后请注意,从上述格式化的位向量中检索门的相应位掩码(巧合)将是0x01, 0x01 & 0x01 = 1,0x02 & 0x01 = 00x03 & 0x01 = 1(再次返回二进制表示并相乘)

于 2012-08-18T19:12:35.993 回答
5

注意二进制,而不仅仅是十六进制。 C十六进制是 12,十进制是1100二进制;F 是1111二进制的。所以

F & 1 == 1, F & 2 == 2, C & F == C, 0 & 0 == 0。

于 2012-08-18T19:02:52.053 回答
1

0xF都是1位:1111任何值 和的按位是相同的值。换句话说,给定位置的AND保留了来自另一个操作数的位。0xF0xF

所以在 中0x0000FFC0 & 0x000012F0F数字保留了相应的数字:

0xF & 0x1 = 0x1
0xF & 0x2 = 0x2
0xC & 0xF = 0xC

相似地:

0xFFC0 & 0x12F0 = 0x12C0

您可能知道,任何值和的按位00。因此,像这样的结构0x0000FF00用于保留第二个最低有效字节。

的使用0xFFC0实际上取决于其余代码如何使用该最低有效字节。在标志的解释中,最低有效字节的上半部分记录为:房间入口。不知何故,这在System.out.println(map[x][y] & $ROOM_ID);.

0xC1100二进制的,因此通过包含0xC00xFFC0掩码中,代码还试图保留该最低有效字节的两个最高有效位 - 最右边 - 字节。请注意,在这两位上,您可以准确地编码4 个值。如果游戏是 2D 并且每个房间都是方形的 Zork 风格,这匹配了一个可以在 4 个罗盘点上进入的游戏设计。

至于位掩码的规则,你可以从wiki 文章开始做得更糟:它很好地涵盖了基础知识。最终这都是布尔代数

于 2012-08-18T19:10:38.983 回答