c - 删除二进制行
问题描述
如果我使用复制俄罗斯方块使用无符号长的位来表示和 8 x 8 的块网格,我可以做哪些按位操作来查找 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 行,则需要更多的逻辑来处理选择正确的行和携带数据。这是一个让你考虑自己做的练习。
推荐阅读
- pandas - 在 DataFrame 建模中实现的 Scaling Feature
- oracle - 在 Oracle Application Express 18.2 期间安装失败
- swift - 试图找出一种使用单个 UITableview 的不那么笨重的方法
- php - 从数据库特定列中的数据库行条目创建数组并用于 foreach 循环
- python - 填充numpy数组的向量方式
- graphql - 如何使用特定上下文查询 Apollo GraphQL 服务器?
- c++ - 模块:AHBot(没有用于初始化“WorldSession”的匹配构造函数)
- c# - 我们可以在 asp.net 3.5 网站中全局设置 ScriptManager 控件的默认属性值吗?
- css - 选择框选项仅在 chrome 中获取滚动条
- php - URL 中的变量