/* Listing 1 */

#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <time.h>       /* for use by randomize */

#define MAX_CIRCLES 150

double distance( double x, double y, int i);
void generate_circles();
void exit_if_kbhit();

typedef struct {
       int x;
       int y;
       int r;
       } circle_type;

circle_type c[ MAX_CIRCLES];

int N, rmax;


/************************************************/

void generate_circles()

/* this function draws a series of circles at random */
/* positions, each one after the first touching the  */
/* nearest circle that has been previously drawn     */

{
   int xmax, ymax, x_pos, y_pos, radius;
   randomize();	  /* initialize the random numbers */
   xmax = getmaxx(); /* maximum x and y positions  */
   ymax = getmaxy(); /* that can be displayed      */

   rmax = max( xmax, ymax)/2;
          /* divisor of 2 can be changed to allow */
          /* different maximum radii              */

   /* select random position and draw first circle */

   x_pos = rand() % xmax;
   y_pos = rand() % ymax;
   radius = rand() % rmax;
   c[0].x = x_pos;
   c[0].y = y_pos;
   c[0].r = radius;
   circle( x_pos, y_pos, radius);

   /* select and draw remaining randomly placed circles */
   /* each tangent to the nearest previously drawn      */
   /* circle                                            */

   for ( N = 1; N <= MAX_CIRCLES; N++)
       {
       do
           {
           exit_if_kbhit();
           x_pos = rand() % xmax;
           y_pos = rand() % ymax;
           radius = new_radius( x_pos, y_pos);
           } while (radius <= 0);
       radius = min( rmax, radius);
       circle( x_pos, y_pos, radius);
       c[N].x = x_pos;
       c[N].y = y_pos;
       c[N].r = radius;
       }
}

/************************************************/

int new_radius( int x, int y)

/* returns the distance from the point x,y to the   */
/* nearest circle; aborts and returns the           */
/* calculated negative or zero distance if x,y lies */
/* on or inside another circle                      */

{
    int i, radius;
    radius = rmax;
    for ( i = 0; i <= N; i++)
        {
        radius = min( radius, (int)distance(x,y,i));
        if ( radius <= 0) return radius;
        }
    return radius;
}

/************************************************/

double distance( double x, double y, int i)

/* returns the distance from the point x,y to    */
/* circle i; returns a negative or zero distance */
/* if x,y is inside or on circle i               */

{
    double xdist, ydist, distancesq;
    xdist = x - c[i].x;
    ydist = y - c[i].y;
    distancesq = xdist*xdist + ydist*ydist;
    return ( sqrt( distancesq) - c[i].r);
}

/************************************************/

int main(void)

/* initializes Borland Graphics Interface in      */
/* "audodetect" mode using default background     */
/* and foreground colors, checks for errors in    */
/* initialization, calls routine to draw circles, */
/* when finished waits for keystroke to erase     */
/* screen and exit                                */

{
   int gdriver = DETECT, gmode, errorcode;
   initgraph(&gdriver, &gmode, "");
   errorcode = graphresult();
   if (errorcode != grOk)  /* an error occurred */
      {
      printf("Graphics error: %s\n",
                       grapherrormsg(errorcode));
      printf("Press any key to halt:");
      getch();
      exit(1);
      }
   generate_circles();
   getch();
   closegraph();
   return 0;
}

/************************************************/

void exit_if_kbhit()

/* exits program if a key has been struck */
/* returns otherwise                      */

{
     if ( kbhit())
        {
        getch();
        closegraph();
        exit(1);
        }
}
