在NetLogo扩展中执行原语中的命令块

时间:2014-01-28 01:06:53

标签: api scala netlogo

我正在写一个原语,它接受两个代理集和一个命令块。它需要调用一些函数,在当前上下文中执行命令块,然后调用另一个函数。这是我到目前为止所做的:

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中包装代理的最简单方法是什么?如果没有,我该怎么办?

1 个答案:

答案 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的缺点是与创建和设置额外的AgentSetJobContext对象以及通过它们指示执行相关的轻微不变开销。

创建和运行单独的作业实际上并不是ifwhile等内置命令的工作方式。它们保留在当前作业中,并通过操作指令指针(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()来终止作业,你只是允许执行失败。

我可以尝试构建一个以这种方式工作的示例,但它需要几个小时;除非有真正的需要,否则我可能不值得去做。