chunks
特定のシーケンスからそれぞれアイテムのベクトルを取得する関数とsize
、それらのチャンクを前面から削除する別の関数を作成できます。
;; note the built-in assumption that s contains enough items;
;; if it doesn't, one chunk less then requested will be produced
(defn take-chunks [chunks size s]
(map vec (partition size (take (* chunks size) s))))
;; as above, no effort is made to handle short sequences in some special way;
;; for a short input sequence, an empty output sequence will be returned
(defn drop-chunks [chunks size s]
(drop (* chunks size) s))
次に、両方を実行する関数を追加します(との後split-at
にモデル化split-with
):
(defn split-chunks [chunks size s]
[(take-chunks chunks size s)
(drop-chunks chunks size s)])
各カードが最初{:face-up false}
にあると仮定すると、次の関数を使用して、スタックの最後のカードをめくることができます。
(defn turn-last-card [stack]
(update-in stack [(dec (count stack)) :face-up] not))
次に、指定されたデッキから初期スタック/チャンクを処理する関数:
(defn deal-initial-stacks [deck]
(dosync
(let [[short-stacks remaining] (split-chunks 6 5 deck)
[long-stacks remaining] (split-chunks 4 6 remaining)]
[remaining
(vec (map turn-last-card
(concat short-stacks long-stacks)))])))
戻り値は、最初の要素がデッキの残りの部分であり、2番目の要素が初期スタックのベクトルであるダブルトンベクトルです。
次に、これをトランザクションで使用して、参照を考慮に入れます。
(dosync (let [[new-deck stacks] (deal-initial-stacks @deck-ref)]
(ref-set deck-ref new-deck)
stacks))
さらに良いことに、ゲームの状態全体を単一のRefまたはAtomに保持し、ref-set
からalter
/に切り替えswap!
ます(この例ではRefを使用し、代わりにアトムを使用するようにdosync
切り替えます):alter
swap!
;; the empty vector is for the stacks
(def game-state-ref (ref [(get-initial-deck) []]))
;; deal-initial-stacks only takes a deck as an argument,
;; but the fn passed to alter will receive a vector of [deck stacks];
;; the (% 0) bit extracts the first item of the vector,
;; that is, the deck; you could instead change the arguments
;; vector of deal-initial-stacks to [[deck _]] and pass the
;; modified deal-initial-stacks to alter without wrapping in a #(...)
(dosync (alter game-state-ref #(deal-initial-stacks (% 0))))
免責事項:これはどれもテストの注目を少しも受けていません(私はそれがうまくいくはずだと思いますが、私が見逃したかもしれない愚かなタイプミスを法として)。でも、それはあなたの練習なので、テスト/研磨の部分はあなたに任せてもいいと思います。:-)