2015-02-11 2 views
2

Я относительно новичок в clojure, но понимаю основные функциональные понятия. Что-то, с чем я действительно борюсь, - это состояние.Состояние карточной игры в Clojure

Я пишу простую карточную игру, она дошла до того, что я пишу движок игры. Таким образом, концепция государства быстро ударила меня в лицо.

мне нужно следить за большим количеством вещей, имеющих отношение к игре:

  • от состояния палубы
  • состояние точек
  • Кто был дилер
  • ...
  • т.д.

Я прочитал, как состояние используется в clojure, Refs, Agents, Atoms и thread local vars. Но ни один из них не кажется правильным вариантом для того, что я делаю.

Итак, мой фактический вопрос: какую конструкцию clojure я использую для поддержания состояния однопоточного игрового движка в clojure?

ответ

3

Похоже, что состояние этой игры состоит из нескольких компонентов, колоды, точек, дилера и т. Д., Поэтому вы можете поместить все это в одну карту и сохранить это в одном из нескоординированных изменяемых типов данных (atom, agent, var) или хранить их отдельно и использовать скоординированный изменяемый тип данных, ref. Поскольку вы говорите, что игра однопоточная, может быть немного легче перейти к нескоординированному маршруту, чтобы сохранить ввод слов dosync несколько раз, хотя это не будет большой разницей в усилиях в любом случае.

(def state-of-game (atom {:deck ... 
          :points 
          :dealer})) 
5

Общий принцип функционального программирования является то, что вы можете сделать ваш код более общим путем замены глобального состояния с дополнительным входным и выходным аргом аргом для каждой функции обращающегося состояния.

В этом случае это означает предоставление игроку game аргументов за каждый раунд игры, а каждый раунд игры возвращает новый game, который будет использоваться в будущем. Этому есть несколько преимуществ. Мутации нет, поэтому нет необходимости управлять и координировать мутацию. Ваши тесты могут состоять из одного оборота функции раунда игры. Если вам нужен ИИ, он может тривиально запустить множество ветвящихся поворотов игры на основе ширины, чтобы проверить вероятные результаты, не мешая состоянию реальной игры.

грубый набросок того, что это может выглядеть следующим образом:

(def make-game 
    [players] 
    (let [[draw & deck] (shuffle cards)] 
    {:draw draw 
    :deck deck 
    :points (zipmap players (repeat 0)) 
    :dealer (first players)}) 

(defn run-round 
    [game] 
    (let [points (update-points (:draw game) (:points game)) 
     [draw & deck] (:deck game)] 
    (assoc game :deck deck :draw draw :points points))) 

(defn winner? 
    [game] 
    (some #(> (val %) 42) (:points game))) 

(defn -main 
    (let [gameplay (take-while #(not (winner? %)) 
          (iterate run-round (make-game)))] 
    (:points (run-round (last gameplay))))) 

Это, конечно, очень тривиальная игра, где точки каждого игрока получает из карты рисуется. Следующая карта будет нарисована из перетасованной колоды на каждом шагу, пока мы не получим общий балл, обозначающий победителя.

Смежные вопросы