【发布时间】:2012-04-17 21:19:01
【问题描述】:
我正在使用 Clojure 开发一个小游戏作为学习练习。我想我已经确定了在任何特定时间将游戏状态表示为“可移动”列表和“地形”(棋盘方格)的 2D 向量向量。
在 95% 的时间里,我希望检查 2D 矢量似乎适合的特定正方形中的碰撞。但在少数情况下,我需要另辟蹊径——找到符合某些条件的单元格的 (x,y) 位置。第一次尝试是这样的:
(defn find-cell-row [fn row x y]
(if (empty? row) nil
(if (fn (first row)) [x y]
(find-cell-row fn (rest row) (inc x) y))))
(defn find-cell [fn grid y]
(if (empty? grid) nil
(or (find-cell-row fn (first grid) 0 y)
(find-cell (rest grid) (inc y)))))
(def sample [[\a \b \c][\d \e \f]])
(find-cell #(= % \c) sample 0) ;; => [2 0]
我尝试了一些更简洁的地图索引,但它很快就变得丑陋了,仍然没有给我想要的东西。是否有更惯用的方法来进行此搜索,或者使用不同的数据结构可能会更好地为我服务?也许是地图 { [x y] -> cell }?使用地图来表示矩阵对我来说感觉很不对 :)
【问题讨论】:
-
你可以使用 Map 但是使用像 cons-cell 这样的不可变数据结构的优点之一是它可以很容易地执行类似 MINI-MAX (en.wikipedia.org/wiki/Minimax) 的算法,因为任何操作基本上将克隆板。另一方面,我发现 car/consing 通过单元格很烦人,通常会求助于一些索引结构(数组或映射)。
-
看起来 Clojure 很好地支持使用 assoc-in 来“编辑”一个单元格(即创建一个新的不可变结构并改变值)。这个游戏中没有人工智能,但我确实希望能够“倒回”到以前的时间,所以不可变结构真的很方便。
-
不确定你对
assoc-in的意思,但是 clojure 中的“普通”地图是作为功能(不可变)树实现的,所以当你修改地图时,你会得到一个新的实例,它与以前的事例。我将 map {[x y] -> cell} 用于 dfs 中的结构,并且效果很好。但是,感觉很“奇怪”,所以我将这个问题添加为书签,看看是否有更好的... -
clojuredocs.org/clojure_core/clojure.core/assoc-in。所以我可以调用
(assoc-in sample [0 2] \z)来创建样本副本,其中\c 更改为\z。感谢你们的反馈。 -
assoc-in 允许进入嵌套数据结构的路径。它将即时创建缺少的中间节点,因此 (assoc-in {} [:a :b :c] 3) => {:a {:b {:c 3}}}