3
\$\begingroup\$

This wasn't originally intended for code-golf, just as a little debugging routine to roughly visualize something "goofy" going on in a model of some (irrelevant here) physical process. But when I saw how surprisingly short it was, compared to my expectations, I just wondered if it can be further shortened. And that's primarily with respect to #statements (rather than #chars just by shortening variable names).

So, the function's void asciigraph ( double *f, int n ) where f[] contains n doubles representing values of some more-or-less continuous function to be illustrated/graphed on your terminal. My implementation is below, along with a test driver, whose output is below that. Can you do better/shorter?...

#include <stdio.h>
#include <math.h>
/* --- entry point --- */
void asciigraph ( double *f, int n ) {
  int    row=0,nrows=24, col=0,ncols=78;
  double bigf=0.0;
  for ( col=0; col<n; col++ )
    if ( fabs(f[col]) > bigf ) bigf = fabs(f[col]);
  for ( row=0; row<nrows; row++ ) {
    double yval = bigf*((double)(nrows/2-row))/((double)(nrows/2));
    for ( col=0; col<ncols; col++ )
      printf("%c",(yval*f[(col*(n-1))/(ncols-1)]>=yval*yval? '*':' '));
    printf("\n"); }
  } /* --- end-of-function asciigraph() --- */

#ifdef TESTDRIVE
int main ( int argc, char *argv[] ) {
  double f[999], pi=3.14159;        /* stored function to be graphed */
  int    i=0, N=511;            /* f[] index */
  void   asciigraph();
  for ( i=0; i<N; i++ ) {
    double x = 2.0*pi*((double)i)/((double)(N-1));
    f[i] = .5*sin(2.*x+pi/3.) + 1.*sin(1.*x+pi/2.); }
  asciigraph(f,N);
  } /* --- end-of-function main() --- */
#endif

Try it online!

Compile it (for linux) as cc -DTESTDRIVE asciigraph.c -lm -o asciigraph and then the sample output is

******                                                                      **
********                                                                  ****
*********                                                                *****
**********                                                              ******
***********                                                            *******
************                                                          ********
*************                                                        *********
*************                                                       **********
**************                                                     ***********
***************                                                   ************
****************                                                 *************
******************************************************************************
                  *********************************************               
                  *******************************************                 
                   *****************************************                  
                    *********************          *****                      
                     *****************                                        
                       ************                                           
                         ********                                             

So, the eleven lines comprising asciigraph() above can be reduced two ways: (a) just "syntactically compressing" the code (e.g., put the final } on the same line as the final statement), or (b) by finding a niftier algorithm than mine, which compares each f-value to the yval "level line" (in which case maybe your algorithm wouldn't need to find that bigf at all). Obviously (I'd think it's obvious), the "niftier algorithm" approach is what I'm more interested in.

    E d i t
--------------

Thanks, @Arnauld, for that Tio edit. Very cute! I wasn't (and still am not) familiar with that, so I failed trying to re-edit it myself. Actually, seeing the gobbledy-gook encoding, I didn't even try editing it. So, why did I want to edit it in the first place??? The Tio stuff looks real cute, and if I'd known about it, I'd have put in a commensurately cuter (see comments following code for explanation of cuteness) test driver, with just four extra lines, as follows.

First, in the header section put the additional #include <stdlib.h> (to accommodate the system() call). And then replace the entire test driver with this (very similar but much cuter) one...

int main ( int argc, char *argv[] ) {
  double f[999], pi=3.14159;            /* stored function to be graphed */
  double t=0.0, dt=0.05, w1=16.,w2=3.;  int Nt=50;
  int    i=0, N=511;                    /* f[] index */
  void   asciigraph();
  while ( --Nt > 0 ) {
    for ( i=0; i<N; i++ ) {
      double x = 2.0*pi*((double)i)/((double)(N-1));
      f[i] = .75*sin(2.*x+pi/3.+w1*t) + 1.*sin(1.*x+pi/2.+w2*t); }
    system("sleep 0.25; clear");
    asciigraph(f,N);
    t += dt; }
  } /* --- end-of-function main() --- */

Explanation of cuteness...
  That'll generate a   50-frame ascii animation   of a travelling wave when you execute it, rather than the single ho-hum static image you're now seeing. (Of course, that's unrelated to asciigraph()'s original and useful debugging purpose, but I think we've maybe gotten a little carried away from that:)

    E d i t # 2
------------------

Darn, I tested the Tio by manually changing the code already there, but system("clear") doesn't seem to work for the Tio. Each frame just appears below the previous one, resulting in 50 static frames of output. But everything works fine in a linux terminal. So if anybody wants to play with it, just download the code and compile on your own box. ...Unless there's maybe an effective way to "clear screen" for that Tio output (n.b., printing the \033[2J ansi escape sequence for clear screen also doesn't work)???

\$\endgroup\$
  • 1
    \$\begingroup\$ No, it has to be \$2\$ passes either way. \$\endgroup\$ – Alexey Burdin Nov 24 '19 at 4:57
  • 1
    \$\begingroup\$ A quick start would be removing whitespace, comments and shortening variable names. Have you had a look at the Tips for golfing in C page? \$\endgroup\$ – Jo King Nov 24 '19 at 5:40
  • 1
    \$\begingroup\$ I've added a TIO link to make it easier to test and modify your code. My understanding is that only the asciigraph() function needs to be golfed, so I've put the other parts in the Header and Footer sections. But feel free to edit if that's not what you meant. \$\endgroup\$ – Arnauld Nov 24 '19 at 8:26
  • 1
    \$\begingroup\$ Would this be a better [code-golf] question than a C tips question? \$\endgroup\$ – my pronoun is monicareinstate Nov 24 '19 at 9:03
  • 3
    \$\begingroup\$ I think this should be changed to a codegolf challenge and opened to all languages. Is there interest in doing so? Otherwise it would be good to have a separate challenge. \$\endgroup\$ – Nick Kennedy Nov 24 '19 at 11:27
3
\$\begingroup\$

C (gcc), 164 167 162 bytes

r,c;void asciigraph(f,n,b,y)double*f,b,y;{for(b=0,r=n;r--;)b=fmax(b,fabs(f[r]));for(;++r<24;puts(""))for(y=b-b/12*r,c=0;c<78;)putchar("* "[y*f[c++*~-n/77]<y*y]);}

Try it online!

Thanks to @Arnauld for -4 and @JohnForkosh for the bugfix.

Slightly golfed less

r,c;
void asciigraph(f,n,b,y)double*f,b,y;{
  for(b=0,r=n;r--;)
    b=fmax(b,fabs(f[r]));
  for(;++r<24;puts(""))
    for(y=b-b/12*r,c=0;c<78;)
      putchar("* "[y*f[c++*~-n/77]<y*y]);
}
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.