Skip to content

Instantly share code, notes, and snippets.

@nareix
Last active June 8, 2024 10:11
Show Gist options
  • Save nareix/600d96bd50a07c68a5a64a13ff0174c3 to your computer and use it in GitHub Desktop.
Save nareix/600d96bd50a07c68a5a64a13ff0174c3 to your computer and use it in GitHub Desktop.
百变方块
#include <stdio.h>
#include <stdint.h>
#include <string.h>
// 本质上是一个“环状”俄罗斯方块,以及每一层只有一个中心是实心的方块
// 状态共 80bit: 15bit + 60bit + 5bit
// 15bit: 积木有没有被使用
// 60bit: 对应位置有没有填满,为 12*5 点阵
// 5bit: 内层有没有被填满
// 状态转移: 找到最左下角的空位,尝试放置下一块积木
#define BLOCK_NR (sizeof(blocks)/sizeof(blocks[0]))
#define W 12
#define H 5
#define BITMAP_FULL ((1UL<<(W*H))-1)
#define SHAPE_W 6
typedef struct {
int w, h;
int center;
char shape[SHAPE_W][SHAPE_W];
uint64_t next[W*2];
int next_nr;
} Block;
Block blocks[] = {
{.shape = {
{1,0,0,0,0,1},
}, .center = 1},
{.shape = {
{0,0,0,1},
{1,1,1,1},
}},
{.shape = {
{0,0,1,1},
{1,1,1,0},
}},
{.shape = {
{0,0,1,0},
{1,1,1,1},
}},
{.shape = {
{1,1},
}, .center = 1},
{.shape = {
{1,1,1,1,1},
}},
{.shape = {
{1,0,1},
}, .center = 1},
{.shape = {
{0,1,1},
{0,1,0},
{1,1,0},
}},
{.shape = {
{1,1,1},
{0,1,0},
{0,1,0},
}},
{.shape = {
{1,0,0,1},
}, .center = 1},
{.shape = {
{0,1,0},
{1,1,1},
{1,0,0},
}},
{.shape = {
{0,0,1},
{0,1,1},
{1,1,0},
}},
{.shape = {
{1,0,0,0,1},
}, .center = 1},
{.shape = {
{0,1,1},
{1,1,1},
}},
{.shape = {
{1,0,1},
{1,1,1},
}},
};
int is_bitmap_set(uint64_t bitmap, int x, int y) {
return (bitmap & (1UL<<(y*W+x))) != 0;
}
void find_first_empty_bit(uint64_t bitmap, int *px, int *py) {
for (int i = 0; i < W*H; i++) {
if ((bitmap & (1UL<<i)) == 0) {
*px = i%W;
*py = i/W;
return;
}
}
}
typedef struct {
uint64_t bitmap;
int i;
} Path;
Path path[BLOCK_NR];
void print_result(int n) {
char used[H+1][W+1] = {};
memset(used, '.', (W+1)*H);
for (int i = 0; i < H; i++) {
used[i][W] = '\n';
}
const char *S = "0123456789abcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < n; i++) {
uint64_t bitmap = path[i].bitmap;
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
if (is_bitmap_set(bitmap, x, y)) {
used[H-y-1][x] = S[path[i].i];
}
}
}
}
printf("%s", &used[0][0]);
}
int total;
int dfs(int depth, uint64_t bitmap, uint64_t used) {
if (bitmap == BITMAP_FULL) {
print_result(depth);
printf("found %d\n", total);
total++;
return 1;
}
int x, y;
find_first_empty_bit(bitmap, &x, &y);
for (int i = 0; i < BLOCK_NR; i++) {
Block *b = &blocks[i];
uint64_t next_used = 1UL<<i;
if (b->center) {
next_used |= 1UL<<(BLOCK_NR+y);
}
if ((used & next_used) == 0) {
for (int j = 0; j < b->next_nr; j++) {
uint64_t next_bitmap = b->next[j] << (y*W);
if ((bitmap & next_bitmap) == 0 &&
is_bitmap_set(bitmap | next_bitmap, x, y)) {
path[depth].i = i;
path[depth].bitmap = next_bitmap;
// printf("path depth=%d x,y=%d,%d block=%d next=%llx\n", depth, x, y, i, next);
// print_result(depth+1);
if (dfs(depth + 1, bitmap | next_bitmap, used | next_used)) {
return 1;
}
}
}
}
}
return 0;
}
uint64_t bitmap_shift(uint64_t bitmap, int off) {
#define MASK ((1UL<<W)-1)
uint64_t bitmap2 = 0;
for (int i = 0; i < H; i++) {
uint64_t r = (bitmap >> (i * W)) & MASK;
r <<= off;
r |= (r & ~MASK) >> W;
r &= MASK;
bitmap2 |= r << (i * W);
}
#undef MASK
return bitmap2;
}
uint64_t shape_to_bitmap(char shape[SHAPE_W][SHAPE_W], int w, int h) {
uint64_t bitmap = 0;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
if (shape[h-y-1][x]) {
bitmap |= 1UL << (y * W + x);
}
}
}
return bitmap;
}
void prepare() {
for (int i = 0; i < BLOCK_NR; i++) {
Block *b = &blocks[i];
for (int y = 0; y < SHAPE_W; y++) {
for (int x = 0; x < SHAPE_W; x++) {
if (b->shape[y][x]) {
if (x+1 > b->w) {
b->w = x+1;
}
if (y+1 > b->h) {
b->h = y+1;
}
}
}
}
uint64_t bitmap = shape_to_bitmap(b->shape, b->w, b->h);
for (int i = 0; i < W; i++) {
b->next[b->next_nr++] = bitmap_shift(bitmap, i);
}
char shape2[SHAPE_W][SHAPE_W] = {};
for (int y = 0; y < b->h; y++) {
for (int x = 0; x < b->w; x++) {
shape2[b->h-y-1][b->w-x-1] = b->shape[y][x];
}
}
if (memcmp(shape2, b->shape, sizeof(b->shape)) != 0) {
uint64_t bitmap = shape_to_bitmap(shape2, b->w, b->h);
for (int i = 0; i < W; i++) {
b->next[b->next_nr++] = bitmap_shift(bitmap, i);
}
}
}
}
int main() {
prepare();
dfs(0, 0, 0);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment