BitBoard を利用してリバーシを実装しています。
石の数は 立っている bit の数を数える(ビットカウントする)ことで求められます。
いくつか実装を比べてみましたが、お手軽な実装が速いです。
bin_count
def count1(board):
return bin(board).count('1')
当初、文字列を経由するので遅いのではないかと思いましたが、最適化されていて速いんだと思います。
試してみたコードは以下です。
# 呼び出しのオーバーヘッド計測のためのダミー関数
def dummy(board):
return 0
# popcount の実装
def count2(board):
board = (board & 0x5555555555555555) + (board >> 1 & 0x5555555555555555)
board = (board & 0x3333333333333333) + (board >> 2 & 0x3333333333333333)
board = (board & 0x0f0f0f0f0f0f0f0f) + (board >> 4 & 0x0f0f0f0f0f0f0f0f)
board = (board & 0x00ff00ff00ff00ff) + (board >> 8 & 0x00ff00ff00ff00ff)
board = (board & 0x0000ffff0000ffff) + (board >> 16 & 0x0000ffff0000ffff)
return (board & 0x00000000ffffffff) + (board >> 32)
# 愚直な方法
def count3(board):
result = 0
while board:
board >>= 1
result += board & 1
return result
def main():
board = 0b0010000000100000000011000011010000111100000110000000000000000000
import time
temp = time.time()
for i in range(100000):
dummy(board)
print(f"dummy : {time.time() - temp}")
temp = time.time()
for i in range(100000):
count1(board)
print(f"count1: {time.time() - temp}")
temp = time.time()
for i in range(100000):
count2(board)
print(f"count2: {time.time() - temp}")
temp = time.time()
for i in range(100000):
count3(board)
print(f"count3: {time.time() - temp}")
if __name__ == "__main__":
main()
結果は以下です。
dummy : 0.010009050369262695
count1: 0.0470428466796875
count2: 0.152146577835083
count3: 1.0559582710266113
count1
は 呼び出し(dummy
)のオーバーヘッドと同じオーダーで計算できています。
count2
のアルゴリズムは popcount と呼ばれる O(logN) のアルゴリズムを利用していますが、遅いです。
count3
と比べると差は歴然です。