Python製の三目並べについて解説

はじめに

ChatGPTにPythonで三目並べを作成してもらった。

仕様

3✖️3のマスに交互に「X」「O」を置き、縦・横・斜めに同じマークを3つ並べたら勝ち。

ソースコード全文

# プレイヤーを表すクラス
class Player:
    def __init__(self, symbol):
        self.symbol = symbol  # 'X' または 'O'

# 盤面を表示する関数
def display_board(board):
    for row in board:
        print(" | ".join(row))
        print("-" * 10)

# マスにマークを置く関数
def make_move(board, row, col, symbol):
    if board[row][col] == " ":
        board[row][col] = symbol
        return True
    return False

# 勝者を判定する関数
def check_winner(board, symbol):
    win_conditions = [
        # 横
        [(0,0), (0,1), (0,2)],
        [(1,0), (1,1), (1,2)],
        [(2,0), (2,1), (2,2)],
        # 縦
        [(0,0), (1,0), (2,0)],
        [(0,1), (1,1), (2,1)],
        [(0,2), (1,2), (2,2)],
        # 斜め
        [(0,0), (1,1), (2,2)],
        [(0,2), (1,1), (2,0)]
    ]
    for condition in win_conditions:
        if all(board[r][c] == symbol for r, c in condition):
            return True
    return False

# 引き分け(満杯)を判定
def is_full(board):
    return all(cell != " " for row in board for cell in row)

# メイン処理
def main():
    board = [[" " for _ in range(3)] for _ in range(3)]  # 空の盤面
    player_x = Player("X")
    player_o = Player("O")
    current_player = player_x

    while True:
        display_board(board)
        print(f"{current_player.symbol}'s turn")

        try:
            row = int(input("Row (0-2): "))
            col = int(input("Col (0-2): "))
        except ValueError:
            print("数字を入力してください。")
            continue

        if not (0 <= row <= 2 and 0 <= col <= 2):
            print("範囲外です。0〜2の数字を入力してください。")
            continue

        if not make_move(board, row, col, current_player.symbol):
            print("そのマスはすでに埋まっています。")
            continue

        if check_winner(board, current_player.symbol):
            display_board(board)
            print(f"{current_player.symbol} wins!")
            break

        if is_full(board):
            display_board(board)
            print("It's a draw!")
            break

        current_player = player_o if current_player == player_x else player_x

if __name__ == "__main__":
    main()

【実行結果】どちらかのプレイヤーが勝つ場合

初回実行。Xのターン

hiroki@shibatahiroshitakanoiMac python % python tic-tac-toe.py
  |   |  
----------
  |   |  
----------
  |   |  
----------
X's turn
Row (0-2): 

0を入力

Row (0-2): 0
Col (0-2):

0を入力。(0, 0)の位置に「X」が入力される。Oのターン

Col (0-2): 0
X |   |  
----------
  |   |  
----------
  |   |  
----------
O's turn
Row (0-2): 

Rowに1、Colに1を入力。Xのターン

Row (0-2): 1   
Col (0-2): 1
X |   |  
----------
  | O |  
----------
  |   |  
----------
X's turn
Row (0-2): 

Rowに1、Colに0を入力。Oのターン

Row (0-2): 1
Col (0-2): 0
X |   |  
----------
X | O |  
----------
  |   |  
----------
O's turn
Row (0-2): 

Rowに2、Colに0を入力。Xのターン

Row (0-2): 2
Col (0-2): 0
X |   |  
----------
X | O |  
----------
O |   |  
----------
X's turn
Row (0-2): 

Rowに0、Colに2を入力。Oのターン

Row (0-2): 0
Col (0-2): 2
X |   | X
----------
X | O |  
----------
O |   |  
----------
O's turn
Row (0-2): 

Rowに0、Colに1を入力。Xのターン

Row (0-2): 0
Col (0-2): 1
X | O | X
----------
X | O |  
----------
O |   |  
----------
X's turn

ここで、Oを勝たせよう。Rowに1、Colに2を入力。Oのターン

Row (0-2): 1
Col (0-2): 2
X | O | X
----------
X | O | X
----------
O |   |  
----------
O's turn
Row (0-2): 

Rowに2、Colに1を入力。Oの勝利

Row (0-2): 2
Col (0-2): 1
X | O | X
----------
X | O | X
----------
O | O |  
----------
O wins!

【実行結果】引き分け

初回実行。Xのターン

hiroki@shibatahiroshitakanoiMac python % python tic-tac-toe.py
  |   |  
----------
  |   |  
----------
  |   |  
----------
X's turn
Row (0-2): 

Rowに0、Colに0を入力。Oのターン

Row (0-2): 0
Col (0-2): 0
X |   |  
----------
  |   |  
----------
  |   |  
----------
O's turn
Row (0-2): 
Row (0-2): 1
Col (0-2): 1
X |   |  
----------
  | O |  
----------
  |   |  
----------
X's turn
Row (0-2): 
Row (0-2): 2
Col (0-2): 2
X |   |  
----------
  | O |  
----------
  |   | X
----------
O's turn
Row (0-2): 
Row (0-2): 0
Col (0-2): 1
X | O |  
----------
  | O |  
----------
  |   | X
----------
X's turn
Row (0-2): 
Row (0-2): 2
Col (0-2): 1
X | O |  
----------
  | O |  
----------
  | X | X
----------
O's turn
Row (0-2): 
Row (0-2): 2
Col (0-2): 0
X | O |  
----------
  | O |  
----------
O | X | X
----------
X's turn
Row (0-2): 
Row (0-2): 0
Col (0-2): 2
X | O | X
----------
  | O |  
----------
O | X | X
----------
O's turn
Row (0-2): 
Row (0-2): 1
Col (0-2): 2
X | O | X
----------
  | O | O
----------
O | X | X
----------
X's turn
Row (0-2): 

引き分け

Row (0-2): 1
Col (0-2): 0
X | O | X
----------
X | O | O
----------
O | X | X
----------
It's a draw!
hiroki@shibatahiroshitakanoiMac python % 

【処理の流れ】プログラム開始→盤面とプレイヤーの定義と表示

if __name__ == "__main__":
    main()
# メイン処理
def main():
    board = [[" " for _ in range(3)] for _ in range(3)]  # 空の盤面
    player_x = Player("X")
    player_o = Player("O")
    current_player = player_x

    while True:
        display_board(board)
        print(f"{current_player.symbol}'s turn")
hiroki@shibatahiroshitakanoiMac python %  /usr/bin/env /usr/local/bin/python3.12 /Users/hiroki/.vscode/extensions/ms-python.debugpy-2025.10.0-darwin-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher 57296 -- /Users/hiroki/Downloads/python/tic-tac-toe.py 
  |   |  
----------
  |   |  
----------
  |   |  
----------
X's turn

空の盤面

board
[[' ', ' ', ' '], [' ', ' ', ' '], [' ', ' ', ' ']]

Playerクラス

# プレイヤーを表すクラス
class Player:
    def __init__(self, symbol):
        self.symbol = symbol  # 'X' または 'O'

盤面を表示する関数

# 盤面を表示する関数
def display_board(board):
    for row in board:
        print(" | ".join(row))
        print("-" * 10)

【処理の流れ】ユーザから行と列の数字を受け付ける

    while True:
        display_board(board)
        print(f"{current_player.symbol}'s turn")

        try:
            row = int(input("Row (0-2): "))
            col = int(input("Col (0-2): "))
        except ValueError:
            print("数字を入力してください。")
            continue

        if not (0 <= row <= 2 and 0 <= col <= 2):
            print("範囲外です。0〜2の数字を入力してください。")
            continue

正常パターン

hiroki@shibatahiroshitakanoiMac python %  /usr/bin/env /usr/local/bin/python3.12 /Users/hiroki/.vscode/extensions/ms-python.debugpy-2025.10.0-darwin-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher 57296 -- /Users/hiroki/Downloads/python/tic-tac-toe.py 
  |   |  
----------
  |   |  
----------
  |   |  
----------
X's turn
Row (0-2): 0
Col (0-2): 0

数字以外

X |   |  
----------
  |   |  
----------
  |   |  
----------
O's turn
Row (0-2): あ
数字を入力してください。
X |   |  
----------
  |   |  
----------
  |   |  
----------
O's turn
Row (0-2): 

範囲外

Row (0-2): 3
Col (0-2): 1
範囲外です。0〜2の数字を入力してください。
X |   |  
----------
  |   |  
----------
  |   |  
----------
O's turn
Row (0-2): 

【処理の流れ】マスにマークを押す

        if not make_move(board, row, col, current_player.symbol):
            print("そのマスはすでに埋まっています。")
            continue

マスを埋める関数

# マスにマークを置く関数
def make_move(board, row, col, symbol):
    if board[row][col] == " ":
        board[row][col] = symbol
        return True
    return False

マスが埋まっていない場合

X |   |  
----------
  |   |  
----------
  |   |  
----------
O's turn
Row (0-2): 1
Col (0-2): 1
board
[['X', ' ', ' '], [' ', 'O', ' '], [' ', ' ', ' ']]

⇨ make_move関数の戻り値は、True

マスが埋まっている場合

X |   |  
----------
  | O |  
----------
  |   |  
----------
X's turn
Row (0-2): 0
Col (0-2): 0
そのマスはすでに埋まっています。
X |   |  
----------
  | O |  
----------
  |   |  
----------
X's turn

⇨ make_move関数の戻り値は、False

【処理の流れ】勝者を判定する

        if check_winner(board, current_player.symbol):
            display_board(board)
            print(f"{current_player.symbol} wins!")
            break

勝者を判定する関数

# 勝者を判定する関数
def check_winner(board, symbol):
    win_conditions = [
        # 横
        [(0,0), (0,1), (0,2)],
        [(1,0), (1,1), (1,2)],
        [(2,0), (2,1), (2,2)],
        # 縦
        [(0,0), (1,0), (2,0)],
        [(0,1), (1,1), (2,1)],
        [(0,2), (1,2), (2,2)],
        # 斜め
        [(0,0), (1,1), (2,2)],
        [(0,2), (1,1), (2,0)]
    ]
    for condition in win_conditions:
        if all(board[r][c] == symbol for r, c in condition):
            return True
    return False

勝者がいない場合

X |   |  
----------
  | O |  
----------
  |   |  
----------
X's turn
Row (0-2): 0
Col (0-2): 1
board
[['X', 'X', ' '], [' ', 'O', ' '], [' ', ' ', ' ']]

⇨ check_winner関数の戻り値は、False

勝者がいる場合

X | X |  
----------
  | O |  
----------
  | O |  
----------
X's turn
Row (0-2): 0
Col (0-2): 2
board
[['X', 'X', 'X'], [' ', 'O', ' '], [' ', 'O', ' ']]
X | X | X
----------
  | O |  
----------
  | O |  
----------
X wins!
hiroki@shibatahiroshitakanoiMac python % 

⇨ check_winner関数の戻り値は、True

【処理の流れ】引き分けを判定する

        if is_full(board):
            display_board(board)
            print("It's a draw!")
            break

        current_player = player_o if current_player == player_x else player_x

引き分けを判定する関数

# 引き分け(満杯)を判定
def is_full(board):
    return all(cell != " " for row in board for cell in row)

引き分けではない時

X |   | X
----------
X | O | O
----------
O |   | X
----------
O's turn
Row (0-2): 0
Col (0-2): 1
board
[['X', 'O', 'X'], ['X', 'O', 'O'], ['O', ' ', 'X']]
X | O | X
----------
X | O | O
----------
O |   | X
----------
X's turn
Row (0-2): 

⇨ is_full関数の戻り値は、False

プレイヤーの切り替えが行われる。

        current_player = player_o if current_player == player_x else player_x

引き分けの時

X | O | X
----------
X | O | O
----------
O |   | X
----------
X's turn
Row (0-2): 2
Col (0-2): 1
board
[['X', 'O', 'X'], ['X', 'O', 'O'], ['O', 'X', 'X']]
X | O | X
----------
X | O | O
----------
O | X | X
----------
It's a draw!

⇨ is_full関数の戻り値は、True

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です