"""
The Sleeping Barber Problem simulated, using a Queue instead of the usual set of four Mutexes

Idea:
- The barbershop has a finite number of chairs
- Customers arrive at random intervals
- If a customer cannot find a chair, they leave without getting a haircut
- If there are no customers, the barber takes a nap

The seats and deltaT variable control the number of chairs and speed of the simulation

Question: if the barber slept in a chair,
how would you add "barber wakes up and gets out of chair" in the barber thread
and require the last customer to wait for the getting-up before sitting down?
"""

from threading import Thread
from queue import Queue, Full
from time import sleep
from random import uniform, randrange

seats = Queue(maxsize=5)
deltaT = 2 # seconds to cut one customer's hair; controls overall simulation speed

def barber():
    served = 0
    while True:
        if seats.empty():
            print('😴 barber takes a nap')
        whom = seats.get()
        served += 1
        print(f'💇 barber cuts hair for {whom} ({served})')
        sleep(deltaT)

def customer(name):
    try:
        seats.put_nowait(name)
        print('🪑', name, "takes a seat")
    except Full:
        print('😠🏃', name, "can't find a seat and leaves")


b = Thread(target=barber)
b.start()

arrived = 0
for _ in range(100):
    sleep(uniform(0,4*deltaT))
    for _ in range(randrange(5)):
        arrived += 1
        c = Thread(target=customer, args=(f'customer {arrived}',))
        c.daemon = True
        c.start()