Tic Tac Toe(井字遊戲)是經典的雙人棋盤遊戲,在一個3x3的方格中進行。
每回合兩個玩家輪流選一個位置,先讓自己的符號( X 或 O)在
水平線、垂直線或對角線上連成一線的玩家宣告獲勝。
透過list comprehension建立長度為9的陣列,並且標上1~9的數字,提示玩家每個位置所代表的數字。
| 1 | 2 | 3 |
| 4 | 5 | 6 |
| 7 | 8 | 9 |
1 對應到左上方的格子。2 對應到正上方的格子。3 對應到右上方的格子。
4 對應到正左方的格子。5 對應到正中央的格子。6 對應到正右方的格子。
7 對應到左下方的格子。8 對應到正下方的格子。9 對應到右下方的格子。
# 初始化棋盤
board = [str(i+1) for i in range(9)]
透過雙層迴圈,輸出3x3的遊戲版,並且以|當作間隔符號。
如圖所示
| 1 | 2 | 3 |
| 4 | X | 6 |
| 7 | 8 | 9 |
# 輸出棋盤
def print_board():
for row in [board[i*3:(i+1)*3] for i in range(3)]:
print('| ' + ' | '.join(row) + ' |')
從鍵盤接收1~9的數字,依照數字在遊戲版上對應的位置放置O的符號。
# 玩家回合
player_move = int(input("選擇一個位置 (1-9): ")) - 1
if board[player_move].isnumeric():
board[player_move] = 'O'
AI根據board遊戲版當前的棋盤狀態,
透過mixMax演算法遞迴展開所有可能的分枝情況。
最小化人類玩家勝率,最大化AI玩家勝率。
選擇對AI玩家最有利的位置,讓X連成一線的機會最大化。
# minMax演算法
# O 代表玩家
# X 代表AI
# AI選擇位置時,會尋找勝率最大的位置
def minimax(board, depth, is_maximizing):
if check_winner(board, 'O'):
return -1
elif check_winner(board, 'X'):
return 1
elif is_draw(board):
return 0
if is_maximizing:
best_score = -math.inf
for i in range(9):
if board[i].isnumeric():
original = board[i]
board[i] = 'X'
score = minimax(board, depth + 1, False)
board[i] = original
best_score = max(score, best_score)
return best_score
else:
best_score = math.inf
for i in range(9):
if board[i].isnumeric():
original = board[i]
board[i] = 'O'
score = minimax(board, depth + 1, True)
board[i] = original
best_score = min(score, best_score)
return best_score
# AI透過mixMax演算法,選擇最好的位置
def best_move():
best_score = -math.inf
move = 0
for i in range(9):
#if board[i] == ' ':
if board[i].isnumeric():
original = board[i]
board[i] = 'X'
score = minimax(board, 0, False)
board[i] = original
if score > best_score:
best_score = score
move = i
return move
檢查遊戲盤上所有水平線、垂直線、大對角線的位置,
看看是否已經有O連成一線或者X連成一線的情況。
如果O連成一線,代表人類玩家宣告獲勝。
如果X連成一線,代表AI玩家宣告獲勝。
# 檢查是否有玩家獲勝
def check_winner(board, player):
win_conditions = [(0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6)]
return any(board[a] == board[b] == board[c] == player for a, b, c in win_conditions)
while 遊戲循環:
...
if check_winner(board, 'O'):
print_board()
print("你贏了!")
break
if check_winner(board, 'X'):
print_board()
print("你輸了!")
break
檢查是有所有位置都已經被填滿O或X的符號?
如果已經沒有剩餘的空位,代表雙方平手。
如果還有空位,則井字遊戲繼續進行。
# 檢查是否平局
def is_draw(board):
space_count = 0
for row in board:
for cell in row:
if cell.isnumeric() == True:
return False
return True
外層以while True迴圈建立遊戲循環機制。
每回合玩家和AI輪流選一個位置放下O或X。
在每回合的末端,判斷是否已經有玩家獲勝或者平手?
如果是,則遊戲結束,break離開遊戲循環機制的while迴圈。
# AI先手
# AI在正中央位置放一個X
ai_move = 4
board[ai_move] = 'X'
print_board()
while True:
# 玩家回合
player_move = int(input("選擇一個位置 (1-9): ")) - 1
if board[player_move].isnumeric():
board[player_move] = 'O'
if check_winner(board, 'O'):
print_board()
print("你贏了!")
break
elif is_draw(board):
print_board()
print("平局!")
break
# AI回合
ai_move = best_move()
board[ai_move] = 'X'
if check_winner(board, 'X'):
print_board()
print("你輸了!")
break
elif is_draw(board):
print_board()
print("平局!")
break
else:
print("位置已被佔用,請選擇其他位置。")
print_board()
import math
# 初始化棋盤
board = [str(i+1) for i in range(9)]
# 輸出棋盤
def print_board():
for row in [board[i*3:(i+1)*3] for i in range(3)]:
print('| ' + ' | '.join(row) + ' |')
# 檢查是否有玩家獲勝
def check_winner(board, player):
win_conditions = [(0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6)]
return any(board[a] == board[b] == board[c] == player for a, b, c in win_conditions)
# 檢查是否平局
def is_draw(board):
space_count = 0
for row in board:
for cell in row:
if cell.isnumeric() == True:
return False
return True
# Minimax演算法
# O 代表玩家
# X 代表AI
# AI選擇位置時,會尋找勝率最大的位置
def minimax(board, depth, is_maximizing):
if check_winner(board, 'O'):
return -1
elif check_winner(board, 'X'):
return 1
elif is_draw(board):
return 0
if is_maximizing:
best_score = -math.inf
for i in range(9):
if board[i].isnumeric():
original = board[i]
board[i] = 'X'
score = minimax(board, depth + 1, False)
board[i] = original
best_score = max(score, best_score)
return best_score
else:
best_score = math.inf
for i in range(9):
if board[i].isnumeric():
original = board[i]
board[i] = 'O'
score = minimax(board, depth + 1, True)
board[i] = original
best_score = min(score, best_score)
return best_score
# AI透過mixMax演算法,選擇最好的位置
def best_move():
best_score = -math.inf
move = 0
for i in range(9):
#if board[i] == ' ':
if board[i].isnumeric():
original = board[i]
board[i] = 'X'
score = minimax(board, 0, False)
board[i] = original
if score > best_score:
best_score = score
move = i
return move
# 遊戲主體
def play_game():
# AI先手
# AI在正中央位置放一個X
ai_move = 4
board[ai_move] = 'X'
print_board()
while True:
# 玩家回合
player_move = int(input("選擇一個位置 (1-9): ")) - 1
if board[player_move].isnumeric():
board[player_move] = 'O'
if check_winner(board, 'O'):
print_board()
print("你贏了!")
break
elif is_draw(board):
print_board()
print("平局!")
break
# AI回合
ai_move = best_move()
board[ai_move] = 'X'
if check_winner(board, 'X'):
print_board()
print("你輸了!")
break
elif is_draw(board):
print_board()
print("平局!")
break
else:
print("位置已被佔用,請選擇其他位置。")
print_board()
if __name__ == '__main__':
play_game()
如果對程式或者演算法有興趣的同學,
可以試著觀察OOXX井字遊戲的規律,
開發更強的連線演算法,嘗試讓兩個AI玩家對戰。
很有趣喔~