2017-02-15 67 views
1

我想表示Clojure中2D位置+鄰居在棋盤遊戲中的圖形。我使用的地圖的位置映射到鄰居的向量:clojure - 基於關鍵值以不同方式更新地圖值

{[0 0] [[0 1] [1 0] [1 1]]} 

我已經寫了一些功能,可以生成相鄰圖表任何大小的板:

(defn positions [size] 
    (for [x (range 0 size) y (range 0 size)] [x y])) 

(defn neighbors [size [x y]] 
    (filter (fn [[x y]] 
     (and (>= x 0) (< x size) (>= y 0) (< y size))) 
     (-> [] 
      (conj [(inc x) y]) 
      (conj [(dec x) y]) 
      (conj [x (inc y)]) 
      (conj [x (dec y)]) 
      (conj [(inc x) (inc y)]) 
      (conj [(dec x) (dec x)])))) 

(defn board-graph 
    [size] 
    (reduce (fn [map position] (assoc map 
            position 
            (neighbors size position))) 
      {} 
      (positions size))) 

這工作正常:

(board-graph 2) 
=> {[0 0] ([1 0] [0 1] [1 1]), [0 1] ([1 1] [0 0]), [1 0] ([0 0] [1 1] [0 0]), [1 1] ([0 1] [1 0] [0 0])} 

然而我現在想添加這個額外的「天涯若比鄰」,以每個都在板的邊緣倉板, .e.g:TOP,:BOTTOM,:LEFT,:RIGHT。所以我想:

(board-graph 2) 
=> {[0 0] (:LEFT :TOP [1 0] [0 1] [1 1]), [0 1] (:LEFT :BOTTOM [1 1] [0 0]), [1 0] (:RIGHT :TOP [0 0] [1 1] [0 0]), [1 1] (:RIGHT :BOTTOM [0 1] [1 0] [0 0])} 

這裏是我的嘗試,到目前爲止,但它並不完全工作的權利,它似乎真的過於複雜:

(defn- filter-keys 
    [pred map] 
    (into {} 
     (filter (fn [[k v]] (pred k)) map))) 


(defn board-graph 
    [size] 
    (let [g (reduce (fn [map position] (assoc map 
              position 
              (neighbors size position))) 
        {} 
        (positions size))] 
    (merge g 
      (reduce-kv #(assoc %1 %2 (conj %3 :TOP)) {} 
         (filter-keys (fn [[x y]] (= y 0)) g)) 
      (reduce-kv #(assoc %1 %2 (conj %3 :BOTTOM)) {} 
         (filter-keys (fn [[x y]] (= y (dec size))) g)) 
      (reduce-kv #(assoc %1 %2 (conj %3 :LEFT)) {} 
         (filter-keys (fn [[x y]] (= x 0)) g)) 
      (reduce-kv #(assoc %1 %2 (conj %3 :RIGHT)) {} 
         (filter-keys (fn [[x y]] (= x (dec size))) g))))) 

我基本上要建立我的地圖,再次檢查它,並且對於某些鍵,根據鍵是什麼來更新相關聯的值。我無法找到一個好辦法來做到這一點,而不訴諸於國家! 有沒有更習慣性的做法呢?

+0

您是否熟悉[更新](https://clojuredocs.org/clojure.core/update)? – RedDeckWins

+0

謝謝。更新僅適用於單個密鑰。我基本上有4個我需要調用更新的密鑰列表。思考我改變了我的搜索,發現這:http://stackoverflow.com/questions/9638271/update-the-values-of-multiple-keys 這可能會修復代碼的最後一部分。 – jimypbr

回答

2

您可以在構建返回的矢量的位置添加幾個表達式到您的線程表達式。爲了使它更好地閱讀,我將它從線程第一個宏->切換到「線程爲」宏as->,它將符號(在本例中)c綁定到在每一步中被線程化的值,以便我可以在條件上的一些階段的表達:

(defn neighbors [size [x y]] 
    (filter (fn [[x y]] 
      (and (>= x 0) (< x size) (>= y 0) (< y size))) 
      (as-> [] c 
       (conj c [(inc x) y]) 
       (conj c [(dec x) y]) 
       (conj c [x (inc y)]) 
       (conj c [x (dec y)]) 
       (conj c [(inc x) (inc y)]) 
       (conj c [(dec x) (dec x)]) 
       (if (zero? x) (conj c :TOP) c) 
       (if (= size x) (conj c :BOTTOM) c) 
       (if (zero? y) (conj c :LEFT) c) 
       (if (= size y) (conj c :RIGHT) c)))) 

每個條件表達式或者返回的更新版本,或通過改變通過它,如果條件不成立。

+0

as->:我正在尋找類似的東西!謝謝。但是,如果遇到以下關鍵字,過濾器將會失敗:TOP。您可以在過濾器謂詞中添加關鍵字檢查來解決這個問題。 – jimypbr

0

這適用於我,但它不是非常接近你原來寫的。

(defn positions [size] 
    (for [x (range 0 size) y (range 0 size)] [x y])) 

(defn neighbors [n [x y]] 
    (let [left (if (zero? x) 
       :LEFT 
       [(dec x) y]) 
     right (if (= x (dec n)) 
       :RIGHT 
       [(inc x) y]) 
     up (if (zero? y) 
      :TOP 
      [x (dec y)]) 
     down (if (= y (dec n)) 
       :BOTTOM 
       [x (inc y)])] 
    (list left right up down))) 

(defn board-graph [n] 
    (let [keys (positions n) 
     vals (map (partial neighbors n) keys)] 
    (zipmap keys vals))) 

然後

(clojure-scratch.core/board-graph 2) 
=> 
{[1 1] ([0 1] :RIGHT [1 0] :BOTTOM), 
[1 0] ([0 0] :RIGHT :TOP [1 1]), 
[0 1] (:LEFT [1 1] [0 0] :BOTTOM), 
[0 0] (:LEFT [1 0] :TOP [0 1])} 

編輯:正如亞瑟指出,這種不處理對角線,如果你想要的。

+0

需要對角線更多的情況。 –

+0

啊錯過了。如果您需要處理8種不同的事情,我對這個解決方案不太感興趣。 – RedDeckWins