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): 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

コメントを残す

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