我正在编写一个包含两个代理集和一个命令 block 的原语。它需要调用几个函数,在当前上下文中执行命令 block ,然后调用另一个函数。这是我到目前为止所拥有的:
class WithContext(pushGraphContext: GraphContext => Unit, popGraphContext: api.World => GraphContext)
extends api.DefaultCommand {
override def getSyntax = commandSyntax(
Array(AgentsetType, AgentsetType, CommandBlockType))
def perform(args: Array[Argument], context: Context) {
val turtleSet = args(0).getAgentSet.requireTurtleSet
val linkSet = args(1).getAgentSet.requireLinkSet
val world = linkSet.world
val gc = new GraphContext(world, turtleSet, linkSet)
val extContext = context.asInstanceOf[ExtensionContext]
val nvmContext = extContext.nvmContext
pushGraphContext(gc)
// execute command block here
popGraphContext(world)
}
}
我查看了一些使用 nvmContext.runExclusively
的示例,但看起来它专门用于让给定代理集运行命令 block 。我希望当前代理(可能是观察者)运行它。我应该将 nvm.agent
包装在代理集中并将其传递给 nvmContext.runExclusively
吗?如果是这样,将代理包装在代理集中的最简单方法是什么?如果没有,我该怎么办?
最佳答案
方法#1
更快但可能更脏的方法是使用 runExclusiveJob
,如(例如)https://github.com/NetLogo/Sample-Scala-Extension/blob/master/src/SampleScalaExtension.scala 中的 create-red-turtles
命令所示。 .
要将当前代理包装在代理集中,您可以使用agent.AgentSetBuilder
。 (您也可以将长度为 1 的 Array[Agent]
传递给 ArrayAgentSet
构造函数之一,但我建议使用 AgentSetBuilder
,因为它的长度更短依赖于可能会发生变化的内部实现细节。)
方法#2
方法 #1 的缺点是与创建和设置额外的 AgentSet
、Job
和 Context
对象相关的轻微持续开销并通过它们指导执行。
创建和运行一个单独的作业实际上并不是像 if
和 while
这样的内置命令的工作方式。它们不会创建新作业,而是保留在当前作业中,并通过操纵指令指针 (nvm.Context.ip
) 跳入它们来导致命令 block 中的命令运行(或不运行)或跳过它们。
我相信扩展命令也可以做到这一点。我不确定以前是否尝试过,但我看不出有任何原因它不起作用。
这样做需要更多地了解 NetLogo 引擎内部结构,如 https://github.com/NetLogo/NetLogo/wiki/Engine-architecture 中所述.你会在例如之后建模你的原语https://github.com/NetLogo/NetLogo/blob/5.0.x/src/main/org/nlogo/prim/etc/_if.java ,包括更改 nvm.CustomAssembled
的实现。 (请注意,运行扩展命令的 prim._extern
将其 assemble
方法委托(delegate)给包装命令自己的 assemble
方法,因此这应该有效。 ) 在您的 assemble
方法中,不是在最后调用 done()
来终止作业,您只是允许执行失败。
我可以尝试构建一个以这种方式工作的示例,但这会花费我几个小时;除非有真正的需要,否则我可能不值得这样做。
关于api - 在 NetLogo 扩展中执行原语中的命令 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21395008/