| | import numpy as np
|
| | from src.bitboard import get_bit, bit_to_row_col, popcount
|
| |
|
| | class OthelloGame:
|
| | def __init__(self):
|
| |
|
| |
|
| |
|
| | self.player_bb = 0x0000000810000000
|
| | self.opponent_bb = 0x0000001008000000
|
| | self.turn = 1
|
| |
|
| | def get_valid_moves(self, player, opponent):
|
| | """Calculates valid moves for 'player' against 'opponent'."""
|
| | empty = ~(player | opponent) & 0xFFFFFFFFFFFFFFFF
|
| |
|
| |
|
| |
|
| |
|
| | mask_h = 0x0101010101010101
|
| | mask_a = 0x8080808080808080
|
| |
|
| |
|
| | shifts = [
|
| | (lambda x: (x & ~mask_h) >> 1),
|
| | (lambda x: (x & ~mask_a) << 1),
|
| | (lambda x: (x << 8) & 0xFFFFFFFFFFFFFFFF),
|
| | (lambda x: (x >> 8) & 0xFFFFFFFFFFFFFFFF),
|
| | (lambda x: (x & ~mask_h) << 7),
|
| | (lambda x: (x & ~mask_a) << 9),
|
| | (lambda x: (x & ~mask_h) >> 9),
|
| | (lambda x: (x & ~mask_a) >> 7)
|
| | ]
|
| |
|
| | valid_moves = 0
|
| | for shift_func in shifts:
|
| | candidates = shift_func(player) & opponent
|
| | for _ in range(6):
|
| | candidates |= shift_func(candidates) & opponent
|
| | valid_moves |= shift_func(candidates) & empty
|
| |
|
| | return valid_moves
|
| |
|
| | def apply_move(self, player, opponent, move_bit):
|
| | """Calculates new boards after move_bit."""
|
| | if move_bit == 0:
|
| | return player, opponent
|
| |
|
| | flipped = 0
|
| | mask_h = 0x0101010101010101
|
| | mask_a = 0x8080808080808080
|
| |
|
| | shifts = [
|
| | (lambda x: (x & ~mask_h) >> 1),
|
| | (lambda x: (x & ~mask_a) << 1),
|
| | (lambda x: (x << 8) & 0xFFFFFFFFFFFFFFFF),
|
| | (lambda x: (x >> 8) & 0xFFFFFFFFFFFFFFFF),
|
| | (lambda x: (x & ~mask_h) << 7),
|
| | (lambda x: (x & ~mask_a) << 9),
|
| | (lambda x: (x & ~mask_h) >> 9),
|
| | (lambda x: (x & ~mask_a) >> 7)
|
| | ]
|
| |
|
| | for shift_func in shifts:
|
| | mask = shift_func(move_bit)
|
| | potential_flips = 0
|
| | while mask & opponent:
|
| | potential_flips |= mask
|
| | mask = shift_func(mask)
|
| | if mask & player:
|
| | flipped |= potential_flips
|
| |
|
| | new_player = player | move_bit | flipped
|
| | new_opponent = opponent & ~flipped
|
| | return new_player, new_opponent
|
| |
|
| | def play_move(self, move_bit):
|
| | if move_bit != 0:
|
| | self.player_bb, self.opponent_bb = self.apply_move(self.player_bb, self.opponent_bb, move_bit)
|
| |
|
| |
|
| | self.player_bb, self.opponent_bb = self.opponent_bb, self.player_bb
|
| | self.turn *= -1
|
| |
|
| | def is_terminal(self):
|
| | p_moves = self.get_valid_moves(self.player_bb, self.opponent_bb)
|
| | o_moves = self.get_valid_moves(self.opponent_bb, self.player_bb)
|
| | return (p_moves == 0) and (o_moves == 0)
|
| |
|