1 /* $Id: biorythm.c,v 1.5 2011-10-22 07:57:00 sverrehu Exp $ */
2 /*------------------------------------------------------------------------
3 | FILE biorythm.c
4 | MODULE OF biorythm - simple biorythm calculation program
5 |
6 | DESCRIPTION
7 |
8 | WRITTEN BY Sverre H. Huseby <shh@thathost.com>
9 +----------------------------------------------------------------------*/
10
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <math.h>
14
15 #include <shhmsg.h>
16 #include <shhopt.h>
17
18 #include "date.h"
19
20 #ifndef M_PI
21 # define M_PI 3.141592654
22 #endif
23
24 /* Periods: Physical, Emotional and Intellectual */
25 #define PHY_PERIOD 23
26 #define EMO_PERIOD 28
27 #define INT_PERIOD 33
28
29 #define PLOT_PHY 1
30 #define PLOT_EMO 2
31 #define PLOT_INT 4
32 #define PLOT_AVG 8
33
34 /*-----------------------------------------------------------------------+
35 | PRIVATE FUNCTIONS |
36 +-----------------------------------------------------------------------*/
37
38 /*------------------------------------------------------------------------
39 | NAME f
40 |
41 | FUNCTION Calculate a curve sample value.
42 |
43 | INPUT birth date of birth.
44 | day the day to get sample from.
45 | period the period of the curve in days.
46 |
47 | RETURNS A value in [-1, 1].
48 */
49 static double
f(Date birth,Date day,int period)50 f(Date birth, Date day, int period)
51 {
52 int n;
53
54 n = dateGetNumDays(birth, day) % period;
55 return sin((double) n * 2.0 * M_PI / period);
56 }
57
58 /*------------------------------------------------------------------------
59 | NAME nearestInt
60 |
61 | FUNCTION Round a double to the nearest integer.
62 |
63 | INPUT x the double to round.
64 |
65 | RETURNS The nearest integer.
66 */
67 static int
nearestInt(double x)68 nearestInt(double x)
69 {
70 return (int) floor(x + 0.5);
71 }
72
73 /*------------------------------------------------------------------------
74 | NAME bioTextPlot
75 |
76 | FUNCTION Make a biorythm graph using text characters.
77 |
78 | INPUT birth date of birth.
79 | from date of first day of plot.
80 | ndays number of days to plot.
81 | what what to plot. (PLOT_PHY | PLOT_EMO ...)
82 */
83 static void
bioTextPlot(Date birth,Date from,int ndays,int what)84 bioTextPlot(Date birth, Date from, int ndays, int what)
85 {
86 #define WIDTH 53
87 int q;
88 char s[WIDTH + 2];
89 double val, sum;
90
91 printf("Day of birth: %s\n", dateStr(birth));
92 if (what & PLOT_PHY)
93 printf("[P]hysical ");
94 if (what & PLOT_EMO)
95 printf("[E]motional ");
96 if (what & PLOT_INT)
97 printf("[I]ntellectual ");
98 if (what & PLOT_AVG)
99 printf("[A]verage");
100 printf("\n");
101
102 for (q = 0; q < 73; q++)
103 printf("-");
104 printf("\n");
105 printf("YYYY-MM-DD down%57s\n", "up age");
106 for (q = 0; q < 73; q++)
107 printf("-");
108 printf("\n");
109
110 while (--ndays >= 0) {
111 for (q = 0; q <= WIDTH; q++)
112 s[q] = ' ';
113 s[q] = '\0';
114 s[0] = s[WIDTH] = '|';
115 s[WIDTH / 2] = '.';
116 printf("%-10.10s ", dateStr(from));
117
118 sum = val = f(birth, from, PHY_PERIOD);
119 if (what & PLOT_PHY)
120 s[nearestInt(((val + 1.0) / 2.0) * WIDTH)] = 'P';
121
122 val = f(birth, from, EMO_PERIOD);
123 sum += val;
124 if (what & PLOT_EMO)
125 s[nearestInt(((val + 1.0) / 2.0) * WIDTH)] = 'E';
126
127 val = f(birth, from, INT_PERIOD);
128 sum += val;
129 if (what & PLOT_INT)
130 s[nearestInt(((val + 1.0) / 2.0) * WIDTH)] = 'I';
131
132 if (what & PLOT_AVG)
133 s[nearestInt((((sum / 3.0) + 1.0) / 2.0) * WIDTH)] = 'A';
134
135 printf("%s %5d\n", s, dateGetNumDays(birth, from));
136
137 dateInc(&from);
138 }
139 }
140
141 /*------------------------------------------------------------------------
142 | NAME version
143 |
144 | FUNCTION Show the version of this program, and exit.
145 */
146 static void
version(void)147 version(void)
148 {
149 printf(
150 "biorythm " VERSION ", by Sverre H. Huseby\n"
151 );
152 exit(0);
153 }
154
155 /*------------------------------------------------------------------------
156 | NAME usage
157 |
158 | FUNCTION Show the usage of this program, and exit.
159 */
160 static void
usage(void)161 usage(void)
162 {
163 printf(
164 "\n"
165 "usage: %s [option] date-of-birth first-day-of-plot number-of-days\n"
166 "\n"
167 " -a, --average plot the average of all three curves\n"
168 " -e, --emotional plot the emotional curve (default)\n"
169 " -h, --help display this help and exit\n"
170 " -i, --intellectual plot the intellectual curve (default)\n"
171 " -p, --physical plot the physical curve (default)\n"
172 " -V, --version output version information and exit\n"
173 "\n"
174 "Dates must be specified as YYYY-MM-DD (ISO date format).\n"
175 "\n",
176 msgGetName()
177 );
178 exit(0);
179 }
180
181 /*-----------------------------------------------------------------------+
182 | PUBLIC FUNCTIONS |
183 +-----------------------------------------------------------------------*/
184
185 int
main(int argc,char * argv[])186 main(int argc, char *argv[])
187 {
188 int ndays = 0, what = 0;
189 int average = 0, emotional = 0, intellectual = 0, physical = 0;
190 Date birth, from;
191 optStruct opt[] = {
192 /* short long type var/func special */
193 { 'h', "help", OPT_FLAG, usage, OPT_CALLFUNC },
194 { 'a', "average", OPT_FLAG, &average, 0 },
195 { 'e', "emotional", OPT_FLAG, &emotional, 0 },
196 { 'i', "intellectual", OPT_FLAG, &intellectual, 0 },
197 { 'p', "physical", OPT_FLAG, &physical, 0 },
198 { 'V', "version", OPT_FLAG, version, OPT_CALLFUNC },
199 { 0, 0, OPT_END, 0, 0 } /* no more options */
200 };
201
202 msgSetName(argv[0]);
203 optParseOptions(&argc, argv, opt, 0);
204 if (argc != 4)
205 usage();
206
207 if (average)
208 what |= PLOT_AVG;
209 if (emotional)
210 what |= PLOT_EMO;
211 if (intellectual)
212 what |= PLOT_INT;
213 if (physical)
214 what |= PLOT_PHY;
215 if (!what)
216 what = PLOT_EMO | PLOT_INT | PLOT_PHY;
217
218 birth = dateFromStr(argv[1]);
219 from = dateFromStr(argv[2]);
220 ndays = atoi(argv[3]);
221 if (ndays < 1 || ndays > 500)
222 msgFatal("number of days must be in [1, 500]\n");
223
224 bioTextPlot(birth, from, ndays, what);
225
226 return 0;
227 }
228