Python製の三目並べ
はじめに
ChatGPTにPythonで三目並べを作成してもらった。
仕様

ソースコード全文
python/tic-tac-toe.py at master · ki-hi-ro/python
# プレイヤーを表すクラス
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を入力、(1, 1)の位置に0が入力された。Xのターン、行の数字を入力する。
Row (0-2): 1   
Col (0-2): 1
X |   |  
----------
  | O |  
----------
  |   |  
----------
X's turn
Row (0-2): Rowに1、Colに0を入力。(1, 0)の位置に、Xが入力された。Oのターン、行の数字を入力する。
Row (0-2): 1
Col (0-2): 0
X |   |  
----------
X | O |  
----------
  |   |  
----------
O's turn
Row (0-2): Rowに2、Colに0を入力。(2, 0)の位置に、0が入力された。Xのターン、行の数字を入力する。
Row (0-2): 2
Col (0-2): 0
X |   |  
----------
X | O |  
----------
O |   |  
----------
X's turn
Row (0-2): Rowに0、Colに2を入力。(0, 2)の位置に、Xが入力された。Oのターン、行の数字を入力する。
Row (0-2): 0
Col (0-2): 2
X |   | X
----------
X | O |  
----------
O |   |  
----------
O's turn
Row (0-2): Rowに0、Colに1を入力。(0, 1)の位置にOが入力された。Xのターン、
Row (0-2): 0
Col (0-2): 1
X | O | X
----------
X | O |  
----------
O |   |  
----------
X's turnここで、Oを勝たせよう。Rowに1、Colに2を入力。(1, 2)の位置に、Xが入力された。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を入力。(2, 1)の位置に、Oが入力された。2列目が全部Oになったので、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を入力。(0, 0)の位置に、Xが入力された。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 % 処理の流れ

- プログラム開始
- 空の盤面を定義する
- プレイヤーを定義する
While True
- 盤面を表示する
- 現在のプレイヤーを表示する
- ユーザから行の数字を受け付ける→ユーザが入力した数字のバリデーション処理
- ユーザから列の数字を受け付ける→ユーザが入力した数字のバリデーション処理
- マスにマークを押す(押せなかった場合、「そのマスはすでに埋まっています。」と出力して、盤面を表示する)
- 勝者を判定する(勝者がいた場合、盤面と勝者を表示して、終了)
- 引き分けを判定する(引き分けの場合、盤面と「引き分けです」の表示をして、終了)
- プレイヤーの切り替え(切り替え後に、盤面を表示する)
ユーザが入力した数字のバリデーション処理
- 数字かどうかを確認→数字以外の場合、「数字を入力してください」と出力して、盤面を表示する
- 0 ~ 2の範囲内にあるかを確認→範囲外の場合、「範囲外です」と出力して、盤面を表示する
プログラム開始→盤面とプレイヤーの定義と表示

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): 1board
[['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): 1board
[['X', 'X', ' '], [' ', 'O', ' '], [' ', ' ', ' ']]⇨ check_winner関数の戻り値は、False
勝者がいる場合
X | X |  
----------
  | O |  
----------
  | O |  
----------
X's turn
Row (0-2): 0
Col (0-2): 2board
[['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): 1board
[['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): 1board
[['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
コメントを残す