Draw a clock: Difference between revisions
(init task) |
(sample c code) |
||
Line 7: | Line 7: | ||
Key points: animate simple object; timed event; polling system resources; code clarity. |
Key points: animate simple object; timed event; polling system resources; code clarity. |
||
=={{header|C}}== |
|||
Draws a crude clock in terminal. |
|||
<lang C>#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <math.h> |
|||
#include <time.h> |
|||
#include <sys/time.h> |
|||
#define PI 3.14159265 |
|||
char * shades = " .:-*ca&#%@"; |
|||
/* distance of (x, y) from line segment (0, 0)->(x0, y0) */ |
|||
double dist(double x, double y, double x0, double y0) { |
|||
double l = (x * x0 + y * y0) / (x0 * x0 + y0 * y0); |
|||
if (l > 1) { |
|||
x -= x0; |
|||
y -= y0; |
|||
} else if (l >= 0) { |
|||
x -= l * x0; |
|||
y -= l * y0; |
|||
} |
|||
return sqrt(x * x + y * y); |
|||
} |
|||
enum { sec = 0, min, hur }; // for subscripts |
|||
void draw(int size) |
|||
{ |
|||
# define for_i for(int i = 0; i < size; i++) |
|||
# define for_j for(int j = 0; j < size * 2; j++) |
|||
double angle, cx = size / 2.; |
|||
double sx[3], sy[3], sw[3]; |
|||
double fade[] = { 1, .35, .35 }; /* opacity of each arm */ |
|||
struct timeval tv; |
|||
struct tm *t; |
|||
/* set width of each arm */ |
|||
sw[sec] = size * .02; |
|||
sw[min] = size * .03; |
|||
sw[hur] = size * .05; |
|||
every_second: |
|||
gettimeofday(&tv, 0); |
|||
t = localtime(&tv.tv_sec); |
|||
angle = t->tm_sec * PI / 30; |
|||
sy[sec] = -cx * cos(angle); |
|||
sx[sec] = cx * sin(angle); |
|||
angle = (t->tm_min + t->tm_sec / 60.) / 30 * PI; |
|||
sy[min] = -cx * cos(angle) * .8; |
|||
sx[min] = cx * sin(angle) * .8; |
|||
angle = (t->tm_hour + t->tm_min / 60.) / 6 * PI; |
|||
sy[hur] = -cx * cos(angle) * .6; |
|||
sx[hur] = cx * sin(angle) * .6; |
|||
printf("\033[s\033[H"); /* goto top left */ |
|||
for_i { |
|||
double y = i - cx; |
|||
for_j { |
|||
double x = (j - 2 * cx) / 2; |
|||
int pix = 0; |
|||
/* calcs how far the "pixel" is from each arm and set |
|||
* shade, with some anti-aliasing. It's ghetto, but much |
|||
* easier than a real scanline conversion. |
|||
*/ |
|||
for (int k = hur; k >= sec; k--) { |
|||
double d = dist(x, y, sx[k], sy[k]); |
|||
if (d < sw[k] - .5) |
|||
pix = 10 * fade[k]; |
|||
else if (d < sw[k] + .5) |
|||
pix = (5 + (sw[k] - d) * 10) * fade[k]; |
|||
} |
|||
putchar(shades[pix]); |
|||
} |
|||
printf("\033[E"); /* CR */ |
|||
} |
|||
printf("\033[u"); /* restore cursor pos so you can bg the job -- value unclear */ |
|||
fflush(stdout); |
|||
sleep(1); /* sleep 1 can at times miss a second, but will catch up next update */ |
|||
goto every_second; |
|||
} |
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
int s; |
|||
if (argc <= 1 || (s = atoi(argv[1])) <= 0) s = 20; |
|||
draw(s); |
|||
}</lang> |
Revision as of 01:32, 4 July 2011
Task: draw a clock. More specific:
- Draw a time keeping device. It can be a stopwatch, hourglass, sundial, a mouth counting "one thousand and one", anything. Only showing the seconds is required, e.g. a watch with just a second hand will suffice. However, it must clearly change every second, and the change must cycle every so often (one minute, 30 seconds, etc.) It must be drawn; printing a string of numbers to your terminal doesn't qualify. Both text-based and graphical drawing are OK.
- The clock is unlikely to be used to control space flights, so it needs not be hyper-accurate, but it should be usable, meaning if one can read the seconds off the clock, it must agree with the system clock.
- A clock is rarely (never?) a major application: don't be a CPU hog and poll the system timer every microsecond, use a proper timer/signal/event from your system or language instead. For a bad example, many OpenGL programs update the framebuffer in a busy loop even if no redraw is needed, which is very undesirable for this task.
- A clock is rarely (never?) a major application: try to keep your code simple and to the point. Don't write something too elaborate or convoluted, instead do whatever is natural, concise and clear in your language.
Key points: animate simple object; timed event; polling system resources; code clarity.
C
Draws a crude clock in terminal. <lang C>#include <stdio.h>
- include <stdlib.h>
- include <math.h>
- include <time.h>
- include <sys/time.h>
- define PI 3.14159265
char * shades = " .:-*ca&#%@";
/* distance of (x, y) from line segment (0, 0)->(x0, y0) */ double dist(double x, double y, double x0, double y0) { double l = (x * x0 + y * y0) / (x0 * x0 + y0 * y0);
if (l > 1) { x -= x0; y -= y0; } else if (l >= 0) { x -= l * x0; y -= l * y0; } return sqrt(x * x + y * y); }
enum { sec = 0, min, hur }; // for subscripts
void draw(int size) {
- define for_i for(int i = 0; i < size; i++)
- define for_j for(int j = 0; j < size * 2; j++)
double angle, cx = size / 2.; double sx[3], sy[3], sw[3]; double fade[] = { 1, .35, .35 }; /* opacity of each arm */ struct timeval tv; struct tm *t;
/* set width of each arm */ sw[sec] = size * .02; sw[min] = size * .03; sw[hur] = size * .05;
every_second: gettimeofday(&tv, 0); t = localtime(&tv.tv_sec);
angle = t->tm_sec * PI / 30; sy[sec] = -cx * cos(angle); sx[sec] = cx * sin(angle);
angle = (t->tm_min + t->tm_sec / 60.) / 30 * PI; sy[min] = -cx * cos(angle) * .8; sx[min] = cx * sin(angle) * .8;
angle = (t->tm_hour + t->tm_min / 60.) / 6 * PI; sy[hur] = -cx * cos(angle) * .6; sx[hur] = cx * sin(angle) * .6;
printf("\033[s\033[H"); /* goto top left */ for_i { double y = i - cx; for_j { double x = (j - 2 * cx) / 2;
int pix = 0; /* calcs how far the "pixel" is from each arm and set * shade, with some anti-aliasing. It's ghetto, but much * easier than a real scanline conversion. */ for (int k = hur; k >= sec; k--) { double d = dist(x, y, sx[k], sy[k]); if (d < sw[k] - .5) pix = 10 * fade[k]; else if (d < sw[k] + .5) pix = (5 + (sw[k] - d) * 10) * fade[k]; } putchar(shades[pix]); } printf("\033[E"); /* CR */ } printf("\033[u"); /* restore cursor pos so you can bg the job -- value unclear */
fflush(stdout); sleep(1); /* sleep 1 can at times miss a second, but will catch up next update */ goto every_second; }
int main(int argc, char *argv[]) { int s; if (argc <= 1 || (s = atoi(argv[1])) <= 0) s = 20; draw(s); }</lang>