{
  "id": "P073",
  "slug": "linked-list",
  "key": "P073-linked-list",
  "title": "Linked list playground",
  "summary": "A singly linked list kept as values and next-slot links, drawn with the slots it lives in: insert, delete (the slot is freed and reused), reverse by the three-pointer walk, the middle by a slow and a fast walker, and a loop closed and found again by Floyd's two walkers.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P073 - Linked list playground\n\nA singly linked list drawn two ways: as the chain from the head, and as\nthe slots its nodes live in, each with its value and the slot of the\nnext node. Insert, delete, reverse, find the middle, and close a loop to\nwatch Floyd's two walkers find it. It starts with 7, 3, 9, 4, 1.\n\n- `main.eml` - the menu, drawing, and the questions\n- `links.eml` - the list as values and links: making nodes in free slots,\n  walking, insert, delete, reverse, the middle, loops and Floyd's method\n\nHow each part works:\n\n- As in the corpus case `linked-list-operations`, a list is two parallel\n  lists - values[i] is node i's value and nexts[i] the slot of the node\n  after it, -1 for the end - and the slot of the head. Pointers are slot\n  numbers.\n- Insert changes two links and moves nothing. A deleted node is unlinked\n  - the node before it skips over it - and its slot is marked free; the\n  next new node takes the lowest free slot, as an allocator reuses memory.\n- Reverse is the corpus case's three-pointer walk: keep the next node,\n  point the current one back at the previous, step on. One pass, nothing\n  new made.\n- Middle: two walkers from the head, the fast one taking two steps for\n  each one of the slow. When the fast one runs out, the slow one is at\n  position n // 2 - with an even number of nodes, the second of the two\n  middles.\n- Loop: the last node is pointed back at a chosen node. The drawing\n  stops where the walk comes round again. Floyd's method finds the loop\n  with no memory of where the walkers have been: if there is a loop, the\n  fast walker catches the slow one inside it. Then one walker from the\n  head and one from the meeting point, a step at a time each, meet\n  exactly where the loop starts. A loop has no end, so insert, delete,\n  reverse and middle wait until it is broken again.\n\nWhat is checked: menu choices 1 to 9; values from 0 to 999; positions\ninside the list; at most 12 nodes. An empty answer cancels.\n\nSessions: `sessions/basic.in` gives:\n- the list, 5 inserted at position 2, 3 deleted (slot 1 freed), and 8\n  added at the end in that freed slot;\n- the reverse, with the head now slot 1, and the middle of 6 nodes;\n- a loop back to position 2, found: it starts at [4] and goes round 4\n  nodes;\n- the loop refusing an insert, then broken, and no loop found.\n\n`sessions/bad-input.in` gives:\n- menu choices 0 and x;\n- the values abc and 1000, position 9 of 0 to 5, then a cancel;\n- deleting 42, which no node holds; loop position 7 of 0 to 4, then a\n  cancel;\n- seven nodes added to fill all 12, a thirteenth refused, and the middle\n  of 12.\n\nBuilt on the verified corpus case `linked-list-operations` (values and\nnext-indices in parallel lists, and the three-pointer reverse).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P073 linked list playground: a singly linked list drawn as its nodes and\n# links, with the slots they live in. Insert, delete, reverse, find the\n# middle, close a loop and find it again with Floyd's two walkers.\nimport links\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    # A whole number of up to 3 digits, or -1.\n    if len(s) == 0 or len(s) > 3:\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 draw(lst):\n    links.walk(lst) => w\n    lst[0] => values\n    \"head\" => line\n    for i in w[0]:\n        line + \" -> [\" + str(values[i]) + \"]\" => line\n    if w[1] == -1:\n        line + \" -> end\" => line\n    else:\n        line + \" -> back to [\" + str(values[w[1]]) + \"]\" => line\n    (\"  \" + line) ^0\n    \"  slot  value  next\" ^0\n    lst[1] => nexts\n    for i in [0:len(nexts) - 1]:\n        if nexts[i] == -2:\n            (\"  \" + lpad(str(i), 4) + \"  (free)\") ^0\n        else:\n            \"end\" => nx\n            if nexts[i] >= 0:\n                str(nexts[i]) => nx\n            (\"  \" + lpad(str(i), 4) + lpad(str(values[i]), 7) + lpad(nx, 6)) ^0\n    (\"  head is slot \" + str(lst[2]) + \".\") ^0\n\ndef looped(lst):\n    return links.walk(lst)[1] != -1\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 add_end(lst):\n    if links.length(lst) == 12:\n        \"The list is full: 12 nodes.\" ^0\n        return lst\n    ask(\"value\", 0, 999) => v\n    if v == -1:\n        \"Cancelled.\" ^0\n        return lst\n    links.insert_at(lst, links.length(lst), v) => lst\n    draw(lst)\n    return lst\n\ndef insert(lst):\n    if links.length(lst) == 12:\n        \"The list is full: 12 nodes.\" ^0\n        return lst\n    ask(\"value\", 0, 999) => v\n    if v == -1:\n        \"Cancelled.\" ^0\n        return lst\n    ask(\"position\", 0, links.length(lst)) => p\n    if p == -1:\n        \"Cancelled.\" ^0\n        return lst\n    links.insert_at(lst, p, v) => lst\n    draw(lst)\n    return lst\n\ndef delete(lst):\n    if links.length(lst) == 0:\n        \"The list is empty.\" ^0\n        return lst\n    ask(\"value\", 0, 999) => v\n    if v == -1:\n        \"Cancelled.\" ^0\n        return lst\n    links.delete_value(lst, v) => r\n    if r[1] == -1:\n        (\"No node holds \" + str(v) + \".\") ^0\n        return lst\n    (\"Deleted \" + str(v) + \" from position \" + str(r[1]) + \"; its slot is free for the next node.\") ^0\n    draw(r[0])\n    return r[0]\n\ndef middle(lst):\n    links.length(lst) => n\n    if n == 0:\n        \"The list is empty.\" ^0\n        return\n    links.middle(lst) => m\n    lst[0][m[0]] => v\n    (str(n) + \" nodes: when the fast walker ran out, the slow one had taken \" + str(m[1]) + \" steps, to [\" + str(v) + \"] at position \" + str(m[1]) + \".\") ^0\n    if n % 2 == 0:\n        \"With an even number of nodes there are two middles; this way finds the second.\" ^0\n\ndef loop(lst):\n    if looped(lst):\n        links.walk(lst) => w\n        lst[0][w[0][len(w[0]) - 1]] => last\n        links.break_loop(lst) => lst\n        (\"Loop broken: [\" + str(last) + \"] points to the end again.\") ^0\n        draw(lst)\n        return lst\n    links.length(lst) => n\n    if n == 0:\n        \"The list is empty.\" ^0\n        return lst\n    ask(\"point the last node back to position\", 0, n - 1) => p\n    if p == -1:\n        \"Cancelled.\" ^0\n        return lst\n    links.close_loop(lst, p) => lst\n    draw(lst)\n    return lst\n\ndef find_loop(lst):\n    links.floyd(lst) => f\n    if not f[0]:\n        (\"No loop: the fast walker reached the end after \" + str(f[1]) + \" steps.\") ^0\n        return\n    links.walk(lst)[0] => order\n    0 => pos\n    for k in [0:len(order) - 1]:\n        if order[k] == f[2]:\n            k => pos\n    (\"A loop: the two walkers met after \" + str(f[1]) + \" steps. It starts at [\" + str(lst[0][f[2]]) + \"], position \" + str(pos) + \", and goes round \" + str(f[3]) + \" nodes.\") ^0\n\nlinks.new_list() => lst\nfor v in [7, 3, 9, 4, 1]:\n    links.insert_at(lst, links.length(lst), v) => lst\n\n\"== Linked list playground ==\" ^0\n\"A singly linked list: each node holds a value and the slot of the next node.\" ^0\nTrue => running\nwhile running:\n    \"\" ^0\n    \"1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\" ^0\n    trim(input(\"choice> \")) => choice\n    if choice == \"1\":\n        draw(lst)\n    elif choice == \"7\":\n        loop(lst) => lst\n    elif choice == \"8\":\n        find_loop(lst)\n    elif choice == \"9\":\n        False => running\n    elif (choice == \"2\" or choice == \"3\" or choice == \"4\" or choice == \"5\" or choice == \"6\") and looped(lst):\n        \"The list has a loop, so it has no end: break the loop first (7).\" ^0\n    elif choice == \"2\":\n        add_end(lst) => lst\n    elif choice == \"3\":\n        insert(lst) => lst\n    elif choice == \"4\":\n        delete(lst) => lst\n    elif choice == \"5\":\n        links.reverse(lst) => lst\n        draw(lst)\n    elif choice == \"6\":\n        middle(lst)\n    else:\n        \"Pick a number from 1 to 9.\" ^0\n\"Bye.\" ^0\n",
      "python": "import links\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) > 3:\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 draw(lst):\n    w = links.walk(lst)\n    values = lst[0]\n    line = \"head\"\n    for i in w[0]:\n        line = line + \" -> [\" + str(values[i]) + \"]\"\n    if w[1] == -1:\n        line = line + \" -> end\"\n    else:\n        line = line + \" -> back to [\" + str(values[w[1]]) + \"]\"\n    print(\"  \" + line)\n    print(\"  slot  value  next\")\n    nexts = lst[1]\n    for i in range(0, len(nexts)):\n        if nexts[i] == -2:\n            print(\"  \" + lpad(str(i), 4) + \"  (free)\")\n        else:\n            nx = \"end\"\n            if nexts[i] >= 0:\n                nx = str(nexts[i])\n            print(\"  \" + lpad(str(i), 4) + lpad(str(values[i]), 7) + lpad(nx, 6))\n    print(\"  head is slot \" + str(lst[2]) + \".\")\n\ndef looped(lst):\n    return links.walk(lst)[1] != -1\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 add_end(lst):\n    if links.length(lst) == 12:\n        print(\"The list is full: 12 nodes.\")\n        return lst\n    v = ask(\"value\", 0, 999)\n    if v == -1:\n        print(\"Cancelled.\")\n        return lst\n    lst = links.insert_at(lst, links.length(lst), v)\n    draw(lst)\n    return lst\n\ndef insert(lst):\n    if links.length(lst) == 12:\n        print(\"The list is full: 12 nodes.\")\n        return lst\n    v = ask(\"value\", 0, 999)\n    if v == -1:\n        print(\"Cancelled.\")\n        return lst\n    p = ask(\"position\", 0, links.length(lst))\n    if p == -1:\n        print(\"Cancelled.\")\n        return lst\n    lst = links.insert_at(lst, p, v)\n    draw(lst)\n    return lst\n\ndef delete(lst):\n    if links.length(lst) == 0:\n        print(\"The list is empty.\")\n        return lst\n    v = ask(\"value\", 0, 999)\n    if v == -1:\n        print(\"Cancelled.\")\n        return lst\n    r = links.delete_value(lst, v)\n    if r[1] == -1:\n        print(\"No node holds \" + str(v) + \".\")\n        return lst\n    print(\"Deleted \" + str(v) + \" from position \" + str(r[1]) + \"; its slot is free for the next node.\")\n    draw(r[0])\n    return r[0]\n\ndef middle(lst):\n    n = links.length(lst)\n    if n == 0:\n        print(\"The list is empty.\")\n        return\n    m = links.middle(lst)\n    v = lst[0][m[0]]\n    print(str(n) + \" nodes: when the fast walker ran out, the slow one had taken \" + str(m[1]) + \" steps, to [\" + str(v) + \"] at position \" + str(m[1]) + \".\")\n    if n % 2 == 0:\n        print(\"With an even number of nodes there are two middles; this way finds the second.\")\n\ndef loop(lst):\n    if looped(lst):\n        w = links.walk(lst)\n        last = lst[0][w[0][len(w[0]) - 1]]\n        lst = links.break_loop(lst)\n        print(\"Loop broken: [\" + str(last) + \"] points to the end again.\")\n        draw(lst)\n        return lst\n    n = links.length(lst)\n    if n == 0:\n        print(\"The list is empty.\")\n        return lst\n    p = ask(\"point the last node back to position\", 0, n - 1)\n    if p == -1:\n        print(\"Cancelled.\")\n        return lst\n    lst = links.close_loop(lst, p)\n    draw(lst)\n    return lst\n\ndef find_loop(lst):\n    f = links.floyd(lst)\n    if not f[0]:\n        print(\"No loop: the fast walker reached the end after \" + str(f[1]) + \" steps.\")\n        return\n    order = links.walk(lst)[0]\n    pos = 0\n    for k in range(0, len(order)):\n        if order[k] == f[2]:\n            pos = k\n    print(\"A loop: the two walkers met after \" + str(f[1]) + \" steps. It starts at [\" + str(lst[0][f[2]]) + \"], position \" + str(pos) + \", and goes round \" + str(f[3]) + \" nodes.\")\n\nlst = links.new_list()\nfor v in [7, 3, 9, 4, 1]:\n    lst = links.insert_at(lst, links.length(lst), v)\nprint(\"== Linked list playground ==\")\nprint(\"A singly linked list: each node holds a value and the slot of the next node.\")\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\")\n    choice = trim(input(\"choice> \"))\n    if choice == \"1\":\n        draw(lst)\n    elif choice == \"7\":\n        lst = loop(lst)\n    elif choice == \"8\":\n        find_loop(lst)\n    elif choice == \"9\":\n        running = False\n    elif (choice == \"2\" or choice == \"3\" or choice == \"4\" or choice == \"5\" or choice == \"6\") and looped(lst):\n        print(\"The list has a loop, so it has no end: break the loop first (7).\")\n    elif choice == \"2\":\n        lst = add_end(lst)\n    elif choice == \"3\":\n        lst = insert(lst)\n    elif choice == \"4\":\n        lst = delete(lst)\n    elif choice == \"5\":\n        lst = links.reverse(lst)\n        draw(lst)\n    elif choice == \"6\":\n        middle(lst)\n    else:\n        print(\"Pick a number from 1 to 9.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "links.eml",
      "eml": "# P073 linked list playground - a singly linked list kept as two parallel\n# lists, as in the corpus case linked-list-operations: values[i] is node\n# i's payload and nexts[i] the index of the node after it, -1 for the end.\n# A deleted node is marked free (next = -2) and its slot is reused by the\n# next node made, the way an allocator reuses memory.\n#\n# A list is [values, nexts, head].\n\ndef new_list():\n    return [[], [], -1]\n\ndef make_node(lst, value):\n    # A slot for a new node: the lowest free one, or a new one at the end.\n    # Returns [list, index].\n    lst[0] => values\n    lst[1] => nexts\n    -1 => slot\n    for i in [0:len(nexts) - 1]:\n        if slot == -1 and nexts[i] == -2:\n            i => slot\n    if slot == -1:\n        values + [value] => values\n        nexts + [-1] => nexts\n        len(values) - 1 => slot\n    else:\n        value => values[slot]\n        -1 => nexts[slot]\n    return [[values, nexts, lst[2]], slot]\n\ndef walk(lst):\n    # The node indices from the head, stopping at the end or at the first\n    # node seen twice (a loop): [indices, index the loop goes back to or -1].\n    lst[1] => nexts\n    [] => out\n    [0] * len(nexts) => seen\n    lst[2] => cur\n    while cur != -1:\n        if seen[cur] == 1:\n            return [out, cur]\n        1 => seen[cur]\n        out + [cur] => out\n        nexts[cur] => cur\n    return [out, -1]\n\ndef length(lst):\n    return len(walk(lst)[0])\n\ndef node_at(lst, pos):\n    # The index of the node at position pos (0 = head).\n    walk(lst)[0] => order\n    return order[pos]\n\ndef insert_at(lst, pos, value):\n    # Insert value so it becomes position pos (0 = new head, length = at\n    # the end): two links change, nothing moves.\n    make_node(lst, value) => made\n    made[0] => lst\n    made[1] => k\n    lst[1] => nexts\n    if pos == 0:\n        lst[2] => nexts[k]\n        return [lst[0], nexts, k]\n    node_at(lst, pos - 1) => before\n    nexts[before] => nexts[k]\n    k => nexts[before]\n    return [lst[0], nexts, lst[2]]\n\ndef delete_value(lst, value):\n    # Unlink the first node holding value and free its slot: the node\n    # before it skips over it. Returns [list, position deleted or -1].\n    lst[0] => values\n    lst[1] => nexts\n    lst[2] => head\n    -1 => prev\n    head => cur\n    0 => pos\n    while cur != -1:\n        if values[cur] == value:\n            if prev == -1:\n                nexts[cur] => head\n            else:\n                nexts[cur] => nexts[prev]\n            -2 => nexts[cur]\n            return [[values, nexts, head], pos]\n        cur => prev\n        nexts[cur] => cur\n        pos + 1 => pos\n    return [lst, -1]\n\ndef reverse(lst):\n    # The corpus case's three-pointer walk: turn every link around in one\n    # pass, keeping the node that comes next before the link is changed.\n    lst[1] => nexts\n    -1 => prev\n    lst[2] => cur\n    while cur != -1:\n        nexts[cur] => following\n        prev => nexts[cur]\n        cur => prev\n        following => cur\n    return [lst[0], nexts, prev]\n\ndef middle(lst):\n    # Two walkers from the head, one taking two steps for each one of the\n    # other. When the fast one reaches the end, the slow one is in the\n    # middle - the second of the two middles when the length is even.\n    # Returns [index, steps the slow walker took].\n    lst[1] => nexts\n    lst[2] => slow\n    lst[2] => fast\n    0 => steps\n    while fast != -1 and nexts[fast] != -1:\n        nexts[slow] => slow\n        nexts[nexts[fast]] => fast\n        steps + 1 => steps\n    return [slow, steps]\n\ndef close_loop(lst, pos):\n    # Point the last node back at the node at position pos.\n    walk(lst)[0] => order\n    lst[1] => nexts\n    order[pos] => nexts[order[len(order) - 1]]\n    return [lst[0], nexts, lst[2]]\n\ndef break_loop(lst):\n    # The last node before the walk comes round again points to the end.\n    walk(lst) => w\n    lst[1] => nexts\n    if w[1] != -1:\n        -1 => nexts[w[0][len(w[0]) - 1]]\n    return [lst[0], nexts, lst[2]]\n\ndef floyd(lst):\n    # Floyd's cycle finding with two walkers, using no memory of where\n    # either has been: [False, steps] if the fast one reaches the end; otherwise\n    # [True, steps to meet, index where the loop starts, loop length].\n    # After they meet, a walker from the head and one from the meeting\n    # point, one step at a time each, meet exactly where the loop starts.\n    lst[1] => nexts\n    lst[2] => slow\n    lst[2] => fast\n    0 => steps\n    while fast != -1 and nexts[fast] != -1:\n        nexts[slow] => slow\n        nexts[nexts[fast]] => fast\n        steps + 1 => steps\n        if slow == fast:\n            lst[2] => a\n            slow => b\n            while a != b:\n                nexts[a] => a\n                nexts[b] => b\n            1 => n\n            nexts[a] => c\n            while c != a:\n                nexts[c] => c\n                n + 1 => n\n            return [True, steps, a, n]\n    return [False, steps]\n",
      "python": "def new_list():\n    return [[], [], -1]\n\ndef make_node(lst, value):\n    values = lst[0]\n    nexts = lst[1]\n    slot = -1\n    for i in range(0, len(nexts)):\n        if slot == -1 and nexts[i] == -2:\n            slot = i\n    if slot == -1:\n        values = values + [value]\n        nexts = nexts + [-1]\n        slot = len(values) - 1\n    else:\n        values[slot] = value\n        nexts[slot] = -1\n    return [[values, nexts, lst[2]], slot]\n\ndef walk(lst):\n    nexts = lst[1]\n    out = []\n    seen = [0] * len(nexts)\n    cur = lst[2]\n    while cur != -1:\n        if seen[cur] == 1:\n            return [out, cur]\n        seen[cur] = 1\n        out = out + [cur]\n        cur = nexts[cur]\n    return [out, -1]\n\ndef length(lst):\n    return len(walk(lst)[0])\n\ndef node_at(lst, pos):\n    order = walk(lst)[0]\n    return order[pos]\n\ndef insert_at(lst, pos, value):\n    made = make_node(lst, value)\n    lst = made[0]\n    k = made[1]\n    nexts = lst[1]\n    if pos == 0:\n        nexts[k] = lst[2]\n        return [lst[0], nexts, k]\n    before = node_at(lst, pos - 1)\n    nexts[k] = nexts[before]\n    nexts[before] = k\n    return [lst[0], nexts, lst[2]]\n\ndef delete_value(lst, value):\n    values = lst[0]\n    nexts = lst[1]\n    head = lst[2]\n    prev = -1\n    cur = head\n    pos = 0\n    while cur != -1:\n        if values[cur] == value:\n            if prev == -1:\n                head = nexts[cur]\n            else:\n                nexts[prev] = nexts[cur]\n            nexts[cur] = -2\n            return [[values, nexts, head], pos]\n        prev = cur\n        cur = nexts[cur]\n        pos = pos + 1\n    return [lst, -1]\n\ndef reverse(lst):\n    nexts = lst[1]\n    prev = -1\n    cur = lst[2]\n    while cur != -1:\n        following = nexts[cur]\n        nexts[cur] = prev\n        prev = cur\n        cur = following\n    return [lst[0], nexts, prev]\n\ndef middle(lst):\n    nexts = lst[1]\n    slow = lst[2]\n    fast = lst[2]\n    steps = 0\n    while fast != -1 and nexts[fast] != -1:\n        slow = nexts[slow]\n        fast = nexts[nexts[fast]]\n        steps = steps + 1\n    return [slow, steps]\n\ndef close_loop(lst, pos):\n    order = walk(lst)[0]\n    nexts = lst[1]\n    nexts[order[len(order) - 1]] = order[pos]\n    return [lst[0], nexts, lst[2]]\n\ndef break_loop(lst):\n    w = walk(lst)\n    nexts = lst[1]\n    if w[1] != -1:\n        nexts[w[0][len(w[0]) - 1]] = -1\n    return [lst[0], nexts, lst[2]]\n\ndef floyd(lst):\n    nexts = lst[1]\n    slow = lst[2]\n    fast = lst[2]\n    steps = 0\n    while fast != -1 and nexts[fast] != -1:\n        slow = nexts[slow]\n        fast = nexts[nexts[fast]]\n        steps = steps + 1\n        if slow == fast:\n            a = lst[2]\n            b = slow\n            while a != b:\n                a = nexts[a]\n                b = nexts[b]\n            n = 1\n            c = nexts[a]\n            while c != a:\n                c = nexts[c]\n                n = n + 1\n            return [True, steps, a, n]\n    return [False, steps]\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n3\nabc\n1000\n5\n9\n\n4\n42\n7\n7\n\n2\n10\n2\n11\n2\n12\n2\n13\n2\n14\n2\n15\n2\n16\n2\n6\n9\n",
      "screen": "== Linked list playground ==\nA singly linked list: each node holds a value and the slot of the next node.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 0\nPick a number from 1 to 9.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> x\nPick a number from 1 to 9.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 3\nvalue (0 to 999)> abc\nType a whole number from 0 to 999.\nvalue (0 to 999)> 1000\nType a whole number from 0 to 999.\nvalue (0 to 999)> 5\nposition (0 to 5)> 9\nType a whole number from 0 to 5.\nposition (0 to 5)> \nCancelled.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 4\nvalue (0 to 999)> 42\nNo node holds 42.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 7\npoint the last node back to position (0 to 4)> 7\nType a whole number from 0 to 4.\npoint the last node back to position (0 to 4)> \nCancelled.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 2\nvalue (0 to 999)> 10\n  head -> [7] -> [3] -> [9] -> [4] -> [1] -> [10] -> end\n  slot  value  next\n     0      7     1\n     1      3     2\n     2      9     3\n     3      4     4\n     4      1     5\n     5     10   end\n  head is slot 0.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 2\nvalue (0 to 999)> 11\n  head -> [7] -> [3] -> [9] -> [4] -> [1] -> [10] -> [11] -> end\n  slot  value  next\n     0      7     1\n     1      3     2\n     2      9     3\n     3      4     4\n     4      1     5\n     5     10     6\n     6     11   end\n  head is slot 0.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 2\nvalue (0 to 999)> 12\n  head -> [7] -> [3] -> [9] -> [4] -> [1] -> [10] -> [11] -> [12] -> end\n  slot  value  next\n     0      7     1\n     1      3     2\n     2      9     3\n     3      4     4\n     4      1     5\n     5     10     6\n     6     11     7\n     7     12   end\n  head is slot 0.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 2\nvalue (0 to 999)> 13\n  head -> [7] -> [3] -> [9] -> [4] -> [1] -> [10] -> [11] -> [12] -> [13] -> end\n  slot  value  next\n     0      7     1\n     1      3     2\n     2      9     3\n     3      4     4\n     4      1     5\n     5     10     6\n     6     11     7\n     7     12     8\n     8     13   end\n  head is slot 0.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 2\nvalue (0 to 999)> 14\n  head -> [7] -> [3] -> [9] -> [4] -> [1] -> [10] -> [11] -> [12] -> [13] -> [14] -> end\n  slot  value  next\n     0      7     1\n     1      3     2\n     2      9     3\n     3      4     4\n     4      1     5\n     5     10     6\n     6     11     7\n     7     12     8\n     8     13     9\n     9     14   end\n  head is slot 0.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 2\nvalue (0 to 999)> 15\n  head -> [7] -> [3] -> [9] -> [4] -> [1] -> [10] -> [11] -> [12] -> [13] -> [14] -> [15] -> end\n  slot  value  next\n     0      7     1\n     1      3     2\n     2      9     3\n     3      4     4\n     4      1     5\n     5     10     6\n     6     11     7\n     7     12     8\n     8     13     9\n     9     14    10\n    10     15   end\n  head is slot 0.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 2\nvalue (0 to 999)> 16\n  head -> [7] -> [3] -> [9] -> [4] -> [1] -> [10] -> [11] -> [12] -> [13] -> [14] -> [15] -> [16] -> end\n  slot  value  next\n     0      7     1\n     1      3     2\n     2      9     3\n     3      4     4\n     4      1     5\n     5     10     6\n     6     11     7\n     7     12     8\n     8     13     9\n     9     14    10\n    10     15    11\n    11     16   end\n  head is slot 0.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 2\nThe list is full: 12 nodes.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 6\n12 nodes: when the fast walker ran out, the slow one had taken 6 steps, to [11] at position 6.\nWith an even number of nodes there are two middles; this way finds the second.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 9\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "1\n3\n5\n2\n4\n3\n2\n8\n5\n6\n7\n2\n1\n8\n2\n7\n8\n9\n",
      "screen": "== Linked list playground ==\nA singly linked list: each node holds a value and the slot of the next node.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 1\n  head -> [7] -> [3] -> [9] -> [4] -> [1] -> end\n  slot  value  next\n     0      7     1\n     1      3     2\n     2      9     3\n     3      4     4\n     4      1   end\n  head is slot 0.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 3\nvalue (0 to 999)> 5\nposition (0 to 5)> 2\n  head -> [7] -> [3] -> [5] -> [9] -> [4] -> [1] -> end\n  slot  value  next\n     0      7     1\n     1      3     5\n     2      9     3\n     3      4     4\n     4      1   end\n     5      5     2\n  head is slot 0.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 4\nvalue (0 to 999)> 3\nDeleted 3 from position 1; its slot is free for the next node.\n  head -> [7] -> [5] -> [9] -> [4] -> [1] -> end\n  slot  value  next\n     0      7     5\n     1  (free)\n     2      9     3\n     3      4     4\n     4      1   end\n     5      5     2\n  head is slot 0.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 2\nvalue (0 to 999)> 8\n  head -> [7] -> [5] -> [9] -> [4] -> [1] -> [8] -> end\n  slot  value  next\n     0      7     5\n     1      8   end\n     2      9     3\n     3      4     4\n     4      1     1\n     5      5     2\n  head is slot 0.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 5\n  head -> [8] -> [1] -> [4] -> [9] -> [5] -> [7] -> end\n  slot  value  next\n     0      7   end\n     1      8     4\n     2      9     5\n     3      4     2\n     4      1     3\n     5      5     0\n  head is slot 1.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 6\n6 nodes: when the fast walker ran out, the slow one had taken 3 steps, to [9] at position 3.\nWith an even number of nodes there are two middles; this way finds the second.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 7\npoint the last node back to position (0 to 5)> 2\n  head -> [8] -> [1] -> [4] -> [9] -> [5] -> [7] -> back to [4]\n  slot  value  next\n     0      7     3\n     1      8     4\n     2      9     5\n     3      4     2\n     4      1     3\n     5      5     0\n  head is slot 1.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 1\n  head -> [8] -> [1] -> [4] -> [9] -> [5] -> [7] -> back to [4]\n  slot  value  next\n     0      7     3\n     1      8     4\n     2      9     5\n     3      4     2\n     4      1     3\n     5      5     0\n  head is slot 1.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 8\nA loop: the two walkers met after 4 steps. It starts at [4], position 2, and goes round 4 nodes.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 2\nThe list has a loop, so it has no end: break the loop first (7).\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 7\nLoop broken: [7] points to the end again.\n  head -> [8] -> [1] -> [4] -> [9] -> [5] -> [7] -> end\n  slot  value  next\n     0      7   end\n     1      8     4\n     2      9     5\n     3      4     2\n     4      1     3\n     5      5     0\n  head is slot 1.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 8\nNo loop: the fast walker reached the end after 3 steps.\n\n1) draw  2) add at the end  3) insert  4) delete  5) reverse  6) middle  7) close or break a loop  8) look for a loop  9) quit\nchoice> 9\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "linked-list-operations",
      "caseId": "101-linked-list-operations",
      "title": "Linked list operations"
    }
  ],
  "updated": "2026-10-14"
}
