{
  "id": "P045",
  "slug": "sorting-visualizer",
  "key": "P045-sorting-visualizer",
  "title": "Sorting visualizer",
  "summary": "A list of up to 12 numbers sorted step by step by bubble sort, insertion sort, merge sort or counting sort - every pass, insertion or merge shown with the part already in place - with the comparisons and moves each one took, or all four side by side on the same list.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P045 - Sorting visualizer\n\nA list of up to 12 numbers from 0 to 99, sorted step by step by bubble sort,\ninsertion sort, merge sort or counting sort. Every pass, insertion or merge\nis shown, with a bar marking the part already in place, and each sort ends\nwith the comparisons and moves it took; or all four run side by side on the\nsame list.\n\n- `main.eml` - the menu, the list and its checks, and the steps on screen\n- `sorts.eml` - the four sorts, each reporting its steps and its counts\n\nHow each part works:\n\n- Bubble sort, as in the corpus case `bubble-sort`, compares neighbours and\n  swaps them when they are out of order; after pass p the last p values are\n  in place, and a pass without a swap stops it early - one pass for a list\n  already sorted.\n- Insertion sort, as in `insertion-sort`, slides each value left past the\n  larger ones before it; the first values are always in order among\n  themselves. Its shifts equal bubble sort's swaps: both are the number of\n  pairs out of order - 15 in the sample, 36 for nine numbers reversed.\n- Merge sort, as in `merge-sort`, sorts each half and merges them, taking\n  the smaller front value each time (the left one on a tie, so equal values\n  keep their order); every merge is shown.\n- Counting sort, as in `counting-sort`, compares nothing: it counts each\n  value from 0 to 99 and writes them out in order. That only works because\n  the values are small whole numbers.\n- A comparison and a move mean slightly different things in each sort: a\n  swap, a shift, or a value written into a merged or counted list.\n\nWhat is checked: 2 to 12 numbers, each a whole number from 0 to 99,\nseparated by spaces or commas; anything else leaves the list as it was. An\nempty answer cancels.\n\nSessions: `sessions/basic.in` runs all four sorts on the sample (eight\nnumbers with a repeat) and compares them; then nine numbers in reverse\norder, where bubble sort makes 36 comparisons and 36 swaps, and six already\nin order, where bubble sort stops after one pass and insertion sort shifts\nnothing. `sessions/bad-input.in` gives menu choices 0 and x, an empty list,\none number, a list with x in it, 100, thirteen numbers and -1, then two\nequal numbers, which every sort leaves alone.\n\nBuilt on the verified corpus cases `bubble-sort`, `insertion-sort`,\n`merge-sort` and `counting-sort` (the four sorts on fixed lists).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P045 sorting visualizer: a list of up to 12 numbers from 0 to 99, sorted\n# step by step by bubble sort, insertion sort, merge sort or counting sort -\n# each step shown, with the comparisons and moves it took - or all four side\n# by side on the same list.\nimport sorts\n\n12 => most_values\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 words(s):\n    [] => out\n    \"\" => word\n    for c in s + \" \":\n        if c == \" \" or c == \",\":\n            if word != \"\":\n                out + [word] => out\n            \"\" => word\n        else:\n            word + c => word\n    return out\n\ndef number(s):\n    if s == \"\" or len(s) > 2:\n        return -1\n    0 => n\n    for c in s:\n        if not (c in \"0123456789\"):\n            return -1\n        n * 10 + int(c) => n\n    return n\n\ndef right(s, width):\n    while len(s) < width:\n        \" \" + s => s\n    return s\n\ndef pad(s, width):\n    while len(s) < width:\n        s + \" \" => s\n    return s\n\ndef row(xs, done, from_right):\n    # The list with a bar between the part in place and the rest: in place\n    # at the end for bubble sort, at the start for insertion sort.\n    \"\" => out\n    len(xs) => n\n    for i in [0:n - 1]:\n        if from_right and i == n - done and done < n:\n            out + \" |\" => out\n        out + \" \" + right(str(xs[i]), 2) => out\n        if not from_right and i == done - 1 and done < n:\n            out + \" |\" => out\n    return out\n\ndef counted(n, words):\n    if n == 1:\n        return \"1 \" + words[0]\n    return str(n) + \" \" + words[1]\n\ndef run(xs, which):\n    [\"bubble\", \"insertion\", \"merge\", \"counting\"] => names\n    if which == 0:\n        sorts.bubble(xs) => r\n    elif which == 1:\n        sorts.insertion(xs) => r\n    elif which == 2:\n        sorts.merge(xs) => r\n    else:\n        sorts.counting(xs) => r\n    (names[which] + \" sort of\" + row(xs, 0, True)) ^0\n    for st in r[1]:\n        if which == 0:\n            (\"  \" + pad(st[0], 18) + row(st[1], st[2], True)) ^0\n        elif which == 1:\n            (\"  \" + pad(st[0], 22) + row(st[1], st[2], False)) ^0\n        else:\n            (\"  \" + st[0]) ^0\n            (\"    ->\" + row(st[1], st[2], True)) ^0\n    [[\"swap\", \"swaps\"], [\"shift\", \"shifts\"], [\"value written\", \"values written\"], [\"value written\", \"values written\"]] => what\n    (\"Sorted:\" + row(r[0], len(r[0]), True) + \" - \" + counted(r[2], [\"comparison\", \"comparisons\"]) + \", \" + counted(r[3], what[which]) + \".\") ^0\n    return r\n\ndef compare(xs):\n    (\"All four on\" + row(xs, 0, True) + \":\") ^0\n    \"               comparisons  moves\" ^0\n    [\"bubble\", \"insertion\", \"merge\", \"counting\"] => names\n    [\"swaps\", \"shifts\", \"values written\", \"values written\"] => what\n    for k in [0:3]:\n        if k == 0:\n            sorts.bubble(xs) => r\n        elif k == 1:\n            sorts.insertion(xs) => r\n        elif k == 2:\n            sorts.merge(xs) => r\n        else:\n            sorts.counting(xs) => r\n        (\"  \" + pad(names[k], 12) + right(str(r[2]), 12) + right(str(r[3]), 7) + \"  (\" + what[k] + \")\") ^0\n    \"Counting sort compares nothing: it only works because the values are small whole numbers.\" ^0\n\ndef ask_list(xs):\n    trim(input(\"numbers (up to 12, from 0 to 99)> \")) => answer\n    if answer == \"\":\n        \"Cancelled.\" ^0\n        return xs\n    [] => out\n    for w in words(answer):\n        number(w) => n\n        if n < 0:\n            (\"Not a number from 0 to 99: \" + w + \". The list stays as it was.\") ^0\n            return xs\n        out + [n] => out\n    if len(out) > most_values:\n        (\"That is \" + str(len(out)) + \" numbers; the most is \" + str(most_values) + \". The list stays as it was.\") ^0\n        return xs\n    if len(out) < 2:\n        \"Give at least 2 numbers. The list stays as it was.\" ^0\n        return xs\n    (\"The list:\" + row(out, 0, True)) ^0\n    return out\n\n\"== Sorting visualizer ==\" ^0\n\"Watch four sorts work on the same list, step by step.\" ^0\n[29, 3, 17, 42, 8, 3, 25, 11] => xs\n(\"The list:\" + row(xs, 0, True)) ^0\nTrue => running\nwhile running:\n    \"\" ^0\n    \"1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\" ^0\n    trim(input(\"choice> \")) => choice\n    if choice == \"1\":\n        ask_list(xs) => xs\n    elif choice == \"2\" or choice == \"3\" or choice == \"4\" or choice == \"5\":\n        run(xs, int(choice) - 2)\n    elif choice == \"6\":\n        compare(xs)\n    elif choice == \"7\":\n        False => running\n    else:\n        \"Pick a number from 1 to 7.\" ^0\n\"Bye.\" ^0\n",
      "python": "import sorts\nmost_values = 12\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 words(s):\n    out = []\n    word = \"\"\n    for c in s + \" \":\n        if c == \" \" or c == \",\":\n            if word != \"\":\n                out = out + [word]\n            word = \"\"\n        else:\n            word = word + c\n    return out\n\ndef number(s):\n    if s == \"\" or len(s) > 2:\n        return -1\n    n = 0\n    for c in s:\n        if not c in \"0123456789\":\n            return -1\n        n = n * 10 + int(c)\n    return n\n\ndef right(s, width):\n    while len(s) < width:\n        s = \" \" + s\n    return s\n\ndef pad(s, width):\n    while len(s) < width:\n        s = s + \" \"\n    return s\n\ndef row(xs, done, from_right):\n    out = \"\"\n    n = len(xs)\n    for i in range(0, n):\n        if from_right and i == n - done and done < n:\n            out = out + \" |\"\n        out = out + \" \" + right(str(xs[i]), 2)\n        if not from_right and i == done - 1 and done < n:\n            out = out + \" |\"\n    return out\n\ndef counted(n, words):\n    if n == 1:\n        return \"1 \" + words[0]\n    return str(n) + \" \" + words[1]\n\ndef run(xs, which):\n    names = [\"bubble\", \"insertion\", \"merge\", \"counting\"]\n    if which == 0:\n        r = sorts.bubble(xs)\n    elif which == 1:\n        r = sorts.insertion(xs)\n    elif which == 2:\n        r = sorts.merge(xs)\n    else:\n        r = sorts.counting(xs)\n    print(names[which] + \" sort of\" + row(xs, 0, True))\n    for st in r[1]:\n        if which == 0:\n            print(\"  \" + pad(st[0], 18) + row(st[1], st[2], True))\n        elif which == 1:\n            print(\"  \" + pad(st[0], 22) + row(st[1], st[2], False))\n        else:\n            print(\"  \" + st[0])\n            print(\"    ->\" + row(st[1], st[2], True))\n    what = [[\"swap\", \"swaps\"], [\"shift\", \"shifts\"], [\"value written\", \"values written\"], [\"value written\", \"values written\"]]\n    print(\"Sorted:\" + row(r[0], len(r[0]), True) + \" - \" + counted(r[2], [\"comparison\", \"comparisons\"]) + \", \" + counted(r[3], what[which]) + \".\")\n    return r\n\ndef compare(xs):\n    print(\"All four on\" + row(xs, 0, True) + \":\")\n    print(\"               comparisons  moves\")\n    names = [\"bubble\", \"insertion\", \"merge\", \"counting\"]\n    what = [\"swaps\", \"shifts\", \"values written\", \"values written\"]\n    for k in range(0, 4):\n        if k == 0:\n            r = sorts.bubble(xs)\n        elif k == 1:\n            r = sorts.insertion(xs)\n        elif k == 2:\n            r = sorts.merge(xs)\n        else:\n            r = sorts.counting(xs)\n        print(\"  \" + pad(names[k], 12) + right(str(r[2]), 12) + right(str(r[3]), 7) + \"  (\" + what[k] + \")\")\n    print(\"Counting sort compares nothing: it only works because the values are small whole numbers.\")\n\ndef ask_list(xs):\n    answer = trim(input(\"numbers (up to 12, from 0 to 99)> \"))\n    if answer == \"\":\n        print(\"Cancelled.\")\n        return xs\n    out = []\n    for w in words(answer):\n        n = number(w)\n        if n < 0:\n            print(\"Not a number from 0 to 99: \" + w + \". The list stays as it was.\")\n            return xs\n        out = out + [n]\n    if len(out) > most_values:\n        print(\"That is \" + str(len(out)) + \" numbers; the most is \" + str(most_values) + \". The list stays as it was.\")\n        return xs\n    if len(out) < 2:\n        print(\"Give at least 2 numbers. The list stays as it was.\")\n        return xs\n    print(\"The list:\" + row(out, 0, True))\n    return out\n\nprint(\"== Sorting visualizer ==\")\nprint(\"Watch four sorts work on the same list, step by step.\")\nxs = [29, 3, 17, 42, 8, 3, 25, 11]\nprint(\"The list:\" + row(xs, 0, True))\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\")\n    choice = trim(input(\"choice> \"))\n    if choice == \"1\":\n        xs = ask_list(xs)\n    elif choice == \"2\" or choice == \"3\" or choice == \"4\" or choice == \"5\":\n        run(xs, int(choice) - 2)\n    elif choice == \"6\":\n        compare(xs)\n    elif choice == \"7\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 7.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "sorts.eml",
      "eml": "# P045 sorting visualizer - four sorts that report what they do. Each one\n# returns [sorted list, steps, comparisons, moves], where every step is\n# [label, the list at that moment, how much of it is in place] and the\n# counting rules are:\n#   bubble    - a comparison of two neighbours; a move is a swap\n#   insertion - a comparison with the value being inserted; a move is a\n#               value shifted one place to the right\n#   merge     - a comparison of the two front values; a move is a value\n#               written into the merged list\n#   counting  - no comparisons; a move is a value written out\n\ndef bubble(xs):\n    # The corpus case bubble-sort, with the early stop: a pass without a\n    # swap means the list is sorted.\n    xs[0:len(xs)] => a\n    len(a) => n\n    [] => steps\n    0 => comps\n    0 => moves\n    1 => p\n    True => going\n    while going and p < n:\n        0 => swaps\n        for i in [0:n - 1 - p]:\n            comps + 1 => comps\n            if a[i] > a[i + 1]:\n                a[i] => t\n                a[i + 1] => a[i]\n                t => a[i + 1]\n                swaps + 1 => swaps\n        moves + swaps => moves\n        # after pass p the last p values are in place - all of them once a\n        # pass swaps nothing\n        p => placed\n        if swaps == 0 or p == n - 1:\n            n => placed\n        steps + [[\"pass \" + str(p) + \": \" + plural(swaps, \"swap\"), a[0:n], placed]] => steps\n        if swaps == 0:\n            False => going\n        p + 1 => p\n    return [a, steps, comps, moves]\n\ndef insertion(xs):\n    # The corpus case insertion-sort: each value slides left past the larger\n    # ones before it.\n    xs[0:len(xs)] => a\n    len(a) => n\n    [] => steps\n    0 => comps\n    0 => moves\n    for i in [1:n - 1]:\n        a[i] => cur\n        i - 1 => j\n        0 => shifted\n        True => going\n        while going and j >= 0:\n            comps + 1 => comps\n            if a[j] > cur:\n                a[j] => a[j + 1]\n                shifted + 1 => shifted\n                j - 1 => j\n            else:\n                False => going\n        cur => a[j + 1]\n        moves + shifted => moves\n        steps + [[\"insert \" + str(cur) + \": \" + str(shifted) + \" shifted\", a[0:n], i + 1]] => steps\n    return [a, steps, comps, moves]\n\ndef merged(left, right, counts):\n    # The merge step: take the smaller front value each time; on a tie the\n    # left one first, which keeps equal values in order. counts holds\n    # [comparisons, moves] and is updated.\n    [] => out\n    0 => i\n    0 => j\n    while i < len(left) and j < len(right):\n        counts[0] + 1 => counts[0]\n        if right[j] < left[i]:\n            out + [right[j]] => out\n            j + 1 => j\n        else:\n            out + [left[i]] => out\n            i + 1 => i\n    out + left[i:len(left)] + right[j:len(right)] => out\n    counts[1] + len(out) => counts[1]\n    return out\n\ndef merge_steps(xs, counts, steps):\n    # The corpus case merge-sort: halves, each sorted the same way, then\n    # merged. Every merge becomes a step, added to steps[0].\n    len(xs) => n\n    if n <= 1:\n        return xs\n    int(n / 2) => mid\n    merge_steps(xs[0:mid], counts, steps) => left\n    merge_steps(xs[mid:n], counts, steps) => right\n    merged(left, right, counts) => out\n    steps[0] + [[\"merge \" + numbers(left) + \" + \" + numbers(right), out, len(out)]] => steps[0]\n    return out\n\ndef merge(xs):\n    [0, 0] => counts\n    [[]] => steps\n    merge_steps(xs, counts, steps) => out\n    return [out, steps[0], counts[0], counts[1]]\n\ndef counting(xs):\n    # The corpus case counting-sort: count each value from 0 to 99, then\n    # write each value out as often as it was counted.\n    [0] * 100 => counts\n    for x in xs:\n        counts[x] + 1 => counts[x]\n    \"\" => seen\n    for v in [0:99]:\n        if counts[v] > 0:\n            if seen != \"\":\n                seen + \", \" => seen\n            seen + str(v) + \" x\" + str(counts[v]) => seen\n    [] => out\n    for v in [0:99]:\n        for k in [1:counts[v]]:\n            out + [v] => out\n    return [out, [[\"counts: \" + seen, out, len(out)]], 0, len(out)]\n\ndef plural(n, word):\n    if n == 1:\n        return \"1 \" + word\n    return str(n) + \" \" + word + \"s\"\n\ndef numbers(xs):\n    \"\" => out\n    for x in xs:\n        if out != \"\":\n            out + \" \" => out\n        out + str(x) => out\n    return \"[\" + out + \"]\"\n",
      "python": "def bubble(xs):\n    a = xs[0:len(xs)]\n    n = len(a)\n    steps = []\n    comps = 0\n    moves = 0\n    p = 1\n    going = True\n    while going and p < n:\n        swaps = 0\n        for i in range(0, n - 1 - p+1):\n            comps = comps + 1\n            if a[i] > a[i + 1]:\n                t = a[i]\n                a[i] = a[i + 1]\n                a[i + 1] = t\n                swaps = swaps + 1\n        moves = moves + swaps\n        placed = p\n        if swaps == 0 or p == n - 1:\n            placed = n\n        steps = steps + [[\"pass \" + str(p) + \": \" + plural(swaps, \"swap\"), a[0:n], placed]]\n        if swaps == 0:\n            going = False\n        p = p + 1\n    return [a, steps, comps, moves]\n\ndef insertion(xs):\n    a = xs[0:len(xs)]\n    n = len(a)\n    steps = []\n    comps = 0\n    moves = 0\n    for i in range(1, n):\n        cur = a[i]\n        j = i - 1\n        shifted = 0\n        going = True\n        while going and j >= 0:\n            comps = comps + 1\n            if a[j] > cur:\n                a[j + 1] = a[j]\n                shifted = shifted + 1\n                j = j - 1\n            else:\n                going = False\n        a[j + 1] = cur\n        moves = moves + shifted\n        steps = steps + [[\"insert \" + str(cur) + \": \" + str(shifted) + \" shifted\", a[0:n], i + 1]]\n    return [a, steps, comps, moves]\n\ndef merged(left, right, counts):\n    out = []\n    i = 0\n    j = 0\n    while i < len(left) and j < len(right):\n        counts[0] = counts[0] + 1\n        if right[j] < left[i]:\n            out = out + [right[j]]\n            j = j + 1\n        else:\n            out = out + [left[i]]\n            i = i + 1\n    out = out + left[i:len(left)] + right[j:len(right)]\n    counts[1] = counts[1] + len(out)\n    return out\n\ndef merge_steps(xs, counts, steps):\n    n = len(xs)\n    if n <= 1:\n        return xs\n    mid = int(n / 2)\n    left = merge_steps(xs[0:mid], counts, steps)\n    right = merge_steps(xs[mid:n], counts, steps)\n    out = merged(left, right, counts)\n    steps[0] = steps[0] + [[\"merge \" + numbers(left) + \" + \" + numbers(right), out, len(out)]]\n    return out\n\ndef merge(xs):\n    counts = [0, 0]\n    steps = [[]]\n    out = merge_steps(xs, counts, steps)\n    return [out, steps[0], counts[0], counts[1]]\n\ndef counting(xs):\n    counts = [0] * 100\n    for x in xs:\n        counts[x] = counts[x] + 1\n    seen = \"\"\n    for v in range(0, 100):\n        if counts[v] > 0:\n            if seen != \"\":\n                seen = seen + \", \"\n            seen = seen + str(v) + \" x\" + str(counts[v])\n    out = []\n    for v in range(0, 100):\n        for k in range(1, counts[v]+1):\n            out = out + [v]\n    return [out, [[\"counts: \" + seen, out, len(out)]], 0, len(out)]\n\ndef plural(n, word):\n    if n == 1:\n        return \"1 \" + word\n    return str(n) + \" \" + word + \"s\"\n\ndef numbers(xs):\n    out = \"\"\n    for x in xs:\n        if out != \"\":\n            out = out + \" \"\n        out = out + str(x)\n    return \"[\" + out + \"]\"\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n1\n\n1\n5\n1\n1 2 x\n1\n100 2\n1\n0 1 2 3 4 5 6 7 8 9 10 11 12\n1\n-1 5\n1\n7,7\n2\n3\n4\n5\n6\n7\n",
      "screen": "== Sorting visualizer ==\nWatch four sorts work on the same list, step by step.\nThe list: 29  3 17 42  8  3 25 11\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 0\nPick a number from 1 to 7.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> x\nPick a number from 1 to 7.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 1\nnumbers (up to 12, from 0 to 99)> \nCancelled.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 1\nnumbers (up to 12, from 0 to 99)> 5\nGive at least 2 numbers. The list stays as it was.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 1\nnumbers (up to 12, from 0 to 99)> 1 2 x\nNot a number from 0 to 99: x. The list stays as it was.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 1\nnumbers (up to 12, from 0 to 99)> 100 2\nNot a number from 0 to 99: 100. The list stays as it was.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 1\nnumbers (up to 12, from 0 to 99)> 0 1 2 3 4 5 6 7 8 9 10 11 12\nThat is 13 numbers; the most is 12. The list stays as it was.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 1\nnumbers (up to 12, from 0 to 99)> -1 5\nNot a number from 0 to 99: -1. The list stays as it was.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 1\nnumbers (up to 12, from 0 to 99)> 7,7\nThe list:  7  7\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 2\nbubble sort of  7  7\n  pass 1: 0 swaps     7  7\nSorted:  7  7 - 1 comparison, 0 swaps.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 3\ninsertion sort of  7  7\n  insert 7: 0 shifted     7  7\nSorted:  7  7 - 1 comparison, 0 shifts.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 4\nmerge sort of  7  7\n  merge [7] + [7]\n    ->  7  7\nSorted:  7  7 - 1 comparison, 2 values written.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 5\ncounting sort of  7  7\n  counts: 7 x2\n    ->  7  7\nSorted:  7  7 - 0 comparisons, 2 values written.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 6\nAll four on  7  7:\n               comparisons  moves\n  bubble                 1      0  (swaps)\n  insertion              1      0  (shifts)\n  merge                  1      2  (values written)\n  counting               0      2  (values written)\nCounting sort compares nothing: it only works because the values are small whole numbers.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 7\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "2\n3\n4\n5\n6\n1\n9 8 7 6 5 4 3 2 1\n2\n1\n1 2 3 4 5 6\n2\n3\n6\n7\n",
      "screen": "== Sorting visualizer ==\nWatch four sorts work on the same list, step by step.\nThe list: 29  3 17 42  8  3 25 11\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 2\nbubble sort of 29  3 17 42  8  3 25 11\n  pass 1: 6 swaps     3 17 29  8  3 25 11 | 42\n  pass 2: 4 swaps     3 17  8  3 25 11 | 29 42\n  pass 3: 3 swaps     3  8  3 17 11 | 25 29 42\n  pass 4: 2 swaps     3  3  8 11 | 17 25 29 42\n  pass 5: 0 swaps     3  3  8 11 17 25 29 42\nSorted:  3  3  8 11 17 25 29 42 - 25 comparisons, 15 swaps.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 3\ninsertion sort of 29  3 17 42  8  3 25 11\n  insert 3: 1 shifted     3 29 | 17 42  8  3 25 11\n  insert 17: 1 shifted    3 17 29 | 42  8  3 25 11\n  insert 42: 0 shifted    3 17 29 42 |  8  3 25 11\n  insert 8: 3 shifted     3  8 17 29 42 |  3 25 11\n  insert 3: 4 shifted     3  3  8 17 29 42 | 25 11\n  insert 25: 2 shifted    3  3  8 17 25 29 42 | 11\n  insert 11: 4 shifted    3  3  8 11 17 25 29 42\nSorted:  3  3  8 11 17 25 29 42 - 21 comparisons, 15 shifts.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 4\nmerge sort of 29  3 17 42  8  3 25 11\n  merge [29] + [3]\n    ->  3 29\n  merge [17] + [42]\n    -> 17 42\n  merge [3 29] + [17 42]\n    ->  3 17 29 42\n  merge [8] + [3]\n    ->  3  8\n  merge [25] + [11]\n    -> 11 25\n  merge [3 8] + [11 25]\n    ->  3  8 11 25\n  merge [3 17 29 42] + [3 8 11 25]\n    ->  3  3  8 11 17 25 29 42\nSorted:  3  3  8 11 17 25 29 42 - 15 comparisons, 24 values written.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 5\ncounting sort of 29  3 17 42  8  3 25 11\n  counts: 3 x2, 8 x1, 11 x1, 17 x1, 25 x1, 29 x1, 42 x1\n    ->  3  3  8 11 17 25 29 42\nSorted:  3  3  8 11 17 25 29 42 - 0 comparisons, 8 values written.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 6\nAll four on 29  3 17 42  8  3 25 11:\n               comparisons  moves\n  bubble                25     15  (swaps)\n  insertion             21     15  (shifts)\n  merge                 15     24  (values written)\n  counting               0      8  (values written)\nCounting sort compares nothing: it only works because the values are small whole numbers.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 1\nnumbers (up to 12, from 0 to 99)> 9 8 7 6 5 4 3 2 1\nThe list:  9  8  7  6  5  4  3  2  1\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 2\nbubble sort of  9  8  7  6  5  4  3  2  1\n  pass 1: 8 swaps     8  7  6  5  4  3  2  1 |  9\n  pass 2: 7 swaps     7  6  5  4  3  2  1 |  8  9\n  pass 3: 6 swaps     6  5  4  3  2  1 |  7  8  9\n  pass 4: 5 swaps     5  4  3  2  1 |  6  7  8  9\n  pass 5: 4 swaps     4  3  2  1 |  5  6  7  8  9\n  pass 6: 3 swaps     3  2  1 |  4  5  6  7  8  9\n  pass 7: 2 swaps     2  1 |  3  4  5  6  7  8  9\n  pass 8: 1 swap      1  2  3  4  5  6  7  8  9\nSorted:  1  2  3  4  5  6  7  8  9 - 36 comparisons, 36 swaps.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 1\nnumbers (up to 12, from 0 to 99)> 1 2 3 4 5 6\nThe list:  1  2  3  4  5  6\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 2\nbubble sort of  1  2  3  4  5  6\n  pass 1: 0 swaps     1  2  3  4  5  6\nSorted:  1  2  3  4  5  6 - 5 comparisons, 0 swaps.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 3\ninsertion sort of  1  2  3  4  5  6\n  insert 2: 0 shifted     1  2 |  3  4  5  6\n  insert 3: 0 shifted     1  2  3 |  4  5  6\n  insert 4: 0 shifted     1  2  3  4 |  5  6\n  insert 5: 0 shifted     1  2  3  4  5 |  6\n  insert 6: 0 shifted     1  2  3  4  5  6\nSorted:  1  2  3  4  5  6 - 5 comparisons, 0 shifts.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 6\nAll four on  1  2  3  4  5  6:\n               comparisons  moves\n  bubble                 5      0  (swaps)\n  insertion              5      0  (shifts)\n  merge                  7     16  (values written)\n  counting               0      6  (values written)\nCounting sort compares nothing: it only works because the values are small whole numbers.\n\n1) new list  2) bubble  3) insertion  4) merge  5) counting  6) compare all  7) quit\nchoice> 7\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "bubble-sort",
      "caseId": "051-bubble-sort",
      "title": "Bubble sort"
    },
    {
      "slug": "insertion-sort",
      "caseId": "054-insertion-sort",
      "title": "Insertion sort"
    },
    {
      "slug": "merge-sort",
      "caseId": "074-merge-sort",
      "title": "Merge sort"
    },
    {
      "slug": "counting-sort",
      "caseId": "067-counting-sort",
      "title": "Counting sort"
    }
  ],
  "updated": "2026-10-10"
}
