Skip to content

Commit f13d0b7

Browse files
committed
Four Basic Sorts
Every level but one of what I consider the "five basic sorts" is available except for quicksort, because its complexity warrants new features that belong in a later update. [ADDED] - Insertion sort, selection sort, and merge sort - A new "dimmed" color style to aid visual comprehension
2 parents 6092637 + 8ebc0f7 commit f13d0b7

20 files changed

+473
-169
lines changed

Diff for: assets/levels.json

-6
This file was deleted.

Diff for: assets/levels.png.import

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[remap]
2+
3+
importer="texture"
4+
type="StreamTexture"
5+
path="res://.import/levels.png-a6e910382d32e95b5c3f382bb559bde4.stex"
6+
metadata={
7+
"vram_texture": false
8+
}
9+
10+
[deps]
11+
12+
source_file="res://assets/levels.png"
13+
dest_files=[ "res://.import/levels.png-a6e910382d32e95b5c3f382bb559bde4.stex" ]
14+
15+
[params]
16+
17+
compress/mode=0
18+
compress/lossy_quality=0.7
19+
compress/hdr_mode=0
20+
compress/bptc_ldr=0
21+
compress/normal_map=0
22+
flags/repeat=0
23+
flags/filter=true
24+
flags/mipmaps=false
25+
flags/anisotropic=false
26+
flags/srgb=2
27+
process/fix_alpha_border=true
28+
process/premult_alpha=false
29+
process/HDR_as_SRGB=false
30+
process/invert_color=false
31+
stream=false
32+
size_limit=0
33+
detect_3d=true
34+
svg/scale=1.0

Diff for: levels/bogo_sort.gd

+16-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1-
extends ComparisonSort
21
class_name BogoSort
2+
extends ComparisonSort
33

4-
func _init(array).(array):
5-
pass
4+
const NAME = "BOGOSORT"
5+
const ABOUT = """
6+
Generates random permutations until the array is sorted.
7+
"""
8+
const CONTROLS = """
9+
Keep on hitting RIGHT ARROW to CONTINUE and hope for the best!
10+
"""
611

7-
func check(action):
8-
return true
12+
func _init(array).(array):
13+
pass
914

10-
func next():
11-
array = ArrayModel.new(array.size)
15+
func next(action):
16+
array = ArrayModel.new(array.size)
17+
if array.is_sorted():
18+
emit_signal("done")
1219

13-
func emphasized(i):
14-
return false
20+
func get_effect(i):
21+
return EFFECTS.NONE

Diff for: levels/bubble_sort.gd

+40-21
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,46 @@
1-
extends ComparisonSort
21
class_name BubbleSort
2+
extends ComparisonSort
33

4-
var swapped = false
4+
const NAME = "BUBBLE SORT"
5+
const ABOUT = """
6+
Bubble sort iterates through the array and looks at each pair of
7+
elements, swapping them if they are out of order. When it has gone
8+
through the entire array without swapping a single pair, it has
9+
finished. Though simple to understand, bubble sort is hopelessly
10+
inefficient on all but the smallest of arrays.
11+
"""
12+
const CONTROLS = """
13+
If the two highlighted elements are out of order, hit LEFT ARROW to swap
14+
them. Otherwise, hit RIGHT ARROW to continue.
15+
"""
516

6-
func _init(array).(array):
7-
pass
17+
var _index = 0 # First of two elements being compared
18+
var _end = array.size # Beginning of sorted subarray
19+
var _swapped = false
820

9-
func check(action):
10-
if array.get(index) > array.get(index + 1):
11-
return action == "swap"
12-
else:
13-
return action == "no_swap"
21+
func _init(array).(array):
22+
pass
1423

15-
func next():
16-
if array.get(index) > array.get(index + 1):
17-
array.swap(index, index + 1)
18-
swapped = true
19-
index += 1
20-
if index == array.size - 1:
21-
if not swapped:
22-
emit_signal("done")
23-
index = 0
24-
swapped = false
24+
func next(action):
25+
if array.at(_index) > array.at(_index + 1):
26+
if action != null and action != ACTIONS.SWAP:
27+
return emit_signal("mistake")
28+
array.swap(_index, _index + 1)
29+
_swapped = true
30+
elif action != null and action != ACTIONS.NO_SWAP:
31+
return emit_signal("mistake")
32+
_index += 1
33+
# Prevent player from having to spam tap through the end
34+
if _index + 1 == _end:
35+
if not _swapped or _end == 2: # Stop if only one element left
36+
emit_signal("done")
37+
_index = 0
38+
_end -= 1
39+
_swapped = false
2540

26-
func emphasized(i):
27-
return i == index or i == index + 1
41+
func get_effect(i):
42+
if i == _index or i == _index + 1:
43+
return EFFECTS.HIGHLIGHTED
44+
if i >= _end:
45+
return EFFECTS.DIMMED
46+
return EFFECTS.NONE

Diff for: levels/comparison_sort.gd

+39-27
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,55 @@
1-
extends Node
21
class_name ComparisonSort
2+
extends Node
33

44
signal done
55
signal mistake
66

7-
const ACTIONS = ["swap", "no_swap"]
7+
const ACTIONS = {
8+
"SWAP": "ui_left",
9+
"NO_SWAP": "ui_right",
10+
11+
"LEFT": "ui_left",
12+
"RIGHT": "ui_right",
13+
}
14+
15+
const EFFECTS = {
16+
"NONE": GlobalTheme.GREEN,
17+
"HIGHLIGHTED": GlobalTheme.ORANGE,
18+
"DIMMED": GlobalTheme.DARK_GREEN,
19+
}
20+
21+
const DISABLE_TIME = 1.0
822

923
var array: ArrayModel
10-
var index = 0
11-
var timer = Timer.new()
1224
var active = true
1325

26+
var _timer = Timer.new()
27+
1428
func _init(array):
15-
self.array = array
16-
timer.one_shot = true
17-
timer.connect("timeout", self, "_on_Timer_timeout")
18-
add_child(timer)
19-
self.connect("mistake", self, "_on_ComparisonSort_mistake")
29+
"""Initialize array and timer."""
30+
self.array = array
31+
_timer.one_shot = true
32+
_timer.connect("timeout", self, "_on_Timer_timeout")
33+
add_child(_timer)
34+
self.connect("mistake", self, "_on_ComparisonSort_mistake")
2035

21-
func check(action):
22-
pass
36+
func _input(event):
37+
"""Pass input events for checking and take appropriate action."""
38+
if not active:
39+
return
40+
for action in ACTIONS.values():
41+
if event.is_action_pressed(action):
42+
return next(action)
2343

24-
func next():
25-
pass
44+
func next(action):
45+
"""Check the action and advance state or emit signal as needed."""
46+
push_error("NotImplementedError")
2647

2748
func _on_ComparisonSort_mistake():
28-
active = false
29-
timer.start(1)
49+
"""Disable the controls for one second."""
50+
active = false
51+
_timer.start(DISABLE_TIME)
3052

3153
func _on_Timer_timeout():
32-
active = true
33-
34-
func _input(event):
35-
if not active:
36-
return
37-
38-
for action in ACTIONS:
39-
if event.is_action_pressed(action):
40-
if check(action):
41-
next()
42-
else:
43-
emit_signal("mistake")
54+
"""Reenable the controls."""
55+
active = true

Diff for: levels/insertion_sort.gd

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
class_name InsertionSort
2+
extends ComparisonSort
3+
4+
const NAME = "INSERTION SORT"
5+
const ABOUT = """
6+
Insertion sort goes through the array and inserts each
7+
element into its correct position. It is most similar to how most people
8+
would sort a deck of cards. It is also slow on large arrays but it is
9+
one of the faster quadratic algorithms. It is often used to sort smaller
10+
subarrays in hybrid sorting algorithms.
11+
"""
12+
const CONTROLS = """
13+
Hit LEFT ARROW to swap the two highlighted elements as long as they are
14+
out of order. When this is no longer the case, hit RIGHT ARROW to
15+
advance.
16+
"""
17+
18+
var _end = 1 # Size of the sorted subarray
19+
var _index = 1 # Position of element currently being inserted
20+
21+
func _init(array).(array):
22+
pass
23+
24+
func next(action):
25+
if array.at(_index - 1) > array.at(_index):
26+
if action != null and action != ACTIONS.SWAP:
27+
return emit_signal("mistake")
28+
array.swap(_index - 1, _index)
29+
_index -= 1
30+
if _index == 0:
31+
_grow()
32+
else:
33+
if action != null and action != ACTIONS.NO_SWAP:
34+
return emit_signal("mistake")
35+
_grow()
36+
37+
func get_effect(i):
38+
if i == _index or i == _index - 1:
39+
return EFFECTS.HIGHLIGHTED
40+
if i < _end:
41+
return EFFECTS.DIMMED
42+
return EFFECTS.NONE
43+
44+
func _grow():
45+
_end += 1
46+
if _end == array.size:
47+
emit_signal("done")
48+
_index = _end

Diff for: levels/merge_sort.gd

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
class_name MergeSort
2+
extends ComparisonSort
3+
4+
const NAME = "MERGE SORT"
5+
const ABOUT = """
6+
Merge sort is an efficient sorting algorithm that splits the array into
7+
single-element chunks. Then it merges each pair of chunks until only one
8+
sorted chunk is left by repeatedly choosing the smaller element at the
9+
head of each chunk and moving the head back. However, it needs an entire
10+
array's worth of auxiliary memory.
11+
"""
12+
const CONTROLS = """
13+
Press the ARROW KEY corresponding to the side that the smaller
14+
highlighted element is on. If you've reached the end of one side, press
15+
the other side's ARROW KEY.
16+
"""
17+
18+
var _left = 0 # Index of left subarray pointer
19+
var _right = 1 # Index of right subarray pointer
20+
var _sub_size = 2 # Combined size of left and right subarrays
21+
var _sub_no = 0 # Currently being merged left-right pair number
22+
23+
func _init(array).(array):
24+
pass
25+
26+
func next(action):
27+
if _left == _get_middle():
28+
if action != null and action != ACTIONS.RIGHT:
29+
return emit_signal("mistake")
30+
_right += 1
31+
elif _right == _get_end():
32+
if action != null and action != ACTIONS.LEFT:
33+
return emit_signal("mistake")
34+
_left += 1
35+
elif array.at(_left) <= array.at(_right):
36+
if action != null and action != ACTIONS.LEFT:
37+
return emit_signal("mistake")
38+
_left += 1
39+
else:
40+
if action != null and action != ACTIONS.RIGHT:
41+
return emit_signal("mistake")
42+
_right += 1
43+
# If both ends have been reached, merge and advance to next block
44+
if _left == _get_middle() and _right == _get_end():
45+
array.sort(_get_begin(), _get_end())
46+
_sub_no += 1
47+
# If last block has been completed, go up a level
48+
if _sub_no == array.size / (_sub_size):
49+
_sub_size *= 2
50+
_sub_no = 0
51+
if _sub_size == array.size * 2:
52+
emit_signal("done")
53+
# Update pointers
54+
_left = _get_begin()
55+
_right = _get_middle()
56+
57+
func get_effect(i):
58+
var is_left = _left != _get_middle() and i == _left
59+
var is_right = _right != _get_end() and i == _right
60+
if is_left or is_right:
61+
return EFFECTS.HIGHLIGHTED
62+
if i < _left or i >= _get_middle() and i < _right or i >= _get_end():
63+
return EFFECTS.DIMMED
64+
return EFFECTS.NONE
65+
66+
func _get_begin():
67+
"""Get the index of the left subarray's head."""
68+
return _sub_no * _sub_size
69+
70+
func _get_middle():
71+
"""Get the index of the right subarray's head."""
72+
return _sub_no * _sub_size + _sub_size / 2
73+
74+
func _get_end():
75+
"""Get the index of one past the right subarray's tail."""
76+
return _sub_no * _sub_size + _sub_size

Diff for: levels/selection_sort.gd

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
class_name SelectionSort
2+
extends ComparisonSort
3+
4+
const NAME = "SELECTION SORT"
5+
const ABOUT = """
6+
Selection sort incrementally builds a sorted array by repeatedly looking
7+
for the smallest element and swapping it onto the end of the sorted
8+
portion of the array, which initially starts with size zero but grows
9+
after each round. It is faster than an unoptimized bubble sort but
10+
slower than insertion sort.
11+
"""
12+
const CONTROLS = """
13+
Keep on hitting RIGHT ARROW until you encounter an element that is
14+
smaller than the left highlighted element, then hit LEFT ARROW and
15+
repeat.
16+
"""
17+
18+
var _base = 0 # Size of sorted subarray
19+
var _min = 0 # Index of smallest known element
20+
var _index = 1 # Element currently being compared
21+
22+
func _init(array).(array):
23+
pass
24+
25+
func next(action):
26+
if array.at(_index) < array.at(_min):
27+
if action != null and action != ACTIONS.SWAP:
28+
return emit_signal("mistake")
29+
_min = _index
30+
elif action != null and action != ACTIONS.NO_SWAP:
31+
return emit_signal("mistake")
32+
_index += 1
33+
if _index == array.size:
34+
array.swap(_base, _min)
35+
_base += 1
36+
_min = _base
37+
_index = _base + 1
38+
if _base == array.size - 1:
39+
emit_signal("done")
40+
41+
func get_effect(i):
42+
if i == _min or i == _index:
43+
return EFFECTS.HIGHLIGHTED
44+
if i < _base:
45+
return EFFECTS.DIMMED
46+
return EFFECTS.NONE

0 commit comments

Comments
 (0)