{
  "id": "P075",
  "slug": "bank-queue",
  "key": "P075-bank-queue",
  "title": "Bank queue",
  "summary": "A simulated day at a bank, minute by minute: random customers from an EML generator, one first-come-first-served line with a limit, a few tellers; waits, people turned away, how busy the tellers were, Little's law exactly, and the same customers with 1 to 5 tellers.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P075 - Bank queue\n\nA simulated day at a bank, minute by minute. Random customers come, wait\nin one line in the order they came, and go to the first free teller. The\nline has a limit, and someone who finds it full leaves. It reports the\nwaits, the people turned away, how busy the tellers were, and the same\ncustomers with 1 to 5 tellers side by side. It starts with 2 tellers, 8\nhours, a customer in 40% of minutes needing 2 to 7 minutes each, and room\nfor 10 in line.\n\n- `main.eml` - the menu, settings, and the reports\n- `bank.eml` - the random customers and the minute-by-minute simulation\n\nHow each part works:\n\n- Customers: each minute a linear congruential generator (the constants\n  of Numerical Recipes, mod 2^32) decides whether someone comes, and if so\n  how long they need. Only its top 16 bits are used, since the low bits of\n  such a generator repeat quickly. The customers are drawn before\n  anything else, so every number of tellers and every line limit sees\n  exactly the same people.\n- Each minute: first every free teller calls the front of the line - a\n  first-come-first-served queue, as in the corpus case `simple-queue`.\n  Then the minute's customer, if any, goes straight to a teller who is\n  still free, or joins the line, or leaves when the line already holds its\n  limit. As the corpus case `bounded-queue-backpressure` says, a full\n  queue has to drop something; here it is the newcomer. The day runs on\n  past closing until the line is empty.\n- Little's law in its exact form: the line's length added up over every\n  minute equals all the customers' waits added up. The program counts\n  both separately and prints both.\n\nWhat is checked: menu choices 1 to 5; 1 to 5 tellers; 30 to 600 minutes\nopen; a 1 to 100% chance of a customer each minute; a service time from 1\nto 30 minutes, the longest no shorter than the shortest; room for 0 to 50\nin line; a seed from 0 to 999999. An empty answer keeps a setting as it\nwas.\n\nSessions: `sessions/basic.in` gives:\n- the starting day: 189 customers, all served, an average wait of 4.01\n  minutes;\n- the same customers with 1 to 5 tellers - one teller turns 80 away;\n- the first 20 minutes;\n- 4 hours at 60%, 2 to 10 minutes, room for 3: 55 turned away with 2\n  tellers, and the day with 1 to 5.\n\n`sessions/bad-input.in` gives:\n- menu choices 0 and x;\n- every setting out of range once (tellers 6, 0 and abc; 29 and 601\n  minutes; 0% and 101%; a 31-minute service; a longest below the\n  shortest; room for 51; seed 1000000);\n- then 1 teller, a customer every minute needing 5 minutes, and nobody\n  able to wait: exactly one in five served.\n\nBuilt on the verified corpus cases `simple-queue` (a queue served in\nthe order people came) and `bounded-queue-backpressure` (what a full\nqueue has to drop).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P075 bank queue: a simulated day at a bank with random customers, one\n# line and a few tellers - the waits, the people turned away when the line\n# is full, how busy the tellers were, and the same customers with 1 to 5\n# tellers side by side.\nimport bank\n\ndef trim(s):\n    0 => i\n    len(s) => j\n    while i < j and s[i] == \" \":\n        i + 1 => i\n    while j > i and s[j - 1] == \" \":\n        j - 1 => j\n    return s[i:j]\n\ndef number(s):\n    if len(s) == 0 or len(s) > 6:\n        return -1\n    0 => n\n    for c in s:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n * 10 + int(c) => n\n    return n\n\ndef lpad(s, n):\n    while len(s) < n:\n        \" \" + s => s\n    return s\n\ndef decimal(a, b):\n    # a / b to two places, rounded half up, for whole a >= 0 and b > 0.\n    200 * a + b => n\n    2 * b => d\n    0 => q\n    while n >= d:\n        d => m\n        1 => k\n        while m + m <= n:\n            m + m => m\n            k + k => k\n        n - m => n\n        q + k => q\n    0 => whole\n    q => r\n    while r >= 100:\n        r - 100 => r\n        whole + 1 => whole\n    if r < 10:\n        return str(whole) + \".0\" + str(r)\n    return str(whole) + \".\" + str(r)\n\ndef clock(m):\n    # Minutes after opening at 9:00 as a time of day.\n    9 => h\n    m => r\n    while r >= 60:\n        r - 60 => r\n        h + 1 => h\n    \"\" => z\n    if r < 10:\n        \"0\" => z\n    return str(h) + \":\" + z + str(r)\n\ndef ask(prompt, low, high):\n    while True:\n        trim(input(prompt + \" (\" + str(low) + \" to \" + str(high) + \")> \")) => a\n        if a == \"\":\n            return -1\n        number(a) => n\n        if n >= low and n <= high:\n            return n\n        (\"Type a whole number from \" + str(low) + \" to \" + str(high) + \".\") ^0\n\ndef settings_text(s):\n    \"1 teller\" => who\n    if s[0] > 1:\n        str(s[0]) + \" tellers\" => who\n    \"nobody can wait in line\" => room\n    if s[5] > 0:\n        \"room for \" + str(s[5]) + \" in line\" => room\n    str(s[3]) + \" to \" + str(s[4]) => service\n    if s[3] == s[4]:\n        str(s[3]) => service\n    return who + \", open \" + str(s[1]) + \" minutes, a customer in \" + str(s[2]) + \"% of minutes, \" + service + \" minutes each, \" + room + \", seed \" + str(s[6])\n\ndef people_of(s):\n    return bank.customers(s[1], s[2], s[3], s[4], s[6])\n\ndef day(s):\n    people_of(s) => people\n    if len(people) == 0:\n        \"Nobody came all day.\" ^0\n        return\n    bank.simulate(people, s[0], s[5], 0) => r\n    (str(len(people)) + \" customers came; \" + str(r[0]) + \" were served and \" + str(r[1]) + \" turned away, finding no room in the line.\") ^0\n    if r[0] > 0:\n        (\"Average wait \" + decimal(r[2], r[0]) + \" minutes; the longest \" + str(r[3]) + \". The line was at most \" + str(r[4]) + \" long.\") ^0\n    (\"The last customer left at \" + clock(r[6]) + \"; the tellers were busy \" + decimal(100 * r[5], s[0] * r[6]) + \"% of that time.\") ^0\n    (\"Little's law: the line held \" + str(r[7]) + \" customer-minutes in all, and the customers waited \" + str(r[2]) + \" minutes in all - the same thing counted two ways.\") ^0\n\ndef compare(s):\n    people_of(s) => people\n    if len(people) == 0:\n        \"Nobody came all day.\" ^0\n        return\n    (str(len(people)) + \" customers, the same ones each time:\") ^0\n    \"  tellers  served  away  average wait  longest  busy\" ^0\n    for k in [1:5]:\n        bank.simulate(people, k, s[5], 0) => r\n        \"-\" => avg\n        if r[0] > 0:\n            decimal(r[2], r[0]) => avg\n        (\"  \" + lpad(str(k), 7) + lpad(str(r[0]), 8) + lpad(str(r[1]), 6) + lpad(avg, 14) + lpad(str(r[3]), 9) + lpad(decimal(100 * r[5], k * r[6]) + \"%\", 8)) ^0\n\ndef opening(s):\n    people_of(s) => people\n    bank.simulate(people, s[0], s[5], 20) => r\n    \"The first 20 minutes:\" ^0\n    for e in r[8]:\n        \"quiet\" => what\n        if e[1] != \"\":\n            e[1][0:len(e[1]) - 2] => what\n        (\"  \" + clock(e[0]) + \"  \" + what + \" - \" + str(e[2]) + \" in line\") ^0\n\ndef change(s):\n    \"Settings, one at a time; an empty answer keeps the old value.\" ^0\n    [[\"tellers\", 1, 5], [\"minutes open\", 30, 600], [\"chance of a customer each minute, %\", 1, 100], [\"shortest service, minutes\", 1, 30], [\"longest service, minutes\", 1, 30], [\"room in the line\", 0, 50], [\"seed\", 0, 999999]] => qs\n    [0] * 7 => out\n    for k in [0:6]:\n        qs[k] => q\n        q[1] => low\n        if k == 4:\n            out[3] => low\n        ask(q[0] + \", now \" + str(s[k]), low, q[2]) => v\n        if v == -1:\n            s[k] => v\n            if k == 4 and v < low:\n                low => v\n        v => out[k]\n    (\"Now: \" + settings_text(out) + \".\") ^0\n    return out\n\n[2, 480, 40, 2, 7, 10, 2026] => settings\n\n\"== Bank queue ==\" ^0\n\"A day at a bank, minute by minute: random customers, one line, a few tellers.\" ^0\nTrue => running\nwhile running:\n    \"\" ^0\n    (settings_text(settings) + \".\") ^0\n    \"1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\" ^0\n    trim(input(\"choice> \")) => choice\n    if choice == \"1\":\n        day(settings)\n    elif choice == \"2\":\n        compare(settings)\n    elif choice == \"3\":\n        opening(settings)\n    elif choice == \"4\":\n        change(settings) => settings\n    elif choice == \"5\":\n        False => running\n    else:\n        \"Pick a number from 1 to 5.\" ^0\n\"Bye.\" ^0\n",
      "python": "import bank\n\ndef trim(s):\n    i = 0\n    j = len(s)\n    while i < j and s[i] == \" \":\n        i = i + 1\n    while j > i and s[j - 1] == \" \":\n        j = j - 1\n    return s[i:j]\n\ndef number(s):\n    if len(s) == 0 or len(s) > 6:\n        return -1\n    n = 0\n    for c in s:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n = n * 10 + int(c)\n    return n\n\ndef lpad(s, n):\n    while len(s) < n:\n        s = \" \" + s\n    return s\n\ndef decimal(a, b):\n    n = 200 * a + b\n    d = 2 * b\n    q = 0\n    while n >= d:\n        m = d\n        k = 1\n        while m + m <= n:\n            m = m + m\n            k = k + k\n        n = n - m\n        q = q + k\n    whole = 0\n    r = q\n    while r >= 100:\n        r = r - 100\n        whole = whole + 1\n    if r < 10:\n        return str(whole) + \".0\" + str(r)\n    return str(whole) + \".\" + str(r)\n\ndef clock(m):\n    h = 9\n    r = m\n    while r >= 60:\n        r = r - 60\n        h = h + 1\n    z = \"\"\n    if r < 10:\n        z = \"0\"\n    return str(h) + \":\" + z + str(r)\n\ndef ask(prompt, low, high):\n    while True:\n        a = trim(input(prompt + \" (\" + str(low) + \" to \" + str(high) + \")> \"))\n        if a == \"\":\n            return -1\n        n = number(a)\n        if n >= low and n <= high:\n            return n\n        print(\"Type a whole number from \" + str(low) + \" to \" + str(high) + \".\")\n\ndef settings_text(s):\n    who = \"1 teller\"\n    if s[0] > 1:\n        who = str(s[0]) + \" tellers\"\n    room = \"nobody can wait in line\"\n    if s[5] > 0:\n        room = \"room for \" + str(s[5]) + \" in line\"\n    service = str(s[3]) + \" to \" + str(s[4])\n    if s[3] == s[4]:\n        service = str(s[3])\n    return who + \", open \" + str(s[1]) + \" minutes, a customer in \" + str(s[2]) + \"% of minutes, \" + service + \" minutes each, \" + room + \", seed \" + str(s[6])\n\ndef people_of(s):\n    return bank.customers(s[1], s[2], s[3], s[4], s[6])\n\ndef day(s):\n    people = people_of(s)\n    if len(people) == 0:\n        print(\"Nobody came all day.\")\n        return\n    r = bank.simulate(people, s[0], s[5], 0)\n    print(str(len(people)) + \" customers came; \" + str(r[0]) + \" were served and \" + str(r[1]) + \" turned away, finding no room in the line.\")\n    if r[0] > 0:\n        print(\"Average wait \" + decimal(r[2], r[0]) + \" minutes; the longest \" + str(r[3]) + \". The line was at most \" + str(r[4]) + \" long.\")\n    print(\"The last customer left at \" + clock(r[6]) + \"; the tellers were busy \" + decimal(100 * r[5], s[0] * r[6]) + \"% of that time.\")\n    print(\"Little's law: the line held \" + str(r[7]) + \" customer-minutes in all, and the customers waited \" + str(r[2]) + \" minutes in all - the same thing counted two ways.\")\n\ndef compare(s):\n    people = people_of(s)\n    if len(people) == 0:\n        print(\"Nobody came all day.\")\n        return\n    print(str(len(people)) + \" customers, the same ones each time:\")\n    print(\"  tellers  served  away  average wait  longest  busy\")\n    for k in range(1, 6):\n        r = bank.simulate(people, k, s[5], 0)\n        avg = \"-\"\n        if r[0] > 0:\n            avg = decimal(r[2], r[0])\n        print(\"  \" + lpad(str(k), 7) + lpad(str(r[0]), 8) + lpad(str(r[1]), 6) + lpad(avg, 14) + lpad(str(r[3]), 9) + lpad(decimal(100 * r[5], k * r[6]) + \"%\", 8))\n\ndef opening(s):\n    people = people_of(s)\n    r = bank.simulate(people, s[0], s[5], 20)\n    print(\"The first 20 minutes:\")\n    for e in r[8]:\n        what = \"quiet\"\n        if e[1] != \"\":\n            what = e[1][0:len(e[1]) - 2]\n        print(\"  \" + clock(e[0]) + \"  \" + what + \" - \" + str(e[2]) + \" in line\")\n\ndef change(s):\n    print(\"Settings, one at a time; an empty answer keeps the old value.\")\n    qs = [[\"tellers\", 1, 5], [\"minutes open\", 30, 600], [\"chance of a customer each minute, %\", 1, 100], [\"shortest service, minutes\", 1, 30], [\"longest service, minutes\", 1, 30], [\"room in the line\", 0, 50], [\"seed\", 0, 999999]]\n    out = [0] * 7\n    for k in range(0, 7):\n        q = qs[k]\n        low = q[1]\n        if k == 4:\n            low = out[3]\n        v = ask(q[0] + \", now \" + str(s[k]), low, q[2])\n        if v == -1:\n            v = s[k]\n            if k == 4 and v < low:\n                v = low\n        out[k] = v\n    print(\"Now: \" + settings_text(out) + \".\")\n    return out\n\nsettings = [2, 480, 40, 2, 7, 10, 2026]\nprint(\"== Bank queue ==\")\nprint(\"A day at a bank, minute by minute: random customers, one line, a few tellers.\")\nrunning = True\nwhile running:\n    print(\"\")\n    print(settings_text(settings) + \".\")\n    print(\"1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\")\n    choice = trim(input(\"choice> \"))\n    if choice == \"1\":\n        day(settings)\n    elif choice == \"2\":\n        compare(settings)\n    elif choice == \"3\":\n        opening(settings)\n    elif choice == \"4\":\n        settings = change(settings)\n    elif choice == \"5\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 5.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "bank.eml",
      "eml": "# P075 bank queue - a day at a bank, minute by minute. Customers arrive at\n# random, wait in one line in the order they came (the corpus case\n# simple-queue), and go to the first free teller. The line has a limit;\n# a customer who finds it full is turned away (the corpus case\n# bounded-queue-backpressure: a full queue has to drop something, and here\n# it is the newcomer).\n\ndef draw(x):\n    # One step of a linear congruential generator (the constants of\n    # Numerical Recipes, mod 2^32): [next state, its top 16 bits]. The low\n    # bits of such a generator repeat quickly, so only the top ones are\n    # used; x / 65536 divides by a power of two below 2^53, which is exact.\n    (1664525 * x + 1013904223) % 4294967296 => x\n    return [x, int(x / 65536)]\n\ndef customers(open_for, chance, low, high, seed):\n    # Who comes, decided before anything else so that every number of\n    # tellers and every line limit sees the same customers: each minute\n    # someone arrives with `chance` percent probability, and needs a\n    # service time from low to high minutes. Returns [[arrival, service]].\n    [] => out\n    seed => x\n    for t in [0:open_for - 1]:\n        draw(x) => d\n        d[0] => x\n        if d[1] % 100 < chance:\n            draw(x) => e\n            e[0] => x\n            out + [[t, low + e[1] % (high - low + 1)]] => out\n    return out\n\ndef simulate(people, tellers, limit, show):\n    # Minute by minute until everyone is served. First each teller who is\n    # free calls the front of the line. Then the minute's customer, if any,\n    # goes straight to a teller who is still free, or joins the line, or -\n    # when the line already holds `limit` - is turned away. Returns\n    # [served, turned away, total wait, longest wait, longest line, busy\n    # teller-minutes, minutes until the last leaves, line-minutes (the\n    # line's length summed over the minutes), log of the first `show`\n    # minutes as [minute, what happened, line length]].\n    [0] * tellers => free_at\n    [] => line\n    0 => i\n    0 => served\n    0 => away\n    0 => total\n    0 => longest\n    0 => most\n    0 => busy\n    0 => line_minutes\n    [] => log\n    0 => t\n    while i < len(people) or len(line) > 0:\n        \"\" => note\n        for k in [0:tellers - 1]:\n            if free_at[k] <= t and len(line) > 0:\n                line[0] => c\n                line[1:len(line)] => line\n                t + c[1] => free_at[k]\n                busy + c[1] => busy\n                served + 1 => served\n                total + t - c[0] => total\n                if t - c[0] > longest:\n                    t - c[0] => longest\n                note + \"teller \" + str(k + 1) + \" calls the one from minute \" + str(c[0]) + \"; \" => note\n        if i < len(people) and people[i][0] == t:\n            people[i] => c\n            i + 1 => i\n            -1 => k\n            for j in [0:tellers - 1]:\n                if k == -1 and free_at[j] <= t:\n                    j => k\n            if k >= 0:\n                t + c[1] => free_at[k]\n                busy + c[1] => busy\n                served + 1 => served\n                note + \"one arrives and goes to teller \" + str(k + 1) + \"; \" => note\n            elif len(line) < limit:\n                line + [c] => line\n                note + \"one arrives and waits; \" => note\n            else:\n                away + 1 => away\n                note + \"one arrives, finds no room in the line and leaves; \" => note\n        if len(line) > most:\n            len(line) => most\n        line_minutes + len(line) => line_minutes\n        if t < show:\n            log + [[t, note, len(line)]] => log\n        t + 1 => t\n    t => last\n    for k in [0:tellers - 1]:\n        if free_at[k] > last:\n            free_at[k] => last\n    return [served, away, total, longest, most, busy, last, line_minutes, log]\n",
      "python": "def draw(x):\n    x = (1664525 * x + 1013904223) % 4294967296\n    return [x, int(x / 65536)]\n\ndef customers(open_for, chance, low, high, seed):\n    out = []\n    x = seed\n    for t in range(0, open_for):\n        d = draw(x)\n        x = d[0]\n        if d[1] % 100 < chance:\n            e = draw(x)\n            x = e[0]\n            out = out + [[t, low + e[1] % (high - low + 1)]]\n    return out\n\ndef simulate(people, tellers, limit, show):\n    free_at = [0] * tellers\n    line = []\n    i = 0\n    served = 0\n    away = 0\n    total = 0\n    longest = 0\n    most = 0\n    busy = 0\n    line_minutes = 0\n    log = []\n    t = 0\n    while i < len(people) or len(line) > 0:\n        note = \"\"\n        for k in range(0, tellers):\n            if free_at[k] <= t and len(line) > 0:\n                c = line[0]\n                line = line[1:len(line)]\n                free_at[k] = t + c[1]\n                busy = busy + c[1]\n                served = served + 1\n                total = total + t - c[0]\n                if t - c[0] > longest:\n                    longest = t - c[0]\n                note = note + \"teller \" + str(k + 1) + \" calls the one from minute \" + str(c[0]) + \"; \"\n        if i < len(people) and people[i][0] == t:\n            c = people[i]\n            i = i + 1\n            k = -1\n            for j in range(0, tellers):\n                if k == -1 and free_at[j] <= t:\n                    k = j\n            if k >= 0:\n                free_at[k] = t + c[1]\n                busy = busy + c[1]\n                served = served + 1\n                note = note + \"one arrives and goes to teller \" + str(k + 1) + \"; \"\n            elif len(line) < limit:\n                line = line + [c]\n                note = note + \"one arrives and waits; \"\n            else:\n                away = away + 1\n                note = note + \"one arrives, finds no room in the line and leaves; \"\n        if len(line) > most:\n            most = len(line)\n        line_minutes = line_minutes + len(line)\n        if t < show:\n            log = log + [[t, note, len(line)]]\n        t = t + 1\n    last = t\n    for k in range(0, tellers):\n        if free_at[k] > last:\n            last = free_at[k]\n    return [served, away, total, longest, most, busy, last, line_minutes, log]\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n4\n6\n0\nabc\n1\n29\n601\n60\n0\n101\n100\n31\n5\n4\n5\n51\n0\n1000000\n7\n1\n3\n5\n",
      "screen": "== Bank queue ==\nA day at a bank, minute by minute: random customers, one line, a few tellers.\n\n2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> 0\nPick a number from 1 to 5.\n\n2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> x\nPick a number from 1 to 5.\n\n2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> 4\nSettings, one at a time; an empty answer keeps the old value.\ntellers, now 2 (1 to 5)> 6\nType a whole number from 1 to 5.\ntellers, now 2 (1 to 5)> 0\nType a whole number from 1 to 5.\ntellers, now 2 (1 to 5)> abc\nType a whole number from 1 to 5.\ntellers, now 2 (1 to 5)> 1\nminutes open, now 480 (30 to 600)> 29\nType a whole number from 30 to 600.\nminutes open, now 480 (30 to 600)> 601\nType a whole number from 30 to 600.\nminutes open, now 480 (30 to 600)> 60\nchance of a customer each minute, %, now 40 (1 to 100)> 0\nType a whole number from 1 to 100.\nchance of a customer each minute, %, now 40 (1 to 100)> 101\nType a whole number from 1 to 100.\nchance of a customer each minute, %, now 40 (1 to 100)> 100\nshortest service, minutes, now 2 (1 to 30)> 31\nType a whole number from 1 to 30.\nshortest service, minutes, now 2 (1 to 30)> 5\nlongest service, minutes, now 7 (5 to 30)> 4\nType a whole number from 5 to 30.\nlongest service, minutes, now 7 (5 to 30)> 5\nroom in the line, now 10 (0 to 50)> 51\nType a whole number from 0 to 50.\nroom in the line, now 10 (0 to 50)> 0\nseed, now 2026 (0 to 999999)> 1000000\nType a whole number from 0 to 999999.\nseed, now 2026 (0 to 999999)> 7\nNow: 1 teller, open 60 minutes, a customer in 100% of minutes, 5 minutes each, nobody can wait in line, seed 7.\n\n1 teller, open 60 minutes, a customer in 100% of minutes, 5 minutes each, nobody can wait in line, seed 7.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> 1\n60 customers came; 12 were served and 48 turned away, finding no room in the line.\nAverage wait 0.00 minutes; the longest 0. The line was at most 0 long.\nThe last customer left at 10:00; the tellers were busy 100.00% of that time.\nLittle's law: the line held 0 customer-minutes in all, and the customers waited 0 minutes in all - the same thing counted two ways.\n\n1 teller, open 60 minutes, a customer in 100% of minutes, 5 minutes each, nobody can wait in line, seed 7.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> 3\nThe first 20 minutes:\n  9:00  one arrives and goes to teller 1 - 0 in line\n  9:01  one arrives, finds no room in the line and leaves - 0 in line\n  9:02  one arrives, finds no room in the line and leaves - 0 in line\n  9:03  one arrives, finds no room in the line and leaves - 0 in line\n  9:04  one arrives, finds no room in the line and leaves - 0 in line\n  9:05  one arrives and goes to teller 1 - 0 in line\n  9:06  one arrives, finds no room in the line and leaves - 0 in line\n  9:07  one arrives, finds no room in the line and leaves - 0 in line\n  9:08  one arrives, finds no room in the line and leaves - 0 in line\n  9:09  one arrives, finds no room in the line and leaves - 0 in line\n  9:10  one arrives and goes to teller 1 - 0 in line\n  9:11  one arrives, finds no room in the line and leaves - 0 in line\n  9:12  one arrives, finds no room in the line and leaves - 0 in line\n  9:13  one arrives, finds no room in the line and leaves - 0 in line\n  9:14  one arrives, finds no room in the line and leaves - 0 in line\n  9:15  one arrives and goes to teller 1 - 0 in line\n  9:16  one arrives, finds no room in the line and leaves - 0 in line\n  9:17  one arrives, finds no room in the line and leaves - 0 in line\n  9:18  one arrives, finds no room in the line and leaves - 0 in line\n  9:19  one arrives, finds no room in the line and leaves - 0 in line\n\n1 teller, open 60 minutes, a customer in 100% of minutes, 5 minutes each, nobody can wait in line, seed 7.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "1\n2\n3\n4\n\n240\n60\n\n10\n3\n\n1\n2\n5\n",
      "screen": "== Bank queue ==\nA day at a bank, minute by minute: random customers, one line, a few tellers.\n\n2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> 1\n189 customers came; 189 were served and 0 turned away, finding no room in the line.\nAverage wait 4.01 minutes; the longest 14. The line was at most 7 long.\nThe last customer left at 17:16; the tellers were busy 88.61% of that time.\nLittle's law: the line held 757 customer-minutes in all, and the customers waited 757 minutes in all - the same thing counted two ways.\n\n2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> 2\n189 customers, the same ones each time:\n  tellers  served  away  average wait  longest  busy\n        1     109    80         41.51       58  99.81%\n        2     189     0          4.01       14  88.61%\n        3     189     0          0.32        4  60.54%\n        4     189     0          0.06        3  45.50%\n        5     189     0          0.01        2  36.40%\n\n2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> 3\nThe first 20 minutes:\n  9:00  quiet - 0 in line\n  9:01  one arrives and goes to teller 1 - 0 in line\n  9:02  quiet - 0 in line\n  9:03  quiet - 0 in line\n  9:04  one arrives and goes to teller 2 - 0 in line\n  9:05  quiet - 0 in line\n  9:06  quiet - 0 in line\n  9:07  one arrives and goes to teller 1 - 0 in line\n  9:08  quiet - 0 in line\n  9:09  quiet - 0 in line\n  9:10  one arrives and goes to teller 1 - 0 in line\n  9:11  quiet - 0 in line\n  9:12  one arrives and goes to teller 2 - 0 in line\n  9:13  quiet - 0 in line\n  9:14  quiet - 0 in line\n  9:15  one arrives and goes to teller 1 - 0 in line\n  9:16  one arrives and goes to teller 2 - 0 in line\n  9:17  quiet - 0 in line\n  9:18  quiet - 0 in line\n  9:19  one arrives and waits - 1 in line\n\n2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> 4\nSettings, one at a time; an empty answer keeps the old value.\ntellers, now 2 (1 to 5)> \nminutes open, now 480 (30 to 600)> 240\nchance of a customer each minute, %, now 40 (1 to 100)> 60\nshortest service, minutes, now 2 (1 to 30)> \nlongest service, minutes, now 7 (2 to 30)> 10\nroom in the line, now 10 (0 to 50)> 3\nseed, now 2026 (0 to 999999)> \nNow: 2 tellers, open 240 minutes, a customer in 60% of minutes, 2 to 10 minutes each, room for 3 in line, seed 2026.\n\n2 tellers, open 240 minutes, a customer in 60% of minutes, 2 to 10 minutes each, room for 3 in line, seed 2026.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> 1\n139 customers came; 84 were served and 55 turned away, finding no room in the line.\nAverage wait 7.20 minutes; the longest 14. The line was at most 3 long.\nThe last customer left at 13:14; the tellers were busy 99.21% of that time.\nLittle's law: the line held 605 customer-minutes in all, and the customers waited 605 minutes in all - the same thing counted two ways.\n\n2 tellers, open 240 minutes, a customer in 60% of minutes, 2 to 10 minutes each, room for 3 in line, seed 2026.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> 2\n139 customers, the same ones each time:\n  tellers  served  away  average wait  longest  busy\n        1      41    98         17.24       29  99.63%\n        2      84    55          7.20       14  99.21%\n        3     122    17          3.11       10  96.18%\n        4     136     3          1.07        7  83.20%\n        5     139     0          0.17        3  68.26%\n\n2 tellers, open 240 minutes, a customer in 60% of minutes, 2 to 10 minutes each, room for 3 in line, seed 2026.\n1) the day  2) 1 to 5 tellers  3) the first 20 minutes  4) change settings  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "simple-queue",
      "caseId": "040-simple-queue",
      "title": "Case corpus: a self-authored FIFO queue"
    },
    {
      "slug": "bounded-queue-backpressure",
      "caseId": "248-bounded-queue-backpressure",
      "title": "Bounded queue backpressure — a bigger buffer is not more capacity"
    }
  ],
  "updated": "2026-10-14"
}
