Race multiple sorting algorithms against the same dataset, animating each one's progress as live ASCII bar charts in your terminal, then compare them on a scoreboard of comparisons, swaps, and wall-time.
Every algorithm is implemented as a Python generator that yields a Step
after each comparison or write it makes, so a caller can watch its progress
incrementally instead of only seeing the final sorted result. A Race steps
several such generators together and renders each tick as ANSI bar charts,
one panel per algorithm, side by side. A benchmark engine runs every
algorithm to completion on the same dataset and ranks the results into a
scoreboard of comparisons, swaps, and wall-time.
Requires Python 3.9+. No third-party dependencies — sorting, generators,
argparse, and dataclasses are all standard library, so there is nothing
to install beyond the package itself:
git clone <this-repository>
cd sortrace
pip install .
Once installed, sortrace races all five algorithms on a random dataset and
prints one ANSI frame per tick:
sortrace
Flags control the dataset and what gets printed:
sortrace --algo quick,merge --size 50 --seed 7 --preset nearly-sorted
sortrace --no-animate
--algo NAME[,NAME...]— comma-separated algorithms to include (default: all). Choices:bubble,insertion,quick,merge,radix.--size N— number of elements in the dataset (default: 30).--seed N— random seed controlling dataset generation (default: 42); the same--size/--seed/--presetcombination always builds the same data.--preset {random,nearly-sorted,reversed}— the dataset's starting shape (default:random).nearly-sortedstarts ascending with a few random pairs swapped;reversedis strictly descending, the worst case for several comparison-based algorithms.--no-animate— skip the live race and print a benchmark scoreboard instead; also the mode to use when stdout isn't a terminal.
Without an installed script, the same CLI runs as a module:
python -m sortrace --no-animate
Import an algorithm and iterate over the Step values it yields:
from sortrace import bubble_sort
for step in bubble_sort([5, 3, 8, 1, 9]):
print(step.action, step.array, "comparisons:", step.comparisons, "swaps:", step.swaps)
# steps[-1].done is True once the array is fully sortedFive algorithms are available, each under the same interface, and also
reachable by name through the ALGORITHMS registry:
from sortrace import ALGORITHMS
for name, algorithm in ALGORITHMS.items():
final_step = list(algorithm([5, 3, 8, 1, 9]))[-1]
print(name, final_step.array, final_step.comparisons, final_step.swaps)bubble_sort/insertion_sort/quick_sort/merge_sort— work on any list of comparable values.radix_sort— LSD radix sort; requires non-negative integers and raisesValueErrorotherwise. It performs no element comparisons, so itscomparisonscount stays at 0; progress shows up inswapsinstead.
generate_dataset(size, seed) builds a shuffled dataset deterministically —
the same (size, seed) pair always produces the same values, so a race can
be replayed frame for frame. animate then runs several algorithms
side by side, printing one ANSI frame per tick:
from sortrace import ALGORITHMS, animate, generate_dataset
data = generate_dataset(size=30, seed=42)
animate(ALGORITHMS, data, width=30, delay=0.02)Each frame clears the screen and draws one panel per algorithm: a header
with its running comparison/swap counts, followed by one horizontal bar per
array element, with the indices the algorithm just touched highlighted in
inverse video. Lower-level pieces (Race, render_frame, render_panel,
render_bar) are available for building custom displays or for testing
against fixed Step values without writing to a terminal.
run_benchmark runs every algorithm to completion, one at a time, on the
same dataset, timing each with a monotonic clock and recording its final
comparison/swap counts. format_scoreboard ranks the results fastest first
into a plain-text table:
from sortrace import ALGORITHMS, format_scoreboard, generate_dataset, run_benchmark
data = generate_dataset(size=500, seed=42)
results = run_benchmark(ALGORITHMS, data)
print(format_scoreboard(results))# name comparisons swaps time (ms)
------------------------------------------------
1 radix 0 1500 0.412
2 quick 4408 1214 1.007
3 merge 4342 1000 1.284
4 insertion 122841 999 12.941
5 bubble 124875 122841 23.706
Unlike Race, algorithms here run sequentially rather than interleaved, so
timing reflects each algorithm's own work with no scheduling overhead from
the others.
Run the test suite with:
python -m unittest discover -s tests
tests/golden/ holds checked-in reference output for one fixed seed+dataset:
the full frame sequence from a three-algorithm race, and a scoreboard table
with time.perf_counter patched to a fixed timeline so even the timing
column is reproducible. tests/test_golden.py regenerates that output on
every run and asserts it is byte-for-byte identical to the recorded file,
catching a formatting or behaviour change that two runs agreeing with each
other would not.
Built autonomously, gated on a passing test suite before any change ships.