|
|
|
|
|
""" |
|
|
|
|
|
sorting_animation.py |
|
|
|
|
|
A minimal sorting algorithm animation: |
|
|
Sorts a shelf of 10 blocks using insertion |
|
|
sort, selection sort and quicksort. |
|
|
|
|
|
Shelfs are implemented using builtin lists. |
|
|
|
|
|
Blocks are turtles with shape "square", but |
|
|
stretched to rectangles by shapesize() |
|
|
--------------------------------------- |
|
|
To exit press space button |
|
|
--------------------------------------- |
|
|
""" |
|
|
from turtle import * |
|
|
import random |
|
|
|
|
|
|
|
|
class Block(Turtle): |
|
|
|
|
|
def __init__(self, size): |
|
|
self.size = size |
|
|
Turtle.__init__(self, shape="square", visible=False) |
|
|
self.pu() |
|
|
self.shapesize(size * 1.5, 1.5, 2) |
|
|
self.fillcolor("black") |
|
|
self.st() |
|
|
|
|
|
def glow(self): |
|
|
self.fillcolor("red") |
|
|
|
|
|
def unglow(self): |
|
|
self.fillcolor("black") |
|
|
|
|
|
def __repr__(self): |
|
|
return "Block size: {0}".format(self.size) |
|
|
|
|
|
|
|
|
class Shelf(list): |
|
|
|
|
|
def __init__(self, y): |
|
|
"create a shelf. y is y-position of first block" |
|
|
self.y = y |
|
|
self.x = -150 |
|
|
|
|
|
def push(self, d): |
|
|
width, _, _ = d.shapesize() |
|
|
|
|
|
y_offset = width / 2 * 20 |
|
|
d.sety(self.y + y_offset) |
|
|
d.setx(self.x + 34 * len(self)) |
|
|
self.append(d) |
|
|
|
|
|
def _close_gap_from_i(self, i): |
|
|
for b in self[i:]: |
|
|
xpos, _ = b.pos() |
|
|
b.setx(xpos - 34) |
|
|
|
|
|
def _open_gap_from_i(self, i): |
|
|
for b in self[i:]: |
|
|
xpos, _ = b.pos() |
|
|
b.setx(xpos + 34) |
|
|
|
|
|
def pop(self, key): |
|
|
b = list.pop(self, key) |
|
|
b.glow() |
|
|
b.sety(200) |
|
|
self._close_gap_from_i(key) |
|
|
return b |
|
|
|
|
|
def insert(self, key, b): |
|
|
self._open_gap_from_i(key) |
|
|
list.insert(self, key, b) |
|
|
b.setx(self.x + 34 * key) |
|
|
width, _, _ = b.shapesize() |
|
|
|
|
|
y_offset = width / 2 * 20 |
|
|
b.sety(self.y + y_offset) |
|
|
b.unglow() |
|
|
|
|
|
def isort(shelf): |
|
|
length = len(shelf) |
|
|
for i in range(1, length): |
|
|
hole = i |
|
|
while hole > 0 and shelf[i].size < shelf[hole - 1].size: |
|
|
hole = hole - 1 |
|
|
shelf.insert(hole, shelf.pop(i)) |
|
|
return |
|
|
|
|
|
def ssort(shelf): |
|
|
length = len(shelf) |
|
|
for j in range(0, length - 1): |
|
|
imin = j |
|
|
for i in range(j + 1, length): |
|
|
if shelf[i].size < shelf[imin].size: |
|
|
imin = i |
|
|
if imin != j: |
|
|
shelf.insert(j, shelf.pop(imin)) |
|
|
|
|
|
def partition(shelf, left, right, pivot_index): |
|
|
pivot = shelf[pivot_index] |
|
|
shelf.insert(right, shelf.pop(pivot_index)) |
|
|
store_index = left |
|
|
for i in range(left, right): |
|
|
if shelf[i].size < pivot.size: |
|
|
shelf.insert(store_index, shelf.pop(i)) |
|
|
store_index = store_index + 1 |
|
|
shelf.insert(store_index, shelf.pop(right)) |
|
|
return store_index |
|
|
|
|
|
def qsort(shelf, left, right): |
|
|
if left < right: |
|
|
pivot_index = left |
|
|
pivot_new_index = partition(shelf, left, right, pivot_index) |
|
|
qsort(shelf, left, pivot_new_index - 1) |
|
|
qsort(shelf, pivot_new_index + 1, right) |
|
|
|
|
|
def randomize(): |
|
|
disable_keys() |
|
|
clear() |
|
|
target = list(range(10)) |
|
|
random.shuffle(target) |
|
|
for i, t in enumerate(target): |
|
|
for j in range(i, len(s)): |
|
|
if s[j].size == t + 1: |
|
|
s.insert(i, s.pop(j)) |
|
|
show_text(instructions1) |
|
|
show_text(instructions2, line=1) |
|
|
enable_keys() |
|
|
|
|
|
def show_text(text, line=0): |
|
|
line = 20 * line |
|
|
goto(0,-250 - line) |
|
|
write(text, align="center", font=("Courier", 16, "bold")) |
|
|
|
|
|
def start_ssort(): |
|
|
disable_keys() |
|
|
clear() |
|
|
show_text("Selection Sort") |
|
|
ssort(s) |
|
|
clear() |
|
|
show_text(instructions1) |
|
|
show_text(instructions2, line=1) |
|
|
enable_keys() |
|
|
|
|
|
def start_isort(): |
|
|
disable_keys() |
|
|
clear() |
|
|
show_text("Insertion Sort") |
|
|
isort(s) |
|
|
clear() |
|
|
show_text(instructions1) |
|
|
show_text(instructions2, line=1) |
|
|
enable_keys() |
|
|
|
|
|
def start_qsort(): |
|
|
disable_keys() |
|
|
clear() |
|
|
show_text("Quicksort") |
|
|
qsort(s, 0, len(s) - 1) |
|
|
clear() |
|
|
show_text(instructions1) |
|
|
show_text(instructions2, line=1) |
|
|
enable_keys() |
|
|
|
|
|
def init_shelf(): |
|
|
global s |
|
|
s = Shelf(-200) |
|
|
vals = (4, 2, 8, 9, 1, 5, 10, 3, 7, 6) |
|
|
for i in vals: |
|
|
s.push(Block(i)) |
|
|
|
|
|
def disable_keys(): |
|
|
onkey(None, "s") |
|
|
onkey(None, "i") |
|
|
onkey(None, "q") |
|
|
onkey(None, "r") |
|
|
|
|
|
def enable_keys(): |
|
|
onkey(start_isort, "i") |
|
|
onkey(start_ssort, "s") |
|
|
onkey(start_qsort, "q") |
|
|
onkey(randomize, "r") |
|
|
onkey(bye, "space") |
|
|
|
|
|
def main(): |
|
|
getscreen().clearscreen() |
|
|
ht(); penup() |
|
|
init_shelf() |
|
|
show_text(instructions1) |
|
|
show_text(instructions2, line=1) |
|
|
enable_keys() |
|
|
listen() |
|
|
return "EVENTLOOP" |
|
|
|
|
|
instructions1 = "press i for insertion sort, s for selection sort, q for quicksort" |
|
|
instructions2 = "spacebar to quit, r to randomize" |
|
|
|
|
|
if __name__=="__main__": |
|
|
msg = main() |
|
|
mainloop() |
|
|
|