;==================== begin updownhill-in-bounds.nls ===========================
; updownhill-in-bounds - Like uphill/downhill but with boundary constraints.
;   Allows control over step size.
;
; By Rik Blok, 2013 <http://www.zoology.ubc.ca/~rikblok/wiki/doku.php>
;
; This is free and unencumbered software released into the public domain.
;
; Anyone is free to copy, modify, publish, use, compile, sell, or
; distribute this software, either in source code form or as a compiled
; binary, for any purpose, commercial or non-commercial, and by any
; means.
;
; Provides:
;
;   downhill-in-bounds
;     Like downhill but within bounds.
;   downhill4-in-bounds
;     Like downhill4 but within bounds.
;   uphill-in-bounds
;     Like uphill but within bounds.
;   uphill4-in-bounds
;     Like uphill4 but within bounds.
;   towards-downhill-in-bounds
;     Reports heading downhill within bounds.
;   towards-downhill4-in-bounds
;     Reports heading downhill4 within bounds.
;   towards-uphill-in-bounds
;     Reports heading uphill within bounds.
;   towards-uphill4-in-bounds
;     Reports heading uphill4 within bounds.
; 
; Usage:
;
;   ; Set _step-size_ to 0 to behave most like native up/downhill procedures.
;   downhill-in-bounds   task [ _patch-variable_ ]  _step-size_  task [ _is-in-bounds?_ ]
;   downhill4-in-bounds  task [ _patch-variable_ ]  _step-size_  task [ _is-in-bounds?_ ]
;   uphill-in-bounds     task [ _patch-variable_ ]  _step-size_  task [ _is-in-bounds?_ ]
;   uphill4-in-bounds    task [ _patch-variable_ ]  _step-size_  task [ _is-in-bounds?_ ]
;   towards-downhill-in-bounds   task [ _patch-variable_ ]  task [ _is-in-bounds?_ ]
;   towards-downhill4-in-bounds  task [ _patch-variable_ ]  task [ _is-in-bounds?_ ]
;   towards-uphill-in-bounds     task [ _patch-variable_ ]  task [ _is-in-bounds?_ ]
;   towards-uphill4-in-bounds    task [ _patch-variable_ ]  task [ _is-in-bounds?_ ]
;
; Example:
;
;   patches-own [ aroma ]
;   to go
;     ; follow your nose :) but only on green patches
;     uphill-in-bounds  task [ aroma ]  0  task [ pcolor = green ]
;   end
;
; Known limitations:
;
;   2013-08-20 - patch-variable must be passed as a task.  Is there a better way?
;              - _step-size_ > 0 gives different behaviour than uphill/downhill
;              - turtles try head towards center of destination patch. Can get stuck. 
; 
; Revisions:
;
;   2013-08-20 - initial release by Rik Blok
;-------------------------------------------------------------------------------


to downhill-in-bounds 
; Like downhill but only over patches in bounds.
; Parameters:
[ dib-patch-variable ; Patch variable to follow, as a string.
  dib-step-size      ; How far to move.
  dib-is-in-bounds?  ; Is destination patch in bounds?  True/false reporter task.
]
  if dib-step-size = 0 [ move-to patch-here ]  ; go to patch center
  ; find a neighbouring patch in bounds with minimum patch-variable
  let p min-one-of ( neighbors with [ runresult dib-is-in-bounds? ] ) 
                   [ runresult dib-patch-variable ]
  if p = nobody [ stop ]
  if [runresult dib-patch-variable] of p < runresult dib-patch-variable 
  [ face p
    ifelse dib-step-size = 0
    [ move-to p 
    ]
    [ jump dib-step-size 
    ]
  ]
end


to downhill4-in-bounds 
; Like downhill4 but only over patches in bounds.
; Parameters:
[ dib-patch-variable ; Patch variable to follow, as a string.
  dib-step-size      ; How far to move.
  dib-is-in-bounds?  ; Is destination patch in bounds?  True/false reporter task.
]
  if dib-step-size = 0 [ move-to patch-here ]  ; go to patch center
  ; find a neighbouring patch in bounds with minimum patch-variable
  let p min-one-of ( neighbors4 with [ runresult dib-is-in-bounds? ] ) 
                   [ runresult dib-patch-variable ]
  if p = nobody [ stop ]
  if [runresult dib-patch-variable] of p < runresult dib-patch-variable 
  [ face p
    ifelse dib-step-size = 0
    [ move-to p 
    ]
    [ jump dib-step-size 
    ]
  ]
end


to uphill-in-bounds 
; Like uphill but only over patches in bounds.
; Parameters:
[ dib-patch-variable ; Patch variable to follow, as a string.
  dib-step-size      ; How far to move.
  dib-is-in-bounds?  ; Is destination patch in bounds?  True/false reporter task.
]
  if dib-step-size = 0 [ move-to patch-here ]  ; go to patch center
  ; find a neighbouring patch in bounds with maximum patch-variable
  let p max-one-of ( neighbors with [ runresult dib-is-in-bounds? ] ) 
                   [ runresult dib-patch-variable ]
  if p = nobody [ stop ]
  if [runresult dib-patch-variable] of p > runresult dib-patch-variable 
  [ face p
    ifelse dib-step-size = 0
    [ move-to p 
    ]
    [ jump dib-step-size 
    ]
  ]
end


to uphill4-in-bounds 
; Like uphill4 but only over patches in bounds.
; Parameters:
[ dib-patch-variable ; Patch variable to follow, as a string.
  dib-step-size      ; How far to move.
  dib-is-in-bounds?  ; Is destination patch in bounds?  True/false reporter task.
]
  if dib-step-size = 0 [ move-to patch-here ]  ; go to patch center
  ; find a neighbouring patch in bounds with maximum patch-variable
  let p max-one-of ( neighbors4 with [ runresult dib-is-in-bounds? ] ) 
                   [ runresult dib-patch-variable ]
  if p = nobody [ stop ]
  if [runresult dib-patch-variable] of p > runresult dib-patch-variable 
  [ face p
    ifelse dib-step-size = 0
    [ move-to p 
    ]
    [ jump dib-step-size 
    ]
  ]
end


to-report towards-downhill-in-bounds
; Reports the turtle heading (between 0 and 359 degrees) in the direction of the 
; minimum value of the variable patch-variable, of neighboring in-bounds patches. 
; Parameters:
[ dib-patch-variable ; Patch variable to follow, as a string.
  dib-is-in-bounds?  ; Is patch in bounds?  True/false reporter task.
]
  ; find a neighbouring patch in bounds with minimum patch-variable
  let p min-one-of ( neighbors with [ runresult dib-is-in-bounds? ] ) 
                   [ runresult dib-patch-variable ]
  if p = nobody 
  [ report heading ; nobody better
  ]
  ifelse [runresult dib-patch-variable] of p < runresult dib-patch-variable 
  [ report towards p
  ]
  [ report heading ; nobody better
  ]
end


to-report towards-downhill4-in-bounds
; Reports the turtle heading (between 0 and 359 degrees) in the direction of the 
; minimum value of the variable patch-variable, of neighboring in-bounds patches. 
; Parameters:
[ dib-patch-variable ; Patch variable to follow, as a string.
  dib-is-in-bounds?  ; Is patch in bounds?  True/false reporter task.
]
  ; find a neighbouring patch in bounds with minimum patch-variable
  let p min-one-of ( neighbors4 with [ runresult dib-is-in-bounds? ] ) 
                   [ runresult dib-patch-variable ]
  if p = nobody 
  [ report heading ; nobody better
  ]
  ifelse [runresult dib-patch-variable] of p < runresult dib-patch-variable 
  [ report towards p
  ]
  [ report heading ; nobody better
  ]
end


to-report towards-uphill-in-bounds
; Reports the turtle heading (between 0 and 359 degrees) in the direction of the 
; maximum value of the variable patch-variable, of neighboring in-bounds patches. 
; Parameters:
[ dib-patch-variable ; Patch variable to follow, as a string.
  dib-is-in-bounds?  ; Is patch in bounds?  True/false reporter task.
]
  ; find a neighbouring patch in bounds with maximum patch-variable
  let p max-one-of ( neighbors with [ runresult dib-is-in-bounds? ] ) 
                   [ runresult dib-patch-variable ]
  if p = nobody 
  [ report heading ; nobody better
  ]
  ifelse [runresult dib-patch-variable] of p > runresult dib-patch-variable 
  [ report towards p
  ]
  [ report heading ; nobody better
  ]
end


to-report towards-uphill4-in-bounds
; Reports the turtle heading (between 0 and 359 degrees) in the direction of the 
; maximum value of the variable patch-variable, of neighboring in-bounds patches. 
; Parameters:
[ dib-patch-variable ; Patch variable to follow, as a string.
  dib-is-in-bounds?  ; Is patch in bounds?  True/false reporter task.
]
  ; find a neighbouring patch in bounds with maximum patch-variable
  let p max-one-of ( neighbors4 with [ runresult dib-is-in-bounds? ] ) 
                   [ runresult dib-patch-variable ]
  if p = nobody 
  [ report heading ; nobody better
  ]
  ifelse [runresult dib-patch-variable] of p > runresult dib-patch-variable 
  [ report towards p
  ]
  [ report heading ; nobody better
  ]
end


;==================== end updownhill-in-bounds.nls =============================