pythonで作る3人でオセロ

早速コードを添付します。
すぐに改良するかもしれません。

一緒に作りましょう☺

# ゲームの説明書
3人で対戦するオセロです。
赤青黄に分かれて対戦します。
順番は赤青黄の順で対戦します。
また一番下のリセットボタンを押すことでゲームをはじめからやり直すことができます。

``` python
import tkinter as tks
from tkinter import messagebox


# 定数の設定
BOARD_SIZE = 8  # オセロボードのサイズ（8x8）
COLORS = {'R': 'red', 'B': 'blue', 'Y': 'yellow', '': 'white'}  # オセロの色のマッピング
DIRECTIONS = [(1, 0), (-1, 0), (0, 1), (0, -1), (1, 1), (1, -1), (-1, 1), (-1, -1)]  # 8方向を表すベクトル

# オセロのゲームロジック部分
class OthelloBoard:
    def __init__(self):
        # 初期化処理
        self.board = [['' for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)]  # 空のボードを作成
        self.initialize_board()  # ボードを初期状態に設定
        self.current_turn = 'R'  # 最初のターンは赤
        self.game_over = False   # ゲーム開始時点では終了していない

    def initialize_board(self):
        # ボードの初期配置
        # 中央にそれぞれの色のオセロを配置する
        self.board[3][3] = 'R'
        self.board[4][4] = 'R'
        self.board[3][4] = 'B'
        self.board[4][5] = 'B'
        self.board[3][2] = 'Y'
        self.board[4][3] = 'Y'
        self.board[5][4] = 'Y'

    def place_stone(self, x, y):
        # オセロを配置する処理
        if self.board[x][y] or not self.valid_move(x, y, self.current_turn):
            return False

        # 8方向ごとにオセロを裏返す処理
        for dx, dy in DIRECTIONS:
            self.flip_stones(x, y, dx, dy, self.current_turn)

        self.board[x][y] = self.current_turn  # オセロを配置

        # 次のターンに移行
        self.next_turn()

        # ゲーム終了をチェック
        self.check_game_over()

        return True

    def valid_move(self, x, y, color):
        if self.board[x][y]:
            return False

        for dx, dy in DIRECTIONS:
            if self.can_flip(x, y, dx, dy, color):
                return True

        return False

    def can_flip(self, x, y, dx, dy, color):
        x += dx
        y += dy

        if x < 0 or x >= BOARD_SIZE or y < 0 or y >= BOARD_SIZE or self.board[x][y] == color or not self.board[x][y]:
            return False

        while 0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE:
            if not self.board[x][y]:
                return False
            if self.board[x][y] == color:
                return True

            x += dx
            y += dy

        return False

    def flip_stones(self, x, y, dx, dy, color):
        if not self.can_flip(x, y, dx, dy, color):
            return

        x += dx
        y += dy

        while 0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE and self.board[x][y] and self.board[x][y] != color:
            self.board[x][y] = color
            x += dx
            y += dy

    def next_turn(self):
        # ターンを次のプレイヤーに変更
        turns = ['R', 'B', 'Y']
        count_check = 0
        while True:
            self.current_turn = turns[(turns.index(self.current_turn) + 1) % 3]
            for x in range(BOARD_SIZE):
                for y in range(BOARD_SIZE):
                    if self.valid_move(x, y, self.current_turn):
                        return
            count_check += 1
            if count_check == 3:
                self.game_over = True
                return

    def check_game_over(self):
        for color in ['R', 'B', 'Y']:
            for x in range(BOARD_SIZE):
                for y in range(BOARD_SIZE):
                    if self.valid_move(x, y, color):
                        return
        self.game_over = True

    def count_stones(self):
        return {'R': sum(row.count('R') for row in self.board),
                'B': sum(row.count('B') for row in self.board),
                'Y': sum(row.count('Y') for row in self.board)}

# オセロのGUI部分
class OthelloGUI:
    def __init__(self, master):
        # 初期化処理
        self.master = master
        self.board = OthelloBoard()

        # キャンバスの作成と配置
        self.canvas = tks.Canvas(master, bg="white")
        self.canvas.pack(fill=tks.BOTH, expand=True)
        self.canvas.bind("<Button-1>", self.on_canvas_click)

        # キャンバスがリサイズされたときの処理をバインド
        self.canvas.bind("<Configure>", self.draw_board)

        # ターン表示用のラベルの作成と配置
        self.turn_label = tks.Label(master, text="", font=("Arial", 16))
        self.turn_label.pack(pady=10)
        
        # ゲームリセット用のボタンの作成と配置
        self.reset_button = tks.Button(master, text="リセット", command=self.reset_game)
        self.reset_button.pack(fill=tks.X)

        self.update_turn_label()  # ゲーム開始時のターンを表示

    def on_canvas_click(self, event):
        width, height = self.canvas.winfo_width(), self.canvas.winfo_height()
        cell_size = min(width, height) / BOARD_SIZE
        board_size = cell_size * BOARD_SIZE
        start_x = (width - board_size) / 2
        start_y = (height - board_size) / 2
    
        x, y = int((event.x - start_x) // cell_size), int((event.y - start_y) // cell_size)
        if 0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE:  # クリック位置がボード上であることを確認
            self.place_stone(x, y)

    def draw_board(self, event=None):
        self.canvas.delete("all")
        
        # ウィンドウのサイズを取得
        width, height = self.canvas.winfo_width(), self.canvas.winfo_height()

        # 碁盤の大きさを計算
        cell_size = min(width, height) / BOARD_SIZE
        board_size = cell_size * BOARD_SIZE

        # 碁盤の開始位置を計算
        start_x = (width - board_size) / 2
        start_y = (height - board_size) / 2

        # 碁盤の背景を緑色にする
        self.canvas.create_rectangle(start_x, start_y, start_x + board_size, start_y + board_size, fill='green', outline='black', width=3)

        for x in range(BOARD_SIZE):
            for y in range(BOARD_SIZE):
                top_left_x = start_x + x * cell_size
                top_left_y = start_y + y * cell_size
                bottom_right_x = start_x + (x + 1) * cell_size
                bottom_right_y = start_y + (y + 1) * cell_size

                color = self.board.board[x][y]
                if color == 'R':
                    self.canvas.create_oval(top_left_x, top_left_y, bottom_right_x, bottom_right_y, fill="red")
                elif color == 'B':
                    self.canvas.create_oval(top_left_x, top_left_y, bottom_right_x, bottom_right_y, fill="blue")
                elif color == 'Y':
                    self.canvas.create_oval(top_left_x, top_left_y, bottom_right_x, bottom_right_y, fill="yellow")

                # 各セルの外枠
                self.canvas.create_rectangle(top_left_x, top_left_y, bottom_right_x, bottom_right_y, outline='black')
            
    def place_stone(self, x, y):
        if not self.board.game_over and self.board.place_stone(x, y):
            self.update_turn_label()  # ターンの変更時にラベルを更新
            self.update_buttons()

            if self.board.game_over:
                counts = self.board.count_stones()
                winner = max(counts, key=counts.get)
                messagebox.showinfo("ゲーム終了", f"赤: {counts['R']}, 青: {counts['B']}, 黄: {counts['Y']}。勝者: {COLORS[winner]}")

    def reset_game(self):
        self.board = OthelloBoard()
        self.update_turn_label()  # ゲームリセット時にラベルを更新
        self.update_buttons()

    def update_turn_label(self):
        self.turn_label.config(text=f"現在のターン: {COLORS[self.board.current_turn]}")

    def update_buttons(self):
        self.draw_board()

if __name__ == '__main__':
    root = tks.Tk()  # メインウィンドウの作成
    gui = OthelloGUI(root)  # GUIのインスタンスを作成
    root.mainloop()  # メインループを開始
```