Netlogo: How using the route variable to actually

2019-07-11 04:04发布

问题:

I use two types of turtles, cars and houses. both are randomly positioned. My goal is to get a route for each car starting from a combined route vector, and have each car move and visit every home that has been assigned to it. First i create a route for each car from the combined route vector. I present my code below. But now, im trying make car follow respective route...

globals [ route-vector ]
breed [carr car]
breed [hous housess]
carr-own [ route ]

to setup
clear-all
create-carros
create-casas
make-routes
end

to create-carros
create-carr cars [ set color green ]
ask carr  [
set shape "car"
set size 1.5
setxy random-xcor random-ycor
 ]
end

to create-casas
create-hous house [ set color red ]
ask hous  [
set shape "house"
set size 1.5
setxy random-xcor random-ycor
]
end


to make-routes
set route-vector [ 3 4 5 6 7 0 1 2 0 1 ] ;5 10 15 20 25
let houses sublist route-vector 0 (length route-vector / 2 )
let carlist sublist route-vector (length route-vector / 2 ) (length route-
vector)
ask carr [ set route [] ]
(foreach carlist houses
 [ [the-car the-house] ->
  ask carr with [who = the-car] [ set route lput the-house route ]
 ]
  )
 end

 to go
  ask carr  [
    ;; if at target, choose a new random target
    ;        if distance route = 0
     ;          [ set route one-of route-vector
     ;            face route ]
    ;        ;; move towards target.  once the distance is less than 1,
     ;        ;; use move-to to land exactly on the target.
    ;        ifelse distance route < 1

    ;let mylist [1 2 3]
     ;foreach route
     face route
     fd 1
;print map last filter first route
    ;    face housess 3
     ;    fd 1

     ;    move-to one-of route
     ;    fd 1

      ]
     ; move-to housess 3
       ;fd 1

      ;tick
      end

I want use the route variable to actually move along the path. but I do not know how to inform each car of their respective route and cause them to move to their homes.

I tried to use the go button with only one car

do: ask car 1 [ face route fd 1 but always get the error ("FACE expected input to be an agent but got the list [4 7] instead.") ] end

in this case I wanted to cause car 1 to move first to house 4 and second to house 7, then back to its original position ... I've tried several ways, but I can not find a solution. I tried to do it separately, I chose the first item from the "route" list for each car but I still could not ..

If someone can help me, I really appreciate it. Thank you

回答1:

Using who numbers to index turtles can cause problems- in this case, you'll run into an issue where you can't really dynamically update the list, because hous and carr numbers are based solely on the order of their creation. It's far better to store the turtles directly in a list, if possible. Check out this example using a modified version of your setup:

globals [ route-vector ]
breed [carr car]
breed [hous housess]
breed [spawns spawn]
carr-own [ route route-counter spawn-target target]

to setup
  clear-all
  create-carros
  create-casas
  make-routes
  reset-ticks
end

to create-carros
  create-carr 3 [ set color green ]
  ask carr  [
    set size 1.5
    setxy random-xcor random-ycor

    ; set up a 'route-counter' to act as an index for a car's route
    set route-counter 0
    set target nobody
    set route []    
    pd
  ]

  ; hatch a 'spawn-target' turtle that can be used to return
  ; the carr back to their starting position
  ask carr [    
    hatch 1 [
      set breed spawns
      ht
    ]
    set spawn-target one-of other turtles-here with [ 
      xcor = [xcor] of myself
    ]
  ]
end

to create-casas
  create-hous 5 [ set color red ]
  ask hous  [
    set shape "house"
    set size 1.5
    setxy random-xcor random-ycor
  ]
end

Now, instead of relying on who numbers to index the houses, use a list of the houses directly in your carr routes:

to make-routes
  ; Just use the car-order 
  let car-order [ 0 1 2 0 1 ] 

  ; Create a list of hous directly by sorting them
  let houses sort hous

  ; Your same foreach procedure, but in this case the carr
  ; are storing the house in the list directly to avoid
  ; indexing problems
  ask carr [  ]
  (foreach car-order houses
    [ [the-car the-house] ->
      ask carr with [who = the-car] [ set route lput the-house route ]
    ]
  )
end

Then, the carr can just iterate over their route to select a new target based on the index value of route-counter (with a small break for their spawn-target).

to go 
  ask carr [

    ; If a car has no target, set the target to the
    ; item indexed by 'route-counter'
    if target = nobody [
      set target item route-counter route
    ]

    ; Movement chunk
    face target
    ifelse distance target > 1 [
      fd 1
    ] [ 
      move-to target

      ; Only advance the route counter if the current target
      ; was not the original spawn point
      if target != spawn-target [
        set route-counter route-counter + 1
      ]
      set target nobody

    ]

    ; If the route counter would index outside of the 
    ; list boundaries, reset it to 0
    if route-counter > length route - 1 [
      set route-counter 0
      set target spawn-target
    ]
  ]  

  tick  
end

This is still not super programmatic, as you are relying on your car-order being the same length as the count of your houses, but I'm not sure what you're actually trying to do so maybe it will work.

EDIT

As per your comment- if you must use the who number, you can still use the "spawn target" example to have the turtles return to their starting position- just have it happen after the carr and hous have been spawned. Again, this is definitely not ideal as your model can 'break' if you're not careful with spawn order, number of carr / house, etc.

So, basic setup and create-casas procedures as above, with this as your new create-carros procedure:

to create-carros
  create-carr 3 [ set color green ]
  ask carr  [
    set size 1.5
    setxy random-xcor random-ycor

    ; set up a 'route-counter' to act as an index for a car's route
    set route-counter 0
    set target nobody
    set route []
    pd
  ]
end

Now, your make-routes can contain the spawn target turtles (this example has the out-of-order houses from your comment):

to make-routes
  set route-vector [4 7 6 3 5 0 1 2 0 1]
  let houses sublist route-vector 0 (length route-vector / 2 )
  let carlist sublist route-vector (length route-vector / 2 ) (length route-vector)

  (foreach carlist houses
    [ [the-car the-house] ->
      ask car the-car [ 
        set route lput ( housess the-house ) route 
      ]
    ]
  )

  ; hatch a 'spawn-target' turtle that can be used to return
  ; the carr back to their starting position
  ask carr [
    hatch 1 [
      set breed spawns
      ht
    ]
    set spawn-target one-of other turtles-here with [
      xcor = [xcor] of myself
    ]
  ]
end

Then, the go procedure from above should work without any change.

EDIT 2

A simple way to have your carr stop is to set a logical flag so that only carr that meet a certain criteria will move. Consider this modified car-own and create-carros setup:

carr-own [ route route-counter spawn-target target route-complete? ]

to create-carros
  create-carr 3 [ set color green ]
  ask carr  [
    set size 1.5
    setxy random-xcor random-ycor

    ; set up a 'route-counter' to act as an index for a car's route
    set route-counter 0
    set target nobody
    set route []
    set route-complete? false
    pd
  ]
end

Here, we now have a boolean (logical) variable called route-complete?, which is set to false for all new carr. Now, you can add a line into the go procedure that says "only cars that have route-complete? set to false, do these actions."

to go
  ; ask carr with route-complete set to false
  ask carr with [ not route-complete? ] [

    ; If a car has no target, set the target to the
    ; item indexed by 'route-counter'
    if target = nobody [
      set target item route-counter route
    ]

    face target
    ifelse distance target > 1 [
      fd 1
    ] [
      move-to target

      ; Only advance the route counter if the current target
      ; was not the original spawn point. ADDITIONALLY,
      ; if the target is the starting target, set route-complete?
      ; to true for that carr
      ifelse target != spawn-target [
        set route-counter route-counter + 1
      ] [
        set route-complete? true
      ]
      set target nobody
    ]

    ; If the route counter would index outside of the
    ; list boundaries, reset it to 0
    if route-counter > length route - 1 [
      set route-counter 0
      set target spawn-target
    ]
  ]
  tick
end

You'll notice that there's a modified bit in the move-to chunk where if the carr is moving back to its starting position, it also sets its route-complete? to true, so that the next timegois called, thatcarr` won't move.

Note that you could change that route-complete? to a counter instead of a true/false if you wanted carr to run through their route a set number of times.