-
Notifications
You must be signed in to change notification settings - Fork 3
/
board.py
134 lines (103 loc) · 5.04 KB
/
board.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import numpy as np
import config
initial_black = np.uint64(0b00010000 << 24 | 0b00001000 << 32)
initial_white = np.uint64(0b00001000 << 24 | 0b00010000 << 32)
class Board:
def __init__(self, black=initial_black, white=initial_white):
self.black = black
self.white = white
self.black_array2d = bit_to_array(self.black, config.board_length).reshape((config.N, config.N))
self.white_array2d = bit_to_array(self.white, config.board_length).reshape((config.N, config.N))
def get_own_and_enemy(self, player):
if player == config.black:
return self.black, self.white
else:
return self.white, self.black
def get_own_and_enemy_array2d(self, player):
if player == config.black:
return self.black_array2d, self.white_array2d
else:
return self.white_array2d, self.black_array2d
def make_move(self, player, move):
if move == config.pass_move:
return Board(self.black, self.white)
bit_move = np.uint64(0b1 << move)
own, enemy = self.get_own_and_enemy(player)
flipped_stones = get_flipped_stones_bit(bit_move, own, enemy)
own |= flipped_stones | bit_move
enemy &= ~flipped_stones
if player == config.black:
return Board(own, enemy)
else:
return Board(enemy, own)
def get_legal_moves(self, player):
own, enemy = self.get_own_and_enemy(player)
legal_moves_without_pass = bit_to_array(get_legal_moves_bit(own, enemy), config.board_length)
if np.sum(legal_moves_without_pass) == 0:
return np.concatenate((legal_moves_without_pass, [1]))
else:
return np.concatenate((legal_moves_without_pass, [0]))
left_right_mask = np.uint64(0x7e7e7e7e7e7e7e7e)
top_bottom_mask = np.uint64(0x00ffffffffffff00)
corner_mask = left_right_mask & top_bottom_mask
def get_legal_moves_bit(own, enemy):
legal_moves = np.uint64(0)
legal_moves |= search_legal_moves_left(own, enemy, left_right_mask, np.uint64(1))
legal_moves |= search_legal_moves_left(own, enemy, corner_mask, np.uint64(9))
legal_moves |= search_legal_moves_left(own, enemy, top_bottom_mask, np.uint64(8))
legal_moves |= search_legal_moves_left(own, enemy, corner_mask, np.uint64(7))
legal_moves |= search_legal_moves_right(own, enemy, left_right_mask, np.uint64(1))
legal_moves |= search_legal_moves_right(own, enemy, corner_mask, np.uint64(9))
legal_moves |= search_legal_moves_right(own, enemy, top_bottom_mask, np.uint64(8))
legal_moves |= search_legal_moves_right(own, enemy, corner_mask, np.uint64(7))
legal_moves &= ~(own | enemy)
return legal_moves
def search_legal_moves_left(own, enemy, mask, offset):
return search_contiguous_stones_left(own, enemy, mask, offset) >> offset
def search_legal_moves_right(own, enemy, mask, offset):
return search_contiguous_stones_right(own, enemy, mask, offset) << offset
def get_flipped_stones_bit(bit_move, own, enemy):
flipped_stones = np.uint64(0)
flipped_stones |= search_flipped_stones_left(bit_move, own, enemy, left_right_mask, np.uint64(1))
flipped_stones |= search_flipped_stones_left(bit_move, own, enemy, corner_mask, np.uint64(9))
flipped_stones |= search_flipped_stones_left(bit_move, own, enemy, top_bottom_mask, np.uint64(8))
flipped_stones |= search_flipped_stones_left(bit_move, own, enemy, corner_mask, np.uint64(7))
flipped_stones |= search_flipped_stones_right(bit_move, own, enemy, left_right_mask, np.uint64(1))
flipped_stones |= search_flipped_stones_right(bit_move, own, enemy, corner_mask, np.uint64(9))
flipped_stones |= search_flipped_stones_right(bit_move, own, enemy, top_bottom_mask, np.uint64(8))
flipped_stones |= search_flipped_stones_right(bit_move, own, enemy, corner_mask, np.uint64(7))
return flipped_stones
def search_flipped_stones_left(bit_move, own, enemy, mask, offset):
flipped_stones = search_contiguous_stones_left(bit_move, enemy, mask, offset)
if own & (flipped_stones >> offset) == np.uint64(0):
return np.uint64(0)
else:
return flipped_stones
def search_flipped_stones_right(bit_move, own, enemy, mask, offset):
flipped_stones = search_contiguous_stones_right(bit_move, enemy, mask, offset)
if own & (flipped_stones << offset) == np.uint64(0):
return np.uint64(0)
else:
return flipped_stones
def search_contiguous_stones_left(own, enemy, mask, offset):
e = enemy & mask
s = e & (own >> offset)
s |= e & (s >> offset)
s |= e & (s >> offset)
s |= e & (s >> offset)
s |= e & (s >> offset)
s |= e & (s >> offset)
return s
def search_contiguous_stones_right(own, enemy, mask, offset):
e = enemy & mask
s = e & (own << offset)
s |= e & (s << offset)
s |= e & (s << offset)
s |= e & (s << offset)
s |= e & (s << offset)
s |= e & (s << offset)
return s
def bit_count(bit):
return bin(bit).count('1')
def bit_to_array(bit, size):
return np.array(list(reversed((("0" * size) + bin(bit)[2:])[-size:])), dtype=np.uint8)