aboutsummaryrefslogtreecommitdiff
path: root/challenge-165/duncan-c-white/C/ch-2.c
diff options
context:
space:
mode:
Diffstat (limited to 'challenge-165/duncan-c-white/C/ch-2.c')
-rw-r--r--challenge-165/duncan-c-white/C/ch-2.c221
1 files changed, 221 insertions, 0 deletions
diff --git a/challenge-165/duncan-c-white/C/ch-2.c b/challenge-165/duncan-c-white/C/ch-2.c
new file mode 100644
index 0000000000..7a71c5f957
--- /dev/null
+++ b/challenge-165/duncan-c-white/C/ch-2.c
@@ -0,0 +1,221 @@
+/*
+ * Task 2: Line of Best Fit
+ *
+ * GUEST LANGUAGE: This is my attempt to translate ch-2.pl into C
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "MySVG.h"
+
+bool debug=0;
+
+// char *s = process_singlearg( argc, argv );
+// Process the -d flag, and check that there is a single
+// remaining argument, return it
+char * process_singlearg( int argc, char **argv )
+{
+ int arg=1;
+ if( argc>1 && strcmp( argv[arg], "-d" ) == 0 )
+ {
+ debug = true;
+ arg++;
+ }
+
+ int left = argc-arg;
+ if( left != 1 )
+ {
+ fprintf( stderr,
+ "Usage: best-fit [-d] filename\n" );
+ exit(1);
+ }
+
+ // element is in argv[arg]
+
+ if( debug )
+ {
+ printf( "debug: remaining argument is in pos %d, and is %s\n",
+ arg, argv[arg] );
+ }
+
+ return argv[arg];
+}
+
+
+typedef struct { int x, y; } datapoint;
+typedef struct { int x1, y1, x2, y2; } dataline;
+
+#define MAXITEMS 1024
+
+int npoints = 0;
+datapoint pt[MAXITEMS]; // input points
+
+datapoint wh; // wh.x == width of our data, wh.y == height of our data
+
+
+/*
+ * updatewh( x, y );
+ * Update wh to include x and y.
+ */
+void updatewh( int x, int y )
+{
+ assert( x>=0 );
+ assert( y>=0 );
+ if( x > wh.x ) wh.x = x;
+ if( y > wh.y ) wh.y = y;
+}
+
+
+/*
+ * bool lineread = readline( in, buf, maxlen );
+ * read a single line from in (a FILE * open for input)
+ * into a character buffer (char *), reading no more than
+ * maxlen characters, removing a trailing '\n' from the
+ * buffer (if there is one).
+ *
+ * If the input line is longer than that, the REMAINDER OF
+ * THE LINE IS LEFT IN the file's input buffer for later reading.
+ * If readline() is called again immediately, the remainder of
+ * the line will be treated as a separate line.
+ *
+ * In caller-space, buf must be a writable character buffer of
+ * size >= maxlen, i.e. typically either a char [n]
+ * or a malloc(n * sizeof(char)) chunk,
+ * where (in both cases) n >= maxlen
+ */
+bool readline( FILE *in, char *buf, int maxlen )
+{
+ if( fgets( buf, maxlen, in ) == 0 )
+ {
+ return false;
+ }
+ int l = strlen(buf);
+ if( l>0 && buf[l-1]=='\n' )
+ {
+ buf[l-1] = '\0';
+ }
+ return true;
+}
+
+
+/*
+ *
+ * read_data( in );
+ * Read data (points) from in.
+ */
+void read_data( FILE *in )
+{
+ #define MAXLINELEN 100
+ char line[MAXLINELEN];
+
+ npoints = 0;
+ while( readline(in, line, MAXLINELEN ) )
+ {
+ int x, y;
+ char *s;
+ char *p;
+
+ s = line;
+ assert( isdigit(*s) );
+ p = strchr(s,',');
+ assert( p != NULL );
+ *p = '\0';
+ x = atoi(s);
+
+ s = p+1;
+ assert( isdigit(*s) );
+ y = atoi(s);
+
+ //fprintf( stderr, "debug: read point %d,%d\n", x, y );
+ pt[npoints].x = x;
+ pt[npoints].y = y;
+ npoints++;
+ updatewh( x, y );
+ }
+}
+
+
+/*
+ * bestfit( points, npoints, &m, &c );
+ * Calculate y=mx+c, the best fit line of the data (each data point an [x,y] pair)
+ */
+void bestfit( datapoint *pt, int npoints, double *m, double *c )
+{
+ int sumx = 0;
+ int sumy = 0;
+ int sumxy = 0;
+ int sumx2 = 0;
+ for( int i=0; i<npoints; i++ )
+ {
+ int x = pt[i].x;
+ int y = pt[i].y;
+ sumx += x;
+ sumy += y;
+ sumxy += x * y;
+ sumx2 += x * x;
+ }
+
+ *m = (npoints * sumxy - sumx * sumy) / (double) (npoints * sumx2 - sumx * sumx);
+ *c = (sumy - *m * sumx) / (double)npoints;
+
+ if( debug )
+ {
+ fprintf( stderr, "bestfit: n=%d, sumx=%d, sumy=%d, sumxy=%d, sumx^2=%d\n",
+ npoints, sumx, sumy, sumxy, sumx2 );
+ fprintf( stderr, "bestfit: m=%.6f, c=%.6f\n", *m, *c );
+ }
+}
+
+
+int main( int argc, char **argv )
+{
+ char *filename = process_singlearg( argc, argv );
+
+ wh.x = -1;
+ wh.y = -1;
+
+ FILE *in = fopen( filename, "r" );
+ assert( in != NULL );
+ read_data( in );
+ fclose( in );
+
+ int w = wh.x;
+ int h = wh.y;
+
+ w += (10-w%10);
+ h += (10-h%10);
+
+ int xscale = w < 200 ? 200/w : 1;
+ int yscale = h < 200 ? 200/h : 1;
+
+ if( debug )
+ {
+ fprintf( stderr, "maxxy rectangle is w %d, h %d, xscale %d, yscale %d\n", w, h, xscale, yscale );
+ }
+
+ double m, c;
+ bestfit( pt, npoints, &m, &c );
+ int y1 = (int) (m + c); // for x==1
+ int y2 = (int) (m * (w-1) + c); // for x==w-1
+
+ start_svg( w * xscale, h * yscale );
+
+ setcolour( "blue" );
+ setlinewidth( 1 );
+ line( 1, y1*yscale, (w-1)*xscale, y2*yscale );
+
+ setcolour( "orange" );
+ for( int i=0; i<npoints; i++ )
+ {
+ point( pt[i].x*xscale, pt[i].y*yscale );
+ }
+
+ end_svg();
+
+ return 0;
+}