-
Notifications
You must be signed in to change notification settings - Fork 47
/
rin042.py
247 lines (202 loc) · 7.87 KB
/
rin042.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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
WHITE = 0
BLACK = 1
BOARD_SIZE = 8
# ボードクラスの実装
class ReversiBoard(object):
def __init__(self):
# 2次元リストを生成する
# 各要素の初期値はNone
self.cells = []
for i in range(BOARD_SIZE):
self.cells.append([None for j in range(BOARD_SIZE)])
# 4つの石を初期配置する
self.cells[3][3] = WHITE
self.cells[3][4] = BLACK
self.cells[4][3] = BLACK
self.cells[4][4] = WHITE
# 石を置くメソッド
def put_disk(self, x, y, player):
"""指定した座標に指定したプレイヤーの石を置く
Args:
x: 置く石のX座標
y: 置く石のY座標
player: 石を置こうとしているプレイヤー(WHITEまたはBLACK)
Returns:
True: 関数の成功を意味する. 指定した座標と
それによって獲得できる石がすべてplayerの色になった場合に返す
False: 関数が以下のいずれかのケースによって失敗した場合に返す
・指定した座標に既に別の石がある
・指定した座標に石を置いても相手側の石を獲得できない
"""
# 既にほかの石があれば置くことができない
if self.cells[y][x] is not None:
return False
# 獲得できる石がない場合も置くことができない
flippable = self.list_flippable_disks(x, y, player)
if flippable == []:
return False
# 実際に石を置く処理
self.cells[y][x] = player
for x, y in flippable:
self.cells[y][x] = player
return True
# ひっくりかえせる石の数を列挙するメソッド
def list_flippable_disks(self, x, y, player):
"""指定した座標に指定したプレイヤーの石を置いた時、ひっくりかえせる全ての石の座標(タプル)をリストにして返す
Args:
x: x座標
y: y座標
player: 石を置こうとしているプレイヤー
Returns:
ひっくりかえすことができる全ての石の座標(タプル)のリスト
または空リスト
"""
PREV = -1
NEXT = 1
DIRECTION = [PREV, 0, NEXT]
flippable = []
for dx in DIRECTION:
for dy in DIRECTION:
if dx == 0 and dy == 0:
continue
tmp = []
depth = 0
while True:
depth += 1
# 方向 × 深さ(距離)を要求座標に加算し直線的な探査をする
rx = x + (dx * depth)
ry = y + (dy * depth)
# 調べる座標(rx, ry)がボードの範囲内ならば
if 0 <= rx < BOARD_SIZE and 0 <= ry < BOARD_SIZE:
request = self.cells[ry][rx]
# Noneを獲得することはできない
if request is None:
break
if request == player: # 自分の石が見つかったとき
if tmp != []: # 探査した範囲内に獲得可能な石があれば
flippable.extend(tmp) # flippableに追加
# 相手の石が見つかったとき
else:
# 獲得可能な石として一時保存
tmp.append((rx, ry))
else:
break
return flippable
# ボードを表示するメソッド
def show_board(self):
"""ボードを表示する"""
print("--" * 20)
for i in self.cells:
for cell in i:
if cell == WHITE:
print("W", end=" ")
elif cell == BLACK:
print("B", end=" ")
else:
print("*", end=" ")
print("\n", end="")
# 指定したプレイヤーの石を置くことができる、すべてのマスの座標をリストにして返すメソッド
def list_possible_cells(self, player):
"""指定したプレイヤーの石を置くことができる、すべてのマスの座標をリストにして返す
Args:
player: 石を置こうとしているプレイヤー
Returns:
石を置くことができるマスの座標のリスト
または空リスト
"""
possible = []
for x in range(BOARD_SIZE):
for y in range(BOARD_SIZE):
if self.cells[y][x] is not None:
continue
if self.list_flippable_disks(x, y, player) == []:
continue
else:
possible.append((x, y))
return possible
if __name__ == "__main__":
board = ReversiBoard()
board.show_board()
board.put_disk(3, 2, BLACK)
board.show_board()
# ゲームクラス
class MenMenAI(OthelloAI):
DRAW = -1
def __init__(self, turn=0, start_player=BLACK):
super().__init__()
self.player = start_player
self.turn = turn
self.winner = None
self.was_passed = False
# def __init__(self):
# self.face = '🐇' # 自分の好きな絵文字
# self.name = 'みな' # 自分の好きな名前
def is_finished(self):
return self.winner is not None
def list_possible_cells(self):
return super().list_possible_cells(self.player)
def get_color(self, player):
if player == WHITE:
return "WHITE"
if player == BLACK:
return "BLACK"
else:
return "DRAW"
def get_current_player(self):
return self.player
def get_next_player(self):
return WHITE if self.player == BLACK else BLACK
def shift_player(self):
self.player = self.get_next_player()
def put_disk(self, x, y):
if super().put_disk(x, y, self.player):
self.was_passed = False
self.player = self.get_next_player()
self.turn += 1
else:
return False
def pass_moving(self):
if self.was_passed:
return self.finish_game()
self.was_passed = True
self.shift_player()
def show_score(self):
"""それぞれのプレイヤーの石の数を表示する"""
print("{}: {}".format("BLACK", self.disks[BLACK]))
print("{}: {}".format("WHITE", self.disks[WHITE]))
def finish_game(self):
self.disks = self.get_disk_map()
white = self.disks[WHITE]
black =self.disks[BLACK]
if white < black:
self.winner = BLACK
elif black < white:
self.winner = WHITE
else:
self.winner = self.on_draw()
return self.winner
def on_draw(self):
"""ゲーム終了時に両社の石の数が同数だった時の処理
デフォルトでは引き分けを認める
"""
return self.DRAW
# ゲームをする
if __name__ == "__main__":
game = MenMenAI(OthelloAI)
while(True):
possible = game.list_possible_cells()
player_name = game.get_color(game.get_current_player())
if game.is_finished():
game.show_board()
game.show_score()
print("Winner: {}".format(game.get_color(game.winner)))
break
if possible == []:
print("player {} can not puts.".format(player_name))
game.pass_moving()
continue
game.show_board()
print("player: " + player_name)
print("put to: " + str(possible))
index = int(input("choose: "))
game.put_disk(*possible[index])