Search code examples
locationnetlogoshortest-pathpath-finding

Movement of turtles between nodes following the shortest path


I am trying to move my citizens from one node (slocation) to another node (new-location) calculating the shortest path. I could only calculate the distance from slocation to new-location using set total-expected-path [distance [slocation] of myself] of new-location.

However, I am pretty sure that the following line after to set total-expected-path are not correct. I got the following error: this code can't be run by a turtle, only a link error while node 35 running LINK-LENGTH

How can I define this distance calculate in the total-expected-path as the minimum between nodes using the link connection between nodes? and after that, how can I move the turtles following this short path?enter image description here to go set-timekeeper ask citizens [find-day-activities] end

to set-timekeeper
tick 
let counter ticks 
if (counter = 2) 
[set timekeeper 2]
end

to find-day-activities
if (timekeeper = 2) 
[Do_7AM_9AM]
end

to Do_7AM_9AM
if (sex = 0 and age = 1 and employment = 0 and household-size = 0 [move-work]
end

to move-work
to move-work
set slocation min-one-of nodes [distance myself]
let new-location min-one-of nodes [distance one-of workbuildings]
let llocation one-of [link-neighbors with-min [link-length]] of new-location
move-to llocation
end

Solution

  • You may want to use the nw extension to take advantage of the nw:turtles-on-path-to or nw:turtles-on-weighted-path-to primitives. With these extensions and variables:

    extensions [nw]
    breed [ nodes node ]
    breed [ walkers walker ]
    links-own [ weight ]
    

    and this setup:

    to setup-example
      ca
      let xs [ 10 -5 -5 -5 -5 2 ]
      let ys [ 0 0 3 6 9 9 ]
      ( foreach xs ys [
        [ x y ] ->
        ask patch x y [
          sprout-nodes 1 [
            set shape "circle"
            set color white
            set size 2.5
          ]
        ]
      ])
      let ind ( range 0 4 )
      foreach ind [
        i ->
        let x item i xs
        let y item i ys
        let xn item ( i + 1 ) xs
        let yn item ( i + 1 ) ys
        ask nodes-on patch x y [
          create-links-with nodes-on patch xn yn
        ]
      ]
      while [ any? nodes with [ count my-links < 2 ] ] [
        ask one-of nodes with [ count my-links < 2 ] [
          let linkable min-one-of other nodes with [ count my-links < 2 ] [distance myself]
          if linkable != nobody [
            create-link-with linkable
          ]
        ] 
      ]
      ask nodes-on patch -5 0 [ set color green ]
      ask nodes-on patch 2 9 [ set color red ]  
    end
    

    This creates a loop network- pretend that the green is the start node and the red is the destination.

    enter image description here

    Now, using nw:turtles-on-path-to you can identify the nodes in the path that gets to the destination by the fewest links:

    to fewest-links
      let start one-of nodes-on patch -5 0
      let target one-of nodes-on patch 2 9
    
      let path nobody 
      ask start [
        set color green
        set path but-first nw:turtles-on-path-to target
        ask turtle-set path [ set color yellow ]
        ask target [ set color red ]
      ]  
    end
    

    enter image description here

    Or, using link-length as the weight variable in nw:turtles-on-weighted-path-to, you can get the shortest distance:

    to shortest-distance
      let start one-of nodes-on patch -5 0
      let target one-of nodes-on patch 2 9
      ask links [ 
        set weight link-length
      ]
      let path nobody 
      ask start [
        set color green
        set path but-first nw:turtles-on-weighted-path-to target weight
        ask turtle-set path [ set color yellow ]
        ask target [ set color red ]
      ]  
    end
    

    enter image description here

    To actually have your people move along a particular path, you can use a combination of the path identifying code above and foreach. Example setup for that:

    to setup
      ca
      create-nodes 10 [ 
        set shape "circle" 
        set color white 
        set size 2.5
      ]
      layout-circle nodes 10
      while [ any? nodes with [ count my-links < 2 ] ] [
        ask one-of nodes with [ count my-links < 2 ] [
          let linkable min-one-of other nodes with [ count my-links < 2 ] [distance myself]
          if linkable != nobody [
            create-link-with linkable
          ]
        ] 
      ]
      ask one-of nodes [ 
       set color green + 1
       hatch-walkers 1 [
          set color blue
          set size 1.5
        ]
      ] 
      reset-ticks
    end
    

    And the movement itself:

    to go
      ask walkers [
        ; Randomly choose a target node to walk to
        let target one-of nodes with [ color = white ]
        if target != nobody [
          ; Remember the starting node
          let current one-of nodes-here 
          ; Define a path variable from the current node- take all but
          ; the first item (as first item is current node)
          let path nobody
          ask links [ set weight link-length ]
          ask current [ 
            set path but-first nw:turtles-on-weighted-path-to target weight
          ]
          ; Indicate the end node
          ask last path [ 
            set color red
            set size 2.5
          ]
          ; Move along the path node-to-node 
          foreach path [
            next-target ->
            face next-target
            move-to next-target
            wait 0.25
            ask next-target [
            set color yellow
            ]
          ]
        ]
        wait 1
        ; Reset
        ask nodes [ set color white ]
        ask one-of nodes-here [ set color green ]
      ]
    end
    

    enter image description here