2025.07.30(更新日: 2025.07.30)
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
コメントを残す