Search code examples
netlogo

Unable to generate multiple 'species' per breed in NetLogo


I'm new to NetLogo and I'm trying to create 2 sub-breeds (denoted by different shapes) within each breed for 2 breeds total (i.e. sharks and fishes). The chunks of code work as expected when ran individually, however, when running both chunks the first sub-breed of the fishes does not seem to initialise in the interface tab. For some reason the initialisation of the shark breed seems to interfere with the initiation of the fishes breed.

Any idea what i'm doing wrong? Code below.

; Create the agents
breed [sharks shark]
breed [fishes fish]

; Create the agents' variables

fishes-own
[
  x0                 
  y0                 
]

globals
[
  species             
  species-f
]

to setup

  ; Always start with this
  clear-all
  reset-ticks

  ; Create sharks and species

  create-sharks N-sharks ; N-sharks is a slider
    [
      set color blue
      
      setxy random-xcor random-ycor 

      set species N-sharks
      ask sharks
        [
          set shape "default"          
          set size 2.5
        ]

      ask sharks with [who >= (species * (1 / 2))]
        [
          set shape "square"          
          set size 2
        ]

      ask sharks with [who < (species * (1 / 6))]
        [
          set shape "star"            
          set size 3
        ]
    ] ; End create sharks and species

  ; Create fishes

  create-fishes N-fishes
    [
      setxy random-xcor random-ycor
      set x0 xcor
      set y0 ycor

      set species-f (N-fishes * species-ratio)    
      ifelse who <= species-f
        [
          set shape "sheep"
          set size 5
        ]
        [
          set shape "cow"
          set size 3
        ]

      set color white

    ] ; End create fishes


end

Solution

  • There seem to be a number of misunderstandings about what code is run when by NetLogo, and what some pieces of code do: when you use create-turtles *number* [*commands*] (or with breeds, as in your case), commands is run once by every turtle being created (first the new turtles are created, then they run the commands in turn).

    That means that every time you use ask sharks within the create-sharks' command block, every new shark will ask all other sharks to set shape and size. For example, if you create 100 sharks, instead of setting the shape and size only once you are doing it 10,000 times (100 * 100).

    So you need to put all those commands out of their respective create-<breed>'s command blocks; for example:

    create-sharks N-sharks [
      set color blue
      setxy random-xcor random-ycor
    ]
    
    ask sharks [
      set size 2.5
    ]
    
    ask sharks with [who >= (species * (1 / 2))] [
      set shape "square"
      set size 2
    ]
    
    ask sharks with [who < (species * (1 / 6))] [
      set shape "star"
      set size 3
    ]
    

    This is still improvable code, but it shows how to achieve exactly the same thing by doing it once and not doing it N-sharks ^ 2 times.

    A better way to do it is to bring those commands back inside the create-<breed>'s command block, but letting each agent carry out the task for itself only. That is, without using ask sharks but using ifelse, so that each shark will check its own condition:

    create-sharks N-sharks [
      set color blue
      setxy random-xcor random-ycor
    
      (ifelse
        who >= (species * (1 / 2))         ; the first condition
          [set shape "square" set size 2]
        who < (species * (1 / 6))          ; the second condition
          [set shape "star" set size 3]
        ; else
          [set size 2.5])
    ]
    

    All of this applies to the other breed too.

    It is generally said that using who is a sign that the code should be improved, but let's not focus on this now.

    You will have noticed that I omitted the part where you set species N-sharks. This is because I think there is another misunderstanding here and it is not clear to me what you wanted to do: species (such as species-f for the other breed) is a global variable. You are basically asking each of the 100 sharks (again, 100 for example) to do the same thing: set the value of a global variable to equal the value of another global variable. In this case, you are asking each shark to set species 100. This seems very unnecessary, especially considering that N-sharks is a slider used for setup and thus probably won't be changed during the simulation (which means that there is probably no need to store the current value of N-sharks as a separate global variable).

    Why are you basing the repartition of your sub-breeds on the value of species? What do you want species to represent? Is it correct for it to be a separate variable from N-sharks? If yes, then it is not clear what is its point; if no, then it can be eliminated.

    You need to make sure that whatever you wanted to do with N-sharks & species, and with N-fishes and species-f, is better reflected in your code.

    Also because I think this is the reason why your first fish sub-breed isn't showing. First of all, what is species-ratio? It is not present in your example, but it seems to be relevant for your question. In any case, if your first fish sub-breed isn't showing, it means that there is no fish who satisfies the condition who <= species-f.

    This doesn't surprise me. who numbers are progressive for turtles: if you create 15 sharks and later you create 10 fish...

    • ... the oldest shark will have who = 0
    • ... the youngest shark will have who = 14
    • ... the oldest fish will have who = 15
    • ... the youngest fish will have who = 24

    As you can see in this example, there is no fish for which who <= N-fishes (where N-fishes = 10). Let alone that in your case you set species-f (N-fishes * species-ratio) and, although you didn't tell what species-ratio is, I imagine it is a value between 0 and 1 - thus making the value of species-f even smaller.