Difference between revisions of "User:Rysc00"
(Blanked the page) (Tag: Blanking) |
|||
| Line 1: | Line 1: | ||
| + | =Problem definition= | ||
| + | |||
| + | =Method= | ||
| + | |||
| + | =Model= | ||
| + | |||
| + | =Results= | ||
| + | |||
| + | =Conclusion= | ||
| + | |||
| + | =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 | ||
Revision as of 19:06, 10 January 2025
Problem definition
Method
Model
Results
Conclusion
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