• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Functions for working with the idealized calendar of Planet Xhilr


Commit MetaInfo

Revisión27fcb962ebed1ab6f8c7122001175fd7cf3d926b (tree)
Tiempo2017-06-13 17:05:27
AutorJoel Matthew Rees <joel.rees@gmai...>
CommiterJoel Matthew Rees

Log Message

starting in C

Cambiar Resumen

Diferencia incremental

--- /dev/null
+++ b/econcal.c
@@ -0,0 +1,535 @@
1+/* This is a program to generate calendars
2+// for novels about Bobbie, Karel, Dan, and Kristie's world,
3+// specifically those in the Economics 101 trilogy.
4+//
5+// By Joel Matthew Rees, March 2017,
6+// Copyright 2017, all rights reserved.
7+//
8+// Fair use acknowledged.
9+// If you want to use it for purposes other than personal entertainment,
10+// rewriting it yourself is not that hard,
11+// you'll understand the math and the science much better that way,
12+// and the result will satisfy your needs much more effectively.
13+//
14+// See
15+// http://joel-rees-economics.blogspot.com/2017/03/soc500-03-08-calendar-math.html
16+// http://joel-rees-economics.blogspot.com/2017/03/soc500-03-09-computer-calendar.html
17+// for more explanation of the code.
18+//
19+// Novel here:
20+// http://joel-rees-economics.blogspot.com/2017/01/soc500-00-00-toc.html
21+//
22+// From the intermediate text of the second draft of Sociology 500, a Novel,
23+// chapter 3 part 7, Family Games:
24+// *************************
25+// Uhm, lemmesee. Where did I put those notes? Oh, here they are.
26+// 353 days per year in about five years out of seven
27+// and 352 in the other two.
28+// So they have two skip years out of seven
29+// where we have one leap year out of four.
30+//
31+// But it isn't exact, of course.
32+// They have to adjust that again every 98 years
33+// and then once again every 343 years.
34+// Already too much detail, and you're falling asleep?
35+//
36+// But they have two moons. Did I mention that?
37+// The smaller moon orbits their earth
38+// in just under seven and an eighth days,
39+// and their larger moon orbits it
40+// in about twenty-eight and seven eighths days.
41+// About forty-nine and a half lunar weeks a year
42+// and about twelve and two fifths lunar months each year.
43+// *************************
44+//
45+// From the tool, econmonths.bc:
46+// *************************
47+// # If you want to do something similar,
48+// # for looking at how leap years in your world
49+// # match the actual orbits and revolutions
50+// # of your world and its moon,
51+// # replace isskip() with an appropriate isleap().
52+// # Left as an exercise for the reader.
53+//
54+// define isskip( y, m ) {
55+// if ( m != 0 ) {
56+// return 0;
57+// }
58+// mem = scale;
59+// scale = 0;
60+// diff7 = y % 7;
61+// diff98 = y % 98;
62+// diff343 = y % 343;
63+// scale = mem;
64+// if ( diff98 == 48 ) {
65+// return 1;
66+// }
67+// if ( ( diff7 != 1 ) && ( diff7 != 4 ) ) {
68+// return 0;
69+// }
70+// if ( diff343 == 186 ) {
71+// return 0;
72+// }
73+// return 1;
74+// }
75+//
76+//
77+// # Note that we are treating the first year as year 0
78+// # and the first month as month 0.
79+// # For your earth, you will need to adjust the year and month input and output.
80+// *************************
81+//
82+// Note also that, in this calendar system,
83+// the day in the month and the day in the year start with day 0.
84+//
85+//
86+// Their two moons were at near zenith on the night their Christ was born,
87+// in addition to the new star, but that's all I'm telling for now.
88+//
89+*/
90+
91+
92+#include <stdio.h>
93+#include <stdlib.h>
94+#include <string.h>
95+
96+#include <limits.h>
97+#if INT_MAX < 0x8000L /* sloppy 8 bit thinking */
98+# define INT_BITS 16
99+#elif INT_MAX < 0x80000000L
100+# define INT_BITS 32
101+#elif INT_MAX < 0x8000000000000000L
102+# define INT_BITS 64
103+#else
104+# warning "INT_BITS greater than 64!!"
105+#endif
106+
107+
108+typedef unsigned char ubyte_t;
109+typedef signed char sbyte_t;
110+
111+
112+#define SPACE ' '
113+
114+
115+#define SKIPyears_per_short 2
116+#define FULLyears_per_short 5
117+#define YEARcycle_short 7
118+#define YEARcycle_medium 98 /* 7^2 * 2 */
119+#define YEARcycle_long 343 /* 7^3 */
120+#define YEARcycle_dbllong 686 /* 7^3 * 2 */
121+
122+#define FULLYEARS_dbllongcycle \
123+( ( YEARcycle_dbllong / YEARcycle_short ) * FULLyears_per_short \
124+- ( YEARcycle_dbllong / YEARcycle_medium ) * 1 + ( YEARcycle_dbllong / YEARcycle_long ) * 1 )
125+
126+#define SKIPYEARS_dbllongcycle ( YEARcycle_dbllong - FULLYEARS_dbllongcycle )
127+
128+
129+/* C double is (barely) sufficient resolution to avoid most of the tricks. */
130+#define YEARfraction ( (double) FULLYEARS_dbllongcycle / YEARcycle_dbllong )
131+#define DAYSperYEARint 352
132+#define DAYSperYEAR ( (double) DAYSperYEARint + YEARfraction )
133+#define DAYSperWEEK 7
134+#define MONTHSperYEAR 12
135+
136+/* Do it in integers.
137+*/
138+#define daysUPTOyear( year ) \
139+( tdays = (year) * DAYSperYEARint + ( ( year ) * FULLYEARS_dbllongcycle ) / YEARcycle_dbllong )
140+
141+#define remainderUPTOyear( year ) \
142+( ( (year) * FULLYEARS_dbllongcycle ) % YEARcycle_dbllong )
143+
144+
145+#define SKIPmonth 0
146+#define SKIPyear_short_1 1
147+#define SKIPyear_short_2 4
148+#define SKIPyear_medium 48
149+#define SKIPyear_long 186 /* Must be short1 or short2 within the seven year cycle. */
150+
151+
152+/* Since skipyears are the exception, we test for skipyears instead of leapyears.
153+// Calendar system starts with year 0, not year 1.
154+// Would need to check and adjust if the calendar started with year 1.
155+*/
156+int isskipyr( long year )
157+{ int rem = year % YEARcycle_medium;
158+ if ( rem == SKIPyear_medium )
159+ { return 1;
160+ }
161+ rem = year % YEARcycle_short;
162+ if ( ( rem != SKIPyear_small_1 ) && ( rem != SKIPyear_small_2 ) )
163+ { return 0;
164+ }
165+ rem = year % YEARcycle_long;
166+ if ( rem == SKIPyear_long ) /* Must be short1 or short2 within the seven year cycle. */
167+ { return 0;
168+ }
169+ return 1;
170+}
171+
172+
173+ubyte_t daysInMonths[ MONTHSperYEAR ] =
174+{ 30,
175+ 29,
176+ 30,
177+ 29,
178+ 29,
179+ 30,
180+ 29,
181+ 30,
182+ 29,
183+ 29,
184+ 30,
185+ 29
186+};
187+
188+#define daysInMonth( month, year ) \
189+( ( month != SKIPmonth ) ? daysInMonths[ (month) ] : daysInMonths[ (month) ] - ( isskipyr( (year) ) ? 1 : 0 ) )
190+
191+/* months are 0 to MONTHSperYEAR - 1 here.
192+// If months were 1 to MONTHSperYEAR, would need to adjust here.
193+*/
194+int yearDaysToMonth( int month, long year )
195+{ unsigned total;
196+ int i;
197+/* */
198+ if ( month >= MONTHSperYEAR )
199+ { month = MONTHSperYEAR - 1;
200+ }
201+ for ( total = 0, i = 0; i < month; ++i )
202+ { total += daysInMonth( i, year );
203+ }
204+ return total;
205+}
206+
207+
208+/* day in month is 0 to max - 1 here.
209+// If day in month were 1 to max, would need to adjust here.
210+*/
211+unsigned long daysUpTo( long year, int month, int day, unsigned * remainderp )
212+{ unsigned long days = daysUPTOyear( year );
213+ unsigned partial = remainderUPTOyear( year );
214+/* */
215+ days +=
216+ * remainderp = partial;
217+ return days;
218+}
219+
220+
221+#define PLANETname "Bokadakr"
222+
223+typedef char * str0_t; /* It looks like the pedants have attacked again. */
224+typedef str0_t str0array_t[]; /* Or I'm losing my memory again. */
225+typedef str0array_t * str0arrayptr_t; /* Wonder which. */
226+
227+str0array_t weekDayNames =
228+{ "Sunday",
229+ "Slowmoonday",
230+ "Aegisday",
231+ "Gefnday",
232+ "Freyday",
233+ "Tewesday",
234+ "Vensday"
235+};
236+
237+str0array_t fakeDayNames =
238+{ "Sunday",
239+ "Monday",
240+ "Tuesday",
241+ "Wednesday",
242+ "Thursday",
243+ "Friday",
244+ "Saturday"
245+};
246+
247+str0array_t fakeMonthNames =
248+{ "January",
249+ "February",
250+ "March",
251+ "April",
252+ "May",
253+ "June",
254+ "July",
255+ "August",
256+ "September",
257+ "October",
258+ "November",
259+ "December",
260+};
261+
262+str0array_t realMonthNames =
263+{ "Time-division",
264+ "Deep-winter",
265+ "War-time",
266+ "Thaw-time",
267+ "Rebirth",
268+ "Brides-month",
269+ "Imperious",
270+ "Senatorious",
271+ "False-summer",
272+ "Harvest",
273+ "Gratitude",
274+ "Winter-month",
275+};
276+
277+
278+void centeredName( char name[], int field )
279+{ int i;
280+ size_t length = strlen( name );
281+ int partial;
282+/* */
283+ if ( field < 1 )
284+ { return;
285+ }
286+ if ( length > field )
287+ { length = field;
288+ }
289+ for ( partial = field; partial > length; partial -= 2 )
290+ { putchar( SPACE );
291+ }
292+ for ( i = 0; i < length; ++i )
293+ { putchar( name[ i ] );
294+ }
295+ for ( partial = field - 1; partial > length; partial -= 2 ) /* weight right */
296+ { putchar( SPACE );
297+ }
298+}
299+
300+void headerNames( str0array_t * daynames, int offset, int field )
301+{ int tracer;
302+/* */
303+ if ( offset >= DAYSperWEEK )
304+ { offset = 0;
305+ }
306+ tracer = offset;
307+ putchar( '|' );
308+ do
309+ { centeredName( (* daynames )[ tracer++ ], field );
310+ putchar( '|' );
311+ if ( tracer >= DAYSperWEEK )
312+ { tracer = 0;
313+ }
314+ } while ( tracer != offset );
315+}
316+
317+int intlog10( int number )
318+{ int result = 1;
319+ int temp = number;
320+/* */
321+ while ( temp > 0 )
322+ { temp /= 10;
323+ ++result;
324+ }
325+ return result;
326+}
327+
328+void header( long year, int month, str0array_t * daynames, str0array_t * monthNames, int dayoffset, int terminalwidth )
329+{ int rightfield = ( terminalwidth - intlog10( year ) - intlog10( month ) - 4 - strlen( PLANETname ) ) / 2;
330+/* */
331+ while ( rightfield-- > 0 )
332+ { putchar ( SPACE );
333+ }
334+ printf( "%s: %ld %s", PLANETname, year, (* monthNames )[ month ] );
335+ putchar( '\n' );
336+ headerNames( daynames, dayoffset, ( ( terminalwidth - 1 ) / DAYSperWEEK ) - 1 );
337+ putchar( '\n' );
338+}
339+
340+/* buffer must have room for field plus trailing NUL!
341+// ** That's one more than field! **
342+// Oh, for a dedicated parameter stack and returnable ad-hoc vectors.
343+// Returns the starting point for the conversion
344+*/
345+char * ulongtostring( char buffer[], unsigned long * numberp, int field, unsigned base )
346+{
347+ char * inpoint = buffer + field; /* Going to store a NUL here! */
348+ unsigned long number = * numberp;
349+/* */
350+ * inpoint = '\0';
351+ * --inpoint = '0';
352+ if ( number > 0 )
353+ { ++inpoint;
354+ while ( ( number > 0 ) && ( inpoint > buffer ) )
355+ { * --inpoint = '0' + number % base;
356+ number /= base;
357+ }
358+ }
359+ * numberp = number; /* leave any leftover. */
360+ return inpoint;
361+}
362+
363+#define LPAREN '('
364+#define RPAREN ')' /* Balance to avoid confusing balancing editors, as well. */
365+
366+char * longtostring( char buffer[], signed long * numberp, int field, unsigned base, char sign )
367+{ signed long number = * numberp;
368+ unsigned long value = ( number < 0 ) ? -number : number;
369+ char * converted = ulongtostring( buffer, &value, ( ( number < 0 ) && ( sign == LPAREN ) ) ? field - 1 : field, base );
370+/* */
371+ if ( ( number < 0 ) && ( converted > buffer ) )
372+ { * --converted = sign;
373+ if ( sign == LPAREN ) /* sign is parenthesis */
374+ { buffer[ field - 1 ] = RPAREN;
375+ buffer[ field ] = '\0';
376+ }
377+ }
378+ * numberp = ( number < 0 ) ? -value : value; /* leave any leftover. */
379+ return converted;
380+}
381+
382+void centeredNumber( int number, int field, int base, char sign, char overfill )
383+{ int rightfield;
384+ int i;
385+ signed long value = number;
386+ char buffer[ field + 1 ]; /* one more for NUL */
387+ char * converted = longtostring( buffer, &value, field, base, sign );
388+ int numberwidth = field - ( converted - buffer );
389+/* */
390+/* printf( "\nnumber: %d, final value: %lu, converted: %s, field: %d\n", number, value, converted, field ); */
391+ if ( ( value > 0 ) || ( ( number < 0 ) && !( converted > buffer ) ) )
392+ { char * p;
393+ for ( p = buffer + field; p > buffer; * --p = overfill )
394+ { /* empty loop */
395+ }
396+ }
397+ rightfield = ( field - numberwidth ) / 2; /* bias left */
398+ for ( i = 0; i < rightfield; ++i )
399+ { putchar( SPACE );
400+ }
401+ fputs ( converted, stdout );
402+ for ( i = rightfield + numberwidth; i < field; ++i )
403+ { putchar( SPACE );
404+ }
405+}
406+
407+int printOneWeek( int month, int day, int field, int offset )
408+{ int column;
409+ int endday = daysInMonths[ ( month > 0 ) ? month - 1 : MONTHSperYEAR - 1 ] - offset + 1;
410+/* */
411+ for ( column = 0; column < offset; ++column )
412+ { putchar( '|' );
413+ centeredNumber( -( endday++ ), field - 1, 10, LPAREN, '*' );
414+ }
415+/* */
416+ for ( /* as is */; ( column < DAYSperWEEK ) && ( day < daysInMonths[ month ] ); ++column )
417+ { putchar( '|' );
418+ centeredNumber( day++, field - 1, 10, LPAREN, '*' );
419+ }
420+/* */
421+ endday = 0;
422+ for ( /* as is */; column < DAYSperWEEK; ++column )
423+ { putchar( '|' );
424+ centeredNumber( -( endday++ ), field - 1, 10, LPAREN, '*' );
425+ }
426+/* */
427+ putchar( '|' );
428+ putchar( '\n' );
429+ return ( day < daysInMonths[ month ] ) ? day : -1;
430+}
431+
432+void printOneMonth( long year, int month, int day, char fake, int wkstart, int terminalWidth )
433+{ long daysfromzero =
434+/* */
435+ str0array_t * daynames = ( fake = 'f' ) ? &fakeDayNames : &weekDayNames;
436+ str0array_t * monthNames = ( fake = 'f' ) ? &fakeMonthNames : &realMonthNames;
437+/* */
438+ header( year, month, daynames, monthNames, wkstart, terminalWidth );
439+ day = printOneWeek( month, day, terminalWidth / 7, 2 );
440+ day = printOneWeek( month, day, terminalWidth / 7, 0 );
441+ day = printOneWeek( month, day, terminalWidth / 7, 0 );
442+ day = printOneWeek( month, day, terminalWidth / 7, 0 );
443+ day = printOneWeek( month, day, terminalWidth / 7, 0 );
444+ putchar( '\n' );
445+}
446+
447+
448+int setlong( long * target, char * source )
449+{ int validity = 0;
450+ char * parsept = source;
451+ long temp = strtol( source, &parsept, 0 );
452+/* */
453+ if ( parsept > source )
454+ { validity = 1;
455+ * target = temp;
456+ }
457+/* */
458+/* printf( "setlong: %s:%s %ld: %d\n", source, parsept, *target, validity ); */
459+ return validity;
460+}
461+
462+
463+int setlongLimited( long * target, char * source, long low, long high )
464+{ long temp;
465+ int validity = setlong( &temp, source );
466+/* */
467+ validity = validity && ( temp >= low ) && ( temp <= high );
468+ if ( validity )
469+ { * target = temp;
470+ }
471+/* printf( "setlongLimited: %s %ld %ld %ld %ld: %d\n", source, low, temp, high, *target, validity ); */
472+ return validity;
473+}
474+
475+
476+int main( int argc, char * argv[] )
477+{
478+ long year = -1;
479+ long month = -1;
480+ int day = 0;
481+ long offset = 0;
482+ int startDay = 0;
483+ int argx = 1;
484+ char fake = 'f';
485+/* */
486+ long terminalWidth = 80;
487+/* */
488+ int valid = 1;
489+/* */
490+ while ( valid && ( argx < argc ) )
491+ {
492+ if ( argv[ argx ][ 0 ] == '-' )
493+ { switch ( argv[ argx ][ 1 ] )
494+ {
495+ case 'y':
496+ valid = setlong( &year, argv[ ++argx ] );
497+ break;
498+ case 'm':
499+ valid = setlongLimited( &month, argv[ ++argx ], 0, MONTHSperYEAR - 1 );
500+ break;
501+ case 'o':
502+ valid = setlongLimited( &offset, argv[ ++argx ], 0, DAYSperWEEK - 1 );
503+ break;
504+ case 'w':
505+ valid = setlongLimited( &terminalWidth, argv[ ++argx ], 0, LONG_MAX );
506+ break;
507+ case 'f':
508+ case 'r':
509+ fake = argv[ argx ][ 1 ];
510+ break;
511+ }
512+ }
513+ else
514+ { if ( year < 0 )
515+ { valid = setlong( &year, argv[ argx ] );
516+ }
517+ else if ( month < 0 )
518+ { valid = setlongLimited( &month, argv[ argx ], 0, MONTHSperYEAR - 1 );
519+ }
520+ }
521+ ++argx;
522+ }
523+
524+ if ( !valid ) /* Not really quite accurate summary. */
525+ { printf( "%s { [ <year> [ <month> ] ] }\n",
526+ argv[ 0 ] );
527+ puts( "\t | { [ -f(ake) | -r(eal) ] [ -y <year> ] [ -m <month> ] [ -o <weekday-offset> ] [ -w <terminal-width> ] }" );
528+ return EXIT_FAILURE;
529+ }
530+
531+
532+ printOneMonth( year, (int) month, day, fake, offset, terminalWidth );
533+
534+ return EXIT_SUCCESS;
535+}