iT邦幫忙

2024 iThome 鐵人賽

DAY 13
0

Current Sprint: 2. 實作遊戲開始
repo: https://github.com/side-project-at-SPT/ithome-ironman-2024-san-juan
swagger docs: https://side-project-at-spt.github.io/ithome-ironman-2024-san-juan/

前情提要

  • 建立卡片模型:染坊 indigo_plant.rb
  • 設置牌庫:抽出玩家人數的染坊卡片,洗勻剩餘卡牌成為牌庫(抽牌堆)

TODO

  1. 產生並儲存 random seed
  2. 洗勻價格卡
  3. 設置牌庫:抽出玩家人數的染坊卡片,洗勻剩餘卡牌成為牌庫(抽牌堆)
  4. 發給每位玩家一張染坊卡片,作為起始建築
  5. 玩家依序從牌庫抽取四張卡片,作為手牌
  6. 決定起始玩家

玩家擁有的建築

遊戲中玩家可以透過建築階段,支付卡片的費用後,將卡片面朝上放置於面前,成為玩家擁有的建築

並且可分為:

  • 工廠建築
    • 玩家自己可以擁有相同名稱的工廠建築
    • 可生產貨物:從牌庫抽取一張卡片,不可查看面朝下放置在工廠上,即為貨物
    • 可賣出貨物:從有貨物的工廠上將卡片移至棄牌堆,根據工廠種類、價格卡價格獲得收入(從牌庫抽取對應張數卡片作為手牌)
  • 城市建築
    • 玩家自己不能擁有相同名稱的工廠建築
    • 提供對應階段的不同加成效果

https://ithelp.ithome.com.tw/upload/images/20240914/20150987frr6IalpvK.jpg

ref: #183 聖胡安 SAN JUAN 桌遊教學影片|勃根地桌遊

定義一下玩家資料的儲存格式

目前的 game 回傳值

# app/views/api/v1/games/_game.json.jbuilder

json.id game.id
json.status game.status
if game.status_unknown?
  json.message "game not set up yet"
else
  json.game_config do
    json.seed game.seed
  end
  json.game_data do
    json.current_price game.current_price
    json.supply_pile game.game_data["supply_pile"]
  end
end

實際遊玩時,有些資料不能被玩家知道,例如 牌庫是什麼牌、貨物是什麼牌、其他玩家的手牌、棄牌堆有什麼牌,==目前先都顯示==

玩家自己棄掉的手牌,也許可以顯示出來,增加決策性?

在 key game_data 中加上 players[]
其中 player 要儲存

  • id
  • hand[]
    • id (card ID)
  • buildings
    • id (card ID)
    • good_id (貨物)
    • card_ids (有些卡片可以在下方放入卡片以計分)

更新 _game.json.jbuilder

# app/views/api/v1/games/_game.json.jbuilder
json.ignore_nil! # 把 nil 的欄位拿掉

# ...

  json.game_data do
    json.current_price game.current_price
    json.supply_pile game.game_data["supply_pile"]
    json.players game.players do |player|
      json.id player.id
      json.hand player.hand
      json.buildings player.buildings do |building|
        json.id building.id
        json.good_id building.good_id
        json.card_ids building.card_ids
      end
    end
  end

# ...

更新 game_spec.rb

  • 玩家數是否為 4
  • 玩家面前建築數是否為 1
  • 該建築 id 是否為 "01" (染坊)
# spec/requests/api/v1/games_spec.rb

# ...

      response '200', 'Game created' do
        schema type: :object,
          properties: {
            id: { type: :integer },
            status: { type: :string }
          },
          required: [ 'id', 'status' ]

        run_test! do
          json = JSON.parse(response.body)
          expect(json['status']).to eq('playing')
          expect(json['game_config']['seed']).to eq('1234567890abcdef')
          expect(json['game_data']['current_price']).to match_array([ 1, 2, 2, 2, 3 ])
          expect(json['game_data']['supply_pile'].size).to eq(110 - 4)
          expect(json['game_data']['supply_pile'][8]).to eq("01")
          expect(json['game_data']['players'].size).to eq(4)
          expect(json['game_data']['players'][0]['buildings'].size).to eq(1)
          expect(json['game_data']['players'][0]['buildings'][0]['id']).to eq("01")
        end
      end

# ...

實作將 染坊 發給每位玩家作為起始建築

  1. 定義 玩家建築 model (use Struct)
# app/models/game.rb

class Game < ApplicationRecord
# ...

  Player = Struct.new(:id, :hand, :buildings) do
    def to_json
      {
        id: id,
        hand: hand,
        buildings: buildings
      }
    end
  end
  Building = Struct.new(:id, :good_id, :card_ids)
  
# ...

end
  1. 新增 generate_players 類別方法
# app/models/game.rb
class Game < ApplicationRecord
# ...

  class << self
  # ...
    private
    
    def generate_players
      human_player = Player.new(1, [], [])
      bot_players = 3.times.map { |i| Player.new(i + 2, [], []) }

      [ human_player ] + bot_players
    end
    
    # ...
  end

# ...
  
end
  1. 新增 players 實體方法,用來將 players JSON data => 物件
# app/models/game.rb
class Game < ApplicationRecord
# ...

  def players
    return [] unless game_data["players"]

    JSON.parse(game_data["players"]).map do |player|
      Player.new(player["id"], player["hand"], player["buildings"].map { |building|
        Building.new(building["id"], building["good_id"], building["card_ids"])
      })
    end
  end

# ...
  
end
  1. start_new_game 加入玩家資訊
# app/models/game.rb
class Game < ApplicationRecord
# ...
  
  class << self
    def start_new_game(seed: nil)
      game.seed = seed || SecureRandom.hex(16)
      # 產生玩家
      game.game_data[:players] = generate_players.to_json
      game.save
    end

    # ...
  
  end

# ...
  
end
  1. 給予所有玩家 染坊 作為起始建築
# app/models/game.rb
class Game < ApplicationRecord
# ...
  
  class << self
    def start_new_game(seed: nil)
      # ...
      
      # 4. Give each player 1 indigo plant as their initial building
      players = game.players

      players.each do |player|
        player.buildings += [ Building.new("01") ]
      end

      game.game_data[:players] = players.to_json

      # 5. deal 4 cards to each player as their initial hand, hidden from other players
      # 6. choose first player

      game.save

      game
    end

    # ...
  
  end

# ...
  
end
  1. 跑測試
rails s

# open another session

curl localhost:3000/api/v1/games -d '' | jq

{
  "id": 3,
  "status": "playing",
  "game_config": {
    "seed": "5b693ed803e9427d4caa738918373d74"
  },
  "game_data": {
    "current_price": [
      1,
      2,
      2,
      2,
      3
    ],
    "supply_pile": [
      // 略
    ],
    "players": [
      {
        "id": 1,
        "hand": [],
        "buildings": [
          {
            "id": "01"
          }
        ]
      },
      {
        "id": 2,
        "hand": [],
        "buildings": [
          {
            "id": "01"
          }
        ]
      },
      {
        "id": 3,
        "hand": [],
        "buildings": [
          {
            "id": "01"
          }
        ]
      },
      {
        "id": 4,
        "hand": [],
        "buildings": [
          {
            "id": "01"
          }
        ]
      }
    ]
  }
}

收工.

  1. 產生並儲存 random seed
  2. 洗勻價格卡
  3. 抽出玩家人數的染坊卡片,洗勻剩餘卡牌成為牌庫(抽牌堆)
  4. 發給每位玩家一張染坊卡片,作為起始建築
  5. 玩家依序從牌庫抽取四張卡片,作為手牌
  6. 決定起始玩家

小結

也可以直接看 diff 7a645a0 /images/emoticon/emoticon82.gif

明天要做什麼

Sprint 2: 實作遊戲開始

以上不代表明天會做,如有雷同純屬巧合


工商服務

SPT (Side Project Taiwan) 的宗旨是藉由Side Project開發來成就自我,透過持續學習和合作,共同推動技術和專業的發展。我們相信每一個參與者,無論是什麼專業,都能在這個社群中找到屬於自己的成長空間。

歡迎所有對Side Project開發有興趣的人加入我們,可以是有點子來找夥伴,也可以是來尋找有興趣的Side Project加入,邀請大家一同打造一個充滿活力且有意義的技術社群!

Discord頻道連結:https://sideproj.tw/dc


上一篇
Day 12 - S2: 設置牌庫
下一篇
Day 14 - S2: 遊戲開始 done.
系列文
透過實作網頁遊戲練習網站工程師的基本素養,以 San Juan(聖胡安) 為例。30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言