Netlogo: How to make a turtle move towards an unique patch target?

I have turtles (patients), and they can only use only one bed each (white patch). Since patients are randomly generated in a waiting room (green patches), sometimes two or more of them get at the same distance and therefore they find the same patch as its target. I tried to add an attribute to the patch with the purpose of assigning that particular bed to a specific patient. The idea is something like this (please indulge on the ugly code, I'm learning :P):

globals [
  waitxmax
  waitxmin
  waitymax
  waitymin
  box
]

breed [ patients patient ]
patients-own [ target ]
patches-own [ assigned ]

to setup-wait-room
  set waitxmax -15
  set waitxmin 15
  set waitymax 11
  set waitymin 15
  ask patches with [
    pxcor >= waitxmax and
    pxcor <= waitxmin and
    pycor >= waitymax and
    pycor <= waitymin
  ] [ set pcolor green ]
end

to setup-beds

  let cmy 7
  let cmx 15
  let dst 3
  let nbox 7

  ask patch cmx cmy [ set pcolor white ]
   
  let i 1
  while [ i < nbox ] [ 
    ask patch (cmx - dst) cmy [ set pcolor white ]
    
    set i i + 1
    set cmx cmx - dst
  ]
  ask patches with [ pcolor = white ] [ set assigned false ]
  
  set box patches with [ pcolor = white ]
end

to setup-patients
  create-patients start-patients [ 
    set shape "person" 
    set target nobody
    move-to one-of patches with [ pcolor = green ] ]
end

to setup [
  clear-all
  setup-wait-room
  setup-beds
  reset-ticks
]

to go
  ask patients [ go-to-bed ]
  tick
end

to go-to-bed
  let _p box with [ self != [ patch-here ] of myself ]

  if target = nobody [
    set target min-one-of _p [ distance myself ]
    ask target [ set assigned myself ]
  ] 
  
  ;;; FIXME
  if ([ assigned ] of target) != self [ show "not true" ]

  if target != nobody [
    face target
    fd 1 
  ]

end

When I print the two sides of the comparison below FIXME, from the command center I actually get the expected result. For example: both patient 0 and patient 1 have the same target (patch -3 7), but that patch is assigned to (patient 0). I would have expected that comparison to force patient 1 to get a new target since the bed doesn't have his name (I haven't written that code yet), but it always evaluates to true. This is more notorious as more patients I add over available beds (if no beds available, they should wait as soon as one gets free).

When inspecting trough the interface I also see that the patch -3 7 says (patient 0), so I don't know what's happening. Command center example:

observer> show [ assigned ] of patch -3 7
observer: (patient 0)
observer> if ([ assigned ] of patch -3 7) = [self] of patient 0  [ show "true" ]
observer: "true"
observer> if ([ assigned ] of patch -3 7) = [self] of patient 1  [ show "true" ]
;;;; SETUP AND GO
(patient 0): (patch -3 7)
(patient 0): (patient 0)
(patient 0): "true"
(patient 2): (patch 12 7)
(patient 2): (patient 2)
(patient 2): "true"
(patient 1): (patch -3 7)
(patient 1): (patient 1)
(patient 1): "true"

Maybe I'm just overthinking this and there are is a simpler way to assign a bed to a patient and vice versa?

Upvotes: 0

Views: 752

Answers (1)

Luke C
Luke C

Reputation: 10291

There seems to be a chunk or two missing from your code above (I can't copy-paste and run it), so please have a look at the option below.

This version works by having a single place to store the 'claimed' beds- in the turtle variable. Since the turtle variables can be queried as a list using of, a bed-less turtle can check if there are any beds that are not already present in that list and, if so, claim one.

turtles-own [ owned-bed ]

to setup
  ca
  ask n-of 5 patches [
    set pcolor green
  ]
  crt 10 [
    set owned-bed nobody
    claim-unclaimed-bed
    if owned-bed != nobody [
      print word "I own the bed " owned-bed
    ]    
  ]
  reset-ticks
end

to claim-unclaimed-bed
  ; If I have no bed
  if owned-bed = nobody [
    ; Pull the current owned beds for comparison
    let all-owned-beds [owned-bed] of turtles
    
    ; Pull those beds that are green AND are not found in 'all-owned-beds'
    let available-beds patches with [ 
      pcolor = green and not member? self all-owned-beds    
    ]
    
    ; If there are any beds available, claim one
    ifelse any? available-beds [
      set owned-bed one-of available-beds
    ] [
      ; If there are none available, print so
      print "There are no available beds."
    ]
  ]  
end

Edit: Forgot the actual question title- to actually move to their owned-bed (if they have one) in the example above, they simply face it and move how you like- for example:

to go
  ask turtles with [ owned-bed != nobody ] [
    ifelse distance owned-bed > 1 [
      face owned-bed
      fd 1
    ] [
      move-to owned-bed
    ]
  ]
  tick
end

Edit: added complexity

Ok, for an added element of severity, you will likely want to avoid using multiple with [ ... = x statements, and instead to use a primitive called min-one-of which returns the agent with the minimum value of some reporter. Then, you want to tell NetLogo to keep asking the next most severe and the next most severe, etc. One way to do this is with a while loop, which basically says "While this condition is met, continue evaluating the following code." Be careful with while loops- if you forget to write your code such that eventually the condition is no longer true, the while loop will just continue running until you will eventually Tools > Halt your model (or, as has happened to me with a large model, NetLogo crashes).

I've reworked the code (much of what was above is unchanged) to include such a while loop. Note as well that, since the model needs to check which beds are available multiple times, I've made that code into a to-report chunk to condense / simplify.

turtles-own [ owned-bed severity ]

to setup
  ca
  ask n-of 5 patches [
    set pcolor green
  ]
  crt 10 [
    set owned-bed nobody
    set severity random-float 10
  ]
  let current-available-beds report-available-beds
  
  while [any? current-available-beds] [
    ; From the turtles with no bed, ask the one with the lowest severity number to 
    ; claim an unclaimed bed. Then, reset the current-available-beds
    ask min-one-of ( turtles with [owned-bed = nobody] ) [ severity ]  [
      claim-unclaimed-bed
      if owned-bed != nobody [
        show ( word "I have a severity of " severity " so I am claiming the bed " owned-bed )
      ]
    ]
    set current-available-beds report-available-beds
  ]
  reset-ticks
end

to-report report-available-beds 
  let all-owned-beds [owned-bed] of turtles
  report patches with [
      pcolor = green and not member? self all-owned-beds
  ]
end

to claim-unclaimed-bed
  ; If I have no bed
  if owned-bed = nobody [
    let available-beds report-available-beds

    ; If there are any beds available, claim one
    ifelse any? available-beds [
      set owned-bed one-of available-beds
    ] [
      ; If there are none available, print so
      print "There are no available beds."
    ]
  ]
end

enter image description here

Upvotes: 2

Related Questions