iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0

今天我們一樣請 chatGPT 針對昨天的遊戲產出基礎的遊戲邏輯,因為我們昨天已經產出簡易的遊戲規則,所以這邊應該能夠快速地迭代一個最初版本的遊戲進程。後續各位看官可以根據自己想要發展的方向再去拓展它。一樣會直接上扣,說明的部分會放結尾

範例

import random

# 初始玩家生命值
initial_health = 50

# 初始卡牌堆
player1_deck = [1, 2, 3, 4, 5]  # 假設玩家1的卡牌堆中有5張卡牌
player2_deck = [6, 7, 8, 9, 10]  # 假設玩家2的卡牌堆中有5張卡牌

# 遊戲狀態字典
game_state = {
    "player1_health": initial_health,
    "player2_health": initial_health,
    "player1_deck": player1_deck,
    "player2_deck": player2_deck,
    "player1_hand": [],
    "player2_hand": [],
    "current_player": 1,  # 1代表玩家1,2代表玩家2
    "winner": None  # 初始沒有獲勝者
}

def draw_card(game_state):
    current_player = game_state["current_player"]
    deck = game_state[f"player{current_player}_deck"]
    hand = game_state[f"player{current_player}_hand"]

    if len(deck) > 0:
        # 從卡牌堆中隨機抽一張卡牌
        card_index = random.randint(0, len(deck) - 1)
        card_id = deck.pop(card_index)
        # 把卡牌加入手牌
        hand.append(card_id)

    # 更新遊戲狀態
    updated_state = {
        f"player{current_player}_deck": deck,
        f"player{current_player}_hand": hand,
    }
    return updated_state

def play_card(game_state, card_id):
    current_player = game_state["current_player"]
    other_player = 3 - current_player  # 切換到對手
    hand = game_state[f"player{current_player}_hand"]
    other_player_health = game_state[f"player{other_player}_health"]

    if card_id in hand:
        # 找到卡牌並計算傷害值(這裡可以根據卡牌的屬性進行計算)
        damage = card_id
        # 更新對手的生命值
        other_player_health -= damage
        if other_player_health <= 0:
            # 如果對手生命值小於等於0,遊戲結束,當前玩家獲勝
            game_state["winner"] = current_player
        # 移除已經使用的卡牌
        hand.remove(card_id)
    
    # 更新遊戲狀態
    updated_state = {
        f"player{other_player}_health": other_player_health,
        f"player{current_player}_hand": hand,
        "current_player": other_player,  # 切換回合
    }
    return updated_state

def check_winner(game_state):
    return game_state["winner"]

# 測試抽牌和出牌
game_state = draw_card(game_state)
print("玩家1的手牌:", game_state["player1_hand"])
game_state = play_card(game_state, game_state["player1_hand"][0])
print("玩家1的生命值:", game_state["player1_health"])
print("玩家2的生命值:", game_state["player2_health"])

解說

因為將遊戲規則簡化到非常單純的程度,所以我們可以很快地利用這個案例建構一個最小可行的版本,同時也能掌握一個基本的卡牌遊戲所需要的基本要素有哪些?

這邊可以看出 chatGPT 有因為我提問給的範例而造成程式碼風格的調整

  1. game_state 是扁平式的 key value 對,這點沒有什麼問題,比較像是個人偏好,對程式維護性沒有太大影響
  2. 產生新的遊戲狀態而不是直接修改遊戲本身的狀態,這是因為這樣我才能將新的遊戲狀態發布給其他 client 端的玩家。在多人連線的環境會蠻需要這個特性的

提問

事後我也交叉比對和 chatGPT 確認它對程式開發風格的一些觀點,蠻符合我的想像的

問:你覺得使用單純的 game_state dict 來表達遊戲狀態,而沒有封裝成 class 和 method 的考量是什麼?

使用單純的 game_state 字典來表達遊戲狀態而不封裝成類和方法的考量主要取決於項目的規模和複雜度,以及開發者的偏好和目標。以下是一些可能的考慮因素:

  1. 專案規模:如果這是一個小型、簡單的遊戲或原型,並且你不打算擴展它,那麼使用一個單純的字典可能是足夠的。對於小規模專案,不一定需要引入類和方法的複雜性。

  2. 學習曲線:使用類和方法需要一定的學習曲線,尤其是對於不熟悉物件導向編程的開發者來說。如果你或你的團隊對於類和方法的使用不太熟悉,或者想快速開始,則使用字典可能更容易上手。

  3. 專注點:將遊戲狀態存儲在一個字典中可以使你更專注於遊戲邏輯本身,而不用擔心類的設計和方法的結構。這可以在快速原型開發或探索新點子時很有用。

  4. 簡單性:有時,保持代碼簡單和直接可以是一個優勢。使用一個字典可以減少冗餘代碼,並使代碼更容易閱讀和理解。

然而,如果你的遊戲計劃變得更加複雜,並且需要更多功能,例如玩家間的互動、卡牌效果的管理、遊戲日誌的記錄等,那麼將遊戲狀態封裝成一個類可能更為合適。這樣可以更好地組織代碼,使其可維護性更高,並且可以更容易擴展遊戲功能。

總之,選擇使用單純的字典還是封裝成類和方法取決於具體情況,並且可以根據項目的需求和開發者的偏好做出適當的選擇。在開始之前,最好考慮項目的規模、複雜度和長期發展計劃。

問:請問你是否理解為何我會選擇採用增量的方式產生 game update state 而不是直接修改 dict 的內容?

是的,我理解你為什麼選擇採用增量的方式產生 game_state 更新而不是直接修改字典的內容。這種方法通常被稱為"不可變性"或"函數式編程",具有以下優點:

  1. 避免副作用:直接修改字典的內容可能會引入副作用,使得代碼難以理解和調試。使用增量方式產生更新可以幫助確保遊戲狀態在不同時間點是可預測且一致的。

  2. 可追蹤性:增量方式產生更新可以更容易地追蹤遊戲狀態的變化。你可以輕鬆地記錄和檢查每個操作的效果,這對於調試和錯誤修復很有幫助。

  3. 並行性:如果你打算實現多玩家遊戲或並行處理,使用增量方式更新狀態可以減少競爭條件和不一致性的風險。

  4. 更好的可讀性:增量方式的更新通常更清晰和可讀,因為它們專注於描述"發生了什麼",而不是"如何修改"。

  5. 功能性編程:這種方式符合功能性編程的原則,並使代碼更容易測試和維護。

總之,使用增量方式產生 game_state 更新是一種良好的設計實踐,有助於提高代碼的可讀性、可維護性和可擴展性,並有助於避免一些潛在的錯誤和問題。這種方法使得遊戲狀態的變化更加可控,有助於確保遊戲的穩定性和一致性。

最後附上完整問答提供大家參考,接下來我們還是會持續迭代,持續完善這個 websocket 連線遊戲!


上一篇
D20 接下來的遊戲規劃
下一篇
D22 來開房間吧 websocket 建立/加入房間以及開始遊戲
系列文
chatGPT 帶你從零開始寫 websocket 連線遊戲31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言