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

Apple Configurator 2.6 - Configure and d...
Apple Configurator makes it easy to deploy iPad, iPhone, iPod touch, and Apple TV devices in your school or business. Use Apple Configurator to quickly configure large numbers of devices connected to... Read more
Amadeus Pro 2.4.4 - Multitrack sound rec...
Amadeus Pro lets you use your Mac for any audio-related task, such as live audio recording, digitizing tapes and records, converting between a variety of sound formats, etc. Thanks to its outstanding... Read more
Mellel 4.0.3 - The word processor for sc...
Mellel is the leading word processor for OS X and has been widely considered the industry standard for long form documents since its inception. Mellel focuses on writers and scholars for technical... Read more
Suitcase Fusion 8 19.0.3 - Font manageme...
Suitcase Fusion 8 is the creative professional's font manager. Every professional font manager should deliver the basics: spectacular previews, powerful search tools, and efficient font organization... Read more
Final Cut Pro X 10.4 - Professional vide...
Final Cut Pro X is a professional video editing solution. Completely redesigned from the ground up, Final Cut Pro adds extraordinary speed, quality, and flexibility to every part of the post-... Read more
Compressor 4.4 - Adds power and flexibil...
Compressor adds power and flexibility to Final Cut Pro X export. Customize output settings, work faster with distributed encoding, and tap into a comprehensive set of delivery features. Features... Read more
Cocktail 11.2 - General maintenance and...
Cocktail is a general purpose utility for macOS that lets you clean, repair and optimize your Mac. It is a powerful digital toolset that helps hundreds of thousands of Mac users around the world get... Read more
Microsoft Office 2016 15.41 - Popular pr...
Microsoft Office 2016 - Unmistakably Office, designed for Mac. The new versions of Word, Excel, PowerPoint, Outlook and OneNote provide the best of both worlds for Mac users - the familiar Office... Read more
Motion 5.4 - Create and customize Final...
Motion is designed for video editors, Motion 5 lets you customize Final Cut Pro titles, transitions, and effects. Or create your own dazzling animations in 2D or 3D space, with real-time feedback as... Read more
Apple Pro Video Formats 2.0.6 - Updates...
Apple Pro Video Formats brings updates to Apple's professional-level codes for Final Cut Pro X, Motion 5, and Compressor 4. Pro Video Formats includes support for the following professional video... Read more

Latest Forum Discussions

See All

Lineage 2: Revolution’s end of year upda...
Now available in 54 countries worldwide, Lineage 2: Revolution is continuing its global quest to be the most popular mobile MMORPG by launching a jam-packed end of year update. Complete with many subtle tweaks to help improve users’ online... | Read more »
The 5 best Star Wars games on iOS
The time has almost come.Star Wars: The Last Jedifinally hits theaters in the cinematic event that might be bigger than Christmas. To celebrate, we're taking a look at the best--and only the best--Star Warsmobile games to date. [Read more] | Read more »
Life Is Strange (Games)
Life Is Strange 1.1 Device: iOS Universal Category: Games Price: $2.99, Version: 1.1 (iTunes) Description: Life Is Strange is a five part episodic game that sets out to revolutionize story-based choice and consequence games by... | Read more »
Oddworld: New 'n' Tasty (Game...
Oddworld: New 'n' Tasty 1.0 Device: iOS Universal Category: Games Price: $7.99, Version: 1.0 (iTunes) Description: ** PLEASE NOTE: Requires 3.6GB free space to install. Runs at variable resolutions based on device capabilities.... | Read more »
Gorogoa (Games)
Gorogoa 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Gorogoa is an elegant evolution of the puzzle genre, told through a beautifully hand-drawn story designed and illustrated by Jason... | Read more »
Why Guns of Boom will be big for mobile...
Earlier this week, Game Insight, the minds that brought you Guns of Boom, revealed plans for an esports mode in the popular FPS title, with big implications for the game's future. Guns of Boom has been quite popular for some time now, so it's... | Read more »
The best mobile games to play on lazy ho...
With the holidays in full swing, there's hopefully going to be a lot of time off work lazing around the house. With all of that free time, it's a perfect opportunity to catch up on some mobile games that you might have missed out on earlier this... | Read more »
Rules of Survival guide - how to boost y...
It's not easy surviving in the "every-man-for-himself" world of Rules of Survival. You'll be facing off against many other players who might be more skilled than you, or are luckier than you. There are a lot of factors weighing against you. With... | Read more »
FEZ Pocket Edition (Games)
FEZ Pocket Edition 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: | Read more »
Amazing Katamari Damacy guide - beginner...
Amazing Katamari Damacy brings the bizarro world of the original games to mobile and shifts them into an endless format that's just as addictive as the PlayStation entries. Your goal is still to roll as much random stuff as you possibly can, though... | Read more »

Price Scanner via MacPrices.net

Updated Price Trackers: Macs, iPads, iPhones,...
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
How to preorder a new iMac Pro and pay zero s...
B&H Photo and Adorama are accepting preorders on multiple configurations of the new Apple iMac Pro. Both resellers charge sales tax for residents of NY & NJ only, and shipping is free.... Read more
Apple Macs back in stock at Amazon with model...
Amazon has MacBook Pros, MacBook Airs, MacBooks, and iMacs on sale for up to $200 off MSRP as part of their Holiday/Christmas sale. Shipping is free. Note that stock of some Macs may come and go (and... Read more
Apple offering free overnight delivery on all...
Apple is now offering free overnight delivery on all in stock products until 3pm local time on December 22nd. This includes new as well as refurbished computers. Click here for more information. Read more
Beats Holiday sale at B&H, headphones and...
B&H Photo has Beats by Dr. Dre headphones, earphones, and speakers on sale for up to $80 off MSRP as part of their Holiday sale. Expedited shipping is free, and B&H charges sales tax to NY... Read more
Holiday sale: Apple resellers offer 2017 15″...
MacMall has 15″ MacBook Pros on sale for $220-$300 off MSRP, each including free shipping: – 15″ 2.8GHz MacBook Pro Space Gray (MPTR2LL/A): $2179, $220 off MSRP – 15″ 2.8GHz MacBook Pro Silver (... Read more
Holiday sale: Apple resellers offer 13″ MacBo...
B&H Photo has 13″ MacBook Pros on sale for up to $150 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13-inch 2.3GHz/128GB Space Gray MacBook Pro (... Read more
Apple Watch Series 2, Certified Refurbished,...
Apple has Certified Refurbished Apple Watch Nike+ Series 2s, 42mm Space Gray Aluminum Case with Anthracite/Black Nike Sport Bands, available for $249 (38mm) or $279 (42mm). The 38mm model was out of... Read more
Apple offers Certified Refurbished 2016 12″ R...
Apple has Certified Refurbished 2016 12″ Retina MacBooks available starting at $949. Apple will include a standard one-year warranty with each MacBook, and shipping is free. The following... Read more
B&H drops price on 13″ 256GB MacBook Air...
B&H has the 13″ 1.8GHz/256GB Apple MacBook Air (MQD42LL/A) now on sale for $1079 including free shipping plus NY & NJ sales tax only. Their price is $120 off MSRP, and it’s the lowest price... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Payments Counsel, *Apple* Pay (payments, cr...
# Payments Counsel, Apple Pay (payments, credit/debit) Job Number: 112941729 Santa Clara Valley, California, United States Posted: 13-Dec-2017 Weekly Hours: 40.00 Read more
*Apple* Solutions Consultant - Apple (United...
# Apple Solutions Consultant Job Number: 113124408 Waterford, CT, Connecticut, United States Posted: 17-Oct-2017 Weekly Hours: 40.00 **Job Summary** Are you Read more
QA Automation Engineer, *Apple* Pay - Apple...
# QA Automation Engineer, Apple Pay Job Number: 113202642 Santa Clara Valley, California, United States Posted: 11-Dec-2017 Weekly Hours: 40.00 **Job Summary** At Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.