【问题标题】:Deleting binary rows删除二进制行
【发布时间】:2021-06-26 00:28:34
【问题描述】:

如果我使用复制俄罗斯方块,使用无符号长的位来表示和 8 x 8 的块网格,我可以执行哪些按位运算来查找 1 的行(填充行)并删除它们?

我可以使用循环找到一行并使用简单的位移删除 last 行,但我的方法不仅无效,位移仅适用于最后一行,因为它会删除其他在上面使用时也行。

【问题讨论】:

  • 使用无符号长整数位。不要只用文字描述代码。请将代码显示为minimal reproducible example
  • unsigned long 的大小是特定于实现的。请更准确地了解您的数据大小,并显示您尝试过的代码。

标签: c binary bit-manipulation


【解决方案1】:

假设您正在处理 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 行,则需要更多的逻辑来处理选择正确的行和携带数据。这是一个你自己考虑做的练习。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-11
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多