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/

# app/models/trading_house.rb
class TradingHouse
# ...
  
  BASE_PRICES = [
    [ 1, 1, 1, 2, 2 ],
    [ 1, 1, 2, 2, 2 ],
    [ 1, 1, 2, 2, 3 ],
    [ 1, 2, 2, 2, 3 ],
    [ 1, 2, 2, 3, 3 ]
  ].each_with_object({}).with_index { |(prices, hash), index|
    hash[index] = prices
  }.freeze
# ...
end
# app/models/trading_house.rb
class TradingHouse
# ...
  
  def initialize(seed: nil)
    raise ArgumentError, "seed must provided" unless seed
    # assume seed is hex
    srand(seed.to_i(16))
    @order = [ 0, 1, 2, 3, 4 ].shuffle
  end
# ...
end
srand() 不提供引數時,會回傳一個 seed number
而當 srand(n) 時,會以 n 為種子取用隨機數
如此給予相同的 n,即能確保隨機方法(例如 shuffle, rand)的結果可控
因此在產生價格卡順序時,使用固定的 game.seed 來 shuffle,讓遊戲狀態可以重現
# app/models/trading_house.rb
class TradingHouse
# ...
  
  def draw_next_trading_house_tile
    el = @order.shift
    @order.push(el)
    self
  end
# ...
end
# app/models/trading_house.rb
class TradingHouse
# ...
  def current_price = BASE_PRICES[@order.first]
  def indigo_price = current_price[0]
  def sugar_price = current_price[1]
  def tobacco_price = current_price[2]
  def coffee_price = current_price[3]
  def silver_price = current_price[4]
# ...
end
TradingHouse 物件,方便操作# app/models/trading_house.rb
class TradingHouse
# ...
  def initialize(params = nil)
    case params
    in Array
      @order = params
    else
      raise ArgumentError, "order or seed must be provided"
    end
  end
# ...
end
宣告一個類別方法負責處理 start new game
- generate a random seed 產生種子
- shuffle the 5 trading house tiles 洗勻價格卡
- deal indigo plant to players as initial building 抽出玩家人數的染坊卡片,發給每位玩家,作為起始建築
- shuffle remaining cards to form a deck 洗勻剩餘卡牌成為牌庫(抽牌堆)
- deal 4 cards to each player as their initial hand, hidden from other players 發給每位玩家四張卡片,作為手牌
- choose first player 決定起始玩家
# app/models/game.rb
class Game < ApplicationRecord
# ...
  
  class << self
    def start_new_game
      game = new(status: :playing)
      # 1. generate a random seed
      game.seed = SecureRandom.hex(16)
      # 2. shuffle the 5 trading house tiles
      game.game_data[:trading_house_order] = TradingHouse.new(seed: game.seed).order
      # 3. deal indigo plant to players as initial building
      # 4. shuffle remaining cards to form a deck
      # 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
# app/controllers/api/v1/games_controller.rb
class Api::V1::GamesController < ApplicationController
# ...
  
  def create
    @game = Game.start_new_game
    render json: { error: @game.errors.full_messages } unless @game.present?
  end
# ...
end
# 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
  end
end
收工
也可以直接看 diff 38959be  
Sprint 2: 實作遊戲開始
以上不代表明天會做,如有雷同純屬巧合
SPT (Side Project Taiwan) 的宗旨是藉由Side Project開發來成就自我,透過持續學習和合作,共同推動技術和專業的發展。我們相信每一個參與者,無論是什麼專業,都能在這個社群中找到屬於自己的成長空間。
歡迎所有對Side Project開發有興趣的人加入我們,可以是有點子來找夥伴,也可以是來尋找有興趣的Side Project加入,邀請大家一同打造一個充滿活力且有意義的技術社群!
Discord頻道連結: https://sideproj.tw/dc