Last active
June 27, 2021 15:03
-
-
Save shiracamus/7b711007df14a4fce5851a10b90bb51b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Board: | |
def __init__(self, size, space=None): | |
self.cells = [[space] * size for i in range(size)] | |
self.space = space | |
def __iter__(self): | |
return (tuple(row) for row in self.cells) | |
def __getitem__(self, pos): | |
x, y = pos | |
return self.cells[y][x] | |
def __setitem__(self, pos, stone): | |
x, y = pos | |
self.cells[y][x] = stone | |
def __contains__(self, pos): | |
x, y = pos | |
return 0 <= y < len(self.cells) and 0 <= x < len(self.cells[y]) | |
def is_space(self, x, y): | |
return self[x, y] == self.space | |
class Action: | |
def __init__(self, board, stone, points): | |
self.board = board | |
self.stone = stone | |
self.points = points | |
def put(self): | |
for x, y in self.points: | |
self.board[x, y] = self.stone | |
class Stone: | |
SPACE = "." | |
BLACK = "X" | |
WHITE = "O" | |
class Othello: | |
DIRS = (-1, -1), (0, -1), (1, -1), (-1, 0), (1, 0), (-1, 1), (0, 1), (1, 1) | |
def __init__(self, stone=Stone): | |
self.black = stone.BLACK | |
self.white = stone.WHITE | |
self.board = Board(size=8, space=stone.SPACE) | |
self.board[3, 3], self.board[3, 4] = self.white, self.black | |
self.board[4, 3], self.board[4, 4] = self.black, self.white | |
def reversibles(self, x, y, stone): | |
"""石を置いたときに反転できる座標、座標が一つでもあれば石を置ける""" | |
if not self.board.is_space(x, y): | |
return () # 空地でなければ座標なし | |
def one_direction(dx, dy): | |
points = [] # 8方向のうちの1方向での反転可能座標 | |
cx, cy = x + dx, y + dy | |
while (cx, cy) in self.board and not self.board.is_space(cx, cy): | |
if self.board[cx, cy] == stone: | |
# 自分のコマに辿り着いた、反転できるコマの座標を返す | |
return points | |
# 相手のコマ、自分のコマに辿り着いたときに反転できる | |
points.append((cx, cy)) | |
cx, cy = cx + dx, cy + dy | |
return [] # 盤の端に到達したか空地に到達したら反転できない | |
return tuple(sum((one_direction(dx, dy) for dx, dy in self.DIRS), [])) | |
def is_playable(self): | |
"""石を置ける場所があるならTrue""" | |
return any(self.reversibles(x, y, stone) | |
for y, row in enumerate(self.board) | |
for x, _ in enumerate(row) | |
for stone in (self.white, self.black)) | |
def actions(self, stone): | |
"""石を置ける座標と、置いたときの操作の辞書データ""" | |
return {(x, y): Action(self.board, stone, ((x, y),) + reversibles) | |
for y, row in enumerate(self.board) | |
for x, _ in enumerate(row) | |
for reversibles in [self.reversibles(x, y, stone)] | |
if reversibles} | |
def count(self, stone): | |
return sum(cell == stone for row in self.board for cell in row) | |
def judge(self): | |
black_stones = self.count(self.black) | |
white_stones = self.count(self.white) | |
return (self.black if black_stones > white_stones else | |
self.white if black_stones < white_stones else | |
None) | |
class Player: | |
def __init__(self, stone, name): | |
self.stone = stone | |
self.name = name | |
def __str__(self): | |
return f"{self.name}({self.stone})" | |
def play(self, othello): | |
actions = othello.actions(self.stone) | |
if not actions: | |
print(f"{self}はコマを置けません。パスします。") | |
return | |
print() | |
print(f"{self}の番です。") | |
print("置ける場所(x y):", " , ".join(f"{x} {y}" for x, y in actions)) | |
while True: | |
try: | |
choice = input(f"コマ({self.stone})を置く位置 x y を指定してください >> ") | |
choice == "quit" and quit() # "quit"と入力されたらゲーム終了 | |
x, y = map(int, choice.split()) | |
if (x, y) in actions: | |
actions[x, y].put() # 選択場所と反転場所にコマを置く | |
return | |
print("その位置にはコマを置けません。") | |
except ValueError: | |
print("x座標とy座標の数値を空白を空けて入力してください。") | |
class OthelloGame: | |
def __init__(self, othello, player1, player2): | |
self.othello = othello | |
self.player1 = player1 | |
self.player2 = player2 | |
def play(self): | |
print("ゲームスタート") | |
self.show() | |
player, opponent = self.player1, self.player2 | |
while self.othello.is_playable(): | |
player.play(self.othello) | |
player, opponent = opponent, player | |
self.show() | |
print("ゲーム終了") | |
self.result() | |
def show(self): | |
othello, player1, player2 = self.othello, self.player1, self.player2 | |
print() | |
print(" 0 1 2 3 4 5 6 7") | |
for y, row in enumerate(othello.board): | |
print(f"{y}", *row) | |
print(f"{player1}のコマ数:", othello.count(player1.stone)) | |
print(f"{player2}のコマ数:", othello.count(player2.stone)) | |
print() | |
def result(self): | |
result = {self.player1.stone: f"{self.player1}の勝ち", | |
self.player2.stone: f"{self.player2}の勝ち", | |
None: "引き分け", | |
}[self.othello.judge()] | |
print("結果:", result) | |
def main(): | |
othello = Othello() | |
player1 = Player(othello.black, "プレーヤー1") | |
player2 = Player(othello.white, "プレーヤー2") | |
OthelloGame(othello, player1, player2).play() | |
if __name__ == "__main__": | |
try: | |
main() | |
except KeyboardInterrupt: | |
print() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment