0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

pythonで作る3人でオセロ

Last updated at Posted at 2023-10-15

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

一緒に作りましょう☺

ゲームの説明書

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

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()  # メインループを開始
0
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?