|
| 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 |
0 commit comments