井字棋遊戲看似簡單,卻蘊含著不少程式設計的技巧。本文將深入探討如何使用 Python 實作井字棋遊戲,包含勝利條件的判斷、遊戲迴圈的設計、以及如何利用 MinMax 演算法提升 AI 對戰的策略性。同時,我們也會探討不同遊戲模式的設計,例如玩家對戰、玩家對戰 AI、以及 AI 對戰 AI,讓讀者更全面地理解井字棋遊戲的開發過程。程式碼中,我們會運用二維列表來表示遊戲板,並使用迴圈和條件判斷來實作遊戲邏輯。此外,MinMax 演算法的應用將讓 AI 擁有更智慧的決策能力,提升遊戲的挑戰性。

遊戲勝利條件檢查

在開發井字棋遊戲時,檢查勝利條件是一個關鍵的部分。以下是檢查勝利條件的步驟和程式碼實作。

勝利條件

遊戲中,玩家可以橫向、豎向或對角線獲勝。因此,我們需要檢查以下幾種情況:

  • 橫向勝利:同一行中的三個格子都被同一玩家佔據。
  • 豎向勝利:同一列中的三個格子都被同一玩家佔據。
  • 對角線勝利:從左上到右下或從右上到左下的對角線上的三個格子都被同一玩家佔據。

程式碼實作

def check_for_win(board):
    # 檢查橫向勝利
    for i in range(3):
        if board[i][0] == board[i][1] == board[i][2] != '':
            winner = board[i][0]
            print(f'{winner} won!')
            return True

    # 檢查豎向勝利
    for i in range(3):
        if board[0][i] == board[1][i] == board[2][i] != '':
            winner = board[0][i]
            print(f'{winner} won!')
            return True

    # 檢查對角線勝利
    if board[0][0] == board[1][1] == board[2][2] != '':
        winner = board[0][0]
        print(f'{winner} won!')
        return True
    elif board[0][2] == board[1][1] == board[2][0] != '':
        winner = board[0][2]
        print(f'{winner} won!')
        return True

    return False

內容解密:

上述程式碼定義了一個函式 check_for_win,它接受一個 3x3 的二維列表 board 作為輸入,代表井字棋的遊戲板。函式遍歷了遊戲板上的所有可能的勝利條件,並在找到勝利條件時列印預出勝利者的資訊並傳回 True。如果沒有找到勝利條件,函式傳回 False

圖表翻譯:

  flowchart TD
    A[開始] --> B[檢查橫向勝利]
    B --> C[檢查豎向勝利]
    C --> D[檢查對角線勝利]
    D --> E[勝利條件成立]
    E --> F[列印勝利者資訊]
    F --> G[傳回 True]
    D --> H[勝利條件不成立]
    H --> I[傳回 False]

此圖表展示了檢查勝利條件的流程,從檢查橫向勝利開始,然後是豎向勝利,最後是對角線勝利。如果找到勝利條件,則列印預出勝利者資訊並傳回 True,否則傳回 False

遊戲迴圈實作

在實作井字棋的遊戲迴圈時,我們需要考慮多個因素,包括如何判斷勝利、如何切換玩家、以及如何印出遊戲板。以下是相關的程式碼實作:

def have_empty_room():
    # 檢查是否還有空間可以下棋
    for row in board:
        for cell in row:
            if cell == '':
                return True
    return False

def print_board():
    # 印出當前的遊戲板
    print(f'{board[0][0]} | {board[0][1]} | {board[0][2]}')
    print('---------')
    print(f'{board[1][0]} | {board[1][1]} | {board[1][2]}')
    print('---------')
    print(f'{board[2][0]} | {board[2][1]} | {board[2][2]}')

def check_win():
    # 檢查是否有人贏了
    for i in range(3):
        if board[i][0] == board[i][1] == board[i][2] != '':
            return board[i][0]
        if board[0][i] == board[1][i] == board[2][i] != '':
            return board[0][i]
    if board[0][0] == board[1][1] == board[2][2] != '':
        return board[0][0]
    if board[0][2] == board[1][1] == board[2][0] != '':
        return board[0][2]
    return None

def start():
    global turn
    while have_empty_room():
        print_board()
        print(f"\n{turn}'s turn")
        # 接收使用者輸入
        row = int(input("Enter row (0-2): "))
        col = int(input("Enter column (0-2): "))
        
        # 更新遊戲板
        if board[row][col] == '':
            board[row][col] = turn
            # 切換玩家
            turn = 'x' if turn == 'o' else 'o'
        else:
            print("Invalid move, try again.")
            continue
        
        # 檢查是否有人贏了
        winner = check_win()
        if winner:
            print_board()
            print(f"\n{winner} won!")
            break
    else:
        print("It's a tie!")

# 初始化遊戲板
board = [['' for _ in range(3)] for _ in range(3)]
turn = 'o'

start()

內容解密:

  1. have_empty_room() 函式用於檢查遊戲板是否還有空間可以下棋。
  2. print_board() 函式負責印出當前的遊戲板。
  3. check_win() 函式用於檢查是否有人贏了,透過檢查行、列、對角線是否有三個相同的符號。
  4. start() 函式是遊戲的主迴圈,負責接收使用者輸入、更新遊戲板、切換玩家、檢查是否有人贏了。

圖表翻譯:

  flowchart TD
    A[開始] --> B[印出遊戲板]
    B --> C[接收使用者輸入]
    C --> D[更新遊戲板]
    D --> E[切換玩家]
    E --> F[檢查是否有人贏了]
    F --> G[有人贏了]
    G --> H[印出贏家]
    F --> I[沒有贏家]
    I --> J[繼續遊戲]
    J --> B

這個圖表展示了遊戲的流程,從開始到有人贏了或遊戲結束。

遊戲迴圈實作

在這個遊戲迴圈中,我們需要實作玩家之間的交替和棋盤的更新。以下是相關的程式碼實作:

def game_loop():
    turn = 'o'  # 初始化遊戲狀態為'o'的回合
    while True:
        # 切換回合
        if turn == 'o':
            turn = 'x'
        else:
            turn = 'o'
        
        print(f'{turn}\'s Turn!')  # 顯示當前回合的玩家
        
        # 取得玩家輸入的座標
        while True:
            try:
                xy = int(input('Enter x and y: '))
                if check_xy(xy):  # 驗證座標是否有效
                    if set_room_state(str(xy), turn):  # 更新棋盤狀態
                        break
                    else:
                        print('This room is full!')  # 如果座標已經被佔據
                else:
                    print('Error!')  # 如果座標無效
            except ValueError:
                print('Invalid input! Please enter a number.')
        
        # 檢查是否有玩家贏得遊戲
        if check_for_win():
            break
        
        # 更新並顯示棋盤
        print_board()

# 啟動遊戲迴圈
game_loop()

內容解密:

  1. 遊戲迴圈: while True 保證遊戲不斷進行,直到有一方贏得遊戲。
  2. 回合切換: if turn == 'o': turn = 'x'else: turn = 'o' 的邏輯保證兩個玩家之間的交替。
  3. 玩家輸入: xy = int(input('Enter x and y: ')) 讓玩家輸入他們想要放置棋子的座標。
  4. 座標驗證: if check_xy(xy): 檢查輸入的座標是否在棋盤的有效範圍內。
  5. 更新棋盤: if set_room_state(str(xy), turn): 將玩家的棋子放置在指定的座標上,並更新棋盤的狀態。
  6. 勝利檢查: if check_for_win(): 在每個回合結束後檢查是否有一方贏得了遊戲。
  7. 棋盤更新: print_board() 顯示最新的棋盤狀態給玩家。

這個遊戲迴圈的實作保證了遊戲的順暢進行和正確性,同時也為玩家提供了良好的使用體驗。

Tic Tac Toe 遊戲開發

遊戲模式

Tic Tac Toe 遊戲支援三種模式:

  • 玩家對戰(2 玩家模式)
  • 玩家對戰 AI(1 玩家模式)
  • AI 對戰 AI(娛樂模式)

遊戲邏輯

最佳移動策略

Tic Tac Toe 的最佳移動策略是透過MinMax 演算法來實作。這個演算法可以讓 AI 在每一步都做出最好的選擇。

遊戲示範

遊戲板

遊戲板將在每次玩家移動後更新。板子的佈局如下:

 7 | 8 | 9 
-----------
 4 | 5 | 6 
-----------
 1 | 2 | 3 

板子的位置與鍵盤的右側數字鍵相同。

程式碼實作

import random

def print_board(board):
    print(f" {board[6]} | {board[7]} | {board[8]} ")
    print("-----------")
    print(f" {board[3]} | {board[4]} | {board[5]} ")
    print("-----------")
    print(f" {board[0]} | {board[1]} | {board[2]} ")

def check_win(board):
    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)]
    for condition in win_conditions:
        if board[condition[0]] == board[condition[1]] == board[condition[2]] != " ":
            return board[condition[0]]
    if " " not in board:
        return "Tie"
    return False

def ai_move(board):
    best_score = float("-inf")
    best_move = 0
    for i in range(len(board)):
        if board[i] == " ":
            board[i] = "O"
            score = min_max(board, 0, False)
            board[i] = " "
            if score > best_score:
                best_score = score
                best_move = i
    return best_move

def min_max(board, depth, is_maximizing):
    result = check_win(board)
    if result:
        if result == "X":
            return -10 + depth
        elif result == "O":
            return 10 - depth
        elif result == "Tie":
            return 0
    if is_maximizing:
        best_score = float("-inf")
        for i in range(len(board)):
            if board[i] == " ":
                board[i] = "O"
                score = min_max(board, depth + 1, False)
                board[i] = " "
                best_score = max(score, best_score)
        return best_score
    else:
        best_score = float("inf")
        for i in range(len(board)):
            if board[i] == " ":
                board[i] = "X"
                score = min_max(board, depth + 1, True)
                board[i] = " "
                best_score = min(score, best_score)
        return best_score

def game():
    board = [" "] * 9
    while True:
        print_board(board)
        move = input("Enter your move (1-9): ")
        if board[int(move) - 1] != " ":
            print("Invalid move, try again.")
            continue
        board[int(move) - 1] = "X"
        result = check_win(board)
        if result:
            print_board(board)
            if result == "X":
                print("You win!")
            elif result == "O":
                print("AI wins!")
            else:
                print("It's a tie!")
            break
        move = ai_move(board)
        board[move] = "O"
        result = check_win(board)
        if result:
            print_board(board)
            if result == "X":
                print("You win!")
            elif result == "O":
                print("AI wins!")
            else:
                print("It's a tie!")
            break

game()

內容解密:

這個程式碼實作了 Tic Tac Toe 遊戲,包含玩家對戰和玩家對戰 AI 兩種模式。AI 的移動策略是透過 MinMax 演算法來實作的。玩家可以輸入移動的位置,AI 會根據當前的板子狀態做出最佳的移動選擇。遊戲會在每次移動後更新板子的狀態,並檢查是否有贏家或平局。

Tic Tac Toe 遊戲設計

遊戲簡介

Tic Tac Toe 是一款經典的兩人棋類遊戲,玩家輪流在 3x3 的棋盤上放置符號(X 或 O),先形成三個符號連線的玩家即為勝利者。

遊戲流程

  1. 玩家準備:遊戲開始前,玩家需要輸入自己的名稱和選擇自己想要的符號(X 或 O)。
  2. 遊戲開始:系統隨機決定哪位玩家先開始。
  3. 玩家回合:每位玩家在自己的回合中需要輸入自己想要放置符號的位置(1-9)。
  4. 勝利判定:系統在每個回合結束後檢查是否有玩家形成三個符號連線,如果有,則宣佈該玩家為勝利者。

程式碼實作

import random

def play():
    # 問玩家是否準備好開始遊戲
    return input("\nAre you ready to play the game? Enter [Y]es or [N]o.\t").upper().startswith('Y')

def names():
    # 玩家名稱輸入
    p1_name = input("\nEnter NAME of PLAYER 1:\t").capitalize()
    p2_name = input("Enter NAME of PLAYER 2:\t").capitalize()
    return (p1_name, p2_name)

def choice():
    # 玩家符號選擇
    p1_choice = ' '
    p2_choice = ' '
    while p1_choice not in ['X', 'O']:
        p1_choice = input(f"\n{p1_name}, Do you want to be X or O?\t")[0].upper()
        if p1_choice not in ['X', 'O']:
            print("INVALID INPUT! Please Try Again!")
    if p1_choice == 'X':
        p2_choice = 'O'
    elif p1_choice == 'O':
        p2_choice = 'X'
    return (p1_choice, p2_choice)

def first_player():
    # 隨機決定先開始的玩家
    return random.choice((0, 1))

def display_board(board, avail):
    # 顯示遊戲板
    print(" " + " {} | {} | {} ".format(board[7], board[8], board[9]) + " " + " {} | {} | {} ".format(avail[7], avail[8], avail[9]))
    print(" " + "-----------" + " " + "-----------")
    print(" " + " {} | {} | {} ".format(board[4], board[5], board[6]) + " " + " {} | {} | {} ".format(avail[4], avail[5], avail[6]))

# 主遊戲迴圈
if play():
    p1_name, p2_name = names()
    p1_choice, p2_choice = choice()
    first = first_player()
    board = [' ' for _ in range(10)]
    avail = [str(i) for i in range(1, 10)]
    while True:
        display_board(board, avail)
        if first == 0:
            move = input(f"\n{p1_name}, enter your move (1-9): ")
            if board[int(move) - 1] == ' ':
                board[int(move) - 1] = p1_choice
                avail[int(move) - 1] = ' '
                first = 1
            else:
                print("INVALID MOVE! Try Again!")
        else:
            move = input(f"\n{p2_name}, enter your move (1-9): ")
            if board[int(move) - 1] == ' ':
                board[int(move) - 1] = p2_choice
                avail[int(move) - 1] = ' '
                first = 0
            else:
                print("INVALID MOVE! Try Again!")
        # 檢查勝利條件
        for i in range(3):
            if board[i*3] == board[i*3 + 1] == board[i*3 + 2] != ' ':
                display_board(board, avail)
                print(f"\n{p1_name if board[i*3] == p1_choice else p2_name} wins!")
                break
            elif board[i] == board[i + 3] == board[i + 6] != ' ':
                display_board(board, avail)
                print(f"\n{p1_name if board[i] == p1_choice else p2_name} wins!")
                break
        else:
            if ' ' not in board:
                display_board(board, avail)
                print("\nIt's a tie!")
                break
            continue
        break

圖表翻譯:

此圖示

  flowchart TD
    A[開始] --> B[玩家準備]
    B --> C[遊戲開始]
    C --> D[玩家回合]
    D --> E[勝利判定]
    E --> F[遊戲結束]

圖表翻譯:

此圖示描述了 Tic Tac Toe 遊戲的流程。遊戲從開始開始,然後進入玩家準備階段,玩家輸入自己的名稱和選擇符號。接著,遊戲開始,系統隨機決定哪位玩家先開始。玩家輪流進行回合,輸入自己想要放置符號的位置。系統在每個回合結束後檢查是否有玩家形成三個符號連線,如果有,則宣佈該玩家為勝利者。遊戲結束後,系統顯示最終結果。

從使用者經驗視角出發,本次針對井字棋遊戲開發的程式碼範例與說明,展現了從簡易勝利條件判斷到整合MinMax演算法的AI對戰,以及最終具備完整遊戲流程與玩家互動設計的迭代過程。分析各階段程式碼,可以發現開發者逐步強化了遊戲的核心功能:勝利條件判斷的精確性、遊戲迴圈的流暢性,以及AI對戰的智慧程度。然而,程式碼的模組化設計仍有改進空間,例如可以將遊戲邏輯、使用者介面和AI演算法分離成獨立模組,提高程式碼的可維護性和擴充套件性。

此外,雖然MinMax演算法提升了AI的難度,但在井字棋這個相對簡單的遊戲中,其效能優勢並不明顯。可以考慮引入其他AI演算法或最佳化MinMax演算法的效率,例如Alpha-Beta剪枝,以提升遊戲體驗。同時,目前的遊戲板以數字1-9代表位置,對於使用者來說不夠直觀,可以考慮改用更易於理解的圖形化介面或座標系統。

展望未來,井字棋遊戲的開發可以朝向更豐富的遊戲模式發展,例如支援不同大小的棋盤、引入不同的勝利條件,或是加入線上對戰功能。同時,可以結合更先進的AI技術,例如強化學習,打造更具挑戰性的AI對手。玄貓認為,持續最佳化使用者經驗和探索新的遊戲模式,將是井字棋遊戲保持趣味性和吸引力的關鍵。