xref: /original-bsd/games/pom/pom.c (revision f0203ecd)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software posted to USENET.
6  *
7  * %sccs.include.redist.c%
8  */
9 
10 #ifndef lint
11 char copyright[] =
12 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
13  All rights reserved.\n";
14 #endif /* not lint */
15 
16 #ifndef lint
17 static char sccsid[] = "@(#)pom.c	5.2 (Berkeley) 06/01/90";
18 #endif /* not lint */
19 
20 /*
21  * Phase of the Moon.  Calculates the current phase of the moon.
22  * Based on routines from `Practical Astronomy with Your Calculator',
23  * by Duffett-Smith.  Comments give the section from the book that
24  * particular piece of code was adapted from.
25  *
26  * -- Keith E. Brandt  VIII 1984
27  *
28  */
29 
30 #include <sys/time.h>
31 #include <stdio.h>
32 #include <tzfile.h>
33 #include <math.h>
34 
35 #define	PI	  3.141592654
36 #define	EPOCH	  85
37 #define	EPSILONg  279.611371	/* solar ecliptic long at EPOCH */
38 #define	RHOg	  282.680403	/* solar ecliptic long of perigee at EPOCH */
39 #define	ECCEN	  0.01671542	/* solar orbit eccentricity */
40 #define	lzero	  18.251907	/* lunar mean long at EPOCH */
41 #define	Pzero	  192.917585	/* lunar mean long of perigee at EPOCH */
42 #define	Nzero	  55.204723	/* lunar mean long of node at EPOCH */
43 
44 main()
45 {
46 	extern int errno;
47 	struct timeval tp;
48 	struct timezone tzp;
49 	struct tm *GMT, *gmtime();
50 	double days, today, tomorrow, dtor(), adj360(), potm();
51 	int cnt;
52 	char *strerror();
53 
54 	if (gettimeofday(&tp,&tzp)) {
55 		(void)fprintf(stderr, "pom: %s\n", strerror(errno));
56 		exit(1);
57 	}
58 	GMT = gmtime(&tp.tv_sec);
59 	days = (GMT->tm_yday + 1) + ((GMT->tm_hour +
60 	    (GMT->tm_min / 60.0) + (GMT->tm_sec / 3600.0)) / 24.0);
61 	for (cnt = EPOCH; cnt < GMT->tm_year; ++cnt)
62 		days += isleap(cnt) ? 366 : 365;
63 	today = potm(days) + .5;
64 	(void)printf("The Moon is ");
65 	if ((int)today == 100)
66 		(void)printf("Full\n");
67 	else if (!(int)today)
68 		(void)printf("New\n");
69 	else {
70 		tomorrow = potm(days + 1);
71 		if ((int)today == 50)
72 			(void)printf("%s\n", tomorrow > today ?
73 			    "at the First Quarter" : "at the Last Quarter");
74 		else {
75 			(void)printf("%s ", tomorrow > today ?
76 			    "Waxing" : "Waning");
77 			if (today > 50)
78 				(void)printf("Gibbous (%1.0f%% of Full)\n",
79 				    today);
80 			else if (today < 50)
81 				(void)printf("Crescent (%1.0f%% of Full)\n",
82 				    today);
83 		}
84 	}
85 }
86 
87 /*
88  * potm --
89  *	return phase of the moon
90  */
91 double
92 potm(days)
93 	double days;
94 {
95 	double N, Msol, Ec, LambdaSol, l, Mm, Ev, Ac, A3, Mmprime;
96 	double A4, lprime, V, ldprime, D, Nm;
97 
98 	N = 360 * days / 365.2422;				/* sec 42 #3 */
99 	adj360(&N);
100 	Msol = N + EPSILONg - RHOg;				/* sec 42 #4 */
101 	adj360(&Msol);
102 	Ec = 360 / PI * ECCEN * sin(dtor(Msol));		/* sec 42 #5 */
103 	LambdaSol = N + Ec + EPSILONg;				/* sec 42 #6 */
104 	adj360(&LambdaSol);
105 	l = 13.1763966 * days + lzero;				/* sec 61 #4 */
106 	adj360(&l);
107 	Mm = l - (0.1114041 * days) - Pzero;			/* sec 61 #5 */
108 	adj360(&Mm);
109 	Nm = Nzero - (0.0529539 * days);			/* sec 61 #6 */
110 	adj360(&Nm);
111 	Ev = 1.2739 * sin(dtor(2*(l - LambdaSol) - Mm));	/* sec 61 #7 */
112 	Ac = 0.1858 * sin(dtor(Msol));				/* sec 61 #8 */
113 	A3 = 0.37 * sin(dtor(Msol));
114 	Mmprime = Mm + Ev - Ac - A3;				/* sec 61 #9 */
115 	Ec = 6.2886 * sin(dtor(Mmprime));			/* sec 61 #10 */
116 	A4 = 0.214 * sin(dtor(2 * Mmprime));			/* sec 61 #11 */
117 	lprime = l + Ev + Ec - Ac + A4;				/* sec 61 #12 */
118 	V = 0.6583 * sin(dtor(2 * (lprime - LambdaSol)));	/* sec 61 #13 */
119 	ldprime = lprime + V;					/* sec 61 #14 */
120 	D = ldprime - LambdaSol;				/* sec 63 #2 */
121 	return(50 * (1 - cos(dtor(D))));			/* sec 63 #3 */
122 }
123 
124 /*
125  * dtor --
126  *	convert degrees to radians
127  */
128 double
129 dtor(deg)
130 	double deg;
131 {
132 	return(deg * PI / 180);
133 }
134 
135 /*
136  * adj360 --
137  *	adjust value so 0 <= deg <= 360
138  */
139 double
140 adj360(deg)
141 	double *deg;
142 {
143 	for (;;)
144 		if (*deg < 0)
145 			*deg += 360;
146 		else if (*deg > 360)
147 			*deg -= 360;
148 		else
149 			break;
150 }
151