在Clojure中处理二维数组的最佳实践是什么?

3
我正在构建一个扫雷游戏,其中游戏板是一个二维数组。
要生成游戏板,我需要获取一个二维数组,随机放置一些炸弹,计算每个格子的所有相邻炸弹,然后将它们与另一个值(是否暴露)一起打包到地图中,这应该是每个格子的最终值。
似乎为了完成所有这些操作,我需要使用像map、filter、nth或zip等函数,但它们不应该在列表上工作,而应该在二维数组上进行操作。我已经开始构建这些函数,但似乎这条路走错了。
有没有一些很酷的抽象方法可以帮助我在二维数组上使用现有的函数?还是已经存在处理二维数组的函数?
编辑:在认为应该有更好的方法之前,我正在使用以下方式进行操作:
(defn mapmap [f xxs]
  (for [xs xxs]
    (map f xs)))

(defn mapmap-coords [f xxs]
  (for [[i xs] (map-indexed list xxs)]
    (map-indexed (fn [j x] (f j i)) xs)))

(defn get-value [board x y]
  (if (or (< x 0) (< y 0) (< (dec (count board)) y))
    false
    (let [xs (nth board y)]
      (if (< (dec (count xs)) x)
        false
        (nth xs x)))))

https://github.com/mikera/core.matrix - A. Webb
2个回答

2

for适用于嵌套的顺序数据。

user> (def game-state
       (let [game '[[_ _ _ _]
                    [1 1 _ _]
                    [! 1 _ _]
                    [1 1 _ _]]]
         (for [[i row] (map-indexed list game)
               [j cell] (map-indexed list row)
               :when (not= '_ cell)]
              {:x i :y j :value cell})))
#'user/game-state
user> (pprint game-state)
({:x 1, :y 0, :value 1}
 {:x 1, :y 1, :value 1}
 {:x 2, :y 0, :value !}
 {:x 2, :y 1, :value 1}
 {:x 3, :y 0, :value 1}
 {:x 3, :y 1, :value 1})
nil

我们可以使用reduce重新构建数据结构(当然,在此过程中可以对状态进行任何转换)。
user> (let [empty-game (vec (repeat 4 '[_ _ _ _]))
            fill-cell (fn [game, {:keys [x y value]}] (assoc-in game [x y] value))
            game (reduce   fill-cell empty-game game-state)]
        (doseq [row game] (apply println row)))
_ _ _ _
1 1 _ _
! 1 _ _
1 1 _ _
nil

谢谢。我知道for如何用来展开我的板子并进行操作,但是我该如何将它们重新包装(成另一个板子)? - sra
这是处理二维数组的“惯用”方式吗?它似乎有点复杂。到目前为止,我使用了像(defn mapmap [f xxs] (for [xs xxs] (map f xs)))这样的函数,可以更轻松地实现类似的功能。在Clojure中使用二维数组甚至是可行的吗? - sra
1
如果您想保留嵌套形状,那是可以的。但是,如果要在单个序列上进行操作,创建扁平版本、对其执行一些操作,然后重新构建2D数组可能更有意义。此外,如果使用mapv而不是formap,则可以获得关联性的好特性(因此可以使用get-in来访问网格的特定单元格,或者使用update-inassoc-in来更新单个单元格并将其余部分保持不变)。 - noisesmith

2
如果您愿意在实现中使用Java类型,请考虑使用: aget将为您提供更自然的访问数组的方法,但您仍需要构建进一步的抽象来获取邻居并对此数据结构执行更新(即重新生成)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接