Skip to content

Commit 377417c

Browse files
committed
feat: add merge sort
Increased array size from 10 to 16 so divide and conquer algorithms split perfectly. However, this makes heights hard to distinguish during merge sort's endgame.
1 parent f65e121 commit 377417c

File tree

4 files changed

+92
-3
lines changed

4 files changed

+92
-3
lines changed

levels/bubble_sort.gd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ func next(action):
3838
_swapped = false
3939

4040
func get_effect(i):
41-
if i >= _end:
42-
return EFFECTS.DIMMED
4341
if i == _index or i == _index + 1:
4442
return EFFECTS.HIGHLIGHTED
43+
if i >= _end:
44+
return EFFECTS.DIMMED
4545
return EFFECTS.NONE

levels/merge_sort.gd

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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 == -1:
28+
if action != null and action != ACTIONS.RIGHT:
29+
return emit_signal("mistake")
30+
_right += 1
31+
elif _right == -1:
32+
if action != null and action != ACTIONS.LEFT:
33+
return emit_signal("mistake")
34+
_left += 1
35+
elif array.get(_left) <= array.get(_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+
# Test if end of subarrays have been reached
44+
if _left == _get_middle():
45+
_left = -1
46+
if _right == _get_end():
47+
_right = -1
48+
# If both ends have been reached, merge and advance to next block
49+
if _left == -1 and _right == -1:
50+
array.sort(_get_begin(), _get_end())
51+
_sub_no += 1
52+
_left = _get_begin()
53+
_right = _get_middle()
54+
# If last block has been completed, go up a level
55+
if _sub_no == array.size / (_sub_size):
56+
_sub_size *= 2
57+
_sub_no = 0
58+
_left = _get_begin()
59+
_right = _get_middle()
60+
if _sub_size == array.size * 2:
61+
emit_signal("done")
62+
63+
func get_effect(i):
64+
if i == _left or i == _right:
65+
return EFFECTS.HIGHLIGHTED
66+
if i < _sub_no * _sub_size or i >= _sub_no * _sub_size + _sub_size:
67+
return EFFECTS.DIMMED
68+
return EFFECTS.NONE
69+
70+
func _get_begin():
71+
"""Get the index of the left subarray's head."""
72+
return _sub_no * _sub_size
73+
74+
func _get_middle():
75+
"""Get the index of the right subarray's head."""
76+
return _sub_no * _sub_size + _sub_size / 2
77+
78+
func _get_end():
79+
"""Get the index of one past the right subarray's tail."""
80+
return _sub_no * _sub_size + _sub_size

models/array_model.gd

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,12 @@ func swap(i, j):
3232
var temp = array[i]
3333
array[i] = array[j]
3434
array[j] = temp
35+
36+
func sort(i, j):
37+
"""Sort the subarray starting at i and up to but not including j."""
38+
# Grr to the developer who made the upper bound inclusive
39+
var front = array.slice(0, i - 1) if i != 0 else []
40+
var sorted = array.slice(i, j - 1)
41+
sorted.sort()
42+
var back = array.slice(j, size - 1) if j != size else []
43+
array = front + sorted + back

views/array_view.gd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func _init(level):
2323
func _process(delta):
2424
"""Update heights of rectangles based on array values."""
2525
for i in range(level.array.size):
26-
rects[i].rect_scale.y = -1 # XXX: Override parent Control scale
26+
rects[i].rect_scale.y = -1 # HACK: Override scale to bypass weird behavior
2727
rects[i].color = level.get_effect(i)
2828
rects[i].rect_size.y = rect_size.y * level.array.get(i) / level.array.size
2929

0 commit comments

Comments
 (0)