char * UsageLines [] = {
       "Usage: p4paths (width) (height) (thickness)",
       "Produces PBM image of specified dimensions, with '1' pixels",
       "inside path formed by joining specified corners with",
       "straight line segments of specified thickness (in pixels).",
       "Reads across and down, one set per line, from standard input.",
       "0 0  corresponds to the upper left corner of the image.",
       "Paths are separated by a blank line.",
       "Writes to standard output.",
       "January 25, 2023.  Newest is at gopher -p users/julianbr sdf.org",
       };
int NumUsageLines = sizeof (UsageLines) / sizeof (UsageLines [0] );


struct Corner {
       int across;
       int down;
       struct Corner * next;
       };


struct Path {
       struct Corner * corners;
       struct Path * next;
       };


#include <stdio.h>
#include <stdlib.h>


struct Path * ReadPaths (void)
       {
       struct Path * paths;
       struct Path * * pathPtr;
       struct Corner * * cornerPtr;
       int lineCount;
       int foundAcross, foundDown, acrossNegative, downNegative;
       int across, down;
       int memoryOk;
       int c;

       paths = NULL;
       pathPtr = & paths;
       memoryOk = 1;
       lineCount = 0;
       c = getchar ();
       while (c == ' ')
               c = getchar ();
       while (c != EOF) {
               lineCount++;
               across = 0;
               foundAcross = 0;
               acrossNegative = 0;
               down = 0;
               foundDown = 0;
               downNegative = 0;
               if (c == '-') {
                       acrossNegative = 1;
                       c = getchar ();
                       }
               while (c >= '0' && c <= '9') {
                       across = 10*across + (c - '0');
                       foundAcross = 1;
                       c = getchar ();
                       }
               if (acrossNegative)
                       across = - across;
               while (c == ' ')
                       c = getchar ();
               if (c == '-') {
                       downNegative = 1;
                       c = getchar ();
                       }
               while (c >= '0' && c <= '9') {
                       down = 10*down + (c - '0');
                       foundDown = 1;
                       c = getchar ();
                       }
               if (downNegative)
                       down = - down;
               while (c == ' ')
                       c = getchar ();
               if (c != '\n' && c != EOF) {
                       fprintf (stderr, "***p4paths: Improper");
                       fprintf (stderr, " '%c' in line %d.\n", c, lineCount);
                       while (c != '\n' && c != EOF)
                               c = getchar ();
                       }
               else if ((acrossNegative && !foundAcross)
                               || (downNegative && !foundDown) ) {
                       fprintf (stderr, "***p4paths: Improper");
                       fprintf (stderr, " '-' in line %d.\n", lineCount);
                       }
               else if (foundAcross && !foundDown) {
                       fprintf (stderr, "***p4paths: Found");
                       fprintf (stderr, " across but not down in");
                       fprintf (stderr, " line %d.\n", lineCount);
                       }
               if (c == '\n')
                       c = getchar ();
               if (foundAcross && foundDown) {
                       if (memoryOk && pathPtr [0] == NULL) {
                               pathPtr [0] = malloc (sizeof (pathPtr [0] [0] ) );
                               if (pathPtr [0] == NULL)
                                       memoryOk = 0;
                               else {
                                       pathPtr [0]->next = NULL;
                                       cornerPtr = & pathPtr [0]->corners;
                                       }
                               }
                       if (memoryOk) {
                               cornerPtr [0] = malloc (sizeof (cornerPtr [0] [0] ) );
                               if (cornerPtr [0] == NULL)
                                       memoryOk = 0;
                               }
                       if (memoryOk) {
                               cornerPtr [0]->across = across;
                               cornerPtr [0]->down = down;
                               cornerPtr [0]->next = NULL;
                               cornerPtr = & cornerPtr [0]->next;
                               }
                       }
               else if (pathPtr [0] != NULL)
                       pathPtr = & pathPtr [0]->next;
               }
       if (!memoryOk)
               fprintf (stderr, "***p4paths: Not enough memory.\n");
       return paths;
       }


void ShowPaths (struct Path * paths)
       {
       struct Path * path;
       struct Corner * corner;

       path = paths;
       while (path != NULL) {
               corner = path->corners;
               while (corner != NULL) {
                       printf ("%d %d  ", corner->across, corner->down);
                       corner = corner->next;
                       }
               printf ("\n");
               path = path->next;
               }
       }


void WritePaths (struct Path * paths, int width, int height, int pathwidth)
       {
       struct Path * path;
       struct Corner * corner;
       int across1, across2, down1, down2;
       int pathheight, segmentwidth, segmentheight;
       int along, along1, along2, below, below1, below2;
       int isOnPath;
       int across, down, weight;
       unsigned char value;

       printf ("P4\n%d %d\n", width, height);
       for (down = 0; down < height; down++) {
               value = 0;
               weight = 128;
               for (across = 0; across < width; across++) {
                       isOnPath = 0;
                       path = paths;
                       while (path != NULL) {
                               corner = path->corners;
                               while (corner != NULL) {
                                       across1 = corner->across;
                                       down1 = corner->down;
                                       if (4*((across - across1)*(across - across1)
                                               + (down - down1)*(down - down1) )
                                                       < pathwidth*pathwidth)
                                               isOnPath = 1;
                                       corner = corner->next;
                                       }
                               corner = path->corners;
                               while (corner != NULL && corner->next != NULL) {
                                       across1 = corner->across;
                                       down1 = corner->down;
                                       across2 = corner->next->across;
                                       down2 = corner->next->down;
                                       segmentwidth = across2 - across1;
                                       if (segmentwidth < 0)
                                               segmentwidth = - segmentwidth;
                                       segmentheight = down2 - down1;
                                       if (segmentheight < 0)
                                               segmentheight = - segmentheight;
                                       if (segmentwidth == 0 && segmentheight == 0)
                                               pathheight = 0;
                                       else if (segmentwidth > segmentheight)
                                               pathheight = pathwidth*segmentwidth
                                                       + pathwidth*segmentheight
                                                       *segmentheight/(2*segmentwidth);
                                       else
                                               pathheight = pathwidth*segmentheight
                                                       + pathwidth*segmentwidth
                                                       *segmentwidth/(2*segmentheight);
                                       along1 = (across2 - across1)*across1
                                               + (down2 - down1)*down1;
                                       below1 = across2*down1 - across1*down2;
                                       along2 = (across2 - across1)*across2
                                               + (down2 - down1)*down2;
                                       along = (across2 - across1)*across
                                               + (down2 - down1)*down;
                                       below = - (down2 - down1)*across
                                               + (across2 - across1)*down;
                                       if (along > along1 && along < along2) {
                                               below2 = below1 - pathheight/2;
                                               if (below > below2
                                               && below < below2 + pathheight)
                                                       isOnPath = 1;
                                               }
                                       corner = corner->next;
                                       }
                               path = path->next;
                               }
                       if (isOnPath)
                               value += weight;
                       weight /= 2;
                       if (weight == 0) {
                               putchar (value);
                               weight = 128;
                               value = 0;
                               }
                       }
               if (weight < 128)
                       putchar (value);
               }
       }


void ClosePaths (struct Path * paths)
       {
       struct Path * path, * nextPath;
       struct Corner * corner, * nextCorner;

       path = paths;
       while (path != NULL) {
               nextPath = path->next;
               corner = path->corners;
               while (corner != NULL) {
                       nextCorner = corner->next;
                       free (corner);
                       corner = nextCorner;
                       }
               free (path);
               path = nextPath;
               }
       }


int main (int argc, char * * argv)
       {
       struct Path * paths;
       int width, height, thickness;
       int i;
       char c;

       if (argc == 1) {
               for (i = 0; i < NumUsageLines; i++)
                       printf ("%s\n", UsageLines [i] );
               }
       else if (argc != 4
                       || sscanf (argv [1], "%d%c", & width, & c) != 1
                       || sscanf (argv [2], "%d%c", & height, & c) != 1
                       || sscanf (argv [3], "%d%c", & thickness, & c) != 1)
               fprintf (stderr, "Usage %s (width) (height) (thickness)\n", argv [0] );
       else {
               paths = ReadPaths ();
               WritePaths (paths, width, height, thickness);
               ClosePaths (paths);
               }
       return 0;
       }