2014-07-14 49 views
3

我有一個表示爲地圖的遊戲狀態和一些更新每個遊戲'tic'狀態的邏輯。但我無法弄清楚如何以任何理智的方式構建更新功能。如何在Clojure中構造複雜的「狀態更新函數」?

構建這樣的函數的習慣模式是什麼?

這裏是我想要做的一些僞代碼:

(defn tic [g] "Return an updated game" 
    g1 = (update-in g [:day] inc) 
    g2 = (if (some-cond) (some-update-func g1) g1) 
    g3 = (update-in g2 [:fu] fu-update) 
    ... many more ... 
    g-last) 

我真的不關心中間狀態,但使用 - >宏不工作(因爲有一些條件語句)。

工作的黑客正在使用重置的本地原子!對於更新函數中的每個'行'。但這不可能是它應該如何完成的!

回答

6

我會建議在一個很好命名的函數中提取每個步驟,以便您可以使用 - >。僞代碼:

(defn tic [g] 
    (-> g 
     inc-day 
     random-weather 
     grow-trees 
     ...)) 

對於任何條件邏輯,您可以執行類似於您在g2步驟中所做的操作。

也許你會發現synthread lib有用。我發現this video非常有教育意義。

看看cond->看看你怎麼可以混合 - >與一些cond。例如您COND可能看起來像:

(cond-> g 
     true (update-in [:day] inc) 
     (some-cond) some-update-fund 
     true (update-in [:fu] fu-update)) 
+0

的命名函數的組合,邏輯塊,並且synthread LIB看起來像一個很好的解決方案。它有類似於其他答案中描述的'mabey'宏的宏(還有更多)。 – 4ZM

3

您仍然可以使用->如果有條件的步驟,你包在一個匿名功能的操作。

(-> g0 
    ... 
    (#(if (some-cond) (u %) %)) 
    ...) 

如果你關心效率(你提到這是一個遊戲),我會建議你使用cond->也許創建您自己的宏。 cond->需要重複true表示總是線程化的表達式,這可能是單調乏味的,具體取決於線程中項目的數量。

這裏是可一起選擇與->使用的宏避免過度創建匿名函數並避免的cond->重複性:

(defmacro maybe [val sym cond expr] 
    `(let [~sym ~val] (if ~cond ~expr ~sym))) 

它可用於這樣的:

(-> g0 
    ... 
    (maybe gn (some-cond gn) (updater gn)) 
    ...) 

如果您不需要在條件表達式中使用部分處理值gn,則可以使用cond->而不是maybe

(-> g0 
    ... 
    (cond-> (some-cond g0) updater) 
    ...) 

又如:

(-> 10 (maybe gn (= gn 10) (* gn 100))) 

計算結果爲1000

+0

你應該看看'cond->',我相信它會很好地代替'maybe'。 – omiel

+0

@omiel'cond->'絕對是一種選擇,所以我相應地編輯了我的答案。但是,如果大多數情況是「真實的」,它看起來很討厭,如果你想使用條件中的當前值,它就不起作用。 我編輯了我的答案,以使'maybe'宏實際上有用 - 它只是移動匿名函數而不是解決它。 – matvore

+1

您誤解了:我建議您在' - >'內嵌套'cond->'形式,而不是僅僅使用'cond->'。 – omiel

相關問題