Search code examples
netlogomovepatchcatch-block

Catch nobody for target patch


I want to check if target patches fulfil a condition. If a patch is found that fulfils the condition, then the turtles should move there. If 'nobody' fulfils this condition, then an error message should be printed.

The condition is that a patch should have in radius 10 2 turtles of the same breed.

I try to achieve this with ifelse and nobody. However, at the moment I always get the error message, even though the target variable is not empty (you can check this with the if loop).

breed [ breed1s breed1 ] 
breed [ breed2s breed2 ]

globals [target1 target2]

to setup   
  ca   
  create-breed1s 1000 [
    setxy random-xcor random-ycor 
  ]
  create-breed1s 1000 [
    setxy random-xcor random-ycor
  ] 
end

to go
 ask turtles [
    set target1  ( count turtles in-radius 10 with [breed = breed1s] ) >= 2
    set target2  ( count turtles in-radius 10 with [breed = breed2s] ) >= 2 
    
    new-position   
 ]
end

to new-position
 ifelse target1 != nobody
    [ if (breed = breed1s) [ move-to one-of patches with [ target1 ] ] ]
    [ print "Not enough agents in the neighborhood" ]
 ifelse target2 != nobody
     [ if (breed = breed2s) [ move-to one-of patches with [ target2 ] ] ]
     [ print "Not enough agents in the neighborhood" ]
 
 ; if (breed = breed1s)
 ;   [ move-to one-of patches with [ target1 ] ]
end

A remark to the efficiency of the model: as I want to add turtles later in every tick, target has to be reevaluated in every tick (therefore it is in "go" and not in "setup").

Another question: is there a possibility to do something like [ breed = myself ] instead of [ breed = breed1s ], so I don't have to type the breed for every breed?

Edit: the turtles that move to the target patch should have the same breed that is also addressed in the target patch.


Solution

  • The problem is actually how you are creating target1, not the check as to whether it is nobody. You have:

    set target1  ( count turtles in-radius 10 with [breed = breed1s] ) >= 2
    

    This line first identifies all the nearby turtles with the appropriate breed and counts them. If the count is 2 or higher, then the variable target1 is set to true and to false if the count is 0 or 1. So you are comparing a boolean true or false to nobody (a special type of agent). That will always be a mismatch and therefore print the error.

    Just a note on debugging - when you get this sort of problem, it's always useful to have a print statement for each side of the check just before doing the check. You would have immediately spotted that target1 wasn't what you thought it was.

    Since you are asking to move to one-of the patches, you probably really want to store the available patches that are within 10 distance (I think) and have enough of the right type of turtles. So, you need something like:

    to go
     ask turtles [
        set target1 patches in-radius 10 with [count breed1s-here >= 2]
        set target2 patches in-radius 10 with [count breed2s-here >= 2]
        new-position   
     ]
    end
    

    Then your emptiness test is any?

    to new-position
     ifelse any? target1
        [ move-to one-of target1 ]
        [ print "Not enough agents in the neighborhood" ]
     ifelse any? target2
         [ move-to one-of target2 ]
         [ print "Not enough agents in the neighborhood" ]
    end
    

    Assuming I have correctly interpreted that you want patches within 10 of the asking turtle (as compared to any patch with sufficient turtles within a distance of 10) and all you care about is the number of turtles of its own breed, then:

    to go
     ask turtles [
        let target-breed [breed] of myself
        set targets patches in-radius 10 with [count turtles-here with [breed = target-breed] >= 2]
        new-position   
     ]
    end
    
    to new-position
     ifelse any? targets
        [ move-to one-of targets ]
        [ print "Not enough agents in the neighborhood" ]
    end
    

    On the efficiency, it depends on how many turtles you have. If you have quite a lot of turtles, then asking each to count its own neighbourhood will be expensive. Instead, you could have patchsets for each breed. That is, set up target1 as patches with [count breed1s-here >= 2] at the beginning of the go procedures. Then you can just do:

    to go
      let targets1 patches with [count breed1s-here >= 2]
      let targets2 patches with [count breed2s-here >= 2]
      ask turtles
      [ set targets targets1 in-radius 10
        new-position   
      ]
    end
    

    However, you can no longer use the breed of the turtle and the myself trick to pick the correct patchset. There are ways to get around this (for example, using a list with two items, breed at first position and the patchset as second position) but that's getting well off track for this answer.

    to new-position
     ifelse any? targets
        [ move-to one-of targets ]
        [ print "Not enough agents in the neighborhood" ]
    end