Skip to content

Instantly share code, notes, and snippets.

@shiracamus
Created December 17, 2020 03:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shiracamus/492201c280cf937beb114224c871a5b5 to your computer and use it in GitHub Desktop.
Save shiracamus/492201c280cf937beb114224c871a5b5 to your computer and use it in GitHub Desktop.
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 __iter__(self):
return iter(self.board)
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)
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)
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 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):
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")
__import__('objectuml').plantuml(locals())
return
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