Skip to content

Instantly share code, notes, and snippets.

@taotao54321
Last active June 8, 2019 02:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save taotao54321/c9d14c6690ac8568f16f41398a55a9ae to your computer and use it in GitHub Desktop.
Save taotao54321/c9d14c6690ac8568f16f41398a55a9ae to your computer and use it in GitHub Desktop.
マジあり氏のぷよぷよシミュレータ読解 (オリジナル: https://pastebin.com/wGLgnvrm)
// 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;
}
.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
#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