Warehouse Simulation

Warehouse Simulation preview image

1 collaborator

Tags

(This model has yet to be categorized with any tags)
Visible to everyone | Changeable by everyone
Model was written in NetLogo 7.0.3 • Viewed 28 times • Downloaded 0 times • Run 0 times
Download the 'Warehouse Simulation' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


WHAT IS IT?

(a general understanding of what the model is trying to show or explain)

HOW IT WORKS

(what rules the agents use to create the overall behavior of the model)

HOW TO USE IT

(how to use the model, including a description of each of the items in the Interface tab)

THINGS TO NOTICE

(suggested things for the user to notice while running the model)

THINGS TO TRY

(suggested things for the user to try to do (move sliders, switches, etc.) with the model)

EXTENDING THE MODEL

(suggested things to add or change in the Code tab to make the model more complicated, detailed, accurate, etc.)

NETLOGO FEATURES

(interesting or unusual features of NetLogo that the model uses, particularly in the Code tab; or where workarounds were needed for missing features)

RELATED MODELS

(models in the NetLogo Models Library and elsewhere which are of related interest)

CREDITS AND REFERENCES

(a reference to the model's URL on the web if it has one, as well as any other necessary credits, citations, and links)

Comments and Questions

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

; ==========================================================
; SORTATION WAREHOUSE (NETLOGO WEB SAFE) + CONGESTION METRICS
; ----------------------------------------------------------
; Inbound trucks  = RED   (unload pallets into BLUE zone)   [finite supply]
; Transfer cars   = GREY  (move pallets BLUE -> READY)
; Humans          = PINK  (assist sorting, stay in BLUE normally)
; Outbound carriers = GREEN (move pallets READY -> OUTFEED doors)
;
; Collisions can happen on FLOOR corridors (if enabled).
; Broken vehicles are towed by BUGs to SERVICE for repair.
; Dead vehicles (battery = 0) are towed by TURTLES to CHARGE to revive.
; After charge/repair, vehicles RESUME their jobs (restore-vehicle-job).
;
; NOTE:
; - NetLogo Web: do plots in Interface (not via code).
; - Congestion metrics go into globals:
;     mean-blocked-now, max-blocked-now
; ==========================================================

; ---------------------------
; BREEDS
; ---------------------------
breed [inbound-trucks inbound-truck]
breed [carriers carrier]
breed [transfer-cars transfer-car]
breed [humans human]
breed [repair-tows repair-tow]
breed [charge-tows charge-tow]

; ---------------------------
; GLOBAL STATE
; ---------------------------
globals [
  deliveries

  toilet-zone
  door-spacing
  ready-zone-color

  ; congestion monitors
  mean-blocked-now
  max-blocked-now

  infeed-bays
  outfeed-bays

  blue-zone
  ready-zone

  
  last-mouse-down?
  last-mouse-patch

  service-stations
  charge-stations
  charge-lot

  broken-queue
  dead-queue

  target-reached?
  shutdown-tick

  initial-pallets
  deliveries-log

  ; --- publish / diagnostics metrics
  pallet-births
  lead-times
  lead-window

  moved-by-humans
  moved-by-transfer

  
 
]

; ---------------------------
; PATCH STATE
; ---------------------------
patches-own [
  celltype
  wall?
  items
  ready?
]

; ---------------------------
; TURTLE STATE
; ---------------------------
turtles-own [
  mstate
  goal-patch
  path
  reserved-next
  blocked-steps

  battery
  service-left
  charge-left

  carry?
  work-left
]

repair-tows-own [
  tstate
  target-truck
  goal2
  path2
  blocked2
]

charge-tows-own [
  tstate
  target-truck
  goal2
  path2
  blocked2
]

; ==========================================================
; SETUP
; ==========================================================

to setup
  clear-all

  set door-spacing 2
  set ready-zone-color violet
  set deliveries 0

  set broken-queue []
  set dead-queue []

  set target-reached? false
  set shutdown-tick -1

  set deliveries-log []

  ; --- publish diagnostics
  set pallet-births []
  set lead-times []
  set lead-window 200
  set moved-by-humans 0
  set moved-by-transfer 0

  ; --- reproducibility (optional)
  if not is-boolean? use-fixed-seed? [ set use-fixed-seed? false ]
  if not is-number? seed [ set seed 12345 ]
  if use-fixed-seed? [ random-seed seed ]

  ; --- slider safety
  if not is-number? robot-speed            [ set robot-speed 2 ]
  if robot-speed <= 0                      [ set robot-speed 2 ]

  if not is-number? collision-prob         [ set collision-prob 0.01 ]
  if collision-prob < 0                    [ set collision-prob 0.01 ]

  if not is-number? max-ticks              [ set max-ticks 0 ]
  if max-ticks < 0                         [ set max-ticks 0 ]

  if not is-number? battery-max            [ set battery-max 2000 ]
  if battery-max <= 0                      [ set battery-max 2000 ]

  if not is-number? battery-drain-per-tick [ set battery-drain-per-tick 2 ]
  if battery-drain-per-tick < 0            [ set battery-drain-per-tick 2 ]

  if not is-number? charge-time            [ set charge-time 25 ]
  if charge-time <= 0                      [ set charge-time 25 ]

  if not is-number? service-time           [ set service-time 35 ]
  if service-time <= 0                     [ set service-time 35 ]

  if not is-number? sort-time              [ set sort-time 2 ]
  if sort-time <= 0                        [ set sort-time 2 ]

  if not is-number? inbound-unload-time    [ set inbound-unload-time 3 ]
  if inbound-unload-time <= 0              [ set inbound-unload-time 3 ]

  if not is-number? max-items-per-patch    [ set max-items-per-patch 6 ]
  if max-items-per-patch <= 0              [ set max-items-per-patch 6 ]

  if not is-number? inbound-pallets-left   [ set inbound-pallets-left 500 ]
  if inbound-pallets-left < 0              [ set inbound-pallets-left 500 ]

  set initial-pallets inbound-pallets-left

  if not is-number? deliveries-target      [ set deliveries-target 0 ]
  if deliveries-target < 0                 [ set deliveries-target 0 ]
  if deliveries-target > initial-pallets   [ set deliveries-target initial-pallets ]

  if not is-number? target-loss-count      [ set target-loss-count 4 ]
  if target-loss-count < 0                 [ set target-loss-count 0 ]

  if not is-boolean? enable-battery?       [ set enable-battery? true ]
  if not is-boolean? enable-collisions?    [ set enable-collisions? true ]

  if not is-string? mouse-tool             [ set mouse-tool "none" ]
  set last-mouse-down? false
  set last-mouse-patch nobody

  if not is-number? num-inbound-trucks     [ set num-inbound-trucks 10 ]
  if num-inbound-trucks < 0                [ set num-inbound-trucks 0 ]

  if not is-number? num-carriers           [ set num-carriers 14 ]
  if num-carriers < 0                      [ set num-carriers 0 ]

  if not is-number? num-transfer-cars      [ set num-transfer-cars 6 ]
  if num-transfer-cars < 0                 [ set num-transfer-cars 0 ]

  if not is-number? num-humans             [ set num-humans 8 ]
  if num-humans < 0                        [ set num-humans 0 ]

  if not is-number? num-repair-tows        [ set num-repair-tows 1 ]
  if num-repair-tows < 0                   [ set num-repair-tows 0 ]

  if not is-number? num-charge-tows        [ set num-charge-tows 2 ]
  if num-charge-tows < 0                   [ set num-charge-tows 0 ]

  setup-layout
  setup-agents

  set mean-blocked-now 0
  set max-blocked-now 0

  reset-ticks
end 

; ==========================================================
; MAIN LOOP
; ==========================================================

to go
  if (max-ticks > 0) and (ticks >= max-ticks) [ stop ]

  if not enable-battery? [
    ask (turtle-set inbound-trucks carriers transfer-cars) [
      set battery battery-max
    ]
  ]

  handle-mouse
  service-and-charge-timers

  inbound-logic
  human-sorting-logic
  transfer-logic
  carrier-logic

  plan-all-vehicle-steps
  resolve-collisions
  move-all-vehicles

  move-repair-tows
  move-charge-tows

  ask (turtle-set inbound-trucks carriers transfer-cars) [
    update-vehicle-appearance
  ]

  update-monitors

  set deliveries-log lput deliveries deliveries-log
  if length deliveries-log > 51 [ set deliveries-log but-first deliveries-log ]

  if system-done? [
    if not target-reached? [
      set target-reached? true
      set shutdown-tick ticks
      finish-and-shutdown
    ]

    let vehicles (turtle-set inbound-trucks carriers transfer-cars)
    if (not any? vehicles with [not member? mstate ["charging" "parked"]]) and
       (not any? humans with [mstate != "resting"])
    [
      stop
    ]
  ]

  tick
end 

to-report target-met?
  let eff-target effective-delivery-target
  report (eff-target > 0 and deliveries >= eff-target)
end 

to-report system-drained?
  if inbound-pallets-left > 0 [ report false ]
  if any? blue-zone with [items > 0] [ report false ]
  if any? ready-zone with [items > 0] [ report false ]
  if any? (turtle-set inbound-trucks carriers transfer-cars) with [carry?] [ report false ]
  report true
end 

; ==========================================================
; INTERACTIVE MOUSE HANDLER
; ==========================================================

to handle-mouse
  if not mouse-down? [
    set last-mouse-down? false
    set last-mouse-patch nobody
  ]

  if mouse-down? [
    let p patch mouse-xcor mouse-ycor
    if p != nobody [
      if (not last-mouse-down?) or (p != last-mouse-patch) [
        set last-mouse-down? true
        set last-mouse-patch p

        if mouse-tool = "toggle-wall" [
          ask p [
            if not (pxcor = min-pxcor or pxcor = max-pxcor or
                    pycor = min-pycor or pycor = max-pycor) [
              if celltype = "floor" [
                set wall? true
                set celltype "wall"
                set pcolor gray
              ]
              if celltype = "wall" [
                set wall? false
                set celltype "floor"
                set pcolor 7
              ]
            ]
          ]
        ]

        if mouse-tool = "add-items-blue" [
          if [celltype] of p = "blue" [
            ask p [ set items min list max-items-per-patch (items + 1) ]
          ]
        ]

        if mouse-tool = "remove-items" [
          ask p [ set items max list 0 (items - 1) ]
        ]

        if mouse-tool = "add-inbound" [
          if (not [wall?] of p) and not any? turtles-on p [
            create-inbound-trucks 1 [
              init-vehicle "to-infeed"
              safe-move-to p
              update-vehicle-appearance
            ]
          ]
        ]

        if mouse-tool = "add-transfer" [
          if (not [wall?] of p) and not any? turtles-on p [
            create-transfer-cars 1 [
              init-vehicle "idle"
              set shape "car"
              set color gray
              set label "T"
              safe-move-to p
              update-vehicle-appearance
            ]
          ]
        ]

        if mouse-tool = "add-carrier" [
          if (not [wall?] of p) and not any? turtles-on p [
            create-carriers 1 [
              init-vehicle "idle"
              safe-move-to p
              update-vehicle-appearance
            ]
          ]
        ]

        let v one-of (turtle-set inbound-trucks carriers transfer-cars) with [patch-here = p]
        if v != nobody [
          if mouse-tool = "break-vehicle" [
            ask v [ become-broken update-vehicle-appearance ]
          ]

          if mouse-tool = "kill-battery" [
            ask v [
              if enable-battery? [
                set battery 0
                become-dead
                update-vehicle-appearance
              ]
            ]
          ]

          if mouse-tool = "repair-now" [
            ask v [
              set mstate "servicing"
              set service-left 1
            ]
          ]

          if mouse-tool = "charge-now" [
            ask v [
              set mstate "charging"
              set charge-left 1
              set battery battery-max
            ]
          ]
        ]
      ]
    ]
  ]
end 

; ==========================================================
; LAYOUT
; ==========================================================

to setup-layout
  ask patches [
    set celltype "floor"
    set pcolor 7
    set wall? false
    set items 0
    set ready? false
    set plabel ""
  ]

  ask patches with [
    pxcor = min-pxcor or pxcor = max-pxcor or
    pycor = min-pycor or pycor = max-pycor
  ] [
    set wall? true
    set celltype "wall"
    set pcolor gray
  ]

  set infeed-bays patches with [
    pxcor = min-pxcor + 1 and (pycor mod door-spacing = 0) and not wall?
  ]
  set outfeed-bays patches with [
    pxcor = max-pxcor - 1 and (pycor mod door-spacing = 0) and not wall?
  ]
  ask infeed-bays  [ set celltype "infeed"  set pcolor red   ]
  ask outfeed-bays [ set celltype "outfeed" set pcolor green ]

  set blue-zone patches with [
    pxcor >= -10 and pxcor <= -2 and
    pycor >= -8  and pycor <= 8 and
    celltype = "floor" and not wall?
  ]
  ask blue-zone [ set celltype "blue" set pcolor blue ]

  set ready-zone patches with [
    pxcor >= 3 and pxcor <= 11 and
    pycor >= -8 and pycor <= 8 and
    celltype = "floor" and not wall?
  ]
  ask ready-zone [ set celltype "ready" set pcolor ready-zone-color ]

  let zoneH 4
  let bottom-y1 (min-pycor + 2)
  let bottom-y2 (bottom-y1 + zoneH - 1)

  let zoneW 5
  let gapW 2
  let tripleW (3 * zoneW + 2 * gapW)

  let centerX round ((min-pxcor + max-pxcor) / 2)
  let leftX (centerX - int (tripleW / 2))

  let sL leftX
  let sR (sL + zoneW - 1)

  let tL (sR + gapW + 1)
  let tR (tL + zoneW - 1)

  let cL (tR + gapW + 1)
  let cR (cL + zoneW - 1)

  set service-stations patches with [
    pxcor >= sL and pxcor <= sR and
    pycor >= bottom-y1 and pycor <= bottom-y2 and
    celltype = "floor" and not wall? and
    pxcor != (min-pxcor + 1) and pxcor != (max-pxcor - 1)
  ]
  ask service-stations [
    set celltype "service"
    set pcolor orange
  ]

  set toilet-zone patches with [
    pxcor >= tL and pxcor <= tR and
    pycor >= bottom-y1 and pycor <= bottom-y2 and
    celltype = "floor" and not wall? and
    pxcor != (min-pxcor + 1) and pxcor != (max-pxcor - 1)
  ]
  ask toilet-zone [
    set celltype "rest"
    set pcolor 25
  ]

  set charge-stations patches with [
    pxcor >= cL and pxcor <= cR and
    pycor >= bottom-y1 and pycor <= bottom-y2 and
    celltype = "floor" and not wall? and
    pxcor != (min-pxcor + 1) and pxcor != (max-pxcor - 1)
  ]
  ask charge-stations [
    set celltype "charge"
    set pcolor yellow
  ]

  let parkH 3
  let top-y2 (max-pycor - 2)
  let top-y1 (top-y2 - parkH - 1 + 1)

  set charge-lot patches with [
    pxcor >= (centerX - 4) and pxcor <= (centerX + 4) and
    pycor >= top-y1 and pycor <= top-y2 and
    celltype = "floor" and not wall?
  ]
  ask charge-lot [
    set celltype "charge-lot"
    set pcolor 53
  ]

  label-doors-and-zones
end 

to label-doors-and-zones
  ask patches [ set plabel "" ]

  let inlist sort-by [[a b] -> [pycor] of a < [pycor] of b] (sort infeed-bays)
  let n 1
  foreach inlist [p ->
    ask p [ set plabel (word "IN" n) set plabel-color white ]
    set n n + 1
  ]

  let outlist sort-by [[a b] -> [pycor] of a < [pycor] of b] (sort outfeed-bays)
  set n 1
  foreach outlist [p ->
    ask p [ set plabel (word "OUT" n) set plabel-color white ]
    set n n + 1
  ]

  if any? blue-zone [
    let bx round mean [pxcor] of blue-zone
    let by max [pycor] of blue-zone
    ask patch bx by [ set plabel "BLUE" set plabel-color white ]
  ]

  if any? ready-zone [
    let rx round mean [pxcor] of ready-zone
    let ry max [pycor] of ready-zone
    ask patch rx ry [ set plabel "READY" set plabel-color white ]
  ]

  if any? service-stations [
    let sx round mean [pxcor] of service-stations
    let sy max [pycor] of service-stations
    ask patch sx sy [ set plabel "SERVICE" set plabel-color white ]
  ]

  if any? charge-stations [
    let cx round mean [pxcor] of charge-stations
    let cy max [pycor] of charge-stations
    ask patch cx cy [ set plabel "CHARGE" set plabel-color black ]
  ]

  if any? charge-lot [
    let px round mean [pxcor] of charge-lot
    let py min [pycor] of charge-lot + 1
    ask patch px py [ set plabel "PARK" set plabel-color black ]
  ]

  if any? toilet-zone [
    let tx round mean [pxcor] of toilet-zone
    let ty max [pycor] of toilet-zone
    ask patch tx ty [ set plabel "REST AREA" set plabel-color white ]
  ]
end 

; ==========================================================
; AGENT CREATION
; ==========================================================

to setup-agents
  create-inbound-trucks num-inbound-trucks [
    init-vehicle "to-infeed"
    safe-move-to (safe-one-of-patches (patches with [celltype = "floor" and not wall? and not any? turtles-here]))
    update-vehicle-appearance
  ]

  create-carriers num-carriers [
    init-vehicle "idle"
    safe-move-to (safe-one-of-patches (patches with [celltype = "floor" and not wall? and not any? turtles-here]))
    update-vehicle-appearance
  ]

  create-transfer-cars num-transfer-cars [
    init-vehicle "idle"
    set shape "car"
    set color gray
    set label "T"
    safe-move-to (safe-one-of-patches (patches with [celltype = "floor" and not wall? and not any? turtles-here]))
    update-vehicle-appearance
  ]

  create-humans num-humans [
    set size 1.1
    set shape "person"
    set color pink
    set label ""
    set mstate "sorting"
    set goal-patch nobody
    set path []
    set reserved-next nobody
    set blocked-steps 0
    set carry? false
    set work-left 0
    safe-move-to (safe-one-of-patches (blue-zone with [not any? turtles-here]))
  ]

  create-repair-tows num-repair-tows [
    set size 1.0
    set shape "bug"
    set color red
    set label "S"
    set tstate "idle"
    set target-truck nobody
    set goal2 nobody
    set path2 []
    set blocked2 0
    safe-move-to (safe-one-of-patches service-stations)
  ]

  create-charge-tows num-charge-tows [
    set size 1.0
    set shape "turtle"
    set color violet
    set label "C"
    set tstate "idle"
    set target-truck nobody
    set goal2 nobody
    set path2 []
    set blocked2 0
    safe-move-to (safe-one-of-patches charge-stations)
  ]
end 

to init-vehicle [initial-state]
  set size 1.2
  set mstate initial-state
  set goal-patch nobody
  set path []
  set reserved-next nobody
  set blocked-steps 0
  set battery battery-max
  set service-left 0
  set charge-left 0
  set carry? false
  set work-left 0
end 

; ==========================================================
; BATTERY POLICY
; ==========================================================

to-report low-battery?
  report enable-battery? and (battery <= (0.15 * battery-max))
end 

to maybe-go-charge
  if not enable-battery? [ stop ]
  if member? mstate ["charging" "to-charge-home" "towed-to-charge" "dead" "broken" "servicing" "parked"] [ stop ]
  if not low-battery? [ stop ]
  let c safe-one-of-patches charge-stations
  if c != nobody [
    set goal-patch c
    set path find-path patch-here goal-patch
    set mstate "to-charge-home"
  ]
end 

; ==========================================================
; INBOUND LOGIC
; ==========================================================

to inbound-logic
  ask inbound-trucks [
    if is-stopped-vehicle? self [ stop ]
    if enable-battery? and battery <= 0 [ become-dead stop ]

    maybe-go-charge
    if mstate = "to-charge-home" [
      if goal-patch != nobody and patch-here = goal-patch [
        set mstate "charging"
        set charge-left charge-time
      ]
      stop
    ]

    if inbound-pallets-left <= 0 [
      set mstate "idle"
      set goal-patch nobody
      set path []
      stop
    ]

    if mstate = "to-infeed" [
      let door safe-one-of-patches infeed-bays
      if door != nobody [
        set goal-patch door
        set path find-path patch-here goal-patch
        set mstate "to-infeed-driving"
      ]
      stop
    ]

    if mstate = "to-infeed-driving" [
      if patch-here = goal-patch [
        let b safe-one-of-patches blue-zone
        if b != nobody [
          set goal-patch b
          set path find-path patch-here goal-patch
          set mstate "to-blue"
        ]
      ]
      stop
    ]

    if mstate = "to-blue" [
      if patch-here = goal-patch [
        set mstate "unloading"
        set work-left inbound-unload-time
      ]
      stop
    ]

    if mstate = "unloading" [
      set work-left work-left - 1
      if work-left <= 0 [
        if inbound-pallets-left > 0 [

          
          ifelse [items] of patch-here < max-items-per-patch [

            ask patch-here [
              set items items + 1
              set ready? false
              set pcolor blue
            ]

            set pallet-births lput ticks pallet-births
            set inbound-pallets-left inbound-pallets-left - 1

            set mstate "to-infeed"
            set goal-patch nobody
            set path []

          ] [

            let b safe-one-of-patches (blue-zone with [items < max-items-per-patch])
            ifelse b != nobody [
              set goal-patch b
              set path find-path patch-here goal-patch
              set mstate "to-blue"
            ] [
              ; wait and retry soon
              set work-left 1
            ]

          ]
        ]

        if inbound-pallets-left <= 0 [
          set mstate "idle"
          set goal-patch nobody
          set path []
        ]
      ]
      stop
    ]
  ]
end 
; ==========================================================
; HUMANS: sort BLUE -> READY, rest when done
; ==========================================================

to human-sorting-logic
  ask humans [
    if mstate = "resting" [ stop ]

    ; --- Sorting countdown (when carrying a pallet)
    if work-left > 0 [
      set work-left work-left - 1
      if work-left <= 0 [
        if carry? [
          let readyspot safe-one-of-patches (ready-zone with [items < max-items-per-patch])
          if readyspot != nobody [
            let before [items] of readyspot
            ask readyspot [
              if items < max-items-per-patch [
                set items items + 1
                set ready? true
                set pcolor 45
              ]
            ]
            if [items] of readyspot > before [
              set carry? false
              set moved-by-humans moved-by-humans + 1
            ]
          ]
        ]
      ]
      stop
    ]

    ; --- Finished sorting but READY was full -> keep trying to drop (do NOT re-sort)
    if carry? and work-left <= 0 [
      let readyspot safe-one-of-patches (ready-zone with [items < max-items-per-patch])
      if readyspot != nobody [
        let before [items] of readyspot
        ask readyspot [
          if items < max-items-per-patch [
            set items items + 1
            set ready? true
            set pcolor 45
          ]
        ]
        if [items] of readyspot > before [
          set carry? false
          set moved-by-humans moved-by-humans + 1
        ]
      ]
      stop
    ]

    ; --- Resting logic (target reached)
    if deliveries-target > 0
       and deliveries >= effective-delivery-target
       and work-left <= 0
       and not carry? [

      if [celltype] of patch-here = "rest" [
        set mstate "resting"
        stop
      ]

      let t safe-one-of-patches toilet-zone
      if t != nobody [
        set goal-patch t
        set path find-path patch-here goal-patch
        step-along-path-safe
      ]

      if [celltype] of patch-here = "rest" [
        set mstate "resting"
      ]
      stop
    ]

    ; --- Resting logic (system done)
    if system-done? and work-left <= 0 and not carry? [
      if [celltype] of patch-here != "rest" [
        let t safe-one-of-patches toilet-zone
        if t != nobody [ safe-move-to t ]
      ]
      set mstate "resting"
      stop
    ]

    ; --- Keep humans in BLUE zone
    if [celltype] of patch-here != "blue" [
      let b safe-one-of-patches (blue-zone with [not any? turtles-here])
      if b != nobody [ safe-move-to b ]
      stop
    ]

    ; --- Yield to a transfer-car that is about to enter this patch
    let blocker one-of transfer-cars with [
      mstate = "to-blue" and not empty? path and first path = [patch-here] of myself
    ]
    if blocker != nobody [
      let opts neighbors with [celltype = "blue" and not any? turtles-here]
      if any? opts [
        let dest max-one-of opts [distance blocker]
        safe-move-to dest
      ]
      stop
    ]

    ; --- Pick from BLUE and start sorting
    if not carry? [
      let src safe-one-of-patches (blue-zone with [items > 0])
      if src != nobody [
        set goal-patch src
        set path find-path patch-here goal-patch
        step-along-path-safe

        if patch-here = goal-patch [
          ask patch-here [
            set items items - 1
            if items < 0 [ set items 0 ]
          ]
          set carry? true
          set work-left sort-time
        ]
      ]
      stop
    ]
  ]
end 

; ==========================================================
; TRANSFER CARS: BLUE -> READY
; ==========================================================

to transfer-logic
  ask transfer-cars [
    if is-stopped-vehicle? self [ stop ]
    if enable-battery? and battery <= 0 [ become-dead stop ]

    maybe-go-charge
    if mstate = "to-charge-home" [
      if goal-patch != nobody and patch-here = goal-patch [
        set mstate "charging"
        set charge-left charge-time
      ]
      stop
    ]

    if mstate = "idle" [
      let src safe-one-of-patches (blue-zone with [items > 0])
      if src != nobody [
        set goal-patch src
        set path find-path patch-here goal-patch
        set mstate "to-blue"
      ]
      stop
    ]

    if mstate = "to-blue" [
      if patch-here = goal-patch [
        let dst safe-one-of-patches (ready-zone with [items < max-items-per-patch])

        ifelse (dst != nobody) and ([items] of patch-here > 0) [
          ask patch-here [
            set items items - 1
            if items < 0 [ set items 0 ]
          ]
          set carry? true
          set goal-patch dst
          set path find-path patch-here goal-patch
          set mstate "to-ready"
        ] [
          set carry? false
          set mstate "idle"
          set goal-patch nobody
          set path []
        ]
      ]
      stop
    ]

    if mstate = "to-ready" [
      if goal-patch = nobody [
        set mstate "idle"
        set goal-patch nobody
        set path []
        stop
      ]

      if patch-here = goal-patch [
        ifelse carry? [

          ; ✅ FIX: this must be IFELSE (no standalone ELSE in NetLogo)
          ifelse [items] of patch-here < max-items-per-patch [
            ask patch-here [
              set items items + 1
              set ready? true
              set pcolor 45
            ]
            set carry? false
            set moved-by-transfer moved-by-transfer + 1
          ] [
            let dst2 safe-one-of-patches (ready-zone with [items < max-items-per-patch])
            ifelse dst2 != nobody [
              set goal-patch dst2
              set path find-path patch-here goal-patch
            ] [
              set path []
            ]
          ]

          set mstate "idle"
          set goal-patch nobody
          set path []

        ] [

          set mstate "idle"
          set goal-patch nobody
          set path []

        ]
      ]
      stop
    ]
  ]
end 

; ==========================================================
; CARRIERS: READY -> OUTFEED
; ==========================================================

to carrier-logic
  ask carriers [
    if is-stopped-vehicle? self [ stop ]
    if enable-battery? and battery <= 0 [ become-dead stop ]

    maybe-go-charge
    if mstate = "to-charge-home" [
      if goal-patch != nobody and patch-here = goal-patch [
        set mstate "charging"
        set charge-left charge-time
      ]
      stop
    ]

    if mstate = "idle" [
      let src safe-one-of-patches (ready-zone with [items > 0])
      if src != nobody [
        set goal-patch src
        set path find-path patch-here goal-patch
        set mstate "to-ready"
      ]
      stop
    ]

    if mstate = "to-ready" [
      if goal-patch = nobody [ set mstate "idle" set path [] stop ]
      if patch-here = goal-patch [
        ifelse [items] of patch-here > 0 [
          ask patch-here [
            set items items - 1
            if items <= 0 [
              set items 0
              set ready? false
              set pcolor ready-zone-color
            ]
          ]
          set carry? true
          let out safe-one-of-patches outfeed-bays
          ifelse out != nobody [
            set goal-patch out
            set path find-path patch-here goal-patch
            set mstate "to-outfeed"
          ] [
            set carry? false
            set mstate "idle"
            set goal-patch nobody
            set path []
          ]
        ] [
          set mstate "idle"
          set goal-patch nobody
          set path []
        ]
      ]
      stop
    ]

    if mstate = "to-outfeed" [
      if goal-patch = nobody [ set mstate "idle" set path [] stop ]
      if patch-here = goal-patch [
        if carry? [
          set deliveries deliveries + 1
          if not empty? pallet-births [
            let birth first pallet-births
            set pallet-births but-first pallet-births
            set lead-times lput (ticks - birth) lead-times
            if length lead-times > lead-window [ set lead-times but-first lead-times ]
          ]
          set carry? false
        ]
        set mstate "idle"
        set goal-patch nobody
        set path []
      ]
      stop
    ]
  ]
end 

; ==========================================================
; TARGET CLAMP
; ==========================================================

to-report effective-delivery-target
  if deliveries-target <= 0 [ report 0 ]

  let max-target initial-pallets - target-loss-count
  if max-target < 0 [ set max-target 0 ]

  if deliveries-target > max-target [ report max-target ]
  report deliveries-target
end 

; ==========================================================
; MOVE + COLLISION
; ==========================================================

to plan-all-vehicle-steps
  ask (turtle-set inbound-trucks carriers transfer-cars) [
    set reserved-next nobody
    if is-stopped-vehicle? self [ stop ]
    if (path = nobody) or empty? path [ stop ]
    let nxt first path
    if (nxt = nobody) or (not is-patch? nxt) [ set path [] stop ]
    set reserved-next nxt
  ]
end 

to resolve-collisions
  if system-done? [ stop ]
  if not enable-collisions? [ stop ]

  let movers (turtle-set inbound-trucks carriers transfer-cars)
  let targets [reserved-next] of movers with [reserved-next != nobody and is-patch? reserved-next]
  if empty? targets [ stop ]

  let contested remove-duplicates filter [pp -> (occurrences pp targets) > 1] targets

  foreach contested [pp ->
    ifelse ([celltype] of pp = "floor") [
      let group movers with [reserved-next = pp]
      if any? group [
        ifelse (random-float 1 < collision-prob) [
          ask one-of group [ become-broken ]
          ask group [ set reserved-next nobody ]
        ] [
          let winner one-of group
          ask group with [self != winner] [ set reserved-next nobody ]
        ]
      ]
    ] [
      let group2 movers with [reserved-next = pp]
      if any? group2 [
        let winner2 one-of group2
        ask group2 with [self != winner2] [ set reserved-next nobody ]
      ]
    ]
  ]
end 

to move-all-vehicles
  ask (turtle-set inbound-trucks carriers transfer-cars) [
    if is-stopped-vehicle? self [ stop ]

    let moved? false

    repeat robot-speed [
      if enable-battery? and (battery <= 0) [ become-dead stop ]

      if reserved-next != nobody [
        if not is-patch? reserved-next [
          set reserved-next nobody
          set path []
          stop
        ]

        ifelse (not [wall?] of reserved-next) and (not any? turtles-on reserved-next) [
          safe-move-to reserved-next
          set moved? true
          if not empty? path [ set path but-first path ]
          set blocked-steps 0
        ] [
          set blocked-steps blocked-steps + 1
          let side safe-one-of-patches (neighbors4 with [not wall? and not any? turtles-here])
          if side != nobody [
            safe-move-to side
            set moved? true
          ]
          if blocked-steps > 10 and goal-patch != nobody [
            set path find-path patch-here goal-patch
            set blocked-steps 0
          ]
        ]
      ]

      set reserved-next nobody
      if (path != nobody) and not empty? path [
        let nxt first path
        ifelse is-patch? nxt [ set reserved-next nxt ] [
          set path []
          set reserved-next nobody
        ]
      ]
    ]

    if enable-battery? and moved? and not system-done? [
      set battery battery - battery-drain-per-tick
      if battery < 0 [ set battery 0 ]
    ]
  ]
end 

; ==========================================================
; BROKEN / DEAD
; ==========================================================

to become-broken
  if member? mstate ["broken" "dead"] [ stop ]
  set mstate "broken"
  set broken-queue lput self broken-queue
  pull-over
end 

to become-dead
  if mstate = "dead" [ stop ]
  set mstate "dead"
  set dead-queue lput self dead-queue
  pull-over
end 

to pull-over
  let opts patches in-radius 6 with [
    not wall? and celltype = "floor" and not any? turtles-here
  ]
  ifelse any? opts [
    safe-move-to (min-one-of opts [distance myself])
  ] [
    let s safe-one-of-patches (neighbors4 with [not wall? and not any? turtles-here])
    if s != nobody [ safe-move-to s ]
  ]
end 

; ==========================================================
; TOW SYSTEM
; ==========================================================

to move-repair-tows
  ask repair-tows [
    if system-done? [ stop ]

    if tstate = "idle" [
      if any? (turtle-set inbound-trucks carriers transfer-cars) with [mstate = "broken"] [
        set broken-queue remove-duplicates
          (sentence broken-queue [self] of
            (turtle-set inbound-trucks carriers transfer-cars) with [mstate = "broken"])
      ]

      if not empty? broken-queue [
        let t first broken-queue
        set broken-queue but-first broken-queue
        if is-vehicle? t and ([mstate] of t = "broken") [
          set target-truck t
          set goal2 [patch-here] of t
          set path2 find-path patch-here goal2
          set tstate "to-truck"
        ]
      ]
      stop
    ]

    if tstate = "to-truck" [
      if (target-truck = nobody) or
         (not is-vehicle? target-truck) or
         ([mstate] of target-truck != "broken")
      [
        set tstate "idle"
        set path2 []
        set target-truck nobody
        stop
      ]
      set goal2 [patch-here] of target-truck
      if empty? path2 [ set path2 find-path patch-here goal2 ]
      tow-step-safe
      if patch-here = goal2 [
        ask target-truck [ set mstate "towed-to-service" ]
        set goal2 safe-one-of-patches service-stations
        set path2 find-path patch-here goal2
        set tstate "to-service"
      ]
      stop
    ]

    if tstate = "to-service" [
      if empty? path2 [ set path2 find-path patch-here goal2 ]
      tow-step-safe

      if target-truck != nobody and is-vehicle? target-truck [
        ask target-truck [ safe-move-to [patch-here] of myself ]
      ]

      if patch-here = goal2 [
        if target-truck != nobody and is-vehicle? target-truck [
          ask target-truck [
            safe-move-to (safe-one-of-patches service-stations)
            set mstate "servicing"
            set service-left service-time
          ]
        ]
        set tstate "idle"
        set target-truck nobody
        set goal2 nobody
        set path2 []
      ]
      stop
    ]
  ]
end 

to move-charge-tows
  ask charge-tows [
    if system-done? [ stop ]

    if tstate = "idle" [
      if any? (turtle-set inbound-trucks carriers transfer-cars) with [mstate = "dead"] [
        set dead-queue remove-duplicates
          (sentence dead-queue [self] of
            (turtle-set inbound-trucks carriers transfer-cars) with [mstate = "dead"])
      ]

      if not empty? dead-queue [
        let t first dead-queue
        set dead-queue but-first dead-queue
        if is-vehicle? t and ([mstate] of t = "dead") [
          set target-truck t
          set goal2 [patch-here] of t
          set path2 find-path patch-here goal2
          set tstate "to-truck"
        ]
      ]
      stop
    ]

    if tstate = "to-truck" [
      if (target-truck = nobody) or
         (not is-vehicle? target-truck) or
         ([mstate] of target-truck != "dead")
      [
        set tstate "idle"
        set path2 []
        set target-truck nobody
        stop
      ]
      set goal2 [patch-here] of target-truck
      if empty? path2 [ set path2 find-path patch-here goal2 ]
      tow-step-safe
      if patch-here = goal2 [
        ask target-truck [ set mstate "towed-to-charge" ]
        set goal2 safe-one-of-patches charge-stations
        set path2 find-path patch-here goal2
        set tstate "to-charge"
      ]
      stop
    ]

    if tstate = "to-charge" [
      if empty? path2 [ set path2 find-path patch-here goal2 ]
      tow-step-safe

      if target-truck != nobody and is-vehicle? target-truck [
        ask target-truck [ safe-move-to [patch-here] of myself ]
      ]

      if patch-here = goal2 [
        if target-truck != nobody and is-vehicle? target-truck [
          ask target-truck [
            safe-move-to (safe-one-of-patches charge-stations)
            set mstate "charging"
            set charge-left charge-time
            set battery battery-max
          ]
        ]
        set tstate "idle"
        set target-truck nobody
        set goal2 nobody
        set path2 []
      ]
      stop
    ]
  ]
end 

; ==========================================================
; RESTORE JOB AFTER SERVICE/CHARGE
; ==========================================================

to restore-vehicle-job
  set reserved-next nobody
  set blocked-steps 0
  set goal-patch nobody
  set path []

  if member? mstate ["broken" "dead" "towed-to-service" "towed-to-charge" "parked"] [ stop ]

  if breed = inbound-trucks [
    ifelse inbound-pallets-left > 0 [ set mstate "to-infeed" ] [
      set mstate "idle"
      set carry? false
    ]
    stop
  ]

  if breed = carriers [
    ifelse carry? [
      let out safe-one-of-patches outfeed-bays
      ifelse out != nobody [
        set goal-patch out
        set path find-path patch-here goal-patch
        set mstate "to-outfeed"
      ] [
        set carry? false
        set mstate "idle"
      ]
    ] [
      set mstate "idle"
    ]
    stop
  ]

  if breed = transfer-cars [
    ifelse carry? [
      let dst safe-one-of-patches (ready-zone with [items < max-items-per-patch])
      ifelse dst != nobody [
        set goal-patch dst
        set path find-path patch-here goal-patch
        set mstate "to-ready"
      ] [
        set carry? false
        set mstate "idle"
      ]
    ] [
      set mstate "idle"
    ]
    stop
  ]

  set mstate "idle"
end 

; ==========================================================
; SERVICE & CHARGE TIMERS
; ==========================================================

to service-and-charge-timers
  ask (turtle-set inbound-trucks carriers transfer-cars) with [mstate = "servicing"] [
    set service-left service-left - 1
    if service-left <= 0 [
      set service-left 0
      set battery battery-max
      set mstate "idle"
      restore-vehicle-job
    ]
  ]

  if system-done? [
    ask (turtle-set inbound-trucks carriers transfer-cars) with [mstate = "charging"] [
      set charge-left 999999
      set battery battery-max
    ]
    stop
  ]

  ask (turtle-set inbound-trucks carriers transfer-cars) with [mstate = "charging"] [
    set charge-left charge-left - 1
    if charge-left <= 0 [
      set charge-left 0
      set battery battery-max
      set mstate "idle"
      restore-vehicle-job
    ]
  ]
end 

; ==========================================================
; DONE? + SHUTDOWN
; ==========================================================

to-report system-done?
  let eff-target effective-delivery-target
  if eff-target > 0 and deliveries >= eff-target [ report true ]

  if inbound-pallets-left > 0 [ report false ]
  if any? blue-zone with [items > 0] [ report false ]
  if any? ready-zone with [items > 0] [ report false ]
  if any? (turtle-set inbound-trucks carriers transfer-cars) with [carry?] [ report false ]

  report true
end 

to finish-and-shutdown
  ask (turtle-set inbound-trucks carriers transfer-cars) with [
    not member? mstate ["charging" "parked" "broken" "dead"
                        "towed-to-service" "towed-to-charge" "servicing"]
  ] [
    let cs one-of charge-lot with [not any? turtles-here]
    ifelse cs != nobody [
      set goal-patch cs
      set path find-path patch-here goal-patch
      set mstate "to-charge-home"
    ] [
      set mstate "parked"
      set path []
      set reserved-next nobody
    ]
  ]

  ask (turtle-set inbound-trucks carriers transfer-cars) [
    if mstate = "to-charge-home" and goal-patch != nobody [
      if patch-here = goal-patch [
        set mstate "charging"
        set charge-left 999999
        set battery battery-max
        set path []
        set reserved-next nobody
      ]
    ]
  ]

  ask (turtle-set inbound-trucks carriers transfer-cars) with [
    member? mstate ["broken" "dead" "towed-to-service" "towed-to-charge" "servicing"]
  ] [
    set mstate "parked"
    set path []
    set reserved-next nobody
    set battery battery-max
  ]

  ask humans with [mstate != "resting"] [
    if [celltype] of patch-here != "rest" [
      let rest-patch safe-one-of-patches (toilet-zone with [not any? turtles-here])
      if rest-patch != nobody [ safe-move-to rest-patch ]
    ]
    set mstate "resting"
  ]
end 

; ==========================================================
; APPEARANCE
; ==========================================================

to update-vehicle-appearance
  ifelse mstate = "broken" [
    set shape "x"
    set color red
    set label "B"
    set label-color white
  ] [
    ifelse mstate = "dead" [
      set shape "face sad"
      set color gray
      set label "D"
      set label-color black
    ] [
      ifelse breed = transfer-cars [
        set shape "car"
        ifelse carry? [ set color cyan ] [ set color gray ]
        set label "T"
      ] [
        set shape "truck"
        ifelse breed = inbound-trucks [
          set color red
          set label "IN"
        ] [
          set color green
          ifelse carry? [ set label "OUT*" ] [ set label "OUT" ]
        ]
      ]
      set label-color black
    ]
  ]
end 

; ==========================================================
; SAFE HELPERS
; ==========================================================

to safe-move-to [dest]
  if (dest = nobody) or (not is-patch? dest) [ stop ]
  move-to dest
end 

to-report safe-one-of-patches [pset]
  if pset = nobody [ report nobody ]
  if not any? pset [ report nobody ]
  report one-of pset
end 

to-report is-vehicle? [t]
  if t = nobody [ report false ]
  if not is-turtle? t [ report false ]
  report member? [breed] of t (list inbound-trucks carriers transfer-cars)
end 

to-report is-stopped-vehicle? [t]
  if not is-vehicle? t [ report false ]
  let s [mstate] of t
  report member? s ["broken" "dead" "towed-to-service" "towed-to-charge"
                    "servicing" "charging" "parked"]
end 

to step-along-path-safe
  if (path = nobody) or empty? path [ set path [] stop ]
  let nxt first path
  if (nxt = nobody) or (not is-patch? nxt) [ set path [] stop ]
  if [wall?] of nxt [ set path [] stop ]
  if not any? turtles-on nxt [
    safe-move-to nxt
    set path but-first path
  ]
end 

to tow-step-safe
  if (path2 = nobody) or empty? path2 [ set path2 [] stop ]
  let nxt first path2
  if (nxt = nobody) or (not is-patch? nxt) [ set path2 [] stop ]
  if [wall?] of nxt [ set path2 [] stop ]

  ifelse (not any? turtles-on nxt) or (nxt = goal2) [
    safe-move-to nxt
    set path2 but-first path2
    set blocked2 0
  ] [
    set blocked2 blocked2 + 1
    let side safe-one-of-patches (neighbors4 with [not wall? and not any? turtles-here])
    if side != nobody [ safe-move-to side ]
    if blocked2 > 6 and goal2 != nobody [
      set path2 find-path patch-here goal2
      set blocked2 0
    ]
  ]
end 

to-report occurrences [target lst]
  report length filter [x -> x = target] lst
end 

; ==========================================================
; PATHFINDING (BFS)
; ==========================================================

to-report find-path [start goal]
  if start = nobody or goal = nobody [ report [] ]
  if not is-patch? start or not is-patch? goal [ report [] ]
  if start = goal [ report [] ]

  let frontier (list start)
  let visited (list start)
  let parents []

  while [not empty? frontier] [
    let current first frontier
    set frontier but-first frontier

    if current = goal [
      report reconstruct-path start goal parents
    ]

    let nbrs [neighbors4] of current
    foreach sort nbrs [n ->
      if (not member? n visited) and (not [wall?] of n) [
        set visited lput n visited
        set frontier lput n frontier
        set parents lput (list n current) parents
      ]
    ]
  ]
  report []
end 

to-report reconstruct-path [start goal parents]
  let path-list (list goal)
  let current goal

  while [current != start] [
    let matches filter [pr -> first pr = current] parents
    if empty? matches [ report [] ]
    let pair first matches
    let parent last pair
    set current parent
    if current != start [
      set path-list fput current path-list
    ]
  ]
  report path-list
end 

; ==========================================================
; CONGESTION REPORTERS + MONITOR UPDATER
; ==========================================================

to-report active-movers
  report (turtle-set inbound-trucks carriers transfer-cars) with [
    not member? mstate ["broken" "dead" "towed-to-service" "towed-to-charge"
                        "servicing" "charging" "parked"]
  ]
end 

to-report mean-blocked
  let ms active-movers
  if not any? ms [ report 0 ]
  report mean [blocked-steps] of ms
end 

to-report max-blocked
  let ms active-movers
  if not any? ms [ report 0 ]
  report max [blocked-steps] of ms
end 

to update-monitors
  set mean-blocked-now mean-blocked
  set max-blocked-now  max-blocked
end 

; ==========================================================
; PUBLISH / DIAGNOSTICS REPORTERS
; ==========================================================

to-report mean-lead-time
  if empty? lead-times [ report 0 ]
  report mean lead-times
end 

to-report median-lead-time
  if empty? lead-times [ report 0 ]
  report median lead-times
end 

to-report p90-lead-time
  if empty? lead-times [ report 0 ]
  let s sort lead-times
  let idx floor ((length s - 1) * 0.9)
  if idx < 0 [ set idx 0 ]
  report item idx s
end 

to-report pct-moved-by-humans
  let total (moved-by-humans + moved-by-transfer)
  if total <= 0 [ report 0 ]
  report 100 * moved-by-humans / total
end 

to-report pct-moved-by-transfer
  let total (moved-by-humans + moved-by-transfer)
  if total <= 0 [ report 0 ]
  report 100 * moved-by-transfer / total
end 

to-report pallet-balance-error
  let blue-items 0
  let ready-items 0
  if blue-zone != nobody  [ set blue-items sum [items] of blue-zone ]
  if ready-zone != nobody [ set ready-items sum [items] of ready-zone ]
  let carried count turtles with [carry?]
  report initial-pallets - (inbound-pallets-left + blue-items + ready-items + carried + deliveries)
end 

There is only one version of this model, created about 3 hours ago by HARISH ULAGANATHAN INDHUMATHI HARISH.

Attached files

File Type Description Last updated
Warehouse Simulation.png preview Preview for 'Warehouse Simulation' about 3 hours ago, by HARISH ULAGANATHAN INDHUMATHI HARISH Download

This model does not have any ancestors.

This model does not have any descendants.