home *** CD-ROM | disk | FTP | other *** search
-
- /* The SortController class is the "brains" of the sorting operations. As the
- * shepherd of a flock of sorts, it keeps an array of Sort objects. The
- * SortController starts off the sort trials when the SortApp gets the "go!"
- * signal. The SortController generates the data and forks off the sort
- * threads. It keeps track of when the sorts finish, starts the next sort
- * when the sorts are running in series, and lets the SortApp know when all
- * the sorts have finished. Most of the controls of the Parameters panel send
- * their target-action methods to the SortController and it sends the changes
- * on to the sorts as necessary. The SortController is also the text delegate
- * for the various text fields and forms of the Parameters panel. It does
- * entry checking to make sure the user enters reasonable values.
- *
- * Author: Julie Zelenski, NeXT Developer Support
- * You may freely copy, distribute and reuse the code in this example.
- * NeXT disclaims any warranty of any kind, expressed or implied, as to
- * its fitness for any particular use.
- */
-
- #import <appkit/appkit.h>
- #import "SortController.h"
- #import "BubbleSort.h"
- #import "InsertionSort.h"
- #import "MergeSort.h"
- #import "QuickSort.h"
- #import "SelectionSort.h"
- #import "ShellSort.h"
- #import "SortApp.h"
- #import "SortView.h"
- #imporUYibc.h>
- #import <math.h>
- #import <mach/cthreads.h>
-
-
- extern BOOL Abort; // global variable to signal abort
-
-
- @implementation SortController:Object
-
-
- - init;
- /* The initialization method is called once, when unarchiving the nib section.
- * There is only one instantiation of the SortConroller object. This method
- * creates a new sort object for each algorithm and initializes some instance
- * variables.
- */
- {
- [super init];
- srandom(time(0)); // Seed random for data generating
- // Create on of each sort object
- sort[BUBBLE_SORT] = [[BubbleSort allocFromZone:[self zone]] init];
- sort[INSERTION_SORT] = [[InsertionSort allocFromZone:[self zone]] init];
- sort[MERGE_SORT] = [[MergeSort allocFromZone:[self zone]] init];
- sort[QUICK_SORT] = [[QuickSort allocFromZone:[self zone]] init];
- sort[SELECTION_SORT] = [[SelectionSort allocFromZone:[self zone]] init];
- sort[SHELL_SORT] = [[ShellSort allocFromZone:[self zone]] init];
- sortOn[QUICK_SORT] = sortOn[INSERTION_SORT] = sortOn[SHELL_SORT] = YES;
- sortOn[BUBBLE_SORT] = sortOn[SELECTION_SORT] = sortOn[MERGE_SORT] = NO;
- numSorts = 3;
- parallel = YES;
- numElements = 50;
- percentSorted = 0;
- return self;
- }
-
- #define SIZE 1 // tags for different text fields
- #define PERCENT 2
- #define COMPARE 3
- #define MOVE 4
- #define FCALL 5
-
-
- /* TEXT DELEGATE METHODS */
-
-
- - (BOOL)textWillEnd:textObject;
- /* Checks to make sure that the entry in each of the text fields is reasonable.
- * Different values are reasonable based on what the field is. You can get the
- * field or form being edited by asking the text object for its delegate. If
- * the value is unreasonable, reject it, and set the value back to the closest
- * reasonable value. Then it sends the action to the target so that change is
- * recorded.
- */
- {
- BOOL entryOK = YES;
- id form;
- int value;
-
- form = [textObject delegate];
- value = [[form selectedCell] intValue];
-
- switch ([form selectedTag]) {
- case SIZE: entryOK = (value > 0 );
- if (value>5000) [[form selectedCell] setIntValue:5000];
- break;
- case PERCENT: entryOK = ((value >= 0) && (value <= 100));
- break;
- case FCALL:
- case MOVE:
- case COMPARE: entryOK = (value >= 0);
- break;
- }
- if (entryOK) [form sendAction:[form action] to:[form target]]U` return (!entryOK);
- }
-
-
-
- /* TARGET-ACTION METHODS (for controls in the Sort Parameters panel) */
-
- - changeAnimate:sender
- /* Changes whether the sorts highlight their comparisions. SortController
- * simply passes this method onto each of the sorts.
- */
- { int c;
- BOOL value = (BOOL)[sender state];
-
- for (c = 0; c < NUM_SORT_TYPES; c++)
- [sort[c] setAnimate:value];
- return self;
- }
-
-
- - changeParallel:sender
- /* Changes whether the sorts run in parallel or series. SortController needs
- * this to know whether to launch all sort threads at once, or to wait until
- * one has finished to start the next sort.
- */
- {
- parallel = (BOOL)[sender selectedTag];
- return self;
- }
-
-
- - changeSpeed:sender;
- /* Changes at what speed the sorts are running. SortController simply passes
- * this method onto each of the sorts.
- */
- {
- int c, speed;
- speed = [(Slider *)sender maxValue] - [sender intValue];
- for (c = 0; c < NUM_SORT_TYPES; c++)
- [sort[c] setSpeed:speed];
- return self;
- }
-
-
- - changeSortOn:sender
- /* Changes whether a selected sort is set to run or not. Increments or
- * decrements the number of sorts in this trial as appropriate.
- */
- { BOOL on;
-
- on = (BOOL)[[sender selectedCell] state];
- sortOn[[sender selectedTag]] = on;
- if (on)
- numSorts++;
- else
- numSorts--;
- return self;
- }
-
-
-
- - changeDataSet:sender;
- /* Changes the size or percent sorted of a data set, uses tag to determine
- * which.
- */
- {
- switch ([sender selectedTag]) {
- case SIZE: numElements = [sender intValue];
- break;
- case PERCENT: percentSorted = [sender intValue];
- break;
- }
- return self;
- }
-
-
- - changeTickValue:sender;
- /* Changes the tick cost of a certain operation, uses tag to determine which.
- * SortController simply passes this method onto each of the sorts.
- */
- {
- int c, value;
-
- value = [sender intValue];
- for (c = 0; c < NUM_SORT_TYPES; c++)
- [sort[c] setTicks:value for:[sender selectedTag]];
- return self;
- }
-
-
-
-
- /* PRIVATE METHODS */
-
-
- - setSortWindow:anObject
- /* The sortWindow is where all the animation takes place.
- */
- {
- sortWindow = anObject;
- [[sortWindow contentView] setFlipped:YES];
- return self;
- }
-
-
- - setUpWindow;
- /* This is the method that adjusts the sorting window for a new trial. It
- Uasizes the window to fit all the needed sort views and then adds those
- * sortviews as subviews of the content view. It removes any sortviews of
- * sorts that aren't scheduled to run in this trial.
- */
- {
- NXPoint pt = {2.0,2.0};
- NXRect windowRect,headerRect;
- float newHeight;
- int c;
-
- [sortWindow disableFlushWindow];
- [sortWindow getFrame:&windowRect];
- [windowHeader getFrame:&headerRect];
- newHeight = headerRect.size.height + numSorts*(VIEW_HEIGHT+2) + 24;
- windowRect.origin.y += windowRect.size.height - newHeight;
- windowRect.size.height = newHeight;
- [sortWindow placeWindow:&windowRect];
- [windowHeader moveTo:headerRect.origin.x :-3];
- pt.y = headerRect.size.height;
- for (c = 0; (c < NUM_SORT_TYPES); c++) {
- if (sortOn[c]) {
- [[sort[c] view] moveTo:pt.x :pt.y];
- [[sortWindow contentView] addSubview:[sort[c] view]];
- pt.y += VIEW_HEIGHT+2.0;
- } else {
- [[sort[c] view] removeFromSuperview];
- }
- }
- [sortWindow display];
- [[[sortWindow reenableFlushWindow] flushWindow] orderFront:self];
- return self;
- }
-
-
- - (int *)newDataSet
- /* This is the method to generate a new data set. Basically, it cycles
- * through a loop numElements times, getting a new number for each position
- * of the array. For completely random data, each element is randomly
- * generated. For partially sorted data, only some of the elements are random,
- * others are inserted in sorted position. Each time through the loop, a
- * random number is first generated to determine whether this array element
- * will be random. If the random number is greater than the percent sorted,
- * it will generate a random number for that array element, otherwise it will
- * assign an element in sorted order to that array element. */
- {
- int max,c,*data;
-
- data = (int *)calloc(numElements,sizeof(int));
- max = floor((VIEW_HEIGHT-15.0)/(ceil((float)numElements/(VIEW_WIDTH-6))));
- for (c = 0; c < numElements ;c++) {
- cthread_yield(); // give the interface a change
- if (((random() % 100) + 1) > percentSorted)
- data[c] = (random() % (int)(max-1))+ 1;
- else
- data[c] = (int)(c*(max/(float)numElements)) +1;
- }
- return data;
- }
-
-
- - setUpData;
- /* This method sends a message to itself to generate a new data set and
- * tUbpasses that data set along to the sorts who are scheduled to run
- * so they can make a copy of it. The sorts will set up their sortviews
- * and draw the data set. (by messaging back to main thread)
- */
- {
- int c, *address;
-
- address = [self newDataSet];
- for (c = 0; c < NUM_SORT_TYPES; c++) {
- if (sortOn[c])
- [sort[c] setSize:numElements address:address];
- }
- cfree(address);
- return self;
- }
-
-
- static any_t sortInThread(aSort)
- id aSort;
- {
- return [aSort sort];
- }
-
-
- - doSort;
- /* This method is called to run a complete trial. It is launched as a thread,
- * so from here on out, I can no longer safely draw and must message to the
- * main thread. This method generates the data for the trial, sets up all
- * the sort views, starts the tick counter, and then launches the sort threads.
- */
- { int c;
-
- [self setUpData];
- if (!Abort)
- [NXApp startTickCounter];
- for (c = 0; c < NUM_SORT_TYPES; c++) {
- if (sortOn[c]) {
- cthread_detach(cthread_fork(sortInThread,sort[c]));
- if (!parallel)
- break;
- }
- }
- return self;
- }
-
-
- static any_t doSort(self)
- id self;
- {
- return [self doSort];
- }
-
-
-
- /* PUBLIC METHODS */
-
- - (BOOL)startSort;
- /* The SortApp object calls this method after the Go button is clicked.
- * If there are no sorts to run or there is no data set, this method returns
- * NO to the SortApp. Otherwise, I resize and set up the sorting window and
- * launch a thread to "doSort" which generates the data and launches the sort
- * threads. By launching a thread, this method will return almost immediately,
- * so the user isn't locked out while I do the work.
- */
- {
- if (!numSorts || !numElements)
- return NO;
- else {
- sortsFinished = 0;
- [self setUpWindow];
- cthread_detach(cthread_fork(doSort,self));
- return YES;
- }
- }
-
-
- - sortFinished:(int)sortNum;
- /* When a sort finishes, it messages back to the main thread who does the final
- * display. The SortApp then calls this method so the SortController can
- * launch the next sort if necessary (i.e. if the sorts are running in series).
- * The SortController also keeps track of how many sorts still need to finish.
- * If all sorts have finished, the SortController lets the SortApp know, so it
- * can clean up, stop the tickUcnter and re-enable all the controls in the
- * Parameters panel.
- */
- {
- sortsFinished++;
- if (sortsFinished == numSorts) // if all sorts finished,
- [NXApp allFinished]; // let SortApp know this
- else if (!parallel) { // if in series, launch next sort
- while (!sortOn[++sortNum]) ;
- [NXApp startTickCounter];
- cthread_detach(cthread_fork(sortInThread,sort[sortNum]));
- }
- return self;
- }
-
-
- - findSortWithNum:(int)sortNum;
- /* Simply returns the sort of the specified number. Called by the SortApp
- * who has only the number of the sort, but needs the actual sort object.
- */
- {
- return sort[sortNum];
- }
-
-
- @end