|
|
| Line 161: |
Line 161: |
| | | | |
| | =Code= | | =Code= |
| − |
| |
| − | globals [
| |
| − | satisfaction-threshold ;; Prahová hodnota pro spokojenost
| |
| − | total-satisfaction ;; Celková průměrná spokojenost zákazníků
| |
| − | total-satisfaction-population
| |
| − | simulation-running ;; Stav simulace (true = běží, false = zastaveno)
| |
| − | shared-self-checkout-queue
| |
| − | last-20-satisfactions
| |
| − | ]
| |
| − |
| |
| − |
| |
| − | breed [customers customer]
| |
| − | breed [checkouts checkout]
| |
| − |
| |
| − | customers-own [
| |
| − | items ;; Počet položek, které zákazník nakupuje
| |
| − | checkout-preference ;; Preference (regular/self-service)
| |
| − | willingness-to-switch ;; Ochota přejít k jiné pokladně
| |
| − | satisfaction ;; Aktuální úroveň spokojenosti
| |
| − | time-spent-in-queue ;; Čas strávený ve frontě
| |
| − | current-checkout
| |
| − | remaining-service-time ;; Celková zbývající doba obsluhy
| |
| − | ]
| |
| − |
| |
| − | checkouts-own [
| |
| − | queue-length ;; Délka fronty na pokladně
| |
| − | checkout-type ;; Typ pokladny (regular nebo self-service)
| |
| − | status ;; true = otevřená, false = zavřená
| |
| − | queue-start-position ;; Souřadnice začátku fronty jako seznam [x y]
| |
| − | currently-served-customer ;; Zákazník, který je aktuálně obsluhován (nebo `nobody`, pokud nikdo)
| |
| − | ]
| |
| − |
| |
| − |
| |
| − | to setup
| |
| − | clear-all
| |
| − | set satisfaction-threshold 70
| |
| − | set total-satisfaction 0
| |
| − | set last-20-satisfactions []
| |
| − | set total-satisfaction-population 0
| |
| − | set simulation-running true ;; Simulace je připravena k běhu
| |
| − | setup-checkouts
| |
| − | set last-20-satisfactions []
| |
| − | reset-ticks
| |
| − | end
| |
| − |
| |
| − |
| |
| − | to setup-checkouts
| |
| − | clear-patches
| |
| − | set shared-self-checkout-queue (list 13 -5)
| |
| − |
| |
| − | ;; Regular checkouts (modré pokladny)
| |
| − | let regular-checkout-positions [
| |
| − | [-17 13] [-12 13] [-7 13] [-2 13] [3 13]
| |
| − | ]
| |
| − | create-checkouts 5 [
| |
| − | set shape "square"
| |
| − | set size 3.5
| |
| − | set color blue
| |
| − | set checkout-type "regular"
| |
| − | set queue-length 0
| |
| − | set currently-served-customer nobody
| |
| − | ;; První regular checkout otevřená, ostatní zavřené
| |
| − | ifelse who = 0 [
| |
| − | set status true
| |
| − | ] [
| |
| − | set status false
| |
| − | ]
| |
| − | ;; Použij hardcodované souřadnice
| |
| − | let pos item who regular-checkout-positions
| |
| − | setxy item 0 pos item 1 pos
| |
| − | ;; Nastav počáteční bod individuální fronty
| |
| − | set queue-start-position (list item 0 pos (item 1 pos - 2)) ;; Fronta začíná 2 jednotky pod pokladnou
| |
| − | ]
| |
| − |
| |
| − | ;; Self-service checkouts (zelené pokladny)
| |
| − | let self-checkout-positions [
| |
| − | [8 13] [18 13] ;; První řada
| |
| − | [8 8] [18 8] ;; Druhá řada
| |
| − | [8 3] [18 3] ;; Třetí řada
| |
| − | [8 -2] [18 -2] ;; Čtvrtá řada
| |
| − | ]
| |
| − | create-checkouts 8 [
| |
| − | set shape "square"
| |
| − | set size 3.5
| |
| − | set color green
| |
| − | set checkout-type "self-service"
| |
| − | set queue-length 0
| |
| − | set currently-served-customer nobody
| |
| − | set status true
| |
| − | ;; Použij hardcodované souřadnice
| |
| − | let pos item (who - 5) self-checkout-positions
| |
| − | setxy item 0 pos item 1 pos
| |
| − |
| |
| − | ;; Nastav počáteční bod fronty na základě ycor a obarvi záplatu
| |
| − | ifelse [ycor] of self = 13 [
| |
| − | ;; Pokud je pokladna v první řadě (y = 13)
| |
| − | let queue-x [xcor] of self
| |
| − | let queue-y ([ycor] of self - 2)
| |
| − | set queue-start-position (list queue-x queue-y)
| |
| − | ] [
| |
| − | ifelse [ycor] of self = 8 [
| |
| − | ;; Pokud je pokladna v druhé řadě (y = 8)
| |
| − | let queue-x [xcor] of self
| |
| − | let queue-y ([ycor] of self - 2)
| |
| − | set queue-start-position (list queue-x queue-y)
| |
| − | ] [
| |
| − | ifelse [ycor] of self = 3 [
| |
| − | ;; Pokud je pokladna ve třetí řadě (y = 3)
| |
| − | let queue-x [xcor] of self
| |
| − | let queue-y ([ycor] of self - 2)
| |
| − | set queue-start-position (list queue-x queue-y)
| |
| − | ] [
| |
| − | ;; Pokud je pokladna ve čtvrté řadě (y = -2)
| |
| − | let queue-x [xcor] of self
| |
| − | let queue-y ([ycor] of self - 2)
| |
| − | set queue-start-position (list queue-x queue-y)
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − |
| |
| − |
| |
| − | update-checkout-colors
| |
| − | end
| |
| − |
| |
| − |
| |
| − | to update-checkout-colors
| |
| − | ;; Iterace přes všechny pokladny
| |
| − | ask checkouts [
| |
| − | ifelse status [
| |
| − | ;; Pokud je pokladna otevřená
| |
| − | ifelse checkout-type = "regular" [
| |
| − | set color blue ;; Modrá pro regular
| |
| − | ] [
| |
| − | set color green ;; Zelená pro self-service
| |
| − | ]
| |
| − | ] [
| |
| − | ;; Pokud je pokladna zavřená
| |
| − | set color gray ;; Šedá barva pro zavřenou pokladnu
| |
| − | ]
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − | to go
| |
| − | if not simulation-running [stop]
| |
| − | ifelse ticks <= 780 [
| |
| − | if any? customers [
| |
| − | consider-switching
| |
| − | ]
| |
| − | generate-customers
| |
| − | assign-checkouts
| |
| − | increment-time-spent-in-queue
| |
| − | process-checkouts
| |
| − | served-customers-leave
| |
| − | update-queue
| |
| − | adjust-checkouts
| |
| − | update-checkout-colors ;; Dynamická aktualizace barev
| |
| − | tick
| |
| − | ] [
| |
| − | ifelse ticks >= 795 [
| |
| − | ask checkouts [
| |
| − | set status false
| |
| − | update-checkout-colors
| |
| − | ]
| |
| − | stop
| |
| − | ] [
| |
| − | increment-time-spent-in-queue
| |
| − | process-checkouts
| |
| − | served-customers-leave
| |
| − | update-queue
| |
| − | adjust-checkouts
| |
| − | update-checkout-colors
| |
| − | tick ;; Přidání volání tick v této části
| |
| − | ]
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − |
| |
| − | to-report random-lognormal [mu sigma]
| |
| − | ;; Vygeneruje náhodnou hodnotu z lognormálního rozdělení
| |
| − | let normal-sample random-normal mu sigma
| |
| − | report exp normal-sample
| |
| − | end
| |
| − |
| |
| − | to-report random-poisson-lognormal [mu sigma]
| |
| − | ;; Výpočet lognormálních parametrů
| |
| − | let lognormal-std-dev sqrt (ln (1 + ((sigma ^ 2) / (mu ^ 2)))) ;; Přesná std dev pro lognormál
| |
| − | let lognormal-mean (ln mu - ((lognormal-std-dev ^ 2) / 2)) ;; Přesná mean pro lognormál
| |
| − |
| |
| − | ;; Generování lognormálního vzorku
| |
| − | let lognormal-sample exp (random-normal lognormal-mean lognormal-std-dev)
| |
| − |
| |
| − | ;; Zaokrouhlení na celá čísla (Poisson-lognormál výstup)
| |
| − | let result round lognormal-sample
| |
| − |
| |
| − | if result > 80 [
| |
| − | set result random-poisson-lognormal mu sigma
| |
| − | ]
| |
| − |
| |
| − | ;; Zajištění minimální hodnoty 1
| |
| − | report ifelse-value (result < 1) [1] [result]
| |
| − | end
| |
| − |
| |
| − |
| |
| − | to generate-customers
| |
| − | let arrivals max list 0 floor random-normal
| |
| − | (ifelse-value
| |
| − | (ticks mod 780 >= 0 and ticks mod 780 < 180) or (ticks mod 780 >= 540 and ticks mod 780 < 660)
| |
| − | [4] ; Špičkové hodiny: 8:00-10:00 a 16:00-18:00
| |
| − | [2] ; Mimo špičku: 10:00-16:00 a 18:00-20:00
| |
| − | ) 1
| |
| − |
| |
| − |
| |
| − | ;; Vytvoř zákazníky specifického plemene "customers"
| |
| − | create-customers arrivals [
| |
| − | ;; Nastavení počtu položek
| |
| − | set items random-poisson-lognormal 14 15
| |
| − |
| |
| − | set remaining-service-time -1
| |
| − |
| |
| − | ;; Generování preference pokladny na škále 1–100
| |
| − | if items > 20 [
| |
| − | set checkout-preference 1 ;; Pouze regular checkouts
| |
| − | ]
| |
| − | if items <= 10 [
| |
| − | let preference random-lognormal 3.8 0.9
| |
| − | set checkout-preference max list 1 (min list (100 - preference) 100)
| |
| − | ]
| |
| − | if items > 10 and items <= 20 [
| |
| − | let preference random-lognormal 3.9 0.9
| |
| − | set checkout-preference max list 1 (min list preference 100)
| |
| − | ]
| |
| − |
| |
| − |
| |
| − | ;; Generování willingness-to-switch (lognormální rozdělení)
| |
| − | set willingness-to-switch min list 100 max list 0 round random-lognormal 2.9 0.4
| |
| − |
| |
| − | ;; Nastavení vzhledu zákazníků
| |
| − | set shape "person"
| |
| − | set size 1.5
| |
| − | ifelse checkout-preference <= 50 [
| |
| − | set color blue ;; Barva se může změnit dle pokladny
| |
| − | ] [
| |
| − | set color green
| |
| − | ]
| |
| − |
| |
| − | ;; Umístění zákazníků na spodní stěnu
| |
| − | let x-start random-xcor
| |
| − | setxy x-start min-pycor
| |
| − |
| |
| − | ;; Další vlastnosti zákazníků
| |
| − | set satisfaction random-normal 80 5
| |
| − | set time-spent-in-queue 0
| |
| − | set current-checkout nobody
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − | to consider-switching
| |
| − | ask customers [
| |
| − | ;; Spočítají si, jak by byli spokojeni na všech dostupných pokladnách
| |
| − | let best-checkout choose-checkout self ;; Vybere pokladnu s nejvyšším potenciálem spokojenosti
| |
| − | if best-checkout != current-checkout [
| |
| − | ;; Spočítá potenciální spokojenost na nejlepší pokladně
| |
| − | let potential-satisfaction (satisfaction + potential-satisfaction-change-on-checkout-x best-checkout self)
| |
| − |
| |
| − | ;; Spočítá aktuální spokojenost v současné frontě na základě pozice
| |
| − | let current-queue-satisfaction calculate-current-queue-satisfaction self
| |
| − |
| |
| − | ;; Spočítá penalizaci za přechod na základě willingness-to-switch
| |
| − | let switch-penalty 0
| |
| − | if willingness-to-switch > 80 [
| |
| − | set switch-penalty 0 ;; Žádná penalizace
| |
| − | ]
| |
| − | if willingness-to-switch <= 80 and willingness-to-switch > 60 [
| |
| − | set switch-penalty random 5 + 1 ;; Penalizace 1–5 bodů
| |
| − | ]
| |
| − | if willingness-to-switch <= 60 and willingness-to-switch > 40 [
| |
| − | set switch-penalty random 5 + 3 ;; Penalizace 3–7 bodů
| |
| − | ]
| |
| − | if willingness-to-switch <= 40 and willingness-to-switch > 20 [
| |
| − | set switch-penalty random 5 + 5 ;; Penalizace 5–9 bodů
| |
| − | ]
| |
| − | if willingness-to-switch <= 20 [
| |
| − | set switch-penalty random 5 + 7 ;; Penalizace 7–11 bodů
| |
| − | ]
| |
| − |
| |
| − | ;; Zvažuje, zda přejít: nová spokojenost musí být vyšší než aktuální
| |
| − | let new-satisfaction (potential-satisfaction - switch-penalty)
| |
| − | if new-satisfaction > current-queue-satisfaction [
| |
| − | ;; Rozhodne se, zda přejde (pravděpodobnost dle willingness-to-switch)
| |
| − | if random-float 100 <= willingness-to-switch [
| |
| − | ;; Přechod na novou pokladnu
| |
| − | move-to-checkout best-checkout
| |
| − | ask current-checkout [
| |
| − | set queue-length queue-length - 1
| |
| − | ]
| |
| − | set current-checkout best-checkout
| |
| − | ask current-checkout [
| |
| − | set queue-length queue-length + 1
| |
| − | ]
| |
| − |
| |
| − |
| |
| − | ;; Snížení willingness-to-switch na polovinu
| |
| − | set willingness-to-switch willingness-to-switch / 2
| |
| − |
| |
| − | ;; Snížení spokojenosti podle penalizace
| |
| − | set satisfaction current-queue-satisfaction - switch-penalty
| |
| − |
| |
| − | ;; Ujisti se, že spokojenost zůstane v rozsahu 0–100
| |
| − | if satisfaction > 100 [ set satisfaction 100 ]
| |
| − | if satisfaction < 0 [ set satisfaction 0 ]
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − | to-report calculate-current-queue-satisfaction [currently-handled-customer]
| |
| − | ;; Spočítá celkový odhadovaný čas, který zákazník stráví čekáním ve frontě
| |
| − | let total-wait-time 0
| |
| − | let handled-customer currently-handled-customer
| |
| − |
| |
| − | ;; Najdi aktuální pokladnu zákazníka
| |
| − | let current-checkout-1 [current-checkout] of self
| |
| − |
| |
| − | ;; Spočítej zákazníky ve frontě před tímto zákazníkem
| |
| − | let queue-start [queue-start-position] of current-checkout-1
| |
| − | let queue-x item 0 queue-start
| |
| − | let queue-y item 1 queue-start
| |
| − |
| |
| − | ;; Najdi zákazníky v aktuální frontě seřazené podle pozice ve frontě
| |
| − | let queue-customers customers with [
| |
| − | current-checkout-1 = myself and xcor = queue-x and ycor <= queue-y
| |
| − | ]
| |
| − | let sorted-queue sort-on [ycor] queue-customers
| |
| − |
| |
| − | ;; Iterace přes zákazníky ve frontě
| |
| − | let position-in-customer-queue 1
| |
| − | foreach sorted-queue [
| |
| − | let customer-1 self ;;PROBLÉM?
| |
| − | ifelse ycor <= [ycor] of handled-customer [
| |
| − | ] [
| |
| − | ifelse position-in-customer-queue = 1 [
| |
| − | ;; První ve frontě: přičti zbývající dobu obsluhy
| |
| − | set total-wait-time total-wait-time + [remaining-service-time] of customer-1
| |
| − | ] [
| |
| − | ;; Další zákazníci: přičti odhadovanou dobu obsluhy
| |
| − | set total-wait-time total-wait-time + estimate-service-time current-checkout-1 customer-1
| |
| − | ]
| |
| − | ]
| |
| − | set position-in-customer-queue position-in-customer-queue + 1
| |
| − | ]
| |
| − |
| |
| − | ;; Spočítej satisfaction na základě čekací doby
| |
| − | ifelse total-wait-time <= 3 [
| |
| − | report satisfaction ;; Spokojenost se nezmění
| |
| − | ] [
| |
| − | report satisfaction - ((10 + (total-wait-time - 3)) * ln (1 + (total-wait-time - 3))) ;; Spokojenost klesá s čekací dobou
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − | to assign-checkouts
| |
| − | ask customers with [current-checkout = nobody] [
| |
| − | let chosen-checkout choose-checkout self
| |
| − | if chosen-checkout != nobody [
| |
| − | set current-checkout chosen-checkout
| |
| − |
| |
| − | ;; Přesuň zákazníka na pozici na konci fronty vybrané pokladny
| |
| − | move-to-checkout chosen-checkout
| |
| − |
| |
| − | ifelse [checkout-type] of chosen-checkout = "regular" [
| |
| − | ;; Zvýšení délky fronty pouze u vybraného regular checkoutu
| |
| − | ask chosen-checkout [
| |
| − | set queue-length queue-length + 1
| |
| − | ]
| |
| − | ] [
| |
| − | ;; Zvýšení délky fronty o 1 u všech self-service checkoutů
| |
| − | ask checkouts with [checkout-type = "self-service"] [
| |
| − | set queue-length queue-length + 1
| |
| − |
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − | to move-to-checkout [chosen-checkout]
| |
| − | ;; Získání cílové souřadnice na konci fronty
| |
| − | let queue-start-of-checkout [queue-start-position] of chosen-checkout
| |
| − | let queue-position [queue-length] of chosen-checkout
| |
| − | if [checkout-type] of chosen-checkout = "self-service" [
| |
| − | set queue-start-of-checkout shared-self-checkout-queue
| |
| − | ]
| |
| − | let target-x (item 0 queue-start-of-checkout)
| |
| − | let target-y (item 1 queue-start-of-checkout - queue-position * 0.5)
| |
| − | if target-y <= min-pycor [
| |
| − | set target-y min-pycor + 0.5
| |
| − | ]
| |
| − |
| |
| − | ;; Pohyb směrem k cíli po malých krocích
| |
| − | while [distancexy target-x target-y > 0.5] [
| |
| − | facexy target-x target-y
| |
| − | fd 0.5 ;; Délka kroku
| |
| − | display ;; Aktualizuje vizuální zobrazení při každém kroku
| |
| − | ]
| |
| − |
| |
| − | ;; Jakmile je dostatečně blízko, nastav souřadnice na cílové místo
| |
| − | setxy target-x target-y
| |
| − | end
| |
| − |
| |
| − | to move-to-self-checkout [chosen-checkout]
| |
| − | ;; Získání cílové souřadnice na konci fronty
| |
| − | let queue-start-of-checkout [queue-start-position] of chosen-checkout
| |
| − | let target-x (item 0 queue-start-of-checkout)
| |
| − | let target-y (item 1 queue-start-of-checkout)
| |
| − |
| |
| − | ;; Pohyb směrem k cíli po malých krocích
| |
| − | while [distancexy target-x target-y > 0.5] [
| |
| − | facexy target-x target-y
| |
| − | fd 0.5 ;; Délka kroku
| |
| − | display ;; Aktualizuje vizuální zobrazení při každém kroku
| |
| − | ]
| |
| − |
| |
| − | ;; Jakmile je dostatečně blízko, nastav souřadnice na cílové místo
| |
| − | setxy target-x target-y
| |
| − | end
| |
| − |
| |
| − |
| |
| − | to-report choose-checkout [customer-to-handle]
| |
| − | let handled-customer customer-to-handle
| |
| − | ;; Inicializace proměnných pro sledování nejlepší satisfaction a pokladen s touto hodnotou
| |
| − | let best-satisfaction -1000
| |
| − | let best-checkouts []
| |
| − |
| |
| − | ;; Projdi všechny otevřené pokladny
| |
| − | ask checkouts with [status = true] [
| |
| − | let potential-satisfaction potential-satisfaction-change-on-checkout-x self handled-customer
| |
| − |
| |
| − | ;; Pokud je satisfaction vyšší než aktuální nejlepší, aktualizuj seznam pokladen
| |
| − | if potential-satisfaction > best-satisfaction [
| |
| − | set best-satisfaction potential-satisfaction
| |
| − | set best-checkouts (list self) ;; Resetuj seznam a přidej tuto pokladnu
| |
| − | ]
| |
| − | ;; Pokud je satisfaction stejná jako aktuální nejlepší, přidej pokladnu do seznamu
| |
| − | if potential-satisfaction = best-satisfaction [
| |
| − | set best-checkouts lput self best-checkouts
| |
| − | ]
| |
| − | ]
| |
| − |
| |
| − | ;; Jinak vrať náhodnou z nejlepších
| |
| − | report one-of best-checkouts
| |
| − | end
| |
| − |
| |
| − |
| |
| − |
| |
| − |
| |
| − | to update-satisfaction [leaving-customer]
| |
| − |
| |
| − | let checkout-type-satisfaction 0
| |
| − | ;; Výpočet satisfaction z typu pokladny
| |
| − | ask leaving-customer[
| |
| − | set checkout-type-satisfaction satisfaction-change-from-checkout-type [checkout-type] of current-checkout self
| |
| − | ]
| |
| − | ;; Výpočet satisfaction z čekací doby
| |
| − | let wait-time-satisfaction 0
| |
| − | if time-spent-in-queue > 3 [
| |
| − | set wait-time-satisfaction (-(10 * ln (1 + (time-spent-in-queue - 3))))
| |
| − | ]
| |
| − |
| |
| − | ;; Aktualizace spokojenosti
| |
| − | set satisfaction (satisfaction + wait-time-satisfaction + checkout-type-satisfaction)
| |
| − |
| |
| − | if satisfaction > 100 [set satisfaction 100]
| |
| − | if satisfaction < 0 [ set satisfaction 0 ]
| |
| − |
| |
| − | ;; Aktualizace celkové spokojenosti všech zákazníků
| |
| − | set total-satisfaction (((total-satisfaction * total-satisfaction-population) + satisfaction) / (total-satisfaction-population + 1))
| |
| − | set total-satisfaction-population (total-satisfaction-population + 1)
| |
| − |
| |
| − | set last-20-satisfactions lput satisfaction last-20-satisfactions
| |
| − | if length last-20-satisfactions > 20 [
| |
| − | set last-20-satisfactions but-first last-20-satisfactions
| |
| − | ]
| |
| − |
| |
| − | end
| |
| − |
| |
| − |
| |
| − | to increment-time-spent-in-queue
| |
| − | ;; Pro všechny zákazníky zvyšte hodnotu time-spent-in-queue o 1
| |
| − | ask customers [
| |
| − | set time-spent-in-queue time-spent-in-queue + 1
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − |
| |
| − | to process-checkouts
| |
| − | ;; Projdi všechny otevřené pokladny
| |
| − | ask checkouts with [status = true] [
| |
| − | ;; Ulož odkaz na aktuální pokladnu
| |
| − | let current-checkout-1 self
| |
| − |
| |
| − | ifelse [checkout-type] of current-checkout-1 = "regular" [
| |
| − | ;; Logika pro regular checkouts
| |
| − | if currently-served-customer = nobody [
| |
| − | ;; Najdi souřadnice začátku fronty
| |
| − | let queue-start [queue-start-position] of current-checkout-1
| |
| − | let queue-start-x item 0 queue-start
| |
| − | let queue-start-y item 1 queue-start
| |
| − |
| |
| − | ;; Najdi zákazníka, který stojí na začátku fronty
| |
| − | let first-in-line one-of customers with [
| |
| − | xcor = queue-start-x and
| |
| − | ycor = queue-start-y
| |
| − | ]
| |
| − |
| |
| − | if first-in-line != nobody [
| |
| − | ;; Nastav tohoto zákazníka jako obsluhovaného
| |
| − | set currently-served-customer first-in-line
| |
| − | ask first-in-line [
| |
| − | let service-time estimate-service-time current-checkout-1 first-in-line
| |
| − | set remaining-service-time service-time
| |
| − | set willingness-to-switch 0
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − |
| |
| − | ;; Načti a nastav zbývající dobu obsluhy zákazníka
| |
| − | if currently-served-customer != nobody [
| |
| − | ask currently-served-customer [
| |
| − | set remaining-service-time (remaining-service-time - 1)
| |
| − | ]
| |
| − | ]
| |
| − | ] [
| |
| − | ;; Logika pro self-service checkouts
| |
| − | if currently-served-customer = nobody [
| |
| − | ;; Sdílená fronta: najdi zákazníka na vrcholu fronty
| |
| − | let queue-start shared-self-checkout-queue
| |
| − | let queue-start-x item 0 queue-start
| |
| − | let queue-start-y item 1 queue-start
| |
| − |
| |
| − | ;; Najdi zákazníka na vrcholu sdílené fronty
| |
| − | let first-in-line one-of customers with [
| |
| − | xcor = queue-start-x and
| |
| − | ycor = queue-start-y
| |
| − | ]
| |
| − |
| |
| − | if first-in-line != nobody [
| |
| − | ;; Nastav tohoto zákazníka jako obsluhovaného
| |
| − | set currently-served-customer first-in-line
| |
| − | ask first-in-line [
| |
| − | move-to-self-checkout current-checkout-1
| |
| − | let service-time estimate-service-time current-checkout-1 first-in-line
| |
| − | set remaining-service-time service-time
| |
| − | set willingness-to-switch 0
| |
| − | ]
| |
| − | update-self-checkouts
| |
| − | ask checkouts with [checkout-type = "self-service"] [
| |
| − | set queue-length (queue-length - 1)
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − | ;; Načti a nastav zbývající dobu obsluhy zákazníka
| |
| − | if currently-served-customer != nobody [
| |
| − | ask currently-served-customer [
| |
| − | set remaining-service-time (remaining-service-time - 1)
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − |
| |
| − |
| |
| − |
| |
| − |
| |
| − | to served-customers-leave
| |
| − | ;; Najdi všechny zákazníky, jejichž zbývající doba obsluhy klesla na 0
| |
| − | ask customers with [remaining-service-time = 0] [
| |
| − | if current-checkout = nobody [
| |
| − | die
| |
| − | ]
| |
| − |
| |
| − | ;; Aktualizuj pokladny, které obsluhují tohoto zákazníka
| |
| − | ask checkouts with [currently-served-customer = myself] [
| |
| − | if [checkout-type] of self = "regular" [
| |
| − | ;; Snížení délky fronty u regular pokladny
| |
| − | set queue-length (queue-length - 1)
| |
| − | ]
| |
| − | set currently-served-customer nobody
| |
| − | ]
| |
| − |
| |
| − | update-satisfaction self
| |
| − | die
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − |
| |
| − | to update-queue
| |
| − | update-regular-checkouts
| |
| − | update-self-checkouts
| |
| − | end
| |
| − |
| |
| − | to update-regular-checkouts
| |
| − | ;; Iterace přes všechny regular pokladny
| |
| − | ask checkouts with [checkout-type = "regular"] [
| |
| − | ;; Ulož odkaz na aktuální pokladnu
| |
| − | let checkout-reference self
| |
| − |
| |
| − | ;; Najdi pozici začátku fronty této pokladny
| |
| − | let queue-start [queue-start-position] of checkout-reference
| |
| − | let queue-start-x item 0 queue-start
| |
| − | let queue-start-y item 1 queue-start
| |
| − |
| |
| − | if currently-served-customer = nobody [
| |
| − | let current-ycor queue-start-y - 0.5
| |
| − |
| |
| − | ;; Iterace pro kontrolu fronty a posun zákazníků
| |
| − | while [any? customers with [xcor = queue-start-x and ycor = current-ycor]] [
| |
| − | ;; Posuň zákazníka na této pozici o 0.5 nahoru
| |
| − | ask customers with [xcor = queue-start-x and ycor = current-ycor] [
| |
| − | set ycor ycor + 0.5
| |
| − | ]
| |
| − | ;; Pokračuj kontrolou další pozice o 0.5 níže
| |
| − | set current-ycor current-ycor - 0.5
| |
| − |
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − | to update-self-checkouts
| |
| − | ;; Pohyb zákazníků ve sdílené frontě self-service pokladen
| |
| − | let queue-start shared-self-checkout-queue
| |
| − | let queue-start-x item 0 queue-start
| |
| − | let queue-start-y item 1 queue-start
| |
| − | let current-ycor queue-start-y
| |
| − |
| |
| − | ifelse any? customers with [xcor = queue-start-x and ycor = current-ycor] [
| |
| − | ][
| |
| − | set current-ycor current-ycor - 0.5
| |
| − |
| |
| − | ;; Procházej zákazníky ve sdílené frontě (od začátku fronty dolů)
| |
| − | while [any? customers with [xcor = queue-start-x and ycor = current-ycor]] [
| |
| − | let customer-on-spot one-of customers with [xcor = queue-start-x and ycor = current-ycor]
| |
| − |
| |
| − | ;; Najdi volnou pozici nad zákazníkem
| |
| − | let target-ycor current-ycor + 0.5
| |
| − | if not any? customers with [xcor = queue-start-x and ycor = target-ycor] [
| |
| − | ;; Posuň zákazníka na volné místo
| |
| − | ask customer-on-spot [
| |
| − | set ycor target-ycor
| |
| − | ]
| |
| − | ]
| |
| − |
| |
| − | ;; Posuň se o 0.5 níže ve frontě
| |
| − | set current-ycor current-ycor - 0.5
| |
| − | ]
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − |
| |
| − | to-report potential-satisfaction-change-on-checkout-x [target-checkout customer-to-handle]
| |
| − | let handled-customer customer-to-handle
| |
| − | ;; Spočítání satisfaction z čekací doby
| |
| − | let satisfaction-from-wait satisfaction-change-from-wait-time target-checkout
| |
| − |
| |
| − | ;; Spočítání satisfaction z typu pokladny a preference
| |
| − | let satisfaction-from-type satisfaction-change-from-checkout-type [checkout-type] of target-checkout handled-customer
| |
| − |
| |
| − | ;; Celková potenciální změna satisfaction
| |
| − | report satisfaction-from-wait + satisfaction-from-type
| |
| − | end
| |
| − |
| |
| − | to-report satisfaction-change-from-wait-time [target-checkout]
| |
| − | ;; Inicializace proměnných
| |
| − | let queue-start [queue-start-position] of target-checkout
| |
| − |
| |
| − | if [checkout-type] of target-checkout = "self-service" [
| |
| − | set queue-start shared-self-checkout-queue
| |
| − | ]
| |
| − |
| |
| − | let current-x item 0 queue-start
| |
| − | let current-y item 1 queue-start
| |
| − | let total-wait-time 0
| |
| − |
| |
| − | ;; Iterace přes pozice fronty
| |
| − | while [any? customers with [xcor = current-x and ycor = current-y]] [
| |
| − | ;; Najdi zákazníka na aktuální pozici
| |
| − | let customer-on-spot one-of customers with [xcor = current-x and ycor = current-y]
| |
| − |
| |
| − | ;; Přidej odhadovaný čas obsluhy zákazníka k celkovému času čekání
| |
| − | set total-wait-time total-wait-time + estimate-service-time target-checkout customer-on-spot
| |
| − |
| |
| − | ;; Posuň se na další pozici
| |
| − | set current-y current-y - 0.5
| |
| − | ]
| |
| − |
| |
| − | if [checkout-type] of target-checkout = "self-service" [
| |
| − | let served-customer [currently-served-customer] of target-checkout
| |
| − | ifelse served-customer = nobody [
| |
| − | set total-wait-time total-wait-time / 8
| |
| − | ][
| |
| − | let current-customer [currently-served-customer] of target-checkout
| |
| − | let ticks-before-leave [remaining-service-time] of current-customer
| |
| − | set total-wait-time ((total-wait-time / 8) + ticks-before-leave)
| |
| − | ]
| |
| − | ]
| |
| − |
| |
| − | ;; Výpočet satisfaction
| |
| − | ifelse total-wait-time <= 3 [
| |
| − | report 0
| |
| − | ] [
| |
| − | report (-((10 + (total-wait-time - 3)) * ln (1 + (total-wait-time - 3))))
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − | to-report satisfaction-change-from-checkout-type [target-checkout-type customer-to-handle]
| |
| − | let handled-customer customer-to-handle
| |
| − | ;; Získání preference zákazníka
| |
| − | let preference [checkout-preference] of handled-customer ;; Preference je atribut zákazníka
| |
| − | let result 0
| |
| − |
| |
| − | ;; Výpočet vlivu typu pokladny na satisfaction
| |
| − | if preference > 60 [
| |
| − | if target-checkout-type = "self-service" [
| |
| − | set result (random 2 + 2) ;; Zvýšení o 2–3 body
| |
| − | ]
| |
| − | if target-checkout-type = "regular" [
| |
| − | set result (-(random 6 + 5)) ;; Snížení o 5–10 bodů
| |
| − | ]
| |
| − | ]
| |
| − | if preference <= 60 and preference > 50 [
| |
| − | if target-checkout-type = "self-service" [
| |
| − | set result (random 2 + 1) ;; Zvýšení o 1–2 body
| |
| − | ]
| |
| − | if target-checkout-type = "regular" [
| |
| − | set result (-(random 5 + 1)) ;; Snížení o 1–5 bodů
| |
| − | ]
| |
| − | ]
| |
| − | if preference <= 50 and preference > 40 [
| |
| − | if target-checkout-type = "self-service" [
| |
| − | set result (-(random 5 + 1)) ;; Snížení o 1–5 bodů
| |
| − | ]
| |
| − | if target-checkout-type = "regular" [
| |
| − | set result (random 2 + 1) ;; Zvýšení o 1–2 body
| |
| − | ]
| |
| − | ]
| |
| − | if preference <= 40 [
| |
| − | if target-checkout-type = "self-service" [
| |
| − | set result (-(random 6 + 5)) ;; Snížení o 5–10 bodů
| |
| − | ]
| |
| − | if target-checkout-type = "regular" [
| |
| − | set result (random 2 + 2) ;; Zvýšení o 2–3 body
| |
| − | ]
| |
| − | ]
| |
| − | report result
| |
| − | end
| |
| − |
| |
| − |
| |
| − | to-report estimate-service-time [target-checkout target-customer]
| |
| − | ;; Inicializace proměnné pro odhadovaný čas
| |
| − | let estimated-time 0
| |
| − |
| |
| − | ;; Pravděpodobnost chyby a čas řešení
| |
| − | let error-probability ifelse-value ([checkout-type] of target-checkout = "regular") [0.001] [0.01]
| |
| − |
| |
| − | ;; Výpočet na základě typu pokladny
| |
| − | if [checkout-type] of target-checkout = "regular" [
| |
| − | set estimated-time
| |
| − | (random-normal 1 0.2 +
| |
| − | 0.8 * [items] of target-customer * random-normal 0.06 0.01 +
| |
| − | 0.2 * [items] of target-customer * random-normal 0.07 0.01)
| |
| − | ]
| |
| − | if [checkout-type] of target-checkout = "self-service" [
| |
| − | set estimated-time
| |
| − | (random-normal 1.2 0.3 +
| |
| − | 0.8 * [items] of target-customer * random-normal 0.07 0.02 +
| |
| − | 0.2 * [items] of target-customer * random-normal 0.08 0.02)
| |
| − | ]
| |
| − |
| |
| − | ;; Přidání času na řešení chyby, pokud k ní dojde
| |
| − | let error-opportunities [items] of target-customer
| |
| − | if error-opportunities > 0 [
| |
| − | if random-float 1 < error-probability [
| |
| − | let error-resolution-time random-normal 0.5 0.1
| |
| − | set estimated-time estimated-time + error-resolution-time
| |
| − | ]
| |
| − | set error-opportunities error-opportunities - 1
| |
| − | ]
| |
| − |
| |
| − | ;; Vrácení odhadovaného času
| |
| − | report ceiling(estimated-time)
| |
| − | end
| |
| − |
| |
| − | to open-new-checkouts
| |
| − | if not empty? last-20-satisfactions [
| |
| − | let average-last-20 mean last-20-satisfactions
| |
| − |
| |
| − | if average-last-20 < satisfaction-threshold [
| |
| − | let closed-checkouts checkouts with [status = false]
| |
| − | if any? closed-checkouts [
| |
| − | let checkout-to-open one-of closed-checkouts
| |
| − | ask checkout-to-open [
| |
| − | set status true
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − | to close-checkouts
| |
| − | ;; Najdi otevřené regular pokladny
| |
| − | let opened-checkouts sort [self] of checkouts with [
| |
| − | checkout-type = "regular" and
| |
| − | status = true
| |
| − | ]
| |
| − |
| |
| − | let opened-checkouts-without-customers []
| |
| − |
| |
| − | foreach opened-checkouts [checkout1 ->
| |
| − | let queue-start [queue-start-position] of checkout1
| |
| − | let queue-start-x item 0 queue-start
| |
| − | let queue-start-y item 1 queue-start
| |
| − | let first-in-line one-of customers with [xcor = queue-start-x and ycor = queue-start-y]
| |
| − | if first-in-line = nobody [
| |
| − | set opened-checkouts-without-customers lput checkout1 opened-checkouts-without-customers
| |
| − | ]
| |
| − | ]
| |
| − |
| |
| − |
| |
| − | ;; Projdi všechny pokladny bez zákazníků
| |
| − | foreach opened-checkouts-without-customers [checkout1 ->
| |
| − | ;; Spočítej aktuální počet otevřených regular pokladen
| |
| − | let num-opened-regular-checkouts length opened-checkouts
| |
| − |
| |
| − | ;; Zavři pokladnu, pokud je otevřených více než 1
| |
| − | if num-opened-regular-checkouts > 1 [
| |
| − | ask checkout1 [
| |
| − | set status false
| |
| − | ]
| |
| − |
| |
| − | ;; Aktualizuj seznam otevřených regular pokladen
| |
| − | set opened-checkouts sort [self] of checkouts with [
| |
| − | checkout-type = "regular" and
| |
| − | status = true
| |
| − | ]
| |
| − | ]
| |
| − | ]
| |
| − | end
| |
| − |
| |
| − | to adjust-checkouts
| |
| − | close-checkouts
| |
| − | open-new-checkouts
| |
| − | end
| |
| − |
| |
| − |
| |
| − |
| |
| − | to stop-simulation
| |
| − | set simulation-running false ;; Nastaví stav simulace na zastaveno
| |
| − | end
| |