TweetFollow Us on Twitter

Jan 94 Challenge
Volume Number:10
Issue Number:1
Column Tag:Programmers’ Challenge

Programmers’ Challenge

Connect The Dots

By Mike Scanlin, MacTech Magazine Regular Contributing Author

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

Here’s how it works:

Each month there will be a different programming challenge presented here. First, you must write some code that solves the challenge. Second, you must optimize your code (a lot). Then, submit your solution to MacTech Magazine (formerly MacTutor). A winner will be chosen based on code correctness, speed, size and elegance (in that order of importance) as well as the postmark of the answer. In the event of multiple equally desirable solutions, one winner will be chosen at random (with honorable mention, but no prize, given to the runners up). The prize for the best solution each month is $50 and a limited edition “The Winner! MacTech Magazine Programming Challenge” T-shirt (not to be found in stores).

In order to make fair comparisons between solutions, all solutions must be in ANSI compatible C (i.e., don’t use Think’s Object extensions). Only pure C code can be used. Any entries with any assembly in them will be disqualified (except for those challenges specifically stated to be in assembly). However, you may call any routine in the Macintosh toolbox you want (i.e., it doesn’t matter if you use NewPtr instead of malloc). All entries will be tested with the FPU and 68020 flags turned off in THINK C. When timing routines, the latest version of THINK C will be used (with ANSI Settings plus “Honor ‘register’ first” and “Use Global Optimizer” turned on) so beware if you optimize for a different C compiler. All code should be limited to 60 characters wide. This will aid us in dealing with e-mail gateways and page layout.

The solution and winners for this month’s Programmers’ Challenge will be published in the issue two months later. All submissions must be received by the 10th day of the month printed on the front of this issue.

All solutions should be marked “Attn: Programmers’ Challenge Solution” and sent to Xplain Corporation (the publishers of MacTech Magazine) via “snail mail” or preferably, e-mail - AppleLink: MT.PROGCHAL, Internet: progchallenge@xplain.com, CompuServe: 71552,174 and America Online: MT PRGCHAL. If you send via snail mail, please include a disk with the solution and all related files (including contact information). See page 2 for information on “How to Contact Xplain Corporation.”

MacTech Magazine reserves the right to publish any solution entered in the Programming Challenge of the Month and all entries are the property of MacTech Magazine upon submission. The submission falls under all the same conventions of an article submission.

CONNECT THE DOTS

Thanks to James Goebel (location unknown) for suggesting this month’s challenge. You are given a set of Points and a PixMapHandle. The goal is to quickly draw a line from each point in the set to the next point in the set (if you have n points then draw n-1 line segments). A really fast version of this routine would help improve the speed of a program that makes line charts, for instance.

The prototype of the function you write is:

/* 1 */
void ConnectTheDots(numDots, theDots, 
 thePixMapHndl, lineColor)
unsigned short numDots;
Point   theDots[];
PixMapHandlethePixMapHndl;
RGBColorlineColor;

NumDots is the 1-based number of Points in the array theDots (range is 2..500). ThePixMapHandle is a handle to the PixMap where the line drawing takes place (maximum dimensions are 4000 pixels square). In order to avoid sub-byte addressing problems, you can assume that the only combinations of pixelSize, cmpSize and cmpCount of the PixMap you’ll have to deal with are (8, 8, 1), (16, 5, 3) and (32, 8, 3) (basically, 256 indexed colors, 16-bit direct (Thousands) and 32-bit direct (Millions)).

LineColor is the RGBColor that you should use to draw each line segment. If the PixMap is indexed then you’ll have to convert the RGBColor to the appropriate index value (using the inverse table of the PixMap’s pmTable field). You may assume that each point in theDots array lies within the bounds of the PixMap. And it’s okay to write or clear the unused bits of each pixel (the alpha bit(s) in the 16-bit or 32-bit direct cases).

Here’s an example: Say numDots is 4, theDots[0] = (1,2), theDots[1] = (1,4), theDots[2] = (2,4) and theDots[3] = (3,6). You would draw 3 lines of the appropriate color from (1,2) to (1,4), from (1,4) to (2,4) and from (2,4) to (3,6).

That’s it. Pretty simple concept, huh? The key is, though, that you can probably do better than the ROM’s Line or LineTo routines given the special circumstances that this drawing takes place in. Your pen size is (1,1), the mode is patCopy, there is no clipping or bounds checking, etc. It boils down to how fast your line algorithm is and how fast you can do byte-aligned pixel addressing. It is not necessary to exactly match QuickDraw’s Line routine; that is, you don’t have to plot the exact same set of pixels when making a line from a given point to some other given point. But your line routine should produce reasonable unbroken lines nonetheless.

TWO MONTHS AGO WINNER

Of the 21 entries I received for the Who Plays Who challenge I only had to disqualify 3 entries: one that used tables of precomputed answers, one that was written in Pascal and one that was incorrect. Of those remaining there were two who were equally fast: Bill Karsh (Chicago, IL) and two-time Challenge winner Bob Boonstra (Westford, MA). Bill wins, though, because his code and data size is about a quarter of Bob’s.

Here are the times, code+data sizes and outpTop 10ut sizes of each entry (the output size represents the concatenated output for many sample runs of the routine). Numbers in parens after a person’s name indicate how many times that person has finished in the top 5 places of all previous Programmer Challenges, not including this one.

Name time code+data output size

Bill Karsh (1) 4 660 27935

Bob Boonstra (3) 4 2430 29157

James Goebel (1) 7 348 29157

Doug Currie 8 298 29066

P Kidwell & G Klesczewski 8 468 29113

Dan Farmer 8 526 29157

Jerry Panagrossi 12 508 29183

Thomas Studer 12 906 29158

Martin Caron 16 676 29158

Jorj Bauer 28 11040 28936

John Chen 34 1828 29027

Michael Panchenko 73 270 35944

Dave Darah 73 780 33682

Allen Stenger (2) 74 728 35158

Stefan Pantke 76 764 33075

Steve Gehrman 81 1294 28813

Jan de Ruiter 145 354 76431

Jeremy Vineyard (1) 4561 592 29069

One thing that the two fastest entries have in common is that they don’t call fprintf (which takes up the bulk of the time for most solutions). Instead, they format the output themselves (since the format requirements are simple), buffer the output to one of their own buffers (allocated on the stack) and then call fwrite (see Bill’s solution below for an example of this).

Although I disqualified the entry from Ernst Munter (Kanata, ON, Canada) for using entirely too many precomputed lookup tables, his output format was interesting (and very compact). Here’s a sample for 12 teams:

Matches are played every 15 minutes,

starting at noon. Teams meet each other

in the designated playing areas.

Playing Areas:

A = Field 1

B = Field 2

C = Field 3

D = Field 4

E = Field 5

F = Field 6

Time: 12 . . . 1 . . . 2 . .

Team:

CycleStealers A A A A A A A A A A A

Beanies A B B B B B B B B B B

RiscTakers B A B C C C C C C C C

GiraffeButts B B A D D D D D D D D

BlueBombers C C C A B E E E E C D

Wackos C D D B A F F F F D C

Peashooters D C D E E A B C D E E

SourGrapes D D C F F B A D C F F

SnowBirds E E E C D E F A B E F

Monarchs E F F D C F E B A F E

Accountants F E F E F C D E F A B

Friends F F E F E D C F E B A

Here’s Bill’s winning solution:

/* 2 */
/* ScheduleMatches ----------------------------------------
 *
 * In response to Nov 93 MacTech programmer's challenge.
 *
 * Object is to:
 * 1)   form all combinations of 'numTeams' 'teamNames',
 * taken two at a time (numTeams even);
 * 2) match these pairs to 'numTeams'/2
 * 'playingAreaNames';
 * 3) schedule 'numTeams'/2 "matches" at a time, starting
 * at 12 noon, with a new set of such matches
 * scheduled every 15 minutes, until all combinations
 * are used;
 * 4) write the whole schedule out to a given ANSI file
 * stream.
 *
 * Some observations:
 *
 * number of combinations = C(numTeams,2) =
 * numTeams*(numTeams-1)/2.
 * There are then (numTeams-1) sets of matches, or,
 * times, which must be scheduled.
 *
 * The pairs can be generated geometrically using
 * central cyclical pattern as demonstrated for
 * numTeams = 6:
 *
 *          1           Connecting rods have fixed
 *          |           orientation.  0 stays in center.
 *          |           Other digits cycle clockwise, 
 *    2---\ 0 /---5     or, cc, around circumference.
 *         ---
 *
 *       3-----4
 *
 * Suggested formatting is as follows:
 *
 * 12:xx
 * areaU: nameJ vs nameK
 * areaV: nameL vs nameM
 * .
 * .
 * {blank line}
 * 12:xx
 * .
 * .
 *
 * billKarsh - solution author.
 *
 */

#pragma options( honor_register, !assign_registers )
#pragma options( !check_ptrs )

#include<string.h>
#include<stdio.h>

void ScheduleMatches(
 unsigned short  numTeams,
 Str255 teamNames[],
 Str255 playingAreaNames[],
 FILE   *outputfile );

#define BufSize  1024

// BufIt modifier codes
#define kTime    -1// write time
#define kStrn    1 // write string + '\n'
#define kStrSep  2 // write string + ': '
#define kStrVs   4 // write string + ' vs '

// useful shorthand inside BufIt
// make sure n bytes available in buffer,
// else empty it out

#define BufReady( n )\
 if( n > b->avail ) {\
 b->p = p;\
 BufFlush();\
 p = b->buf;\
 }

typedef struct {
 FILE   *file; // ANSI stream
 Byte   *buf;  // start of private buffer
 Byte   *p; // current position in buffer
 short  avail; // available bytes in buffer
 short  padding;// global data 4-byte aligned
} BufRec;

static  BufRec gBuf;


/* BufFlush -----------------------------------------------
 *
 * Write current buffer to file.
 */
 
static void BufFlush( void )
{
 register BufRec *b = &gBuf;
 size_t  n = b->p - b->buf;
 
 if( n ) {
 
 fwrite( b->buf, 1, n, b->file );
 
 // reset buffer
 
 b->p   = b->buf;
 b->avail = BufSize;
 }
}


/* BufIt --------------------------------------------------
 *
 * 1) Write string to local buffer if room,
 * otherwise,
 * 2) Dump buffer to file,
 * 3) resume with step 1.
 *
 * If behavior code, mod, as defined above is >= 0:
 * data is data starting address,
 * nBytes of data to write.
 *
 * If mod is special code kTime:
 * data indexes internal minute string,
 * nBytes = hour.
 */
 
static void BufIt(
 register Byte *data,
 register short  nBytes,
 short  mod )
{
 register BufRec *b= &gBuf;
 register Byte *p= b->p;
 static  Byte  mins[8]  = "00153045";

 if( mod < 0 ) { // write a time
 
 BufReady( 7 );
 
 *p++ = '\n';
 
 // hour
 
 if( !nBytes ) {
 *p++ = '1';
 *p++ = '2';
 b->avail--;
 }
 else
 *p++ = nBytes + '0';
 
 *p++  =':';
 
 // mins
 
 data += (long)mins;
 *p++ = *data++;
 *p++ = *data;
 
 *p++ = '\n';
 b->avail -= 6;
 }
 else { // write a string
 
 BufReady( nBytes + mod );
 
 memcpy( p, data, nBytes );
 p += nBytes;
 b->avail -= nBytes + mod;
 
 switch( mod ) { // write string suffix
 case kStrn:
 *p++ = '\n';
 break;
 case kStrSep:
 *p++ = ':';
 *p++ = ' ';
 break;
 case kStrVs:
 *p++ = ' ';
 *p++ = 'v';
 *p++ = 's';
 *p++ = ' ';
 break;
 }
 }
 
 b->p = p;
}


/* ScheduleMatches ----------------------------------------
 *
 * Driver routine.
 */
 
void ScheduleMatches(
 unsigned short  numTeams,
 Str255 teamNames[],
 Str255 playingAreaNames[],
 FILE   *outputfile )
{
 register Byte *area, *tmJ, *tmK;
 register short  N = numTeams,
 set  = 0, nAreas;
 register long t1= (long)*teamNames + 256,
 tN= t1 + ((N-2)<<8);
 Byte   localBuf[BufSize];
 
 if( !N || N & 1 ) return;
 
// init local buffer

 gBuf.file= outputfile;
 gBuf.buf = gBuf.p = localBuf;
 gBuf.avail = BufSize;
 
 // loop over sets of matches (times)
 
 do {
 
 // do first pair separately, because team[0]
 // is at center, so this pair disjoint from
 // others.
 
 nAreas = N>>1;
 area = *playingAreaNames;
 
 BufIt( (Byte*)((set&3)<<1), set>>2, kTime );
 BufIt( area+1, *area, kStrSep );
 
 tmJ = (Byte*)t1 - 256;
 tmK = (Byte*)t1 + (set<<8);
 
 BufIt( tmJ+1, *tmJ, kStrVs );
 BufIt( tmK+1, *tmK, kStrn  );
 
 tmJ = tmK;
 
 // loop over remaining areas (pairs)
 
 while( --nAreas ) {
 
 area += 256;
 BufIt( area+1, *area, kStrSep );
 
 // next pair
 
 tmJ = (long)tmJ < tN ? tmJ+256 : (Byte*)t1;
 tmK = (long)tmK > t1 ? tmK-256 : (Byte*)tN;
 
 BufIt( tmJ+1, *tmJ, kStrVs );
 BufIt( tmK+1, *tmK, kStrn  );
 };
 
 } while( ++set < N - 1 );
 
 BufFlush();
}
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

How to build a successful civilisation i...
GodFinger 2 grants you godlike powers, leaving you to raise a civilization of followers. In the spirit of games like Black & White, the GodFinger games will see you building bigger and better villages, developing more advanced technology and... | Read more »
How to get all the crabs in Mr Crab 2
Mr. Crab 2 may look like a cutesy platformer for kids, but if you're the kind of person who likes to complete a game 100%, you'll soon realise that it's a tougher than a crustacean's shell. [Read more] | Read more »
How to be a star in Britney Spears: Amer...
If you've ever wanted to be a star, baby, then you've probably already checked out Britney Spears: American Dream and are happily making your way up the charts. But fame doesn't come easy, and everyone needs a helping hand sometimes. So we've got... | Read more »
AppSpy is hiring a part time Staff Write...
| Read more »
How to save lives in ER Surgery Simulato...
A serious earthquake has struck a nearby town in ER Surgery Simulator - Emergency Doctor, and it’s up to you to save the victims. [Read more] | Read more »
Tips and tricks to get a high score in G...
Ketchapp Games loves the endless runner genre. And its newest game, Gravity Switch, is no exception. Gravity Switch takes a fresh approach, though, as you move a block, suspended in zero gravity, safely through a maze of shifting pillars. If the... | Read more »
Tips and tricks to get a high score in S...
Smash Fu is a high-paced tile-tapping game that requires quick reflexes and some practice. You’ll have to smash bricks with the skill of a seasoned black belt to get a high score. To raise the stakes a bit, you’ll also have to avoid tapping any... | Read more »
How to keep the ball rolling in Dropple
If you're new to the minimalist puzzler Dropple, you may find yourself struggling to make it beyond the first couple of steps before your ball falls into the endless abyss below. [Read more] | Read more »
Game Craft releases new Legend of War ti...
Set for release at the end of this month, real time strategy title Legend of War seems sure to delight with a veritable feast of sweet features to get stuck into. Developed by Game Craft, the game is due for release through both the App Store and... | Read more »
How not to die in Traffic Rider
Traffic Rider, an Out Run-esque game in which your ride a motorcycle recklessly into trffic, might not seem particularly complicated. [Read more] | Read more »

Price Scanner via MacPrices.net

Apple refurbished iMacs available for up to $...
Apple has Certified Refurbished 2015 21″ & 27″ iMacs available for up to $350 off MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: - 21″ 3.... Read more
Textkraft Professional Becomes A Mobile Produ...
The new update 4.1 of Textkraft Professional for the iPad comes with many new and updated features that will be particularly of interest to self-publishers of e-books. Highlights include import and... Read more
SnipNotes 2.0 – Intelligent note-taking for i...
Indie software developer Felix Lisczyk has announced the release and immediate availability of SnipNotes 2.0, the next major version of his productivity app for iOS devices and Apple Watch.... Read more
Pitch Clock – The Entrepreneur’s Wingman Laun...
Grand Rapids, Michigan based Skunk Tank has announced the release and immediate availability of Pitch Clock – The Entrepreneur’s Wingman 1.1, the company’s new business app available exclusively on... Read more
13-inch 2.9GHz Retina MacBook Pro on sale for...
B&H Photo has the 13″ 2.9GHz Retina MacBook Pro (model #MF841LL/A) on sale for $1599 including free shipping plus NY tax only. Their price is $200 off MSRP. Amazon also has the 13″ 3.9GHz Retina... Read more
Apple price trackers, updated continuously
Scan our Apple Price Trackers for the latest information on sales, bundles, and availability on systems from Apple’s authorized internet/catalog resellers. We update the trackers continuously: - 15″... Read more
Clearance 12-inch Retina MacBooks available s...
B&H Photo has dropped prices on leftover 2015 12″ Retina MacBooks with models now available starting at $999. Shipping is free, and B&H charges NY tax only: - 12″ 1.1GHz Gray Retina MacBook... Read more
Check Apple prices on any device with the iTr...
MacPrices is proud to offer readers a free iOS app (iPhones, iPads, & iPod touch) and Android app (Google Play and Amazon App Store) called iTracx, which allows you to glance at today’s lowest... Read more
New 2016 13-inch 256GB MacBook Air on sale fo...
B&H Photo has the new 13″ 1.6GHz/256GB MacBook Air (model MMGG2LL/A) on sale for $1149 including free shipping plus NY sales tax only. Their price is $50 off MSRP. Amazon has the 13″ 1.6GHz/256GB... Read more
Apple refurbished iPad Air 2s available start...
Apple has Certified Refurbished iPad Air 2 available starting at $339. Apple’s one-year warranty is included with each model, and shipping is free: - 128GB Wi-Fi iPad Air 2: $499 - 64GB Wi-Fi iPad... Read more

Jobs Board

*Apple* Nissan Service Technicians - Apple A...
Apple Automotive is one of the fastest growing dealer...and it shows. Consider making the switch to the Apple Automotive Group today! At Apple Automotive , Read more
ISCS *Apple* ID Site Support Engineer - APP...
…position, we are looking for an individual who has experience supporting customers with Apple ID issues and enjoys this area of support. This person should be Read more
Automotive Sales Consultant - Apple Ford Linc...
…you. The best candidates are smart, technologically savvy and are customer focused. Apple Ford Lincoln Apple Valley is different, because: $30,000 annual salary Read more
*Apple* Support Technician II - Worldventure...
…global, fast growing member based travel company, is currently sourcing for an Apple Support Technician II to be based in our Plano headquarters. WorldVentures is Read more
Restaurant Manager (Neighborhood Captain) - A...
…in every aspect of daily operation. WHY YOU'LL LIKE IT: You'll be the Big Apple . You'll solve problems. You'll get to show your ability to handle the stress and Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.