2017-02-15 6 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])} 

EDIT:アーサーは指摘したように、あなたがそれを望むならば、これは、対角線を処理しません。

+0

は対角線に対してさらに2つのケースが必要です。 –

+0

ああそれを逃した。あなたが8つの異なる事をする必要があるなら、私はこの解決法に少し魅了されます。 – RedDeckWins

関連する問題