如何对不相同的变量执行按位比较 size/type
How do I perform bitwise comparison on variables that are not the same size/type
我目前正在用 C 语言解决一些小问题,所以这是我的问题:我要制作一个控制台程序,像这样在标准输入中获取俄罗斯方块
.#..
.#..
.#..
.#..
..#.
###.
....
....
....
.##.
.##.
....
etc... (max 26 pieces)
我必须弄清楚如何使它们适合最小的正方形(不旋转)和最左上角的集中,以便为前面的示例输出以下内容:
ABB.
ABBC
ACCC
A...
(字母按出现顺序分配)。
所以我认为让我的计算机测试一块是否适合地图中某个点的最快方法是执行按位 &
操作。如果给出 0,则适合。
这样我就可以检查
1100
1100
0000
0000
适合:
1000
1000
1000
1000
我可以 if (a & b == 0)
如果它是真的那么它适合。现在我的作品不适合这种方式,但如果我向右移动它,它将:
b >> 1 =
0110
0110
0000
0000
这样我就可以连续比较一块的可能位置,并在找到合适的位置时将其放在地图上。
我唯一的问题是我的作品存放在 short int
(16 位)中,我必须将它与更大的类型进行比较(例如 long long
,如果我的地图是 8x8) 0 因为它很容易从 :
0110
0110
0000
0000
到
0000
0000
0011
0011
只需移动位,但我怎样才能做到这一点:
00000000
00110000
00110000
00000000
00000000
00000000
00000000
00000000
一个 64 位整数,在 0
的海洋中与 1
的形状相同。
当你在移位运算符中使用较小的类型(short int
)时,它会自动转换为int
。在你的情况下,这通常是不够的,但解决方案很简单:
首先将一块分配给更大的类型,然后通过位掩码和移位来固定行。然后再次移动以将元素移动到您希望的位置。
我还建议使用无符号整数类型,因为在某些情况下,有符号类型的转换是实现定义的。当您使用它时,我真的建议您使用 stdint.h
.
中的 uintN_t
类型
所以你需要这样的东西:
// bool type is from stdbool.h
bool isPieceInMap(uint16_t piece, uint64_t map) {
uint64_t bigPiece = piece;
// Fix lines
bigPiece =
(bigPiece & 0x000F) |
(bigPiece & 0x00F0) << 4 |
(bigPiece & 0x0F00) << 8 |
(bigPiece & 0xF000) << 12;
bigPiece = // Do position shifting as needed
return (bigPiece & map) == 0;
}
根据@user694733的建议,这里有一个将一小块转置到大地图的lower-right象限的实现:
uint64_t pieceToMap(uint16_t little) {
static uint16_t row = 0b1111;
uint64_t big = 0;
for (char i = 0; i < 16; i += 4) {
big |= (little & (row << i)) << i;
}
return big;
}
我已经编写了一个测试程序来确认算法是否正常工作:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
uint64_t pieceToMap(uint16_t);
void printPiece(uint16_t);
void printMap(uint64_t);
int main(int argc, char *argv[]) {
uint16_t a = 0b0110011000000000;
uint64_t b = pieceToMap(a);
uint64_t c = b << 36;
printPiece(a);
printf("\r\n");
printMap(b);
printf("\r\n");
printMap(c);
return EXIT_SUCCESS;
}
uint64_t pieceToMap(uint16_t little) {
static uint16_t row = 0b1111;
uint64_t big = 0;
for (char i = 0; i < 16; i += 4) {
big |= (little & (row << i)) << i;
}
return big;
}
void printPiece(uint16_t little) {
static uint16_t i = 1;
char row, col;
for (row = 3; row >= 0; row--) {
for (col = 3; col >= 0; col--) {
printf("%c", (little & (i << (row * 4 + col))) ? '1' : '0');
}
printf("\r\n");
}
}
void printMap(uint64_t big) {
static uint64_t i = 1;
char row, col;
for (row = 7; row >= 0; row--) {
for (col = 7; col >= 0; col--) {
printf("%c", (big & (i << (row * 8 + col))) ? '1' : '0');
}
printf("\r\n");
}
}
如我所料,输出是:
0110
0110
0000
0000
00000000
00000000
00000000
00000000
00000110
00000110
00000000
00000000
01100000
01100000
00000000
00000000
00000000
00000000
00000000
00000000
我目前正在用 C 语言解决一些小问题,所以这是我的问题:我要制作一个控制台程序,像这样在标准输入中获取俄罗斯方块
.#..
.#..
.#..
.#..
..#.
###.
....
....
....
.##.
.##.
....
etc... (max 26 pieces)
我必须弄清楚如何使它们适合最小的正方形(不旋转)和最左上角的集中,以便为前面的示例输出以下内容:
ABB.
ABBC
ACCC
A...
(字母按出现顺序分配)。
所以我认为让我的计算机测试一块是否适合地图中某个点的最快方法是执行按位 &
操作。如果给出 0,则适合。
这样我就可以检查
1100
1100
0000
0000
适合:
1000
1000
1000
1000
我可以 if (a & b == 0)
如果它是真的那么它适合。现在我的作品不适合这种方式,但如果我向右移动它,它将:
b >> 1 =
0110
0110
0000
0000
这样我就可以连续比较一块的可能位置,并在找到合适的位置时将其放在地图上。
我唯一的问题是我的作品存放在 short int
(16 位)中,我必须将它与更大的类型进行比较(例如 long long
,如果我的地图是 8x8) 0 因为它很容易从 :
0110
0110
0000
0000
到
0000
0000
0011
0011
只需移动位,但我怎样才能做到这一点:
00000000
00110000
00110000
00000000
00000000
00000000
00000000
00000000
一个 64 位整数,在 0
的海洋中与 1
的形状相同。
当你在移位运算符中使用较小的类型(short int
)时,它会自动转换为int
。在你的情况下,这通常是不够的,但解决方案很简单:
首先将一块分配给更大的类型,然后通过位掩码和移位来固定行。然后再次移动以将元素移动到您希望的位置。
我还建议使用无符号整数类型,因为在某些情况下,有符号类型的转换是实现定义的。当您使用它时,我真的建议您使用 stdint.h
.
uintN_t
类型
所以你需要这样的东西:
// bool type is from stdbool.h
bool isPieceInMap(uint16_t piece, uint64_t map) {
uint64_t bigPiece = piece;
// Fix lines
bigPiece =
(bigPiece & 0x000F) |
(bigPiece & 0x00F0) << 4 |
(bigPiece & 0x0F00) << 8 |
(bigPiece & 0xF000) << 12;
bigPiece = // Do position shifting as needed
return (bigPiece & map) == 0;
}
根据@user694733的建议,这里有一个将一小块转置到大地图的lower-right象限的实现:
uint64_t pieceToMap(uint16_t little) {
static uint16_t row = 0b1111;
uint64_t big = 0;
for (char i = 0; i < 16; i += 4) {
big |= (little & (row << i)) << i;
}
return big;
}
我已经编写了一个测试程序来确认算法是否正常工作:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
uint64_t pieceToMap(uint16_t);
void printPiece(uint16_t);
void printMap(uint64_t);
int main(int argc, char *argv[]) {
uint16_t a = 0b0110011000000000;
uint64_t b = pieceToMap(a);
uint64_t c = b << 36;
printPiece(a);
printf("\r\n");
printMap(b);
printf("\r\n");
printMap(c);
return EXIT_SUCCESS;
}
uint64_t pieceToMap(uint16_t little) {
static uint16_t row = 0b1111;
uint64_t big = 0;
for (char i = 0; i < 16; i += 4) {
big |= (little & (row << i)) << i;
}
return big;
}
void printPiece(uint16_t little) {
static uint16_t i = 1;
char row, col;
for (row = 3; row >= 0; row--) {
for (col = 3; col >= 0; col--) {
printf("%c", (little & (i << (row * 4 + col))) ? '1' : '0');
}
printf("\r\n");
}
}
void printMap(uint64_t big) {
static uint64_t i = 1;
char row, col;
for (row = 7; row >= 0; row--) {
for (col = 7; col >= 0; col--) {
printf("%c", (big & (i << (row * 8 + col))) ? '1' : '0');
}
printf("\r\n");
}
}
如我所料,输出是:
0110
0110
0000
0000
00000000
00000000
00000000
00000000
00000110
00000110
00000000
00000000
01100000
01100000
00000000
00000000
00000000
00000000
00000000
00000000