我正在写一个原语,它接受两个代理集和一个命令块。它需要调用一些函数,在当前上下文中执行命令块,然后调用另一个函数。这是我到目前为止所做的:
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
的示例,但这看起来特别适合让给定的代理程序集运行命令块。我想要当前的代理(可能是观察者)来运行它。我应该将nvm.agent
包裹在代理集中并将其传递给nvmContext.runExclusively
吗?如果是这样,在agentset中包装代理的最简单方法是什么?如果没有,我该怎么办?
答案 0 :(得分:2)
方法#1
更快但可以说更脏的方法是使用runExclusiveJob
,如https://github.com/NetLogo/Sample-Scala-Extension/blob/master/src/SampleScalaExtension.scala中的create-red-turtles
命令所示。
要将当前代理程序包装在代理程序集中,您可以使用agent.AgentSetBuilder
。 (您也可以将长度为Array[Agent]
的{{1}}传递给ArrayAgentSet
构造函数之一,但我建议使用AgentSetBuilder
,因为它较少依赖于可能会发生变化的内部实现细节。)
方法#2
方法#1的缺点是与创建和设置额外的AgentSet
,Job
和Context
对象以及通过它们指示执行相关的轻微不变开销。
创建和运行单独的作业实际上并不是if
和while
等内置命令的工作方式。它们保留在当前作业中,并通过操作指令指针(nvm.Context.ip
)来跳转到它们或跳过它们,从而使命令块中的命令运行(或不运行),而不是创建新作业。 p>
我相信扩展命令也可以这样做。我不确定它是否曾经被尝试过,但我看不出它有什么理由不起作用。
这样做将涉及了解有关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
方法委托给包装命令自己的assemble
方法,因此这应该可行。)在assemble
方法中,改为在结束时调用done()
来终止作业,你只是允许执行失败。
我可以尝试构建一个以这种方式工作的示例,但它需要几个小时;除非有真正的需要,否则我可能不值得去做。