Biorhythm

This file is part of Timex Sinclair Public Domain Library Tape 1003 . Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 1000

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:

  1. Initialisation (lines 10–430): Arrays and strings are set up — cumulative day-of-year offsets in A() and F(), month name strings in M$(), and day-name strings in X$() and D$().
  2. User input (lines 440–740): Prompts for analysis duration (ZA), start date (M, D, Y), birth date (MB, DB, YB), and user name (A$).
  3. Date calculation (lines 830–870): Converts calendar dates to a linear day count (T and TB); computes the age in days (X = T - TB).
  4. Header printing (lines 1120–1310): Prints title, start date, birth date, and cycle legend.
  5. 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.
  6. 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:

LineVariableCyclePeriod usedCorrect period
770NIIntellectual3333 ✓
790NEEmotional2828 ✓
810NPPhysical2823 ✗

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 1600 on 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)=0 and clears F$(I) when two positions are equal, but also falls through incorrectly due to missing GOTO.
  • The print loop at lines 1620–1650 prints TAB(F(I)) and TAB(F(J)), but J is the inner loop variable left over from the sort loop (value 4 after exit), not an independent iterator — so only F(J) with J=4 is 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 using RM (which is initialised to 0 and never updated, so the condition RM=60 etc. is also always false).
  • Lines 1740 and 1760 handle February leap-year and non-leap-year cases but are only reachable if the preceding IF at 1720 does not branch — since the branch target is 1800, these lines are effectively dead code; the program always reaches 1780 and sets L=31.
  • The variable RH is 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 by 35.

Content

Appears On

Assembled by Tim Ward from many sources. Contains programs 10122 – 10175.

Related Products

Related Articles

Related Content

Image Gallery

Biorhythm

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.

People

No people associated with this content.

Scroll to Top