-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathothello_py.py
221 lines (191 loc) · 7.45 KB
/
othello_py.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# 定数
hw = 8
hw2 = 64
dy = [0, 1, 0, -1, 1, 1, -1, -1]
dx = [1, 0, -1, 0, 1, -1, 1, -1]
black = 0
white = 1
legal = 2
vacant = 3
# 座標(y, x)が盤面内にあるかを見る関数
def inside(y, x):
return 0 <= y < hw and 0 <= x < hw
# オセロのクラス
class othello:
# 初期化
def __init__(self):
# 盤面の状態 0: 黒 1: 白 2: 合法手 3: 非合法手
self.grid = [[vacant for _ in range(hw)] for _ in range(hw)]
self.grid[3][3] = white
self.grid[3][4] = black
self.grid[4][3] = black
self.grid[4][4] = white
# プレーヤー情報 0: 黒 1: 白 -1: 終局
self.player = black
# 石数 n_stones[0]: 黒 n_stones[1]: 白
self.n_stones = [2, 2]
# 合法手生成 合法手が1つ以上あればTrueを、なければFalseを返す
def check_legal(self):
# 盤面の合法手表示をなくす
for ny in range(hw):
for nx in range(hw):
if self.grid[ny][nx] == legal:
self.grid[ny][nx] = vacant
# 返す値
have_legal = False
# 各マスについて合法かどうかチェック
for y in range(hw):
for x in range(hw):
# すでに石が置いてあれば必ず非合法
if self.grid[y][x] != vacant:
continue
# 8方向それぞれ合法か見ていく
legal_flag = False
for dr in range(8):
dr_legal_flag1 = False
dr_legal_flag2 = False
ny = y
nx = x
for _ in range(hw - 1):
ny += dy[dr]
nx += dx[dr]
if not inside(ny, nx):
dr_legal_flag1 = False
break
elif self.grid[ny][nx] == vacant or self.grid[ny][nx] == legal:
dr_legal_flag1 = False
break
elif self.grid[ny][nx] != self.player:
dr_legal_flag1 = True
elif self.grid[ny][nx] == self.player:
dr_legal_flag2 = True
break
if dr_legal_flag1 and dr_legal_flag2:
legal_flag = True
break
# 合法だったらgridの値を更新
if legal_flag:
self.grid[y][x] = legal
have_legal = True
# 合法手が1つ以上あるかを返す
return have_legal
# 着手 着手成功ならTrueが、失敗したらFalseが返る
def move(self, y, x):
# 置けるかの判定
if not inside(y, x):
print('盤面外です')
return False
if self.grid[y][x] != legal:
print('非合法手です')
return False
# ひっくり返した枚数(着手したぶんはカウントしない)
n_flipped = 0
# 8方向それぞれ合法か見ていき、合法ならひっくり返す
for dr in range(8):
dr_legal_flag = False
dr_n_flipped = 0
ny = y
nx = x
for d in range(hw - 1):
ny += dy[dr]
nx += dx[dr]
if not inside(ny, nx):
dr_legal_flag = False
break
elif self.grid[ny][nx] == vacant or self.grid[ny][nx] == legal:
dr_legal_flag = False
break
elif self.grid[ny][nx] != self.player:
dr_legal_flag = True
elif self.grid[ny][nx] == self.player:
dr_n_flipped = d
break
if dr_legal_flag:
n_flipped += dr_n_flipped
for d in range(dr_n_flipped):
ny = y + dy[dr] * (d + 1)
nx = x + dx[dr] * (d + 1)
self.grid[ny][nx] = self.player
# 着手部分の更新
self.grid[y][x] = self.player
# 石数の更新
self.n_stones[self.player] += n_flipped + 1
self.n_stones[1 - self.player] -= n_flipped
# 手番の更新
self.player = 1 - self.player
# ひっくり返したのでTrueを返す
return True
# 返る石 着手成功ならTrueが、失敗したらFalseが返る
def flippable(self, y, x):
# 置けるかの判定
if not inside(y, x):
print('盤面外です')
return []
if self.grid[y][x] != legal:
print('非合法手です')
return []
res = []
# ひっくり返した枚数(着手したぶんはカウントしない)
n_flipped = 0
# 8方向それぞれ合法か見ていき、合法ならひっくり返す
for dr in range(8):
dr_legal_flag = False
dr_n_flipped = 0
ny = y
nx = x
for d in range(hw - 1):
ny += dy[dr]
nx += dx[dr]
if not inside(ny, nx):
dr_legal_flag = False
break
elif self.grid[ny][nx] == vacant or self.grid[ny][nx] == legal:
dr_legal_flag = False
break
elif self.grid[ny][nx] != self.player:
dr_legal_flag = True
elif self.grid[ny][nx] == self.player:
dr_n_flipped = d
break
if dr_legal_flag:
n_flipped += dr_n_flipped
for d in range(dr_n_flipped):
ny = y + dy[dr] * (d + 1)
nx = x + dx[dr] * (d + 1)
res.append([ny, nx])
return res
# 標準入力からの入力で着手を行う
def move_stdin(self):
coord = input(('黒' if self.player == black else '白') + ' 着手: ')
try:
y = int(coord[1]) - 1
x = ord(coord[0]) - ord('A')
if not inside(y, x):
x = ord(coord[0]) - ord('a')
if not inside(y, x):
print('座標を A1 や c5 のように入力してください')
self.move_stdin()
return
if not self.move(y, x):
self.move_stdin()
except:
print('座標を A1 や c5 のように入力してください')
self.move_stdin()
# 盤面などの情報を表示
def print_info(self):
#盤面表示 X: 黒 O: 白 *: 合法手 .: 非合法手
print(' A B C D E F G H')
for y in range(hw):
print(y + 1, end=' ')
for x in range(hw):
if self.grid[y][x] == black:
print('X', end=' ')
elif self.grid[y][x] == white:
print('O', end=' ')
elif self.grid[y][x] == legal:
print('*', end=' ')
else:
print('.', end=' ')
print('')
# 石数表示
print('黒 X ', self.n_stones[0], '-', self.n_stones[1], ' O 白')