{
  "id": "P053",
  "slug": "help-desk",
  "key": "P053-help-desk",
  "title": "Help desk queue",
  "summary": "Support tickets with four priorities, served most urgent first and first come, first served within a priority, kept in a binary heap. Open, serve, list the line, change a waiting ticket's priority or cancel it, and see the queue grouped by priority next to what has been served.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P053 - Help desk queue\n\nSupport tickets wait in one queue and are served most urgent first, and,\nwithin each priority, in the order they were opened. Open tickets with one\nof four priorities - urgent, high, normal, low - serve the next one, see\nthe whole line, change a waiting ticket's priority or cancel it, and see\nthe queue grouped by priority. At most 30 tickets wait at a time.\n\n- `main.eml` - the menu, reading tickets and answers, and the messages\n- `heap.eml` - the queue: a binary heap with pushing, serving, removing\n  any ticket, a priority change, and the serving order\n\nHow each part works:\n\n- The waiting tickets are a binary min-heap, as in the corpus case\n  `binary-heap`: one list, with no links between entries, where the entry\n  at index i has its children at 2i + 1 and 2i + 2. Every parent comes\n  before its children, so the root is always the next ticket to serve.\n- \"Comes before\" compares the priority first and then the ticket number.\n  Numbers only grow, so at the same priority the older ticket goes first.\n  Without that second rule a heap would serve equal priorities in no\n  particular order.\n- A new ticket goes at the end and moves up while it comes before its\n  parent. Serving takes the root, puts the last entry there, and moves it\n  down below the smaller child until neither child comes before it.\n  Cancelling a ticket from the middle does the same at that index; a\n  priority change moves the ticket up or down from where it is. Each of\n  these touches one path from the root to a leaf, never the whole queue.\n- The waiting line is worked out by serving a copy of the heap to the\n  end, so the queue itself is left as it was. The summary puts the waiting\n  tickets in one bucket per priority, as the corpus case\n  `task-priority-bucketer` sorts tasks into buckets, next to how many of\n  each priority have been served.\n\nWhat is checked: menu choices 1 to 8; a title of up to 40 characters; a\npriority from 1 to 4; a ticket number, with or without #, that is\nwaiting; at most 30 waiting tickets. An empty answer cancels.\n\nSessions: `sessions/basic.in` opens the eight sample tickets and shows\nthe line: two urgent first, in the order they came, then two high, two\nnormal and two low.\n- The two urgent tickets are served.\n- #8 is raised from normal to urgent and goes to the front.\n- #6 is cancelled.\n- A new high ticket, #9, goes in behind the two high tickets already\n  waiting, number 4 in line.\n- The summary has one bucket per priority. Two more tickets are served and\n  the line is shown again.\n\n`sessions/bad-input.in` gives:\n- menu choices 0 and x;\n- every action on the empty queue;\n- an empty title, a title over 40 characters, and priorities 5, x and an\n  empty one;\n- tickets x and #99, a change to the priority a ticket already has, and a\n  change and a cancel that are cancelled;\n- the sample three times, a fourth that would pass 30 tickets, five more\n  tickets up to 30, one too many, and the summary of the full queue.\n\nBuilt on the verified corpus cases `binary-heap` (a min-heap with sift up\nand sift down in one list) and `task-priority-bucketer` (tasks sorted into\npriority buckets).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P053 help-desk queue: open support tickets with a priority, serve them\n# most urgent first and, within a priority, in the order they came in;\n# change a waiting ticket's priority or cancel it, and see the queue grouped\n# by priority.\nimport heap\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 level_name(p):\n    return [\"urgent\", \"high\", \"normal\", \"low\"][p - 1]\n\ndef counted(n, one, many):\n    if n == 1:\n        return \"1 \" + one\n    return str(n) + \" \" + many\n\ndef ticket(t):\n    return \"#\" + str(t[1]) + \" \" + t[2] + \" (\" + level_name(t[0]) + \")\"\n\ndef place_in_line(q, number):\n    heap.service_order(q[0]) => order\n    for k in [0:len(order) - 1]:\n        if order[k][1] == number:\n            return k + 1\n    return 0\n\ndef ask_priority(prompt):\n    while True:\n        trim(input(prompt + \" (1 urgent, 2 high, 3 normal, 4 low)> \")) => answer\n        if answer == \"\":\n            return 0\n        if answer == \"1\" or answer == \"2\" or answer == \"3\" or answer == \"4\":\n            return int(answer)\n        \"Type 1, 2, 3 or 4.\" ^0\n\ndef ask_ticket(q, prompt):\n    # The index in the heap of a waiting ticket, or -1 when the answer is\n    # empty.\n    while True:\n        trim(input(prompt)) => answer\n        if answer == \"\":\n            return -1\n        if len(answer) > 1 and answer[0] == \"#\":\n            answer[1:len(answer)] => answer\n        True => digits\n        for c in answer:\n            if not (c >= \"0\" and c <= \"9\"):\n                False => digits\n        if answer != \"\" and digits and len(answer) < 6:\n            heap.find(q[0], int(answer)) => i\n            if i >= 0:\n                return i\n            (\"No ticket #\" + answer + \" is waiting.\") ^0\n        else:\n            \"Type a ticket number, like 3 or #3.\" ^0\n\ndef add(q, title, priority):\n    [priority, q[1], title] => t\n    q[1] + 1 => q[1]\n    heap.push(q[0], t) => q[0]\n    return t\n\ndef new_ticket(q):\n    if len(q[0]) == 30:\n        \"30 tickets are waiting, the most the queue holds - serve some first.\" ^0\n        return\n    while True:\n        trim(input(\"title> \")) => title\n        if title == \"\":\n            \"Cancelled.\" ^0\n            return\n        if len(title) <= 40:\n            break\n        \"Keep the title to 40 characters.\" ^0\n    ask_priority(\"priority\") => p\n    if p == 0:\n        \"Cancelled.\" ^0\n        return\n    add(q, title, p) => t\n    (\"Opened \" + ticket(t) + \": number \" + str(place_in_line(q, t[1])) + \" in line of \" + str(len(q[0])) + \".\") ^0\n\ndef serve(q):\n    if len(q[0]) == 0:\n        \"No ticket is waiting.\" ^0\n        return\n    heap.pop(q[0]) => res\n    res[1] => q[0]\n    res[0] => t\n    q[2][t[0] - 1] + 1 => q[2][t[0] - 1]\n    (\"Serving \" + ticket(t) + \". \" + counted(len(q[0]), \"ticket\", \"tickets\") + \" still waiting.\") ^0\n\ndef waiting(q):\n    if len(q[0]) == 0:\n        \"No ticket is waiting.\" ^0\n        return\n    heap.service_order(q[0]) => order\n    for k in [0:len(order) - 1]:\n        str(k + 1) => n\n        while len(n) < 3:\n            \" \" + n => n\n        (n + \". \" + ticket(order[k])) ^0\n\ndef change(q):\n    if len(q[0]) == 0:\n        \"No ticket is waiting.\" ^0\n        return\n    ask_ticket(q, \"ticket> \") => i\n    if i == -1:\n        \"Cancelled.\" ^0\n        return\n    q[0][i] => t\n    ask_priority(\"new priority\") => p\n    if p == 0:\n        \"Cancelled.\" ^0\n        return\n    if p == t[0]:\n        (\"#\" + str(t[1]) + \" is \" + level_name(p) + \" already.\") ^0\n        return\n    level_name(t[0]) => was\n    heap.reprioritized(q[0], i, p)\n    (\"#\" + str(t[1]) + \" \" + t[2] + \": \" + was + \" -> \" + level_name(p) + \", now number \" + str(place_in_line(q, t[1])) + \" in line.\") ^0\n\ndef cancel(q):\n    if len(q[0]) == 0:\n        \"No ticket is waiting.\" ^0\n        return\n    ask_ticket(q, \"ticket to cancel> \") => i\n    if i == -1:\n        \"Cancelled.\" ^0\n        return\n    heap.removed_at(q[0], i) => res\n    res[1] => q[0]\n    (\"Cancelled \" + ticket(res[0]) + \". \" + counted(len(q[0]), \"ticket\", \"tickets\") + \" still waiting.\") ^0\n\ndef summary(q):\n    # Waiting tickets in one bucket per priority, as the corpus case\n    # task-priority-bucketer sorts tasks into buckets, and how many of each\n    # priority have been served.\n    [0, 0, 0, 0] => counts\n    for t in q[0]:\n        counts[t[0] - 1] + 1 => counts[t[0] - 1]\n    \"priority  waiting  served\" ^0\n    for p in [1:4]:\n        level_name(p) => name\n        while len(name) < 10:\n            name + \" \" => name\n        str(counts[p - 1]) => w\n        while len(w) < 7:\n            \" \" + w => w\n        str(q[2][p - 1]) => s\n        while len(s) < 8:\n            \" \" + s => s\n        name + w + s => line\n        if counts[p - 1] > 0:\n            line + \"  \" + \"#\" * counts[p - 1] => line\n        line ^0\n    (\"Waiting \" + str(len(q[0])) + \", served \" + str(q[2][0] + q[2][1] + q[2][2] + q[2][3]) + \", next ticket number #\" + str(q[1]) + \".\") ^0\n\ndef sample(q):\n    for t in [[\"Printer out of toner\", 4], [\"Cannot log in to email\", 2], [\"Server room too warm\", 1],\n              [\"New laptop for Maria\", 3], [\"VPN drops every hour\", 2], [\"Update the wiki page\", 4],\n              [\"Payroll system down\", 1], [\"Monitor flickers\", 3]]:\n        add(q, t[0], t[1])\n\n\"== Help desk ==\" ^0\n\"Tickets are served most urgent first, and in the order they came within a priority.\" ^0\n# [the heap, the next ticket number, served per priority]\n[[], 1, [0, 0, 0, 0]] => q\nTrue => running\nwhile running:\n    \"\" ^0\n    \"1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\" ^0\n    trim(input(\"choice> \")) => choice\n    if choice == \"1\":\n        new_ticket(q)\n    elif choice == \"2\":\n        serve(q)\n    elif choice == \"3\":\n        waiting(q)\n    elif choice == \"4\":\n        change(q)\n    elif choice == \"5\":\n        cancel(q)\n    elif choice == \"6\":\n        summary(q)\n    elif choice == \"7\":\n        if len(q[0]) + 8 > 30:\n            \"The sample would take the queue past 30 tickets.\" ^0\n        else:\n            q[1] => first\n            sample(q)\n            (\"Opened 8 sample tickets, #\" + str(first) + \" to #\" + str(q[1] - 1) + \".\") ^0\n    elif choice == \"8\":\n        False => running\n    else:\n        \"Pick a number from 1 to 8.\" ^0\n\"Bye.\" ^0\n",
      "python": "import heap\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 level_name(p):\n    return [\"urgent\", \"high\", \"normal\", \"low\"][p - 1]\n\ndef counted(n, one, many):\n    if n == 1:\n        return \"1 \" + one\n    return str(n) + \" \" + many\n\ndef ticket(t):\n    return \"#\" + str(t[1]) + \" \" + t[2] + \" (\" + level_name(t[0]) + \")\"\n\ndef place_in_line(q, number):\n    order = heap.service_order(q[0])\n    for k in range(0, len(order)):\n        if order[k][1] == number:\n            return k + 1\n    return 0\n\ndef ask_priority(prompt):\n    while True:\n        answer = trim(input(prompt + \" (1 urgent, 2 high, 3 normal, 4 low)> \"))\n        if answer == \"\":\n            return 0\n        if answer == \"1\" or answer == \"2\" or answer == \"3\" or answer == \"4\":\n            return int(answer)\n        print(\"Type 1, 2, 3 or 4.\")\n\ndef ask_ticket(q, prompt):\n    while True:\n        answer = trim(input(prompt))\n        if answer == \"\":\n            return -1\n        if len(answer) > 1 and answer[0] == \"#\":\n            answer = answer[1:len(answer)]\n        digits = True\n        for c in answer:\n            if not (c >= \"0\" and c <= \"9\"):\n                digits = False\n        if answer != \"\" and digits and len(answer) < 6:\n            i = heap.find(q[0], int(answer))\n            if i >= 0:\n                return i\n            print(\"No ticket #\" + answer + \" is waiting.\")\n        else:\n            print(\"Type a ticket number, like 3 or #3.\")\n\ndef add(q, title, priority):\n    t = [priority, q[1], title]\n    q[1] = q[1] + 1\n    q[0] = heap.push(q[0], t)\n    return t\n\ndef new_ticket(q):\n    if len(q[0]) == 30:\n        print(\"30 tickets are waiting, the most the queue holds - serve some first.\")\n        return\n    while True:\n        title = trim(input(\"title> \"))\n        if title == \"\":\n            print(\"Cancelled.\")\n            return\n        if len(title) <= 40:\n            break\n        print(\"Keep the title to 40 characters.\")\n    p = ask_priority(\"priority\")\n    if p == 0:\n        print(\"Cancelled.\")\n        return\n    t = add(q, title, p)\n    print(\"Opened \" + ticket(t) + \": number \" + str(place_in_line(q, t[1])) + \" in line of \" + str(len(q[0])) + \".\")\n\ndef serve(q):\n    if len(q[0]) == 0:\n        print(\"No ticket is waiting.\")\n        return\n    res = heap.pop(q[0])\n    q[0] = res[1]\n    t = res[0]\n    q[2][t[0] - 1] = q[2][t[0] - 1] + 1\n    print(\"Serving \" + ticket(t) + \". \" + counted(len(q[0]), \"ticket\", \"tickets\") + \" still waiting.\")\n\ndef waiting(q):\n    if len(q[0]) == 0:\n        print(\"No ticket is waiting.\")\n        return\n    order = heap.service_order(q[0])\n    for k in range(0, len(order)):\n        n = str(k + 1)\n        while len(n) < 3:\n            n = \" \" + n\n        print(n + \". \" + ticket(order[k]))\n\ndef change(q):\n    if len(q[0]) == 0:\n        print(\"No ticket is waiting.\")\n        return\n    i = ask_ticket(q, \"ticket> \")\n    if i == -1:\n        print(\"Cancelled.\")\n        return\n    t = q[0][i]\n    p = ask_priority(\"new priority\")\n    if p == 0:\n        print(\"Cancelled.\")\n        return\n    if p == t[0]:\n        print(\"#\" + str(t[1]) + \" is \" + level_name(p) + \" already.\")\n        return\n    was = level_name(t[0])\n    heap.reprioritized(q[0], i, p)\n    print(\"#\" + str(t[1]) + \" \" + t[2] + \": \" + was + \" -> \" + level_name(p) + \", now number \" + str(place_in_line(q, t[1])) + \" in line.\")\n\ndef cancel(q):\n    if len(q[0]) == 0:\n        print(\"No ticket is waiting.\")\n        return\n    i = ask_ticket(q, \"ticket to cancel> \")\n    if i == -1:\n        print(\"Cancelled.\")\n        return\n    res = heap.removed_at(q[0], i)\n    q[0] = res[1]\n    print(\"Cancelled \" + ticket(res[0]) + \". \" + counted(len(q[0]), \"ticket\", \"tickets\") + \" still waiting.\")\n\ndef summary(q):\n    counts = [0, 0, 0, 0]\n    for t in q[0]:\n        counts[t[0] - 1] = counts[t[0] - 1] + 1\n    print(\"priority  waiting  served\")\n    for p in range(1, 5):\n        name = level_name(p)\n        while len(name) < 10:\n            name = name + \" \"\n        w = str(counts[p - 1])\n        while len(w) < 7:\n            w = \" \" + w\n        s = str(q[2][p - 1])\n        while len(s) < 8:\n            s = \" \" + s\n        line = name + w + s\n        if counts[p - 1] > 0:\n            line = line + \"  \" + \"#\" * counts[p - 1]\n        print(line)\n    print(\"Waiting \" + str(len(q[0])) + \", served \" + str(q[2][0] + q[2][1] + q[2][2] + q[2][3]) + \", next ticket number #\" + str(q[1]) + \".\")\n\ndef sample(q):\n    for t in [[\"Printer out of toner\", 4], [\"Cannot log in to email\", 2], [\"Server room too warm\", 1], [\"New laptop for Maria\", 3], [\"VPN drops every hour\", 2], [\"Update the wiki page\", 4], [\"Payroll system down\", 1], [\"Monitor flickers\", 3]]:\n        add(q, t[0], t[1])\n\nprint(\"== Help desk ==\")\nprint(\"Tickets are served most urgent first, and in the order they came within a priority.\")\nq = [[], 1, [0, 0, 0, 0]]\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\")\n    choice = trim(input(\"choice> \"))\n    if choice == \"1\":\n        new_ticket(q)\n    elif choice == \"2\":\n        serve(q)\n    elif choice == \"3\":\n        waiting(q)\n    elif choice == \"4\":\n        change(q)\n    elif choice == \"5\":\n        cancel(q)\n    elif choice == \"6\":\n        summary(q)\n    elif choice == \"7\":\n        if len(q[0]) + 8 > 30:\n            print(\"The sample would take the queue past 30 tickets.\")\n        else:\n            first = q[1]\n            sample(q)\n            print(\"Opened 8 sample tickets, #\" + str(first) + \" to #\" + str(q[1] - 1) + \".\")\n    elif choice == \"8\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 8.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "heap.eml",
      "eml": "# P053 help-desk queue - the waiting tickets as a binary min-heap, the\n# corpus case binary-heap's structure: no child pointers, the entry at index\n# i has its children at 2i + 1 and 2i + 2. An entry is a ticket\n# [priority, number, title]. One ticket comes before another when its\n# priority is more urgent (a smaller number), or, at the same priority, when\n# it was opened first (a smaller ticket number) - first come, first served\n# within each priority.\n\ndef before(a, b):\n    return a[0] < b[0] or (a[0] == b[0] and a[1] < b[1])\n\ndef swap(h, i, j):\n    h[i] => t\n    h[j] => h[i]\n    t => h[j]\n\ndef sift_up(h, i):\n    while i > 0:\n        int((i - 1) / 2) => p\n        if not before(h[i], h[p]):\n            return\n        swap(h, i, p)\n        p => i\n\ndef sift_down(h, i):\n    len(h) => n\n    while True:\n        2 * i + 1 => l\n        l + 1 => r\n        i => m\n        if l < n and before(h[l], h[m]):\n            l => m\n        if r < n and before(h[r], h[m]):\n            r => m\n        if m == i:\n            return\n        swap(h, i, m)\n        m => i\n\ndef push(h, entry):\n    # Returns the heap with entry in it (the list grows by +, which makes a\n    # new list, so the caller keeps the returned one).\n    h + [entry] => h\n    sift_up(h, len(h) - 1)\n    return h\n\ndef removed_at(h, i):\n    # Returns [the entry at index i, the heap without it]. The last entry\n    # moves into the gap and sifts up or down - only one of the two moves it.\n    h[i] => out\n    h[len(h) - 1] => last\n    h[0:len(h) - 1] => h\n    if i < len(h):\n        last => h[i]\n        sift_up(h, i)\n        sift_down(h, i)\n    return [out, h]\n\ndef pop(h):\n    return removed_at(h, 0)\n\ndef find(h, number):\n    for i in [0:len(h) - 1]:\n        if h[i][1] == number:\n            return i\n    return -1\n\ndef reprioritized(h, i, priority):\n    priority => h[i][0]\n    sift_up(h, i)\n    sift_down(h, i)\n\ndef service_order(h):\n    # The waiting tickets in the order they will be served: popped one by one\n    # from a copy, so the queue itself is left alone.\n    h[0:len(h)] => c\n    [] => out\n    while len(c) > 0:\n        pop(c) => res\n        out + [res[0]] => out\n        res[1] => c\n    return out\n",
      "python": "def before(a, b):\n    return a[0] < b[0] or a[0] == b[0] and a[1] < b[1]\n\ndef swap(h, i, j):\n    t = h[i]\n    h[i] = h[j]\n    h[j] = t\n\ndef sift_up(h, i):\n    while i > 0:\n        p = int((i - 1) / 2)\n        if not before(h[i], h[p]):\n            return\n        swap(h, i, p)\n        i = p\n\ndef sift_down(h, i):\n    n = len(h)\n    while True:\n        l = 2 * i + 1\n        r = l + 1\n        m = i\n        if l < n and before(h[l], h[m]):\n            m = l\n        if r < n and before(h[r], h[m]):\n            m = r\n        if m == i:\n            return\n        swap(h, i, m)\n        i = m\n\ndef push(h, entry):\n    h = h + [entry]\n    sift_up(h, len(h) - 1)\n    return h\n\ndef removed_at(h, i):\n    out = h[i]\n    last = h[len(h) - 1]\n    h = h[0:len(h) - 1]\n    if i < len(h):\n        h[i] = last\n        sift_up(h, i)\n        sift_down(h, i)\n    return [out, h]\n\ndef pop(h):\n    return removed_at(h, 0)\n\ndef find(h, number):\n    for i in range(0, len(h)):\n        if h[i][1] == number:\n            return i\n    return -1\n\ndef reprioritized(h, i, priority):\n    h[i][0] = priority\n    sift_up(h, i)\n    sift_down(h, i)\n\ndef service_order(h):\n    c = h[0:len(h)]\n    out = []\n    while len(c) > 0:\n        res = pop(c)\n        out = out + [res[0]]\n        c = res[1]\n    return out\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n2\n3\n4\n5\n6\n1\n\n1\nThis title is far too long to be accepted here\nShort title\n5\nx\n\n1\nBroken chair\n4\n4\nx\n#99\n1\n4\n4\n#1\n\n5\n\n7\n7\n7\n7\n1\nExtra one\n3\n1\nExtra two\n3\n1\nExtra three\n3\n1\nExtra four\n3\n1\nExtra five\n3\n1\n6\n8\n",
      "screen": "== Help desk ==\nTickets are served most urgent first, and in the order they came within a priority.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 0\nPick a number from 1 to 8.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> x\nPick a number from 1 to 8.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 2\nNo ticket is waiting.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 3\nNo ticket is waiting.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 4\nNo ticket is waiting.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 5\nNo ticket is waiting.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 6\npriority  waiting  served\nurgent          0       0\nhigh            0       0\nnormal          0       0\nlow             0       0\nWaiting 0, served 0, next ticket number #1.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 1\ntitle> \nCancelled.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 1\ntitle> This title is far too long to be accepted here\nKeep the title to 40 characters.\ntitle> Short title\npriority (1 urgent, 2 high, 3 normal, 4 low)> 5\nType 1, 2, 3 or 4.\npriority (1 urgent, 2 high, 3 normal, 4 low)> x\nType 1, 2, 3 or 4.\npriority (1 urgent, 2 high, 3 normal, 4 low)> \nCancelled.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 1\ntitle> Broken chair\npriority (1 urgent, 2 high, 3 normal, 4 low)> 4\nOpened #1 Broken chair (low): number 1 in line of 1.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 4\nticket> x\nType a ticket number, like 3 or #3.\nticket> #99\nNo ticket #99 is waiting.\nticket> 1\nnew priority (1 urgent, 2 high, 3 normal, 4 low)> 4\n#1 is low already.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 4\nticket> #1\nnew priority (1 urgent, 2 high, 3 normal, 4 low)> \nCancelled.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 5\nticket to cancel> \nCancelled.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 7\nOpened 8 sample tickets, #2 to #9.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 7\nOpened 8 sample tickets, #10 to #17.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 7\nOpened 8 sample tickets, #18 to #25.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 7\nThe sample would take the queue past 30 tickets.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 1\ntitle> Extra one\npriority (1 urgent, 2 high, 3 normal, 4 low)> 3\nOpened #26 Extra one (normal): number 19 in line of 26.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 1\ntitle> Extra two\npriority (1 urgent, 2 high, 3 normal, 4 low)> 3\nOpened #27 Extra two (normal): number 20 in line of 27.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 1\ntitle> Extra three\npriority (1 urgent, 2 high, 3 normal, 4 low)> 3\nOpened #28 Extra three (normal): number 21 in line of 28.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 1\ntitle> Extra four\npriority (1 urgent, 2 high, 3 normal, 4 low)> 3\nOpened #29 Extra four (normal): number 22 in line of 29.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 1\ntitle> Extra five\npriority (1 urgent, 2 high, 3 normal, 4 low)> 3\nOpened #30 Extra five (normal): number 23 in line of 30.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 1\n30 tickets are waiting, the most the queue holds - serve some first.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 6\npriority  waiting  served\nurgent          6       0  ######\nhigh            6       0  ######\nnormal         11       0  ###########\nlow             7       0  #######\nWaiting 30, served 0, next ticket number #31.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 8\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "7\n3\n2\n2\n4\n8\n1\n5\n#6\n1\nCoffee machine leaks\n2\n6\n2\n2\n3\n8\n",
      "screen": "== Help desk ==\nTickets are served most urgent first, and in the order they came within a priority.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 7\nOpened 8 sample tickets, #1 to #8.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 3\n  1. #3 Server room too warm (urgent)\n  2. #7 Payroll system down (urgent)\n  3. #2 Cannot log in to email (high)\n  4. #5 VPN drops every hour (high)\n  5. #4 New laptop for Maria (normal)\n  6. #8 Monitor flickers (normal)\n  7. #1 Printer out of toner (low)\n  8. #6 Update the wiki page (low)\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 2\nServing #3 Server room too warm (urgent). 7 tickets still waiting.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 2\nServing #7 Payroll system down (urgent). 6 tickets still waiting.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 4\nticket> 8\nnew priority (1 urgent, 2 high, 3 normal, 4 low)> 1\n#8 Monitor flickers: normal -> urgent, now number 1 in line.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 5\nticket to cancel> #6\nCancelled #6 Update the wiki page (low). 5 tickets still waiting.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 1\ntitle> Coffee machine leaks\npriority (1 urgent, 2 high, 3 normal, 4 low)> 2\nOpened #9 Coffee machine leaks (high): number 4 in line of 6.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 6\npriority  waiting  served\nurgent          1       2  #\nhigh            3       0  ###\nnormal          1       0  #\nlow             1       0  #\nWaiting 6, served 2, next ticket number #10.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 2\nServing #8 Monitor flickers (urgent). 5 tickets still waiting.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 2\nServing #2 Cannot log in to email (high). 4 tickets still waiting.\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 3\n  1. #5 VPN drops every hour (high)\n  2. #9 Coffee machine leaks (high)\n  3. #4 New laptop for Maria (normal)\n  4. #1 Printer out of toner (low)\n\n1) new ticket  2) serve next  3) waiting  4) change priority  5) cancel  6) summary  7) sample  8) quit\nchoice> 8\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "binary-heap",
      "caseId": "096-binary-heap",
      "title": "Binary heap (min-heap priority queue)"
    },
    {
      "slug": "task-priority-bucketer",
      "caseId": "045-task-priority-bucketer",
      "title": "Task priority bucketer"
    }
  ],
  "updated": "2026-10-10"
}
