2017-02-15 65 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