有没有一种简单的方法来为 netlogo 中的一系列刻度线编码?

Is there a simple way to code for a sequence of multiples of ticks in netlogo?

我如何让模型每 x 刻度减少一个变量,而不是简单地编写一个长列表?似乎应该有一种方法可以使用ticks,例如每 20n ticks 减少变量,其中 n = 1, 2, 3,...,但我想不出它是如何工作的,所以我只是创建了一个列表。

例如,在下面的代码中,我将变量 octopamine-level 每 20 个 ticks 减少 1 个单位,超过 first-leader-tick。

if (ticks - first-leader-tick = 20) or (ticks - first-leader-tick = 40) or (ticks - first-leader-tick = 60) or (ticks - first-leader-tick = 80) or (ticks - first-leader-tick = 100) or (ticks - first-leader-tick = 120) or (ticks - first-leader-tick = 140) or (ticks - first-leader-tick = 160) or (ticks - first-leader-tick = 180)
    [set octopamine-level octopamine-level - 1]

但是,我计划使用一个更大的变量,这将需要一个长得离谱的列表,因此更简洁的方法会非常有帮助。

谢谢!

简单方法#1

您可以在下次需要更新值时使用提醒

globals [
 next-update
 octopamine-level
]

to setup
 clear-all
 reset-ticks
  
 set octopamine-level 10
 type "initial level of octopamine: " print octopamine-level
  
 set next-update "none"     ; This is needed because, otherwise, the first iteration (i.e. where
                            ; 'ticks = 0') would always satisfy the 'if (ticks = next-update)'
                            ; condition. Doing 'set next-update - 1' would work too, depending on
                            ; which approach you find more relevant and/or elegant.
end

to go
; With this first block of commands I'm just randomly choosing the
; initial tick for starting the reduction.
 if (octopamine-level = 10) AND (random 100 < 1) [
  set octopamine-level octopamine-level - 1
  set next-update ticks + 20
    
  type "ticks = " type ticks type ", octopamine = " type octopamine-level print ", reduction started"
]

 if (ticks = next-update) [
  set octopamine-level octopamine-level - 1
  set next-update ticks + 20
    
  type "ticks = " type ticks type ", octopamine = " print octopamine-level
]

 if (octopamine-level = 0) [stop]

 tick
end

简单方法#2

如果您还想更容易地访问关于下一次更新需要多长时间/自上次更新以来已经过了多长时间的信息,您可以创建一个计数器:

globals [
 counter
 counter-on?          ; See comment to in 'to setup'.
 octopamine-level
]

to setup
 clear-all
 reset-ticks

 set octopamine-level 10
 type "initial level of octopamine: " print octopamine-level
 
 set counter "none"
 set counter-on? FALSE     ; This, together with the condition in which it is used, is needed
                           ; because we cannot simply 'set counter "none"', as that will give
                           ; a runtime error when executing 'set counter counter - 1' (and using
                           ; 'if (is-number? counter) [set counter counter - 1]' doesn't look
                           ; very nice to me).
                           ; Note that you could get rid of all the 'counter-on?' thing and just
                           ; do 'set counter -1' upon setup. This would work, but would also
                           ; execute 'set counter counter - 1' at every tick, bringing 'counter'
                           ; to always more negative numbers before the reduction actually starts -
                           ; which I personally don't really like.
end

to go
; With this first block of commands I'm just randomly choosing the
; initial tick for starting the reduction.
 if (octopamine-level = 10) AND (random 100 < 1) [
  set counter-on? TRUE
  set counter 20
  set octopamine-level octopamine-level - 1
  
  type "ticks = " type ticks type ", octopamine = " type octopamine-level print ", reduction started"  
 ]

 if (counter = 0) [
  set octopamine-level octopamine-level - 1
  set counter 20
  
  type "ticks = " type ticks type ", octopamine = " print octopamine-level
 ]

 if (octopamine-level = 0) [stop]

 if (counter-on?) [
   set counter counter - 1 
 ]
  
 tick
end

这种方法的另一个积极方面是,如果需要,它可以很容易地随时暂停和恢复计数器,只需使用 set counter-on? FALSEset counter-on? TRUE.

不太简单的方法

要采用一种看起来更类似于您的思路的方法(但比之前的选项更复杂),这种需求也可以通过使用 remainders 来解决,在 NetLogo 中你确实可以使用 remainder (check here).

您可以使用以下例程每 20 个刻度执行一次命令。

if (remainder ticks 20 = remainder first-leader-tick 20) [
 set octopamine-level octopamine-level - 1
]

总的来说,执行我之前针对其他方法讨论的调整类型,它看起来像:

globals [
 first-leader-tick
 reduction-on?
 octopamine-level
]

to setup
 clear-all
 reset-ticks
  
 set octopamine-level 10
 type "initial level of octopamine: " print octopamine-level
  
 set reduction-on? FALSE
end

to go
; With this first block of commands I'm just randomly choosing the
; initial tick for starting the reduction.
 if (octopamine-level = 10) AND (random 100 < 1) [
  set reduction-on? TRUE
  set first-leader-tick ticks
  set octopamine-level octopamine-level - 1
    
  type "ticks = " type ticks type ", octopamine = " type octopamine-level print ", reduction started"
 ]
  
 if (reduction-on?) AND (ticks > first-leader-tick) AND (remainder ticks 20 = remainder first-leader-tick 20) [
  set octopamine-level octopamine-level - 1
  
  type "ticks = " type ticks type ", octopamine = " print octopamine-level
 ]
  
 if (octopamine-level = 0) [stop]
  
 tick
end

需要(reduction-on?)条件,否则tick 0总是会通过测试(事实上remainder 20 20 = remainder 0 20)。

需要(ticks > first-leader-tick)条件,因为(remainder ticks 20 = remainder first-leader-tick 20)在缩减开始时(即ticks = first-leader-tick时)也为真,这将导致执行两次set octopamine-level octopamine-level - 1在减少开始时打勾(一次在第一个 if 块中,一次在第二个 if 块中)。

或者,如果您愿意,可以通过 :

摆脱 (ticks > first-leader-tick) 条件
  • 从第一个 if 块中删除 set octopamine-level octopamine-level - 1 行;
  • 将第二个 if 块(计算余数的那个)放在第一个 if 块(开始减少的那个)之前。

非常简单,您可以使用 MOD 运算符来完成此操作。

MOD 除法,然后 returns 余数。

这有一个很大的副作用,即总是返回一个介于 0 和比除数小 1 之间的数字。

更简单:ticks MOD 20 总是给出 0 到 19 之间的数字。100 mod 20 是 0。119 mod 20 是 19。120 mod 20又归零了。看?整洁,对吧?

所以你可以做

If (ticks - first-leader-tick) mod 20 = 0 [ ;;每 20 个滴答做一次你做的事情。 ]

请注意,这也会使其在第一次执行此操作。所以相应地调整你的逻辑。