This program calculates and displays a 30-day biorhythm analysis for a user-specified start date, computing Physical (23-day), Emotional (28-day), and Intellectual (33-day) cycles using sine functions scaled to a range of ±20. The user enters birth date and start date in month/day/year format, and the program derives the day-count difference to feed into the cycle calculations via GOSUB routines at lines 770–820. The code uses cumulative day-of-year arrays (A() and F(), which are duplicated and identical) to convert calendar dates to Julian-style day numbers with the formula at lines 830–840. Several notable anomalies are present: the Intellectual cycle at line 770 correctly uses period 33, but the Physical cycle at line 810 incorrectly uses period 28 (same as Emotional), and the sort/print loop for plotting biorhythm positions on screen (lines 1470–1650) contains control-flow bugs that prevent correct column-ordered output. Summary statistics at line 2510–2530 report total days, hours, and approximate heartbeats since birth before looping back to restart.
Program Analysis
Program Structure
The program is divided into several logical phases:
- Initialisation (lines 10–430): Arrays and strings are set up — cumulative day-of-year offsets in
A()andF(), month name strings inM$(), and day-name strings inX$()andD$(). - User input (lines 440–740): Prompts for analysis duration (
ZA), start date (M,D,Y), birth date (MB,DB,YB), and user name (A$). - Date calculation (lines 830–870): Converts calendar dates to a linear day count (
TandTB); computes the age in days (X = T - TB). - Header printing (lines 1120–1310): Prints title, start date, birth date, and cycle legend.
- Main biorhythm loop (lines 1350–1940): For each day, calls GOSUB routines to compute cycle values, attempts to sort positions for tabular output, and advances the date.
- Closing summary (lines 2500–2560): Displays total days, hours, and estimated heartbeats since birth, then restarts.
Cycle Calculation Subroutines
Three GOSUB routines compute biorhythm values as integers in the range −20 to +20:
| Line | Variable | Cycle | Period used | Correct period |
|---|---|---|---|---|
| 770 | NI | Intellectual | 33 | 33 ✓ |
| 790 | NE | Emotional | 28 | 28 ✓ |
| 810 | NP | Physical | 28 | 23 ✗ |
The Physical cycle subroutine at line 810 uses a period of 28 days instead of the correct 23, making it identical to the Emotional cycle. This is a straightforward copy-paste bug.
Date-to-Day Conversion
Lines 830–840 use a compact formula to convert a calendar date to a sequential day number:
T = INT(D + 365.25*Y + A(M) + 0.01*M - 0.01)
The 365.25*Y term approximates leap years; the small 0.01*M and offset corrections fine-tune month boundary alignment. The cumulative day-of-year array A() stores the day number at which each month begins (January=0, February=31, etc.). Notably, array F() is initialised to identical values at lines 290–400 but is later reused as a column-position array for the print loop — a recycling of an array name that may cause confusion.
Day-of-Week Calculation
Lines 870 and 1150 compute the day of the week for the birth date and start date respectively:
RB = TB - 1 - INT((TB-1)/7)*7
This is a modulo-7 operation yielding a value 0–6, used to index into X$() and D$() for full and abbreviated day names.
Column Sort and Print Loop — Key Bugs
Lines 1470–1650 attempt to sort the four plot positions (F(1)–F(4) for median, I, E, P markers) into left-to-right screen order, then print them with TAB. Several serious bugs prevent correct operation:
- The inner sort loop (lines 1490–1600) jumps to
GOTO 1600on the true branch of line 1490, skipping the swap at lines 1530–1580 entirely — the sort never executes a swap. - Line 1500 sets
F(I)=0and clearsF$(I)when two positions are equal, but also falls through incorrectly due to missingGOTO. - The print loop at lines 1620–1650 prints
TAB(F(I))andTAB(F(J)), butJis the inner loop variable left over from the sort loop (value 4 after exit), not an independent iterator — so onlyF(J)withJ=4is printed on every iteration.
Date Advancement Logic
Lines 1700–1920 advance the date by one day, handling month-end rollovers. However the structure has significant flow issues:
- Line 1720 checks
IF M=40(never true for a valid month) alongside correct 30-day month checks usingRM(which is initialised to 0 and never updated, so the conditionRM=60etc. is also always false). - Lines 1740 and 1760 handle February leap-year and non-leap-year cases but are only reachable if the preceding
IFat 1720 does not branch — since the branch target is 1800, these lines are effectively dead code; the program always reaches 1780 and setsL=31. - The variable
RHis used at line 1690 (LET R=RH) but is never assigned after line 59 initialises it to 0, so the day-of-week display never advances.
Duplicate Array Initialisation
Arrays A() (lines 60–160) and F() (lines 290–400) are initialised to exactly the same cumulative day-of-year values. The loop at lines 410–430 iterates over A(I) but merely assigns each element to the scalar A, discarding every value — it performs no useful work. The same applies to the loops at lines 950–970 and 1050–1110 for X$() and M$().
Closing Summary
After the loop completes, lines 2510–2530 print motivational statistics. Note that X at this point has been incremented by 0.5 each half-iteration (line 1660), so the expression X-1 will not equal the integer day count. The heartbeat estimate uses XS*24*90 — approximately 90 beats per minute is reasonable but the factor should be *60*60*24*~70 beats/day; the formula as written gives beats per hour rather than total beats.
Notable Idioms and Observations
INT(M),INT(D),INT(Y)at lines 610–630 guard against fractional input values.- The sub-day half-step iteration at line 1660 (
LET X=X+.5) with the guard at 1670 (IF INT(X)<>X THEN GOTO 1360) is an attempt to interpolate between days for smoother sine calculation, but since the print routine is re-entered at 1350 on the half-step, it effectively doubles the output rows. - Line 1180 contains a malformed PRINT statement:
"M$(M)STR$ (D)"is a string literal rather than evaluated expressions, so the starting date is never actually printed correctly. - Line 1260 prints
STR$(64)and the literal(35)— this appears to be an attempt to print a divider line but produces the string"64"followed by35.
Content
Source Code
10 REM "BIORYTHM"
20 CLEAR
21 LET L=0
30 DIM A(12)
35 DIM X$(7)
40 DIM M$(12)
45 DIM D$(7)
48 LET Z=0
50 DIM F(12)
53 LET R=0
55 DIM F$(12)
58 LET RH=0
59 LET RM=0
60 LET A(1)=0
70 LET A(2)=31
80 LET A(3)=59
85 LET A(4)=90
90 LET A(5)=120
100 LET A(6)=151
110 LET A(7)=181
120 LET A(8)=212
130 LET A(9)=243
140 LET A(10)=273
150 LET A(11)=304
160 LET A(12)=334
170 LET M$(1)="JAN"
180 LET M$(2)="FEB"
190 LET M$(3)="MAR"
200 LET M$(4)="APR"
210 LET M$(5)="MAY"
220 LET M$(6)="JUN"
230 LET M$(7)="JUL"
240 LET M$(8)="AUG"
250 LET M$(9)="SEP"
260 LET M$(10)="OCT"
270 LET M$(11)="NOV"
280 LET M$(12)="DEC"
290 LET F(1)=0
300 LET F(2)=31
310 LET F(3)=59
320 LET F(4)=90
330 LET F(5)=120
340 LET F(6)=151
350 LET F(7)=181
360 LET F(8)=212
370 LET F(9)=243
380 LET F(10)=273
390 LET F(11)=304
400 LET F(12)=334
410 FOR I=1 TO 12
420 LET A=A(I)
430 NEXT I
440 CLS
450 PRINT
460 PRINT
470 PRINT
480 PRINT
490 PRINT "THIS PROGRAM WILL PRINT OUT YOUR PERSONAL BIO-RYTHM AALYSIS"
500 PRINT "FOR A 30 DAY PERIOD STARTING AT ANY DAY YOU SELECT"
510 PRINT "DATES SHOULD BE ENTERED MONTH, DAY, YEAR"
520 PRINT "EX. 7,4,76"
530 PRINT "FOR HOW MANY DAYS DO YOU WANT YOUR BIO-RYTHM ANALYSIS?"
540 INPUT ZA
550 PRINT ZA
560 PRINT "WHAT IS THE DATE AT WHICH YOU WOULD LIKE THE 30 DAY AALYSIS TO START?"
570 INPUT M
580 INPUT D
590 INPUT Y
600 PRINT M ,D ,Y
610 LET M=INT (M)
620 LET D=INT (D)
630 LET Y=INT (Y)
640 PRINT "WHAT IS THE DATE OF YOUR BIRTH"
650 INPUT MB
660 INPUT DB
670 INPUT YB
680 PRINT MB ,DB ,YB
690 LET MB=INT (MB)
700 LET DB=INT (DB)
710 LET YB=INT (YB)
720 PRINT "WHAT IS YOUR NAME"
730 INPUT A$
740 PRINT A$
750 PRINT
760 GOTO 830
770 LET NI=INT (20*SIN (2*PI*X/33)+.5)
780 RETURN
790 LET NE=INT (20*SIN (2*PI*X/28)+.5)
800 RETURN
810 LET NP=INT (20*SIN (2*PI*X/28)+.5)
820 RETURN
830 LET T=INT (D+365.25*Y+A(M)+.01*M-.01)
840 LET TB=INT (DB+365.25*YB+A(MB)+.01*MB-.03)
850 LET X=T-TB
860 LET V=INT ((40-LEN (A$))/2)
870 LET RB=TB-1-INT ((TB-1)/7)*7
880 LET X$(1)="MONDAY"
890 LET X$(2)="TUESDAY"
900 LET X$(3)="WEDNESDAY"
910 LET X$(4)="THURSDAY"
920 LET X$(5)="FRIDAY"
930 LET X$(6)="SATURDAY"
940 LET X$(7)="SUNDAY"
950 FOR I=1 TO 7
960 LET X$=X$(I)
970 NEXT I
980 LET D$(1)="MON"
990 LET D$(2)="TUE"
\n1000 LET D$(3)="WED"
\n1010 LET D$(4)="THU"
\n1020 LET D$(5)="FRI"
\n1030 LET D$(6)="SAT"
\n1040 LET D$(7)="SUN"
\n1050 FOR I=1 TO 7
\n1060 LET D$=D$(I)
\n1070 NEXT I
\n1080 LET S=0
\n1090 FOR I=1 TO 12
\n1100 LET M$=M$(I)
\n1110 NEXT I
\n1120 CLS
\n1130 PRINT
\n1140 PRINT "THIS IS A ";ZA;" DAY BIO-RYTHM ANALYSIS FOR ";A$
\n1150 LET R=T-1-INT ((T-1)/7)*7
\n1160 LET LE=21+LEN (X$(R))+LEN (M$(M))+LEN (STR$ (D))+LEN (STR$ (Y))
\n1170 LET V2=INT ((64-LE)/2)
\n1180 PRINT "STARTING DATE";X$(R);"M$(M)STR$ (D)";"19;"
\n1190 PRINT STR$ (YB)
\n1200 PRINT
\n1210 LET LL=LEN (X$(RB))+LEN (M$(MB))
\n1220 LET LB=LL+18
\n1230 LET VB=INT ((64-LB)/2)
\n1240 PRINT "BIRTH DATE ";X$(RB),M$(MB),STR$ (DB),"19"
\n1250 PRINT STR$ (YB)
\n1260 PRINT STR$ (64),(35)
\n1270 PRINT "(P)STANDS FOR PHYSICAL CYCLE"
\n1280 PRINT "(I) STANDS FOR INTELLECTUAL CYCLE"
\n1290 PRINT "(E)STANDS FOR EMOTIONAL CYCLE"
\n1300 PRINT "WHENEVER A CYCLE CROSSES THE MEDIAN LINE, THIS IS A CRITICAL DAY"
\n1310 PRINT "%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*BE CAREFUL%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*"
\n1340 PRINT " DOWN CRITICAL UP"
\n1350 PRINT D$(R);D;M$(M)
\n1360 LET F(1)=42
\n1370 LET F$(1)="*"
\n1380 GOSUB 770
\n1390 LET F(2)=42+NI
\n1400 LET F$(2)="I"
\n1410 GOSUB 790
\n1420 LET F(3)=42+NE
\n1430 LET F$(3)="E"
\n1440 GOSUB 810
\n1450 LET F(4)=42+NP
\n1460 LET F$(4)="P"
\n1470 FOR I=1 TO 3
\n1480 FOR J=I+1 TO 3
\n1490 IF F(I)<F(J) THEN GOTO 1600
\n1500 IF F(I)=F(J) THEN LET F(I)=0
\n1510 LET F$(I)=""
\n1515 LET F$(J)="X"
\n1520 GOTO 1600
\n1530 LET Q=F(I)
\n1540 LET Q$=F$(I)
\n1550 LET F(I)=F(J)
\n1560 LET F$(I)=F$(J)
\n1570 LET F(J)=Q
\n1580 LET F$(J)=Q$
\n1600 NEXT J
\n1610 NEXT I
\n1620 FOR I=1 TO 4
\n1630 PRINT TAB (F(I))
\n1640 PRINT TAB (F(J))
\n1650 NEXT I
\n1660 LET X=X+.5
\n1670 IF INT (X)<>X THEN GOTO 1360
\n1680 IF Z=ZA-1 THEN GOTO 2500
\n1690 LET R=RH
\n1700 IF R=7 THEN LET R=0
\n1710 LET D=D+1
\n1720 IF M=40 OR RM=60 OR RM=90 OR RM=11 THEN LET L=30
\n1730 GOTO 1800
\n1740 IF M=2 AND Y/4=INT (Y/4) THEN LET L=29
\n1750 GOTO 1800
\n1760 IF M=2 THEN LET L=28
\n1770 GOTO 1800
\n1780 LET L=31
\n1800 IF D>L THEN LET D=D-L
\n1810 LET M=M+1
\n1820 GOTO 1900
\n1830 PRINT
\n1840 LET Z=ZH
\n1850 GOTO 1350
\n1900 IF M=13 THEN LET M=1
\n1910 LET Z=Z+1
\n1920 GOTO 1350
\n1930 LET Z=Z+1
\n1940 GOTO 1350
\n2500 PRINT
\n2510 PRINT "IT HAS BEEN ";X-1;" DAYS OR ";(X-1)*24;" HOURS SINCE YOU WERE BORN"
\n2520 LET XS=X
\n2530 PRINT "OR APPROX, ";XS*24*90;" HEARTBEAT SINCE THE DAY OF YOUR BIRTH"
\n2540 INPUT QR
\n2550 CLEAR
\n2560 GOTO 10
\n3000 STOP
\n3010 SAVE "1016%9"
\n3020 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
