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
コメントを残す