Вы можете написать функцию, которая будет брать 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)))])))
Возвращаемым значением является вектор дублета, первый элемент которого является остатком колоды, а вторым элементом является вектор начальных стеков.
Затем используйте это в транзакции для учета Ref:
(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))))
Отказ от ответственности: Ничто из этого не получило ни малейшего количества проверочного внимания (хотя я думаю, что оно должно работать нормально, по модулю любых глупых опечаток, которые я мог пропустить). Однако это ваше упражнение, поэтому я думаю, что оставить часть тестирования / полировки - это хорошо. : -)