home *** CD-ROM | disk | FTP | other *** search
/ The Devil's Doorknob BBS Capture (1996-2003) / devilsdoorknobbbscapture1996-2003.iso / Dloads / 100UTILI / LRNBAS-1.ZIP / SORTDEMO.BAS < prev   
BASIC Source File  |  1988-11-02  |  26KB  |  715 lines

  1. ' ============================================================================
  2. '                                 SORTDEMO
  3. ' This program graphically demonstrates six common sorting algorithms.  It
  4. ' prints 25 or 43 horizontal bars, all of different lengths and all in random
  5. ' order, then sorts the bars from smallest to longest.
  6. '
  7. ' The program also uses SOUND statements to generate different pitches,
  8. ' depending on the location of the bar being printed. Note that the SOUND
  9. ' statements delay the speed of each sorting algorithm so you can follow
  10. ' the progress of the sort.  Therefore, the times shown are for comparison
  11. ' only. They are not an accurate measure of sort speed.
  12. '
  13. ' If you use these sorting routines in your own programs, you may notice
  14. ' a difference in their relative speeds (for example, the exchange
  15. ' sort may be faster than the shell sort) depending on the number of
  16. ' elements to be sorted and how "scrambled" they are to begin with.
  17. ' ============================================================================
  18.  
  19. DEFINT A-Z      ' Default type integer.
  20.  
  21. ' Declare FUNCTION and SUB procedures, and the number and type of arguments:
  22.   DECLARE FUNCTION RandInt% (lower, Upper)
  23.  
  24.   DECLARE SUB BoxInit ()
  25.   DECLARE SUB BubbleSort ()
  26.   DECLARE SUB CheckScreen ()
  27.   DECLARE SUB DrawFrame (TopSide, BottomSide, LeftSide, RightSide)
  28.   DECLARE SUB ElapsedTime (CurrentRow)
  29.   DECLARE SUB ExchangeSort ()
  30.   DECLARE SUB HeapSort ()
  31.   DECLARE SUB Initialize ()
  32.   DECLARE SUB InsertionSort ()
  33.   DECLARE SUB PercolateDown (MaxLevel)
  34.   DECLARE SUB PercolateUp (MaxLevel)
  35.   DECLARE SUB PrintOneBar (Row)
  36.   DECLARE SUB QuickSort (Low, High)
  37.   DECLARE SUB Reinitialize ()
  38.   DECLARE SUB ShellSort ()
  39.   DECLARE SUB SortMenu ()
  40.   DECLARE SUB SwapBars (Row1, Row2)
  41.   DECLARE SUB ToggleSound (Row, Column)
  42.  
  43. ' Define the data type used to hold the information for each colored bar:
  44.   TYPE SortType
  45.      Length AS INTEGER         ' Bar length (the element compared
  46.                                ' in the different sorts)
  47.      ColorVal AS INTEGER       ' Bar color
  48.      BarString AS STRING * 43  ' The bar (a string of 43 characters)
  49.   END TYPE
  50.  
  51. ' Declare global constants:
  52.   CONST FALSE = 0, TRUE = NOT FALSE, LEFTCOLUMN = 49
  53.   CONST NUMOPTIONS = 11, NUMSORTS = 6
  54.  
  55. ' Declare global variables, and allocate storage space for them.  SortArray
  56. ' and SortBackup are both arrays of the data type SortType defined above:
  57.   DIM SHARED SortArray(1 TO 43) AS SortType, SortBackup(1 TO 43) AS SortType
  58.   DIM SHARED OptionTitle(1 TO NUMOPTIONS) AS STRING * 12
  59.   DIM SHARED StartTime AS SINGLE
  60.   DIM SHARED Foreground, Background, NoSound, Pause
  61.   DIM SHARED Selection, MaxRow, InitRow, MaxColors
  62.  
  63. ' Data statements for the different options printed in the sort menu:
  64.   DATA Insertion, Bubble, Heap, Exchange, Shell, Quick,
  65.   DATA Toggle Sound, , <   (Slower), >   (Faster)
  66.  
  67. ' Begin logic of module-level code:
  68.  
  69.   Initialize             ' Initialize data values.
  70.   SortMenu               ' Print sort menu.
  71.   WIDTH 80, InitRow      ' Restore original number of rows.
  72.   COLOR 7, 0             ' Restore default color    
  73.   CLS
  74.   END
  75.  
  76. ' GetRow, MonoTrap, and RowTrap are error-handling routines invoked by
  77. ' the CheckScreen SUB procedure.  GetRow determines whether the program
  78. ' started with 25, 43, or 50 lines.  MonoTrap determines the current
  79. ' video adapter is monochrome.  RowTrap sets the maximum possible
  80. ' number of rows (43 or 25).
  81.  
  82. GetRow:
  83.    IF InitRow = 50 THEN
  84.       InitRow = 43
  85.       RESUME
  86.    ELSE
  87.       InitRow = 25
  88.       RESUME NEXT
  89.    END IF
  90.  
  91. MonoTrap:
  92.    MaxColors = 2
  93.    RESUME NEXT
  94.  
  95. RowTrap:
  96.    MaxRow = 25
  97.    RESUME
  98.  
  99. ' =============================== BoxInit ====================================
  100. '    Calls the DrawFrame procedure to draw the frame around the sort menu,
  101. '    then prints the different options stored in the OptionTitle array.
  102. ' ============================================================================
  103. '
  104. SUB BoxInit STATIC
  105.    DrawFrame 1, 22, LEFTCOLUMN - 3, 78
  106.  
  107.    LOCATE 3, LEFTCOLUMN + 2: PRINT "QUICKBASIC SORTING DEMO";
  108.    LOCATE 5
  109.    FOR I = 1 TO NUMOPTIONS - 1
  110.       LOCATE , LEFTCOLUMN: PRINT OptionTitle(I)
  111.    NEXT I
  112.  
  113.    ' Don't print the last option (> Faster) if the length of the Pause
  114.    ' is down to 1 clock tick:
  115.    IF Pause > 1 THEN LOCATE , LEFTCOLUMN: PRINT OptionTitle(NUMOPTIONS);
  116.  
  117.    ' Toggle sound on or off, then print the current value for NoSound:
  118.    NoSound = NOT NoSound
  119.    ToggleSound 12, LEFTCOLUMN + 12
  120.  
  121.    LOCATE NUMOPTIONS + 6, LEFTCOLUMN
  122.    PRINT "Type first character of"
  123.    LOCATE , LEFTCOLUMN
  124.    PRINT "choice ( I B H E S Q T < > )"
  125.    LOCATE , LEFTCOLUMN
  126.    PRINT "or ESC key to end program: ";
  127. END SUB
  128.  
  129. ' ============================== BubbleSort ==================================
  130. '    The BubbleSort algorithm cycles through SortArray, comparing adjacent
  131. '    elements and swapping pairs that are out of order.  It continues to
  132. '    do this until no pairs are swapped.
  133. ' ============================================================================
  134. '
  135. SUB BubbleSort STATIC
  136.    Limit = MaxRow
  137.    DO
  138.       Switch = FALSE
  139.       FOR Row = 1 TO (Limit - 1)
  140.  
  141.          ' Two adjacent elements are out of order, so swap their values
  142.          ' and redraw those two bars:
  143.          IF SortArray(Row).Length > SortArray(Row + 1).Length THEN
  144.             SWAP SortArray(Row), SortArray(Row + 1)
  145.             SwapBars Row, Row + 1
  146.             Switch = Row
  147.          END IF
  148.       NEXT Row
  149.  
  150.       ' Sort on next pass only to where the last switch was made:
  151.       Limit = Switch
  152.    LOOP WHILE Switch
  153.  
  154. END SUB
  155.  
  156. ' ============================== CheckScreen =================================
  157. '     Checks for type of monitor (VGA, EGA, CGA, or monochrome) and
  158. '     starting number of screen lines (50, 43, or 25).
  159. ' ============================================================================
  160. '
  161. SUB CheckScreen STATIC
  162.  
  163.    ' Try locating to the 50th row; if that fails, try the 43rd. Finally,
  164.    ' if that fails, the user was using 25-line mode:
  165.    InitRow = 50
  166.    ON ERROR GOTO GetRow
  167.    LOCATE InitRow, 1
  168.  
  169.    ' Try a SCREEN 1 statement to see if the current adapter has color
  170.    ' graphics; if that causes an error, reset MaxColors to 2:
  171.    MaxColors = 15
  172.    ON ERROR GOTO MonoTrap
  173.    SCREEN 1
  174.    SCREEN 0
  175.  
  176.    ' See if 43-line mode is accepted; if not, run this program in 25-line
  177.    ' mode:
  178.    MaxRow = 43
  179.    ON ERROR GOTO RowTrap
  180.    WIDTH 80, MaxRow
  181.    ON ERROR GOTO 0              ' Turn off error trapping.
  182. END SUB
  183.  
  184. ' ============================== DrawFrame ===================================
  185. '   Draws a rectangular frame using the high-order ASCII characters ╔ (201) ,
  186. '   ╗ (187) , ╚ (200) , ╝ (188) , ║ (186) , and ═ (205). The parameters
  187. '   TopSide, BottomSide, LeftSide, and RightSide are the row and column
  188. '   arguments for the upper-left and lower-right corners of the frame.
  189. ' ============================================================================
  190. '
  191. SUB DrawFrame (TopSide, BottomSide, LeftSide, RightSide) STATIC
  192.    CONST ULEFT = 201, URIGHT = 187, LLEFT = 200, LRIGHT = 188
  193.    CONST VERTICAL = 186, HORIZONTAL = 205
  194.  
  195.    FrameWidth = RightSide - LeftSide - 1
  196.    LOCATE TopSide, LeftSide
  197.    PRINT CHR$(ULEFT); STRING$(FrameWidth, HORIZONTAL); CHR$(URIGHT);
  198.    FOR Row = TopSide + 1 TO BottomSide - 1
  199.       LOCATE Row, LeftSide
  200.       PRINT CHR$(VERTICAL); SPC(FrameWidth); CHR$(VERTICAL);
  201.    NEXT Row
  202.    LOCATE BottomSide, LeftSide
  203.    PRINT CHR$(LLEFT); STRING$(FrameWidth, HORIZONTAL); CHR$(LRIGHT);
  204. END SUB
  205.  
  206. ' ============================= ElapsedTime ==================================
  207. '    Prints seconds elapsed since the given sorting routine started.
  208. '    Note that this time includes both the time it takes to redraw the
  209. '    bars plus the pause while the SOUND statement plays a note, and
  210. '    thus is not an accurate indication of sorting speed.
  211. ' ============================================================================
  212. '
  213. SUB ElapsedTime (CurrentRow) STATIC
  214.    CONST FORMAT = "  &###.### seconds  "
  215.  
  216.    ' Print current selection and number of seconds elapsed in
  217.    ' reverse video:
  218.    COLOR Foreground, Background
  219.    LOCATE Selection + 4, LEFTCOLUMN - 2
  220.    PRINT USING FORMAT; OptionTitle(Selection); TIMER - StartTime;
  221.  
  222.    IF NoSound THEN
  223.       SOUND 30000, Pause            ' Sound off, so just pause.
  224.    ELSE
  225.       SOUND 60 * CurrentRow, Pause  ' Sound on, so play a note while
  226.    END IF                           ' pausing.
  227.  
  228.    COLOR MaxColors, 0               ' Restore regular foreground and
  229.                                     ' background colors.
  230. END SUB
  231.  
  232. ' ============================= ExchangeSort =================================
  233. '   The ExchangeSort compares each element in SortArray - starting with
  234. '   the first element - with every following element.  If any of the
  235. '   following elements is smaller than the current element, it is exchanged
  236. '   with the current element and the process is repeated for the next
  237. '   element in SortArray.
  238. ' ============================================================================
  239. '
  240. SUB ExchangeSort STATIC
  241.    FOR Row = 1 TO MaxRow
  242.       SmallestRow = Row
  243.       FOR J = Row + 1 TO MaxRow
  244.          IF SortArray(J).Length < SortArray(SmallestRow).Length THEN
  245.             SmallestRow = J
  246.             ElapsedTime J
  247.          END IF
  248.       NEXT J
  249.  
  250.       ' Found a row shorter than the current row, so swap those
  251.       ' two array elements:
  252.       IF SmallestRow > Row THEN
  253.          SWAP SortArray(Row), SortArray(SmallestRow)
  254.          SwapBars Row, SmallestRow
  255.       END IF
  256.    NEXT Row
  257. END SUB
  258.  
  259. ' =============================== HeapSort ===================================
  260. '  The HeapSort procedure works by calling two other procedures - PercolateUp
  261. '  and PercolateDown.  PercolateUp turns SortArray into a "heap," which has
  262. '  the properties outlined in the diagram below:
  263. '
  264. '                               SortArray(1)
  265. '                               /          \
  266. '                    SortArray(2)           SortArray(3)
  267. '                   /          \            /          \
  268. '         SortArray(4)   SortArray(5)   SortArray(6)  SortArray(7)
  269. '          /      \       /       \       /      \      /      \
  270. '        ...      ...   ...       ...   ...      ...  ...      ...
  271. '
  272. '
  273. '  where each "parent node" is greater than each of its "child nodes"; for
  274. '  example, SortArray(1) is greater than SortArray(2) or SortArray(3),
  275. '  SortArray(3) is greater than SortArray(6) or SortArray(7), and so forth.
  276. '
  277. '  Therefore, once the first FOR...NEXT loop in HeapSort is finished, the
  278. '  largest element is in SortArray(1).
  279. '
  280. '  The second FOR...NEXT loop in HeapSort swaps the element in SortArray(1)
  281. '  with the element in MaxRow, rebuilds the heap (with PercolateDown) for
  282. '  MaxRow - 1, then swaps the element in SortArray(1) with the element in
  283. '  MaxRow - 1, rebuilds the heap for MaxRow - 2, and continues in this way
  284. '  until the array is sorted.
  285. ' ============================================================================
  286. '
  287. SUB HeapSort STATIC
  288.    FOR I = 2 TO MaxRow
  289.       PercolateUp I
  290.    NEXT I
  291.  
  292.    FOR I = MaxRow TO 2 STEP -1
  293.       SWAP SortArray(1), SortArray(I)
  294.       SwapBars 1, I
  295.       PercolateDown I - 1
  296.    NEXT I
  297. END SUB
  298.  
  299. ' ============================== Initialize ==================================
  300. '    Initializes the SortBackup and OptionTitle arrays.  It also calls the
  301. '    CheckScreen, BoxInit, and RandInt% procedures.
  302. ' ============================================================================
  303. '
  304. SUB Initialize STATIC
  305.    DIM TempArray(1 TO 43)
  306.  
  307.    CheckScreen                  ' Check for monochrome or EGA and set
  308.                                 ' maximum number of text lines.
  309.    FOR I = 1 TO MaxRow
  310.       TempArray(I) = I
  311.    NEXT I
  312.  
  313.    MaxIndex = MaxRow
  314.  
  315.    RANDOMIZE TIMER              ' Seed the random-number generator.
  316.    FOR I = 1 TO MaxRow
  317.  
  318.       ' Call RandInt% to find a random element in TempArray between 1
  319.       ' and MaxIndex, then assign the value in that element to BarLength:
  320.       Index = RandInt%(1, MaxIndex)
  321.       BarLength = TempArray(Index)
  322.  
  323.       ' Overwrite the value in TempArray(Index) with the value in
  324.       ' TempArray(MaxIndex) so the value in TempArray(Index) is
  325.       ' chosen only once:
  326.       TempArray(Index) = TempArray(MaxIndex)
  327.  
  328.       ' Decrease the value of MaxIndex so that TempArray(MaxIndex) can't
  329.       ' be chosen on the next pass through the loop:
  330.       MaxIndex = MaxIndex - 1
  331.  
  332.       ' Assign the BarLength value to the .Length element, then store
  333.       ' a string of BarLength block characters (ASCII 223: ▀) in the
  334.       ' .BarString element:
  335.       SortBackup(I).Length = BarLength
  336.       SortBackup(I).BarString = STRING$(BarLength, 223)
  337.  
  338.       ' Store the appropriate color value in the .ColorVal element:
  339.       IF MaxColors > 2 THEN
  340.          SortBackup(I).ColorVal = (BarLength MOD MaxColors) + 1
  341.       ELSE
  342.          SortBackup(I).ColorVal = MaxColors
  343.       END IF
  344.    NEXT I
  345.  
  346.    FOR I = 1 TO NUMOPTIONS      ' Read SORT DEMO menu options and store
  347.       READ OptionTitle(I)       ' them in the OptionTitle array.
  348.    NEXT I
  349.  
  350.    CLS
  351.    Reinitialize         ' Assign values in SortBackup to SortArray and draw
  352.                         ' unsorted bars on the screen.
  353.    NoSound = FALSE
  354.    Pause = 2            ' Initialize Pause to 2 clock ticks (@ 1/9 second).
  355.    BoxInit              ' Draw frame for the sort menu and print options.
  356.  
  357. END SUB
  358.  
  359. ' ============================= InsertionSort ================================
  360. '   The InsertionSort procedure compares the length of each successive
  361. '   element in SortArray with the lengths of all the preceding elements.
  362. '   When the procedure finds the appropriate place for the new element, it
  363. '   inserts the element in its new place, and moves all the other elements
  364. '   down one place.
  365. ' ============================================================================
  366. '
  367. SUB InsertionSort STATIC
  368.    DIM TempVal AS SortType
  369.    FOR Row = 2 TO MaxRow
  370.       TempVal = SortArray(Row)
  371.       TempLength = TempVal.Length
  372.       FOR J = Row TO 2 STEP -1
  373.  
  374.          ' As long as the length of the J-1st element is greater than the
  375.          ' length of the original element in SortArray(Row), keep shifting
  376.          ' the array elements down:
  377.          IF SortArray(J - 1).Length > TempLength THEN
  378.             SortArray(J) = SortArray(J - 1)
  379.             PrintOneBar J               ' Print the new bar.
  380.             ElapsedTime J               ' Print the elapsed time.
  381.  
  382.          ' Otherwise, exit the FOR...NEXT loop:
  383.          ELSE
  384.             EXIT FOR
  385.          END IF
  386.       NEXT J
  387.  
  388.       ' Insert the original value of SortArray(Row) in SortArray(J):
  389.       SortArray(J) = TempVal
  390.       PrintOneBar J
  391.       ElapsedTime J
  392.    NEXT Row
  393. END SUB
  394.  
  395. ' ============================ PercolateDown =================================
  396. '   The PercolateDown procedure restores the elements of SortArray from 1 to
  397. '   MaxLevel to a "heap" (see the diagram with the HeapSort procedure).
  398. ' ============================================================================
  399. '
  400. SUB PercolateDown (MaxLevel) STATIC
  401.    I = 1
  402.  
  403.    ' Move the value in SortArray(1) down the heap until it has
  404.    ' reached its proper node (that is, until it is less than its parent
  405.    ' node or until it has reached MaxLevel, the bottom of the current heap):
  406.    DO
  407.       Child = 2 * I             ' Get the subscript for the child node.
  408.  
  409.       ' Reached the bottom of the heap, so exit this procedure:
  410.       IF Child > MaxLevel THEN EXIT DO
  411.  
  412.       ' If there are two child nodes, find out which one is bigger:
  413.       IF Child + 1 <= MaxLevel THEN
  414.          IF SortArray(Child + 1).Length > SortArray(Child).Length THEN
  415.             Child = Child + 1
  416.          END IF
  417.       END IF
  418.  
  419.       ' Move the value down if it is still not bigger than either one of
  420.       ' its children:
  421.       IF SortArray(I).Length < SortArray(Child).Length THEN
  422.          SWAP SortArray(I), SortArray(Child)
  423.          SwapBars I, Child
  424.          I = Child
  425.  
  426.       ' Otherwise, SortArray has been restored to a heap from 1 to MaxLevel,
  427.       ' so exit:
  428.       ELSE
  429.          EXIT DO
  430.       END IF
  431.    LOOP
  432. END SUB
  433.  
  434. ' ============================== PercolateUp =================================
  435. '   The PercolateUp procedure converts the elements from 1 to MaxLevel in
  436. '   SortArray into a "heap" (see the diagram with the HeapSort procedure).
  437. ' ============================================================================
  438. '
  439. SUB PercolateUp (MaxLevel) STATIC
  440.    I = MaxLevel
  441.  
  442.    ' Move the value in SortArray(MaxLevel) up the heap until it has
  443.    ' reached its proper node (that is, until it is greater than either
  444.    ' of its child nodes, or until it has reached 1, the top of the heap):
  445.    DO UNTIL I = 1
  446.       Parent = I \ 2            ' Get the subscript for the parent node.
  447.  
  448.       ' The value at the current node is still bigger than the value at
  449.       ' its parent node, so swap these two array elements:
  450.       IF SortArray(I).Length > SortArray(Parent).Length THEN
  451.          SWAP SortArray(Parent), SortArray(I)
  452.          SwapBars Parent, I
  453.          I = Parent
  454.  
  455.       ' Otherwise, the element has reached its proper place in the heap,
  456.       ' so exit this procedure:
  457.       ELSE
  458.          EXIT DO
  459.       END IF
  460.    LOOP
  461. END SUB
  462.  
  463. ' ============================== PrintOneBar =================================
  464. '  Prints SortArray(Row).BarString at the row indicated by the Row
  465. '  parameter, using the color in SortArray(Row).ColorVal.
  466. ' ============================================================================
  467. '
  468. SUB PrintOneBar (Row) STATIC
  469.    LOCATE Row, 1
  470.    COLOR SortArray(Row).ColorVal
  471.    PRINT SortArray(Row).BarString;
  472. END SUB
  473.  
  474. ' ============================== QuickSort ===================================
  475. '   QuickSort works by picking a random "pivot" element in SortArray, then
  476. '   moving every element that is bigger to one side of the pivot, and every
  477. '   element that is smaller to the other side.  QuickSort is then called
  478. '   recursively with the two subdivisions created by the pivot.  Once the
  479. '   number of elements in a subdivision reaches two, the recursive calls end
  480. '   and the array is sorted.
  481. ' ============================================================================
  482. '
  483. SUB QuickSort (Low, High)
  484.    IF Low < High THEN
  485.  
  486.       ' Only two elements in this subdivision; swap them if they are out of
  487.       ' order, then end recursive calls:
  488.       IF High - Low = 1 THEN
  489.          IF SortArray(Low).Length > SortArray(High).Length THEN
  490.             SWAP SortArray(Low), SortArray(High)
  491.             SwapBars Low, High
  492.          END IF
  493.       ELSE
  494.  
  495.          ' Pick a pivot element at random, then move it to the end:
  496.          RandIndex = RandInt%(Low, High)
  497.          SWAP SortArray(High), SortArray(RandIndex)
  498.          SwapBars High, RandIndex
  499.          Partition = SortArray(High).Length
  500.          DO
  501.  
  502.             ' Move in from both sides towards the pivot element:
  503.             I = Low: J = High
  504.             DO WHILE (I < J) AND (SortArray(I).Length <= Partition)
  505.                I = I + 1
  506.             LOOP
  507.             DO WHILE (J > I) AND (SortArray(J).Length >= Partition)
  508.                J = J - 1
  509.             LOOP
  510.  
  511.             ' If we haven't reached the pivot element, it means that two
  512.             ' elements on either side are out of order, so swap them:
  513.             IF I < J THEN
  514.                SWAP SortArray(I), SortArray(J)
  515.                SwapBars I, J
  516.             END IF
  517.          LOOP WHILE I < J
  518.  
  519.          ' Move the pivot element back to its proper place in the array:
  520.          SWAP SortArray(I), SortArray(High)
  521.          SwapBars I, High
  522.  
  523.          ' Recursively call the QuickSort procedure (pass the smaller
  524.          ' subdivision first to use less stack space):
  525.          IF (I - Low) < (High - I) THEN
  526.             QuickSort Low, I - 1
  527.             QuickSort I + 1, High
  528.          ELSE
  529.             QuickSort I + 1, High
  530.             QuickSort Low, I - 1
  531.          END IF
  532.       END IF
  533.    END IF
  534. END SUB
  535.  
  536. ' =============================== RandInt% ===================================
  537. '   Returns a random integer greater than or equal to the Lower parameter
  538. '   and less than or equal to the Upper parameter.
  539. ' ============================================================================
  540. '
  541. FUNCTION RandInt% (lower, Upper) STATIC
  542.    RandInt% = INT(RND * (Upper - lower + 1)) + lower
  543. END FUNCTION
  544.  
  545. ' ============================== Reinitialize ================================
  546. '   Restores the array SortArray to its original unsorted state, then
  547. '   prints the unsorted color bars.
  548. ' ============================================================================
  549. '
  550. SUB Reinitialize STATIC
  551.    FOR I = 1 TO MaxRow
  552.       SortArray(I) = SortBackup(I)
  553.    NEXT I
  554.  
  555.    FOR I = 1 TO MaxRow
  556.       LOCATE I, 1
  557.       COLOR SortArray(I).ColorVal
  558.       PRINT SortArray(I).BarString;
  559.    NEXT I
  560.  
  561.    COLOR MaxColors, 0
  562. END SUB
  563.  
  564. ' =============================== ShellSort ==================================
  565. '  The ShellSort procedure is similar to the BubbleSort procedure.  However,
  566. '  ShellSort begins by comparing elements that are far apart (separated by
  567. '  the value of the Offset variable, which is initially half the distance
  568. '  between the first and last element), then comparing elements that are
  569. '  closer together (when Offset is one, the last iteration of this procedure
  570. '  is merely a bubble sort).
  571. ' ============================================================================
  572. '
  573. SUB ShellSort STATIC
  574.  
  575.    ' Set comparison offset to half the number of records in SortArray:
  576.    Offset = MaxRow \ 2
  577.  
  578.    DO WHILE Offset > 0          ' Loop until offset gets to zero.
  579.       Limit = MaxRow - Offset
  580.       DO
  581.          Switch = FALSE         ' Assume no switches at this offset.
  582.  
  583.          ' Compare elements and switch ones out of order:
  584.          FOR Row = 1 TO Limit
  585.             IF SortArray(Row).Length > SortArray(Row + Offset).Length THEN
  586.                SWAP SortArray(Row), SortArray(Row + Offset)
  587.                SwapBars Row, Row + Offset
  588.                Switch = Row
  589.             END IF
  590.          NEXT Row
  591.  
  592.          ' Sort on next pass only to where last switch was made:
  593.          Limit = Switch - Offset
  594.       LOOP WHILE Switch
  595.  
  596.       ' No switches at last offset, try one half as big:
  597.       Offset = Offset \ 2
  598.    LOOP
  599. END SUB
  600.  
  601. ' =============================== SortMenu ===================================
  602. '   The SortMenu procedure first calls the Reinitialize procedure to make
  603. '   sure the SortArray is in its unsorted form, then prompts the user to
  604. '   make one of the following choices:
  605. '
  606. '               * One of the sorting algorithms
  607. '               * Toggle sound on or off
  608. '               * Increase or decrease speed
  609. '               * End the program
  610. ' ============================================================================
  611. '
  612. SUB SortMenu STATIC
  613.    Escape$ = CHR$(27)
  614.  
  615.    ' Create a string consisting of all legal choices:
  616.    Option$ = "IBHESQ><T" + Escape$
  617.  
  618.    DO
  619.  
  620.       ' Make the cursor visible:
  621.       LOCATE NUMOPTIONS + 8, LEFTCOLUMN + 27, 1
  622.  
  623.       Choice$ = UCASE$(INPUT$(1))          ' Get the user's choice and see
  624.       Selection = INSTR(Option$, Choice$)  ' if it's one of the menu options.
  625.  
  626.       ' User chose one of the sorting procedures:
  627.       IF (Selection >= 1) AND (Selection <= NUMSORTS) THEN
  628.          Reinitialize                      ' Rescramble the bars.
  629.          LOCATE , , 0                      ' Make the cursor invisible.
  630.          Foreground = 0                    ' Set reverse-video values.
  631.          Background = 7
  632.          StartTime = TIMER                 ' Record the starting time.
  633.       END IF
  634.  
  635.       ' Branch to the appropriate procedure depending on the key typed:
  636.       SELECT CASE Choice$
  637.          CASE "I"
  638.             InsertionSort
  639.          CASE "B"
  640.             BubbleSort
  641.          CASE "H"
  642.             HeapSort
  643.          CASE "E"
  644.             ExchangeSort
  645.          CASE "S"
  646.             ShellSort
  647.          CASE "Q"
  648.             QuickSort 1, MaxRow
  649.          CASE ">"
  650.  
  651.             ' Decrease pause length to speed up sorting time, then redraw
  652.             ' the menu to clear any timing results (since they won't compare
  653.             ' with future results):
  654.             Pause = (2 * Pause) / 3
  655.             BoxInit
  656.  
  657.          CASE "<"
  658.  
  659.             ' Increase pause length to slow down sorting time, then redraw
  660.             ' the menu to clear any timing results (since they won't compare
  661.             ' with future results):
  662.             Pause = (3 * Pause) / 2
  663.             BoxInit
  664.  
  665.          CASE "T"
  666.             ToggleSound 12, LEFTCOLUMN + 12
  667.  
  668.          CASE Escape$
  669.  
  670.             ' User pressed ESC, so exit this procedure and return to
  671.             ' module level:
  672.             EXIT DO
  673.  
  674.          CASE ELSE
  675.  
  676.             ' Invalid key
  677.       END SELECT
  678.  
  679.       IF (Selection >= 1) AND (Selection <= NUMSORTS) THEN
  680.          Foreground = MaxColors            ' Turn off reverse video.
  681.          Background = 0
  682.          ElapsedTime 0                     ' Print final time.
  683.       END IF
  684.  
  685.    LOOP
  686.  
  687. END SUB
  688.  
  689. ' =============================== SwapBars ===================================
  690. '   Calls PrintOneBar twice to switch the two bars in Row1 and Row2,
  691. '   then calls the ElapsedTime procedure.
  692. ' ============================================================================
  693. '
  694. SUB SwapBars (Row1, Row2) STATIC
  695.    PrintOneBar Row1
  696.    PrintOneBar Row2
  697.    ElapsedTime Row1
  698. END SUB
  699.  
  700. ' ============================== ToggleSound =================================
  701. '   Reverses the current value for NoSound, then prints that value next
  702. '   to the "Toggle Sound" option on the sort menu.
  703. ' ============================================================================
  704. '
  705. SUB ToggleSound (Row, Column) STATIC
  706.    NoSound = NOT NoSound
  707.    LOCATE Row, Column
  708.    IF NoSound THEN
  709.       PRINT ": OFF";
  710.    ELSE
  711.       PRINT ": ON ";
  712.    END IF
  713. END SUB
  714.  
  715.