Last active
June 8, 2019 02:45
-
-
Save taotao54321/c9d14c6690ac8568f16f41398a55a9ae to your computer and use it in GitHub Desktop.
マジあり氏のぷよぷよシミュレータ読解 (オリジナル: https://pastebin.com/wGLgnvrm)
This file contains hidden or 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
// header {{{ | |
#include <bits/stdc++.h> | |
#include <x86intrin.h> | |
#include <fmt/format.h> | |
#include <fmt/ostream.h> | |
using namespace std; | |
#define CPP_STR(x) CPP_STR_I(x) | |
#define CPP_CAT(x,y) CPP_CAT_I(x,y) | |
#define CPP_STR_I(args...) #args | |
#define CPP_CAT_I(x,y) x ## y | |
#define ASSERT(expr...) assert((expr)) | |
using i8 = int8_t; | |
using u8 = uint8_t; | |
using i16 = int16_t; | |
using u16 = uint16_t; | |
using i32 = int32_t; | |
using u32 = uint32_t; | |
using i64 = int64_t; | |
using u64 = uint64_t; | |
using f32 = float; | |
using f64 = double; | |
// }}} | |
//#define LOG_MODE | |
//#define NO_DBG | |
// util {{{ | |
#define FOR(i, start, end) for(int i = (start), CPP_CAT(i,xxxx_end)=(end); i < CPP_CAT(i,xxxx_end); ++i) | |
#define REP(i, n) FOR(i, 0, n) | |
template<typename T> | |
void DBG_IMPL(int line, const char* expr, const T& value) { | |
cerr << "[L " << line << "]: "; | |
cerr << expr << " = \n"; | |
cerr << value << "\n"; | |
cerr << "\n"; | |
} | |
#ifdef NO_DBG | |
#define DBG(expr) | |
#else | |
#define DBG(expr) DBG_IMPL(__LINE__, CPP_STR(expr), (expr)) | |
#endif | |
template<typename T, typename U, typename Comp=less<>> | |
inline bool chmax(T& xmax, const U& x, Comp comp={}) { | |
if(comp(xmax, x)) { | |
xmax = x; | |
return true; | |
} | |
return false; | |
} | |
template<typename T, typename U, typename Comp=less<>> | |
inline bool chmin(T& xmin, const U& x, Comp comp={}) { | |
if(comp(x, xmin)) { | |
xmin = x; | |
return true; | |
} | |
return false; | |
} | |
// }}} | |
class Rng { | |
public: | |
explicit Rng(u32 seed) { init(seed); } | |
u32 next() { | |
x_ = update(x_); | |
return x_; | |
} | |
private: | |
void init(u32 seed) { | |
u32 tmp = seed; | |
REP(_, 5) { | |
tmp = update(tmp); | |
} | |
tmp >>= 16; | |
REP(_, 5) { | |
tmp = update(tmp); | |
} | |
x_ = tmp; | |
} | |
static u32 update(u32 r) { | |
return 0x5D588B65*r + 0x269EC3; | |
} | |
u32 x_; | |
}; | |
constexpr struct PuyoConst { | |
u8 TUMO_BASE_AMAKUCHI[256]; | |
u8 TUMO_BASE_TYUKARA[256]; | |
u32 PLACEMENTS[126]; | |
constexpr PuyoConst() | |
: TUMO_BASE_AMAKUCHI(), TUMO_BASE_TYUKARA(), PLACEMENTS() | |
{ | |
REP(i, 256) { | |
TUMO_BASE_AMAKUCHI[i] = u8(i % 3); | |
} | |
REP(i, 256) { | |
TUMO_BASE_TYUKARA[i] = u8(i % 4); | |
} | |
// comb(9,4) の列挙 | |
PLACEMENTS[0] = (1U<<4)-1; | |
FOR(i, 1, 126) { | |
u32 x = PLACEMENTS[i-1]; | |
u32 t = (x | (x-1)) + 1; | |
PLACEMENTS[i] = t | ((~t & (t-1)) >> (__builtin_ctz(x)+1)); | |
} | |
} | |
} PUYO; | |
void tumo_gen(Rng& rng, u8 (&tumo)[256]) { | |
auto shuf = [&rng](u8 (&v)[256]) { | |
REP(i, 15) { | |
REP(_, 8) { | |
u32 k1 = (rng.next()>>28) + 16*i; | |
u32 k2 = (rng.next()>>28) + 16*(i+1); | |
swap(v[k1], v[k2]); | |
} | |
} | |
REP(i, 7) { | |
REP(_, 16) { | |
u32 k1 = (rng.next()>>27) + 32*i; | |
u32 k2 = (rng.next()>>27) + 32*(i+1); | |
swap(v[k1], v[k2]); | |
} | |
} | |
REP(i, 3) { | |
REP(_, 32) { | |
u32 k1 = (rng.next()>>26) + 64*i; | |
u32 k2 = (rng.next()>>26) + 64*(i+1); | |
swap(v[k1], v[k2]); | |
} | |
} | |
}; | |
memcpy(tumo, PUYO.TUMO_BASE_AMAKUCHI, sizeof(tumo)); | |
shuf(tumo); | |
u8 head[4]; | |
memcpy(head, tumo, sizeof(head)); | |
memcpy(tumo, PUYO.TUMO_BASE_TYUKARA, sizeof(tumo)); | |
shuf(tumo); | |
memcpy(tumo, head, sizeof(head)); | |
} | |
void board_init(u64 (&board)[5], const u8 (&puyo)[24], u32 placement) { | |
memset(board, 0, sizeof(board)); | |
board[2] |= 1ULL << puyo[1]; | |
board[3] |= 1ULL << puyo[0]; | |
int cnt2 = 1; | |
int cnt3 = 1; | |
FOR(i, 1, 10) { | |
if(placement & (1U<<(i-1))) { | |
board[3] |= 1ULL << (puyo[2*i+1] + 4*cnt3); | |
board[3] |= 1ULL << (puyo[2*i] + 4*(cnt3+1)); | |
cnt3 += 2; | |
} | |
else { | |
board[2] |= 1ULL << (puyo[2*i+1] + 4*cnt2); | |
board[2] |= 1ULL << (puyo[2*i] + 4*(cnt2+1)); | |
cnt2 += 2; | |
} | |
} | |
board[2] |= 1ULL << (44+puyo[20]); | |
board[2] |= 1ULL << (48+puyo[21]); | |
board[1] |= 1ULL << puyo[23]; | |
board[1] |= 1ULL << (4+puyo[22]); | |
// delta swap | |
u64 tmp = (board[2] ^ (board[2]>>4)) & 0x000000F0'00000000; | |
board[2] ^= tmp ^ (tmp<<4); | |
} | |
int board_erase(u64 (&board)[5]) { | |
// 消えるぷよ(全色) | |
// 各nibbleは消える場合 0b1111 に、消えない場合 0 になる | |
u64 erase_mask[5] {}; | |
// 色ごとに消去判定 | |
REP(color, 4) { | |
// 今見ている色だけ抜き出す | |
u64 board_one[5]; | |
REP(x, 5) { | |
board_one[x] = (board[x]>>color) & 0x11111111'11111111; | |
} | |
// 各ぷよの連結数を求める | |
// 13段目は消去判定に関与しないため、適宜12段目まででマスクする | |
u64 link[5] {}; | |
FOR(x, 1, 4) { | |
// L | |
link[x] += board_one[x] & board_one[x-1]; | |
// R | |
link[x] += board_one[x] & board_one[x+1]; | |
// D | |
link[x] += board_one[x] & (board_one[x]<<4); | |
// U | |
link[x] += board_one[x] & ((board_one[x]&0x0000FFFF'FFFFFFFF)>>4); | |
link[x] &= 0x0000FFFF'FFFFFFFF; | |
} | |
// 連結数3以上のぷよを求める | |
u64 link_3[5] {}; | |
FOR(x, 1, 4) { | |
// 各nibbleに1を加えて4で割った商が1になるものだけ抽出 | |
link_3[x] |= ((link[x]+0x11111111'11111111)>>2) & 0x11111111'11111111; | |
} | |
// 連結数2以上のぷよを求める | |
// 結果は link に上書きする | |
FOR(x, 1, 4) { | |
// 各nibbleに2を加えて4で割った商が1になるものだけ抽出 | |
link[x] = ((link[x]+0x22222222'22222222)>>2) & 0x11111111'11111111; | |
} | |
// 連結数2以上のぷよ同士で連結しているものを求める | |
u64 link_link_2[5] {}; | |
FOR(x, 1, 4) { | |
// L | |
link_link_2[x] |= link[x] & link[x-1]; | |
// R | |
link_link_2[x] |= link[x] & link[x+1]; | |
// D | |
link_link_2[x] |= link[x] & (link[x]<<4); | |
// U | |
link_link_2[x] |= link[x] & (link[x]>>4); | |
} | |
// 消えるぷよを求める | |
u64 erase_one[5] {}; | |
FOR(x, 1, 4) { | |
// 連結数2以上のぷよ同士で連結しているか、連結数3以上 | |
erase_one[x] |= link_link_2[x] | link_3[x]; | |
// 左が連結数2以上のぷよ同士で連結しているか、連結数3以上 | |
erase_one[x] |= board_one[x] & (link_link_2[x-1] | link_3[x-1]); | |
// 右が連結数2以上のぷよ同士で連結しているか、連結数3以上 | |
erase_one[x] |= board_one[x] & (link_link_2[x+1] | link_3[x+1]); | |
// 上が連結数2以上のぷよ同士で連結しているか、連結数3以上 | |
erase_one[x] |= board_one[x] & ((link_link_2[x] | link_3[x]) >> 4); | |
// 下が連結数2以上のぷよ同士で連結しているか、連結数3以上 | |
erase_one[x] |= board_one[x] & ((link_link_2[x] | link_3[x]) << 4); | |
erase_mask[x] |= erase_one[x]; | |
} | |
} | |
int n_erased = 0; | |
FOR(x, 1, 4) { | |
n_erased += __builtin_popcountll(erase_mask[x]); | |
erase_mask[x] |= erase_mask[x] << 1; | |
erase_mask[x] |= erase_mask[x] << 2; | |
} | |
// 消去/落下処理 | |
FOR(x, 1, 4) { | |
board[x] = _pext_u64(board[x], ~erase_mask[x]); | |
} | |
return n_erased; | |
} | |
void go(u32 seed) { | |
Rng rng(seed); | |
u8 tumo[256]; | |
tumo_gen(rng, tumo); | |
u8 puyo[24]; | |
memcpy(puyo, tumo, sizeof(puyo)); | |
{ | |
u8 cnt[4] {}; | |
for(auto p : puyo) | |
++cnt[p]; | |
auto [imin,imax] = minmax_element(begin(cnt), end(cnt)); | |
if(*imin < 4 || *imax < 8) return; | |
} | |
REP(i, 126) { | |
u32 placement = PUYO.PLACEMENTS[i]; | |
u64 board[5]; | |
board_init(board, puyo, placement); | |
u64 board_orig[5]; | |
memcpy(board_orig, board, sizeof(board)); | |
int cnt[2] {}; | |
cnt[0] = board_erase(board); | |
if(cnt[0] >= 4) | |
cnt[1] = board_erase(board); | |
#ifndef LOG_MODE | |
if(cnt[1] < 19) continue; | |
#endif | |
fmt::print("seed: 0x{:08x}, sort_num: {}\n", seed, i); | |
fmt::print("{:016x}\n", board_orig[1]); | |
fmt::print("{:016x}\n", board_orig[2]); | |
fmt::print("{:016x}\n", board_orig[3]); | |
fmt::print("--\n"); | |
fmt::print("{:016x}\n", board[1]); | |
fmt::print("{:016x}\n", board[2]); | |
fmt::print("{:016x}\n", board[3]); | |
fmt::print("{} {}\n\n", cnt[0], cnt[1]); | |
} | |
} | |
int main() { | |
#ifdef LOG_MODE | |
FOR(seed, 0x42000, 0x50000+1) { | |
#else | |
FOR(seed, 0x42000, 0x400000+1) { | |
#endif | |
go(seed); | |
} | |
return 0; | |
} |
This file contains hidden or 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
.PHONY: all clean | |
CXX := g++ | |
CXXFLAGS := \ | |
-std=c++17 \ | |
-Wall -Wextra \ | |
-Wconditionally-supported \ | |
-Wconversion \ | |
-Wduplicated-cond \ | |
-Wduplicated-branches \ | |
-Wextra-semi \ | |
-Wfloat-equal \ | |
-Wformat=2 \ | |
-Wlogical-op \ | |
-Wnull-dereference \ | |
-Wold-style-cast \ | |
-Wshadow \ | |
-Wswitch-default \ | |
-Wswitch-enum \ | |
-Wundef \ | |
-Wuseless-cast \ | |
-Wvla \ | |
-Wzero-as-null-pointer-constant | |
LDFLAGS := -lfmt | |
ifdef NO_OPTIMIZE | |
CXXFLAGS += -g -fsanitize=undefined -fno-sanitize-recover=all -D_GLIBCXX_DEBUG | |
else | |
ARCH := native | |
#ARCH := haswell | |
CXXFLAGS += -O2 -march=$(ARCH) -mtune=$(ARCH) -mbmi2 | |
#CXXFLAGS += -O3 -march=$(ARCH) -mtune=$(ARCH) | |
#CXXFLAGS += -pg | |
endif | |
SRCS := $(wildcard *.cpp) | |
OBJS := $(SRCS:%.cpp=%.o) | |
DEPS := $(SRCS:%.cpp=%.d) | |
TARGET := a.out | |
all: $(TARGET) maziari_puyo | |
-include $(DEPS) | |
$(TARGET): $(OBJS) | |
$(CXX) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) | |
maziari_puyo: maziari_puyo.c | |
gcc -Wall -Wextra -O2 -march=native -mtune=native -o $@ $< | |
%.o: %.cpp | |
$(CXX) $(CXXFLAGS) -c -MMD -MP $< | |
clean: | |
-$(RM) $(TARGET) maziari_puyo *.o |
This file contains hidden or 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> | |
//#define LOG_MODE | |
void next_rand(unsigned int *rand); | |
void init_arr_puyo(int arr[256], int color); | |
void shuffle_arr_puyo(int arr[256], unsigned int *rand); | |
void init_arr_sort(int arr[126]); | |
void count_puyo_color(int arr_12[24], int arr_count[4]); | |
void dispos_puyo(long long int board[3], int arr[24], int num); | |
int count_bit(long long int bits); | |
int count_erase_puyo(long long int board[5]); | |
int main(void) { | |
int i, j; | |
unsigned int seed; | |
unsigned int tmp_seed; | |
unsigned int rand; | |
int arr_amakuchi[256]; // 甘口のツモ (tyukara 初期化にのみ使われる) | |
int arr_tyukara[256]; // 中辛のツモ | |
// 配置パターン | |
// 9bit中4bitが立っているものたち (comb(9,4)=126) | |
int arr_sort[126]; | |
int arr_puyo_12[24]; // arr_tyukara 先頭24個 | |
int arr_num_puyo_color[4]; // 色ごとの個数(降順)。枝刈り用 | |
// 盤面(5列) | |
// 列0と列4は常に空(番兵) | |
// 4bitが1マス。色に対応したbitが立つ。 | |
long long int board_puyo[5]; | |
int num_erase_puyo; | |
board_puyo[0] = 0; | |
board_puyo[4] = 0; | |
#if 0 | |
long long int tmp[3]; | |
#endif | |
#ifdef LOG_MODE | |
for (i = 0x42000; i <= 0x50000; i++) { | |
#else | |
for (i = 0x42000; i <= 0x400000; i++) { | |
#endif | |
seed = i; // First Seed | |
tmp_seed = seed; | |
for (j = 0; j < 5; j++) { | |
next_rand(&tmp_seed); | |
} | |
/* Init Rand */ | |
rand = tmp_seed >> 16; | |
for (j = 0; j < 5; j++) { | |
next_rand(&rand); | |
} | |
/* Init Memory */ | |
init_arr_puyo(arr_amakuchi, 3); | |
init_arr_puyo(arr_tyukara, 4); | |
/* Shuffle Memory */ | |
shuffle_arr_puyo(arr_amakuchi, &rand); | |
shuffle_arr_puyo(arr_tyukara, &rand); | |
for (j = 0; j < 4; j++) { | |
arr_tyukara[j] = arr_amakuchi[j]; | |
arr_num_puyo_color[j] = 0; | |
} | |
/* Make Sort Array*/ | |
init_arr_sort(arr_sort); | |
/* Init 12 Puyo Array */ | |
for (j = 0; j < 24; j++) { | |
arr_puyo_12[j] = arr_tyukara[j]; | |
} | |
/* Count Each Puyo Color */ | |
count_puyo_color(arr_puyo_12, arr_num_puyo_color); | |
// 最大数が8未満または最小数が4未満なら却下 | |
if (arr_num_puyo_color[0] < 8 || arr_num_puyo_color[3] < 4) { | |
continue; | |
} | |
for (j = 0; j < 126; j++) { | |
/* Disposition Puyo*/ | |
dispos_puyo(&board_puyo[1], arr_puyo_12, arr_sort[j]); | |
#ifdef LOG_MODE | |
// ログ出力(verify用) | |
printf("seed: 0x%08x, sort_num: %d\n", seed, j); | |
printf("%016llx\n", board_puyo[1]); | |
printf("%016llx\n", board_puyo[2]); | |
printf("%016llx\n", board_puyo[3]); | |
printf("--\n"); | |
int cnt[2] = {}; | |
cnt[0] = num_erase_puyo = count_erase_puyo(board_puyo); | |
if(num_erase_puyo >= 4) | |
cnt[1] = num_erase_puyo = count_erase_puyo(board_puyo); | |
printf("%016llx\n", board_puyo[1]); | |
printf("%016llx\n", board_puyo[2]); | |
printf("%016llx\n", board_puyo[3]); | |
printf("%d %d\n\n", cnt[0], cnt[1]); | |
#else | |
long long int tmp[3]; | |
tmp[2] = board_puyo[3]; | |
tmp[1] = board_puyo[2]; | |
tmp[0] = board_puyo[1]; | |
/* Rensa and Count Erasing Puyo */ | |
num_erase_puyo = count_erase_puyo(board_puyo); | |
if (num_erase_puyo >= 4) { | |
num_erase_puyo = count_erase_puyo(board_puyo); | |
if (num_erase_puyo >= 19) { | |
printf("seed: %08x, sort_num: %d\n", seed, j); | |
printf("\nsort: %d\n", arr_sort[j]); | |
printf("\n%016llx\n", tmp[2]); | |
printf("%016llx\n", tmp[1]); | |
printf("%016llx\n", tmp[0]); | |
printf("\n%016llx\n", board_puyo[3]); | |
printf("%016llx\n", board_puyo[2]); | |
printf("%016llx\n", board_puyo[1]); | |
printf("\n%d\n", num_erase_puyo); | |
} | |
} | |
#endif | |
} | |
} | |
//printf("end."); | |
return 0; | |
} | |
void next_rand(unsigned int *rand) { | |
*rand = (*rand * 0x5D588B65 + 0x269EC3) & 0xFFFFFFFF; | |
} | |
void init_arr_puyo(int arr[256], int color) { | |
int i; | |
for (i = 0; i < 256; i++) { | |
arr[i] = i % color; | |
} | |
} | |
void shuffle_arr_puyo(int arr[256], unsigned int *rand) { | |
int i, j; | |
int tmp; | |
unsigned int num1, num2; | |
for (i = 0; i < 15; i++) { | |
for (j = 0; j < 8; j++) { | |
next_rand(rand); | |
num1 = (*rand >> 28) + i * 0x10; | |
next_rand(rand); | |
num2 = (*rand >> 28) + (i + 1) * 0x10; | |
tmp = arr[num1]; | |
arr[num1] = arr[num2]; | |
arr[num2] = tmp; | |
} | |
} | |
for (i = 0; i < 7; i++) { | |
for (j = 0; j < 16; j++) { | |
next_rand(rand); | |
num1 = (*rand >> 27) + i * 0x20; | |
next_rand(rand); | |
num2 = (*rand >> 27) + (i + 1) * 0x20; | |
tmp = arr[num1]; | |
arr[num1] = arr[num2]; | |
arr[num2] = tmp; | |
} | |
} | |
for (i = 0; i < 3; i++) { | |
for (j = 0; j < 32; j++) { | |
next_rand(rand); | |
num1 = (*rand >> 26) + i * 0x40; | |
next_rand(rand); | |
num2 = (*rand >> 26) + (i + 1) * 0x40; | |
tmp = arr[num1]; | |
arr[num1] = arr[num2]; | |
arr[num2] = tmp; | |
} | |
} | |
} | |
void init_arr_sort(int arr[126]) { | |
int i, j; | |
int bit_cnt, arr_cnt = 0; | |
// 9bit数のうちbitが4つ立っているものを列挙 | |
// comb(9,4) で 126 通り | |
for (i = 0; i < 512; i++) { | |
bit_cnt = 0; | |
for (j = 0; j < 9; j++) { | |
if (i & (1 << j)) bit_cnt++; | |
} | |
if (bit_cnt == 4) { | |
arr[arr_cnt] = i; | |
arr_cnt++; | |
} | |
} | |
} | |
// 色ごとの個数を求める(arr_count に降順で返る) | |
void count_puyo_color(int arr_12[24], int arr_count[4]) { | |
int i, j; | |
for (i = 0; i < 24; i++) { | |
arr_count[arr_12[i]]++; | |
} | |
// 降順ソート | |
for (i = 0; i < 3; i++) { | |
for (j = 3; j > i; j--) { | |
if (arr_count[j - 1] < arr_count[j]) { | |
// swap処理 | |
// arr_count[j-1] ^= arr_count[j]; | |
// arr_count[j] ^= arr_count[j-1]; | |
// arr_count[j-1] ^= arr_count[j]; | |
//arr_count[j - 1] ^= arr_count[j] ^= arr_count[j - 1] ^= arr_count[j]; | |
// -Wsequence-point に引っかかるので素朴なコードに変更 | |
int tmp = arr_count[j-1]; | |
arr_count[j-1] = arr_count[j]; | |
arr_count[j] = tmp; | |
} | |
} | |
} | |
#if 0 | |
for(i = 0; i < 4; ++i) | |
printf("%d: %d\n", i, arr_count[i]); | |
#endif | |
} | |
// 盤面にぷよを配置 | |
void dispos_puyo(long long int board[3], int arr[24], int num) { | |
int i, j; | |
unsigned long long int bit_mask; | |
int cnt_column_4, cnt_column_5; | |
for (i = 0; i < 3; i++) { | |
board[i] = 0; | |
} | |
cnt_column_4 = 1; | |
cnt_column_5 = 1; | |
for (j = 0; j <= 11; j++) { | |
if (j == 0) { | |
board[1] |= (long long int)1 << arr[1]; | |
board[2] |= (long long int)1 << arr[0]; | |
} | |
if (j >= 1 && j <= 9) { | |
// board[2] には 2*4 個積まれる | |
if (num & (1 << (j - 1))) { | |
board[2] |= (long long int)1 << (arr[j * 2 + 1] + cnt_column_5 * 4); | |
board[2] |= (long long int)1 << (arr[j * 2] + (cnt_column_5 + 1) * 4); | |
cnt_column_5 += 2; | |
} | |
// board[1] には 2*5 個積まれる | |
else { | |
board[1] |= (long long int)1 << (arr[j * 2 + 1] + cnt_column_4 * 4); | |
board[1] |= (long long int)1 << (arr[j * 2] + (cnt_column_4 + 1) * 4); | |
cnt_column_4 += 2; | |
} | |
} | |
// この時点で | |
// board[1] には 11 個積まれている | |
// board[2] には 9 個積まれている | |
if (j == 10) { | |
board[1] |= (long long int)1 << (arr[20] + 44); | |
board[1] |= (long long int)1 << (arr[21] + 48); | |
} | |
if (j == 11) { | |
board[0] |= (long long int)1 << arr[23]; | |
board[0] |= (long long int)1 << (arr[22] + 4); | |
} | |
} | |
// いわゆる delta swap (bit36-39,bit40-43 のswap) | |
// ループ内で board[1] に積んだ10個目と11個目を入れ替える | |
bit_mask = ((board[1] >> 4) ^ board[1]) & 0x00000f000000000; | |
bit_mask = (bit_mask << 4) | bit_mask; | |
board[1] ^= bit_mask; | |
} | |
// popcount | |
int count_bit(long long int bits) { | |
const int bit_table[256] = { | |
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | |
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | |
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | |
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | |
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | |
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | |
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | |
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, | |
}; | |
return bit_table[bits & 0xff] + bit_table[(bits >> 8) & 0xff] | |
+ bit_table[(bits >> 16) & 0xff] + bit_table[(bits >> 24) & 0xff] | |
+ bit_table[(bits >> 32) & 0xff] + bit_table[(bits >> 40) & 0xff] | |
+ bit_table[(bits >> 48) & 0xff] + bit_table[(bits >> 56) & 0xff]; | |
} | |
int count_erase_puyo(long long int board[5]) { | |
int i, j; | |
// 周囲との連結数が2以上のぷよ | |
long long int link[5]; | |
// 連結数2以上のぷよとの連結数が2以上のぷよ | |
long long int link_link_2[5]; | |
// 周囲との連結数が3以上のぷよ | |
long long int link_3[5]; | |
// 消えるぷよ(1色) | |
// 各nibble内の最下位bitのみが意味を持つ | |
long long int erase_color[5]; | |
// 消えるぷよ(全色) | |
// 各nibbleは消える場合 0b1111 に、消えない場合 0 になる | |
long long int erase_integ[5]; | |
// board から1色だけ抜き出したもの(各nibble内の最下位bitのみが意味を持つ) | |
long long int abst_color[5]; | |
// 消去/落下処理用 | |
// 落下しないぷよのマスク | |
long long int drop_prot_mask[5]; | |
// 消去/落下処理用 | |
// | |
long long int drop_diff_mask[5]; | |
// 消去/落下処理用 | |
long long int tmp_board; | |
// 消えたぷよ数(戻り値) | |
int num_erase_puyo = 0; | |
for (i = 0; i < 5; i++) { // j: 列 | |
erase_integ[i] = 0; | |
} | |
for (i = 0; i < 4; i++) { // i: 色 | |
for (j = 0; j < 5; j++) { // j: 列 | |
link[j] = 0; | |
link_link_2[j] = 0; | |
link_3[j] = 0; | |
erase_color[j] = 0; | |
// 今見ている色だけ抜き出す | |
abst_color[j] = (board[j] >> i) & 0x1111111111111111; | |
drop_prot_mask[j] = 0; | |
drop_diff_mask[j] = 0; | |
} | |
// 各ぷよの連結数を求め、link[] 内の各nibbleに格納 | |
// 13段目は消去判定に関与しないため、12段目まででマスクする | |
for (j = 1; j <= 3; j++) { // j: 列 | |
// L | |
link[j] += (abst_color[j] & abst_color[j - 1]) & 0x0000ffffffffffff; | |
// R | |
link[j] += (abst_color[j] & abst_color[j + 1]) & 0x0000ffffffffffff; | |
// D | |
link[j] += (abst_color[j] & (abst_color[j] << 4)) & 0x0000ffffffffffff; | |
// U | |
link[j] += (abst_color[j] & ((abst_color[j] & 0x0000ffffffffffff) >> 4)) & 0x0000ffffffffffff; | |
//printf("%d: color=%d, link[%d]=%016llx\n", __LINE__, i, j, link[j]); | |
} | |
// 連結数3以上のぷよを求める | |
for (j = 1; j <= 3; j++) { // j: 列 | |
// 各nibbleに1を加えて4で割って1になったものだけ抽出 | |
link_3[j] |= ((link[j] + 0x1111111111111111) >> 2) & 0x1111111111111111; | |
} | |
// 連結数2以上のぷよを求める | |
// 結果は link[] に上書きする | |
for (j = 1; j <= 3; j++) { // j: 列 | |
// 各nibbleに2を加えて4で割って1になったものだけ抽出 | |
link[j] = ((link[j] + 0x2222222222222222) >> 2) & 0x1111111111111111; | |
} | |
// 連結数2以上のぷよ同士で連結しているものを求める | |
for (j = 1; j <= 3; j++) { // j: 列 | |
// L | |
link_link_2[j] |= link[j] & link[j - 1] & 0x1111111111111111; | |
// R | |
link_link_2[j] |= link[j] & link[j + 1] & 0x1111111111111111; | |
// D | |
link_link_2[j] |= link[j] & (link[j] << 4) & 0x1111111111111111; | |
// U | |
link_link_2[j] |= link[j] & (link[j] >> 4) & 0x1111111111111111; | |
} | |
// 消えるぷよを求める | |
for (j = 1; j <= 3; j++) { // j: 列 | |
// 連結数2以上のぷよ同士で連結しているか、連結数3以上 | |
erase_color[j] |= abst_color[j] & (link_link_2[j] | link_3[j]); | |
// 左が連結数2以上のぷよ同士で連結しているか、連結数3以上 | |
erase_color[j] |= abst_color[j] & (link_link_2[j - 1] | link_3[j - 1]); | |
// 右が連結数2以上のぷよ同士で連結しているか、連結数3以上 | |
erase_color[j] |= abst_color[j] & (link_link_2[j + 1] | link_3[j + 1]); | |
// 上が連結数2以上のぷよ同士で連結しているか、連結数3以上 | |
erase_color[j] |= abst_color[j] & ((link_link_2[j] | link_3[j]) >> 4); | |
// 下が連結数2以上のぷよ同士で連結しているか、連結数3以上 | |
erase_color[j] |= abst_color[j] & ((link_link_2[j] | link_3[j]) << 4); | |
num_erase_puyo += count_bit(erase_color[j]); | |
// erase_integ 更新(消える場合、該当nibbleを 0b1111 に) | |
erase_color[j] = erase_color[j] + (erase_color[j] << 1) + (erase_color[j] << 2) + (erase_color[j] << 3); | |
erase_integ[j] |= erase_color[j]; | |
} | |
} | |
// 消去/落下処理 | |
// | |
// ex. | |
// board = 12142881 | |
// erase_integ = 0F0F0FF0 | |
// drop_prot_mask = 0000000F | |
// drop_diff_mask = 00000FF0 | |
// tmp_board = 00000001 | |
// | |
// board = 00121421 | |
// erase_integ = 000F0F00 | |
while (erase_integ[1] | erase_integ[2] | erase_integ[3]) { | |
for (j = 1; j <= 3; j++) { // j: 列 | |
// 落下しないぷよを求める | |
// x ^ (x-1): 最右の1とそれより右の0を1に、他を0にする | |
drop_prot_mask[j] = (erase_integ[j] ^ (erase_integ[j] - (long long int)1)) >> 1; | |
// 消えるぷよのうち最も下にある連続した塊を求める | |
// 以下の式で最右の連続した1が求まる | |
drop_diff_mask[j] = (~erase_integ[j] - ((erase_integ[j] - 1) ^ erase_integ[j])) & erase_integ[j]; | |
// 落下しないぷよを保護 | |
tmp_board = board[j] & drop_prot_mask[j]; | |
// drop_diff_mask に該当するぷよを消し、それより上を落下させる | |
board[j] = ((board[j] >> count_bit(drop_diff_mask[j])) & ~drop_prot_mask[j]) | tmp_board; | |
// 消えた段数を考慮して erase_integ を更新 | |
erase_integ[j] = (erase_integ[j] ^ drop_diff_mask[j]) >> count_bit(drop_diff_mask[j]); | |
} | |
} | |
return num_erase_puyo; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment