Last active
June 8, 2024 10:11
-
-
Save nareix/600d96bd50a07c68a5a64a13ff0174c3 to your computer and use it in GitHub Desktop.
百变方块
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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