This program calculates and prints a biorhythm chart for a given person, plotting their physical (23-day), emotional (28-day), and intellectual (33-day) cycles over a user-specified date range. It accepts a birth date and start/end dates in MM.DD.YYYY format, computes a Julian Day number using a modified Chronological Julian Day algorithm with corrections for the Julian/Gregorian calendar boundary, and outputs a text-based sine-wave chart to both the screen and a printer via LPRINT. The display uses a 32-column ASCII chart where “P”, “E”, and “I” markers are positioned horizontally based on scaled sine values, with inverse video and asterisks marking coincident cycles. A subroutine at line 1340 handles month-length calculation including a two-condition leap year test.
Program Analysis
Program Structure
The program is organized into a main sequential flow and four subroutines:
- Lines 30–170: Initialization, screen/printer setup, and collection of the person’s name, place, and birthdate via INPUT.
- Lines 180–560: Date parsing and Julian Day computation for birthdate, start date, and end date; prints header information to the printer.
- Lines 570–1030: Main chart loop — iterates day by day, computes sine values for all three cycles, renders the chart on screen, and uses COPY to send completed screen pages to the printer.
- Lines 1040–1140: End-of-chart finalization, COPY of the last partial page, and STOP.
- Lines 1150–1260:
GO SUB 1150— date parser; splits the MM.DD.YYYY stringQ$intoM,D,Yintegers. - Lines 1270–1330:
GO SUB 1270— Julian Day calculation, returning the day count inF. - Lines 1340–1400:
GO SUB 1340— computes the number of days in the current month, storing it inDAYS, with leap year handling.
Date Parsing (Lines 1150–1260)
The subroutine uses a 2-element numeric array L(2) to record the positions of the two period delimiters in the input string Q$. It then uses VAL with string slicing to extract month, day, and year. A two-digit year is corrected to a four-digit year by adding 1900 at line 1250, which correctly handles the 1700–2200 range only for years entered as four digits — the two-digit fallback would misplace any year outside 1900–1999.
Julian Day Calculation (Lines 1270–1330)
The algorithm computes a modified Julian Day number F using the standard formula based on Meeus, with separate branches for January/February (months treated as 13/14 of the prior year). Two post-calculation corrections at lines 1310–1320 handle the Gregorian/Julian calendar reform boundary: dates after the Gregorian cutoff (F > 146097) are decremented by 1, and dates on or before two earlier thresholds receive additive corrections to account for missing leap days in the Julian calendar. The final output offsets F by 2342031 to produce a conventional Julian Day Number for display.
Biorhythm Chart Loop (Lines 670–1030)
The loop iterates over the days of each month using DAYS from the month-length subroutine. For each day, the three cycle values are computed as sine functions of the cumulative day offset DIF divided by the cycle period (23, 28, 33). The sine result, ranging from −1 to +1, is scaled to a screen column by line 800–820:
INT((sin_value + 1) * 13 + 4.55)
This maps the range [−1, +1] to approximately columns 4–30, with column 17 representing zero. The constant 4.55 provides a fractional offset to center the zero crossing at column 17.
Screen Output and COPY Paging
The chart is drawn to the screen 22 lines at a time (rows 0–21), tracked by counter N. When N exceeds 21, COPY sends the screen contents to the printer, then CLS clears the screen for the next page. The final partial page is handled separately at lines 1040–1140, with a branch depending on whether N is 18 or less (printed inline) or greater (a fresh COPY is issued first).
Coincidence and Zero-Crossing Markers
Lines 890–900 detect when any two cycle markers share the same column position, printing an asterisk * at that column to flag a biorhythm coincidence. Lines 840, 860, and 880 detect when a cycle value falls exactly on column 17 (the zero crossing) and render the marker in inverse video for emphasis.
Printer Output Details
The program makes heavy use of LPRINT for permanent output. The chart header at line 600 uses INVERSE 1 with a block graphic sequence \::\:: (two solid-block characters) to create a decorative banner. Month and weekday names are extracted from packed lookup strings M$ (4 characters per month) and W$ (9 characters per weekday) using computed substring slices.
Variable Summary
| Variable | Role |
|---|---|
Q$ | Reused input buffer for name, place, and all three dates |
D$ | Packed string of two-digit day numbers 01–31 |
Y$ | Single-character month abbreviations (J,F,M,A,M,J,J,A,S,O,N,D) |
M$ | Four-character month abbreviations for printer output |
W$ | Nine-character weekday names for printer output |
F | Computed reduced Julian Day number |
D1, D2, D3 | Julian Day values for birthdate, start date, end date |
DIF | Running day count from birth, used as cycle phase |
P, E, I | Physical, emotional, intellectual cycle values (sine → column) |
N | Current screen row counter (0–21) |
DAYS | Number of days in the current month |
S, S1 | Day-of-week index (1–7) |
L(2) | Positions of period delimiters in date string |
Notable Techniques and Anomalies
- The
D$string at line 40 stores zero-padded day numbers as a lookup table;D$(2*Z-1 TO 2*Z)efficiently retrieves the two-character day label for screen display without any numeric formatting. - The leap year test at line 1380 uses a Boolean expression sum:
(Y/4=INT(Y/4))+(Y/100<>INT(Y/100))=2checks that the year is divisible by 4 AND not divisible by 100, giving 29 days. Line 1390 then separately handles the year 2000 exception. This correctly implements the Gregorian rule for the supported range, though it misses the general divisible-by-400 rule (only patched for 2000 explicitly). - The month iteration at lines 990–1030 increments
Mand wraps at 12, but the inner loop at lines 710–980 exits viaGO TO 1040whenDIF+D1 > D3, so the outerGO TO 700loop at line 1030 is only reached after a full month is processed — theNEXT Zat line 980 is therefore unreachable in normal operation once the end date is passed, but is reached correctly at month boundaries. - Line 1500 contains three consecutive
STOPstatements, which appears to be a placeholder or debugging remnant with no functional effect beyond the first. - The
POKE 23658,8at line 30 sets the system variable FLAGS2 to enable the printer buffer, a common TS2068/Spectrum technique to ensure LPRINT operates correctly.
Content
Source Code
10 REM BIORHYTHM (1700-2200)
20 REM \* 1983 I. Auersbacher
30 POKE 23658,8: CLS : BORDER 5
35 PRINT " BIORHYTHM COMPUTER (1700-2200) ": PRINT " FOR TS-2068 & PRINTER ": PRINT
40 LET D$="01020304050607080910111213141516171819202122232425262728293031"
50 LET Y$="JFMAMJJASOND"
60 PRINT "NAME:"
70 INPUT Q$
80 PRINT Q$
90 LPRINT INVERSE 1;"NAME "; INVERSE 0;": ";Q$
100 PRINT "PLACE:"
110 INPUT Q$
120 PRINT Q$
130 LPRINT INVERSE 1;"PLACE"; INVERSE 0;": ";Q$
140 PRINT "BIRTHDATE (MM.DD.YYYY):"
150 INPUT Q$
160 PRINT Q$
170 LPRINT "BIRTHDATE: ";Q$
180 GO SUB 1150
190 GO SUB 1270
200 LET D1=F
210 LET M$="JAN.FEB.MAR.APR.MAY JUN.JUL.AUG.SEP.OCT.NOV.DEC."
220 LET W$="SUNDAY MONDAY TUESDAY WEDNESDAYTHURSDAY FRIDAY SATURDAY "
230 LET S=F-(7*INT (F/7))+1
240 LPRINT M$(4*M-3 TO 4*M);D;",";Y;" ";W$(9*S-8 TO 9*S)
250 LPRINT "JULIAN DAY = ";F+2342031
260 PRINT
270 LPRINT
280 PRINT "START DATE(MM.DD.YYYY):"
290 INPUT Q$
300 PRINT Q$
310 LPRINT "START DATE: ";Q$
320 GO SUB 1150
330 LET M1=M
340 LET Y1=Y
350 LET D=1
360 GO SUB 1270
370 LET S=F-(7*INT (F/7))+1
380 LET S1=S
390 LPRINT M$(4*M-3 TO 4*M);D;",";Y;" ";W$(9*S-8 TO 9*S)
400 LET JD=F+2342031
410 LPRINT "JULIAN DAY = ";JD
420 LPRINT F-D1;" DAYS OLD ON ";Q$
430 LPRINT
440 LET D2=F
450 LET DIF=D2-D1
460 PRINT "END DATE (MM.DD.YYYY):"
470 INPUT Q$
480 PRINT Q$
490 LPRINT "STOP DATE : ";Q$
500 GO SUB 1150
510 GO SUB 1270
520 LET S=F-(7*INT (F/7))+1
530 LPRINT M$(4*M-3 TO 4*M);D;",";Y;" ";W$(9*S-8 TO 9*S)
540 LPRINT "JULIAN DAY = ";F+2342031
550 PAUSE 100
560 LET D3=F
570 FOR Z=1 TO 4
580 LPRINT
590 NEXT Z
600 LPRINT INVERSE 1;"\::\:: BIORHYTHM CHART STARTING "
610 LPRINT TAB 5;M$(4*M1-3 TO 4*M1);"1,";Y1;" ";W$(9*S1-8 TO 9*S1)
620 LPRINT
630 CLS
640 LPRINT
650 LPRINT "DAY";TAB 6;"LOW (-)";TAB 17;"0";TAB 24;"HIGH (+)"
660 LPRINT "-----------------+--------------"
670 LET N=0
680 LET M=M1
690 LET Y=Y1
700 GO SUB 1340
710 FOR Z=1 TO DAYS
720 LET P=DIF/23
730 LET P=SIN (2*PI*(P-INT P))
740 LET E=DIF/28
750 LET E=SIN (2*PI*(E-INT E))
760 LET I=DIF/33
770 LET I=SIN (2*PI*(I-INT I))
780 PRINT AT N,0;Y$(M);D$(2*Z-1 TO 2*Z)
790 PRINT AT N,17;":"
800 LET P=INT ((P+1)*13+4.55)
810 LET E=INT ((E+1)*13+4.55)
820 LET I=INT ((I+1)*13+4.55)
830 PRINT AT N,P;"P"
840 IF P=17 THEN PRINT AT N,17; INVERSE 1;"P"
850 PRINT AT N,E;"E"
860 IF E=17 THEN PRINT AT N,17; INVERSE 1;"E"
870 PRINT AT N,I;"I"
880 IF I=17 THEN PRINT AT N,17; INVERSE 1;"I"
890 IF (P=E)+(P=I) THEN PRINT AT N,P;"*"
900 IF E=I THEN PRINT AT N,E;"*"
910 LET N=N+1
920 IF N<=21 THEN GO TO 960
930 LET N=0
940 COPY
950 CLS
960 LET DIF=DIF+1
970 IF DIF+D1>D3 THEN GO TO 1040
980 NEXT Z
990 LET M=M+1
1000 IF M<=12 THEN GO TO 1030
1010 LET M=1
1020 LET Y=Y+1
1030 GO TO 700
1040 IF N<=18 THEN GO TO 1100
1050 COPY
1060 LPRINT
1070 LPRINT
1080 LPRINT " *** END OF BIO-OUTPUT ***"
1090 STOP
1100 PRINT
1110 PRINT
1120 PRINT " *** END OF BIO-OUTPUT ***"
1130 COPY
1140 STOP
1150 DIM L(2)
1160 LET L=1
1170 FOR Z=1 TO LEN Q$
1180 IF (Q$(Z)<>".") THEN GO TO 1210
1190 LET L(L)=Z
1200 LET L=L+1
1210 NEXT Z
1220 LET M=VAL Q$( TO L(1)-1)
1230 LET D=VAL Q$(L(1)+1 TO L(2)-1)
1240 LET Y=VAL Q$(L(2)+1 TO )
1250 IF Y<100 THEN LET Y=Y+1900
1260 RETURN
1270 IF M>2 THEN GO TO 1300
1280 LET F=INT (30.6*(M+13))+INT (365.25*(Y-1))+D-621049
1290 GO TO 1310
1300 LET F=INT (30.6*(M+1))+INT (365.25*Y)+D-621049
1310 IF F>146097 THEN LET F=F-1
1320 IF F<=73047 THEN LET F=F+(F<=73047)+(F<=36522)
1330 RETURN
1340 IF (M=4)+(M=6)+(M=9)+(M=11) THEN LET DAYS=30
1350 IF (M=1)+(M=3)+(M=5)+(M=7)+(M=8)+(M=10)+(M=12) THEN LET DAYS=31
1360 IF M<>2 THEN GO TO 1400
1370 LET DAYS=28
1380 IF (Y/4=INT (Y/4))+(Y/100<>INT (Y/100))=2 THEN LET DAYS=29
1390 IF Y=2000 THEN LET DAYS=29
1400 RETURN
1500 STOP : STOP : STOP
2000 SAVE "bio" LINE 10
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

