ここで花札といっているのは一組48枚で、12か月折々の花とかが4枚ずつに書き込まれているあれのことです。全ての札を区別して扱うとして、それぞれの札に0~47の番号を割り振ると、札の有無をuint64_tで表すことができます。『手札にi番目の札がある⇔i番目のビットが立っている』みたいなやつです。花札には多くの遊び方がありますが、以降こいこいの話をします。
合法手生成
手札がuint64_t上でbitboard表現されているとして、以下のようなコードで手札を全列挙できます。わかりますね。
void func1(uint64_t hand) { for (unsigned long i = 0; _BitScanForward64(&i, hand); hand &= hand - 1) { cout << i << "番目の札を持っている。" << endl; } }
手札を場に出すとき、同じ月の札が場に2枚以上あったらどちらの札を取るか選ばなければいけないため、手札を全列挙しただけでは合法手を全列挙したことにはなりません。ここで場札もuint64_t上でbitboard表現されているとして、合法手の全列挙は以下のように書けます。
void func2(uint64_t hand, uint64_t field) { for (unsigned long i = 0; _BitScanForward64(&i, hand); hand &= hand - 1) { const uint64_t mask = 0b1111ULL << (i & 0b111100ULL); uint64_t capture = field & mask; if (capture == 0) { cout << i << "番目の札を場に出す。" << endl; } else { for (unsigned long j = 0; _BitScanForward64(&j, capture); capture &= capture - 1) { cout << i << "番目の札を場に出し、場にある" << j << "番目の札と合わせて取る。" << endl; } } } }
役の判定
取った札がuint64_t上でbitboard表現されているとして、役が成立しているかどうかはマジックナンバーとandしてpopcountすればわかります。例えば、蝶は20番目、猪は24番目、鹿は36番目の札のとき、猪鹿蝶のためのマジックナンバーはです。