在Clojure中,如何合并两个地图向量?

格雷格·K

我有一个实体(映射)的向量,我已将此向量过滤到具有特定键的那些实体。然后,我应用一个函数来更新这些实体中的某些值,现在有一个我想与原始超集合并的子集。

world     [{a} {b} {c} {d} {e}]
a         [{b} {d} {e}]            ; (filter matches? world)
b         [{b'} {d'} {e'}]         ; (map func a)
new-world [{a} {b'} {c} {d'} {e'}] ; (merge world b)

如何将更新b与原始合并world

我的地图结构是:

{:id identity
 :attrs {:property1 {:param1 value
                     :param2 value}
         :property2 {}}

可以有可变数量的属性。属性可以具有0({})或更多参数。映射中唯一更改的部分是值,并且其中只有一部分。

我必须查看每张地图以识别它,然后进行相应合并?惯用的方法是什么?

Clojure的map函数可以采用多个序列,但是不会将我的子集b与整个超进行比较world,只能b将世界实体的数量进行比较,并且一旦b耗尽就停止

> (map #(str %1 " " %2) [1 2 3 4 5] [6 7 8])
("1 6" "2 7" "3 8")

首先我是否为数据选择了错误的结构?如果没有矢量和仅一张地图,我会更好吗?

{:entid1
   {:property1 {:param1 value :param2 value}
    :property2 {}}
 :entid2
   {:property1 {:param1 value :param2 value}
    :property2 {:param1 value}
    :property3 {:param1 value :param2 value :param3 value}}}

这个问题看起来很相似,但是不能正确合并我的向量。


现实世界中的实现

我的实际代码是我正在写的游戏的一部分,以使自己熟悉Clojure(在这种情况下为ClojureScript)。

游戏状态(世界)如下:

[{:id :player,
  :attrs
    {:gravity {:weight 10},
     :jump {:height 60, :falling false, :ground true},
     :renderable {:width 37, :height 35},
     :position {:x 60, :y 565},
     :walk {:step 4, :facing :right},
     :input {},
     :solid {:blocked false}}}
 {:id wall1,
  :attrs
    {:solid {},
     :position {:x 0, :y 0},
     :renderable {:width 20, :height 600}}}
 {:id wall2,
  :attrs
    {:solid {},
     :position {:x 780, :y 0},
     :renderable {:width 20, :height 600}}}
 {:id platform3,
  :attrs
    {:solid {},
     :position {:x 20, :y 430},
     :renderable {:width 600, :height 20}}}] 

我在每个动画帧上更新世界,然后重新渲染画布。

(defn game-loop []
  (ui/request-frame game-loop)
  (-> world
      system/update!
      ui/render))

system/update! 是:

(defn update! [world]
  (let [new-world (->> @world
                      (phys/move @player/input-cmd))]
    (player/clear-cmd)
    (reset! world new-world)
    @world))

我的计划是让一系列系统在线程最后一个宏中更新世界。我正在写作中phys/move

这意味着系统必须更新世界,而不仅仅是返回它们对世界的影响(变化的向量)。

我正在考虑让该system/update!功能管理世界上的效果(应用更新)是否更易于管理。因此,系统仅返回其更改列表。就像是:

(defn update! [world]
  (let [updates []
        game @world]
     (conj updates (phys/move @player/input-cmd game))
     (conj updates (camera/track :player game))
     ; etc.
     (reset! world
       (map #(update-world updates %) world))
     @world))

重复的(conj updates (func world))感觉虽然笨拙。这可能不仅仅是在系统功能中合并更新(或返回修改后的实体)的工作。

如何优雅地通过我的系统功能之间的状态变化(phys/movecamera/track),和子系统的功能(walkjump)?

我在将Joaquin的仅地图方法应用于我的move系统上的尝试是

(ns game.phys)

(def step 4)
(def height 50)

(defn walk?
  "is this a walk command?"
  [cmd]
  (#{:left :right} cmd))

(defn walks?
  "update? equivalent"
  [entity]
  (contains? (:attrs entity) :position))

(defn walk
  [cmd entity]
  (if (walks? entity)
    (let [x (get-in entity [:attrs :position :x]
          op (if (= cmd :left) - +)
          update {:attrs {:position {:x (op x step)}
                          :walk     {:facing cmd}}}]
      (merge entity update))
    entity))

; cmd is a deref'ed atom that holds player input commands
; e.g. :left :right: :jump
(defn move
  [cmd world]
  (cond
    (walk? cmd) (map #(walk input-cmd %) world)
    (jump? cmd) (map #(jump height %) world)
    :else world))
华金

它比所有方法都要简单(拥有地图矢量是很常见的事情,它可能会适当地解决您的问题)。不用先做过滤器再做地图,只需做一个地图即可:

(defn update? [entity] ...)
(defn update-entity [entity] ...)

(defn update-world [world]
  (let [update #(if (matches? %) (update-entity %) %)]
    (map update world)))

这种更新或仅保留某些内容的模式非常普遍,使更新某些内容的函数返回更新的内容或旧的内容(如果它什么都不做)是惯用的,因此最后它就像:

(defn update-entity?
  "Predicate that returns if an entity needs updating"
  [entity] ...)

(defn update-entity
  "Updates an entity if it is needed.
   Otherwise returns the unchanged entity"
  [entity]
  (if (update-entity? entity)
    (assoc entity :something :changed)
    entity))

(defn update-world [world]
  (map update-entity world))

您可以在此蛇游戏的游戏逻辑中看到有关此行为的一些示例:

https://github.com/joakin/cnake/blob/master/src/cnake/game.cljs#L54-L66
https://github.com/joakin/cnake/blob/master/src/cnake/game.cljs #L102-L114

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在 clojure 中操作地图的两个向量

来自分类Dev

如何在Clojure中创建具有两个列表(或向量)的地图?

来自分类Dev

Clojure-合并两个不同大小的向量的向量

来自分类Dev

如何合并两个向量?

来自分类Dev

从Clojure中的两个向量创建子向量

来自分类Dev

从Clojure中的两个向量创建子向量

来自分类Dev

合并两个向量并获得R中的向量列表

来自分类Dev

如何使用Java在Spark中合并或合并两个稀疏向量?

来自分类Dev

Clojure中两个地图之间的交点

来自分类Dev

如何在Clojure中交错两个长度不同的向量

来自分类Dev

在Scala中合并两个嵌套地图

来自分类Dev

根据R中的索引合并两个向量

来自分类Dev

Scala的两个地图合并

来自分类Dev

将两个向量与“或”合并

来自分类Dev

将两个地图合并到Groovy中的结果地图

来自分类Dev

Clojure:如何合并具有相同值的地图向量

来自分类Dev

如何合并两个排序的向量并合并重叠的元素?

来自分类Dev

如何合并两个排序的向量并合并重叠的元素?

来自分类Dev

如何合并两个:not()?

来自分类Dev

Clojure:将两个向量与新的键和值合并到一个映射中

来自分类Dev

合并Clojure中的地图

来自分类Dev

合并Clojure中的地图

来自分类Dev

如何从两个列表中创建地图?

来自分类Dev

如何对R中两个不等向量的值求和?

来自分类Dev

如何对R中两个不等向量的值求和?

来自分类Dev

在Git中合并两个合并

来自分类Dev

在合并中合并两个AnyPublisher

来自分类Dev

Clojure-在哈希图向量中,返回两个键匹配的最低哈希图

来自分类Dev

如何比较两个向量中的两个值,然后在C ++中更新向量值?

Related 相关文章

热门标签

归档