假设您正在处理 8x8 位的单个 64 位无符号整数,让我们从使用正确的数据类型开始:uint64_t
现在,让我们采用“高于”位的约定,因为您没有具体说明这一点。我假设高位代表更高的行,因此删除一行将涉及向右移动位。
最后,我假设“底部”是第 0 行,而“顶部”是第 7 行。这意味着例如,您可以执行以下操作来获取对应于单行的位的掩码:
uint64_t row_mask = (uint64_t)0xff << row * 8;
我相信您可以看到如何使用此掩码来检测所有掩码。您只需对您的状态进行按位与运算并检查结果是掩码本身。这是一个非常简单的方法:
int row = 0;
while (row < 8) {
uint64_t row_mask = (uint64_t)0xff << row * 8;
if ((state & row_mask) == row_mask) {
remove_row(&state, row);
} else {
++row;
}
}
现在我们已经建立了如何处理行的实际规范,假设您现在要删除第 3 行。为此,您必须将第 3 行上方的所有行向右移动,并保留第 0-2 行不变。
请注意,您可以使用一种技巧来获取特定行下方每一行中的位的掩码,如下所示:
uint64_t rows_below_mask = ((uint64_t)1 << row * 8) - 1;
这是通过将 1 移到当前行的最后一位,然后减 1,这将清除该位并将所有位设置到右侧。
您可以使用相同的值为当前行上方的所有行派生掩码。只需反转它,然后向左移动以便我们忽略当前行:
uint64_t rows_above_mask = ~rows_below_mask << 8;
这几乎就是您所需要的......只需遮盖各个部分,移动并组合:
void remove_row(uint64_t *state, int row)
{
uint64_t rows_below_mask = ((uint64_t)1 << row * 8) - 1;
uint64_t rows_above_mask = ~rows_below_mask << 8;
*state = (*state & rows_below_mask) | (*state & rows_above_mask) >> 8;
}
如果您希望将多个值链接在一起,假设您的俄罗斯方块游戏中有超过 8 行,则需要更多的逻辑来处理选择正确的行和携带数据。这是一个你自己考虑做的练习。