Biorhythm

This file is part of and 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

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"
 1000 LET D$(3)="WED"
 1010 LET D$(4)="THU"
 1020 LET D$(5)="FRI"
 1030 LET D$(6)="SAT"
 1040 LET D$(7)="SUN"
 1050 FOR I=1 TO 7
 1060 LET D$=D$(I)
 1070 NEXT I
 1080 LET S=0
 1090 FOR I=1 TO 12
 1100 LET M$=M$(I)
 1110 NEXT I
 1120 CLS 
 1130 PRINT 
 1140 PRINT "THIS IS A ";ZA;" DAY BIO-RYTHM ANALYSIS FOR ";A$
 1150 LET R=T-1-INT ((T-1)/7)*7
 1160 LET LE=21+LEN (X$(R))+LEN (M$(M))+LEN (STR$ (D))+LEN (STR$ (Y))
 1170 LET V2=INT ((64-LE)/2)
 1180 PRINT "STARTING DATE";X$(R);"M$(M)STR$ (D)";"19;"
 1190 PRINT STR$ (YB)
 1200 PRINT 
 1210 LET LL=LEN (X$(RB))+LEN (M$(MB))
 1220 LET LB=LL+18
 1230 LET VB=INT ((64-LB)/2)
 1240 PRINT "BIRTH DATE ";X$(RB),M$(MB),STR$ (DB),"19"
 1250 PRINT STR$ (YB)
 1260 PRINT STR$ (64),(35)
 1270 PRINT "(P)STANDS FOR PHYSICAL CYCLE"
 1280 PRINT "(I) STANDS FOR INTELLECTUAL CYCLE"
 1290 PRINT "(E)STANDS FOR EMOTIONAL CYCLE"
 1300 PRINT "WHENEVER A CYCLE CROSSES THE MEDIAN LINE, THIS IS A CRITICAL DAY"
 1310 PRINT "%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*BE CAREFUL%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*"
 1340 PRINT "                   DOWN      CRITICAL            UP"
 1350 PRINT D$(R);D;M$(M)
 1360 LET F(1)=42
 1370 LET F$(1)="*"
 1380 GOSUB 770
 1390 LET F(2)=42+NI
 1400 LET F$(2)="I"
 1410 GOSUB 790
 1420 LET F(3)=42+NE
 1430 LET F$(3)="E"
 1440 GOSUB 810
 1450 LET F(4)=42+NP
 1460 LET F$(4)="P"
 1470 FOR I=1 TO 3
 1480 FOR J=I+1 TO 3
 1490 IF F(I)<F(J) THEN GOTO 1600
 1500 IF F(I)=F(J) THEN LET F(I)=0
 1510 LET F$(I)=""
 1515 LET F$(J)="X"
 1520 GOTO 1600
 1530 LET Q=F(I)
 1540 LET Q$=F$(I)
 1550 LET F(I)=F(J)
 1560 LET F$(I)=F$(J)
 1570 LET F(J)=Q
 1580 LET F$(J)=Q$
 1600 NEXT J
 1610 NEXT I
 1620 FOR I=1 TO 4
 1630 PRINT TAB (F(I))
 1640 PRINT TAB (F(J))
 1650 NEXT I
 1660 LET X=X+.5
 1670 IF INT (X)<>X THEN GOTO 1360
 1680 IF Z=ZA-1 THEN GOTO 2500
 1690 LET R=RH
 1700 IF R=7 THEN LET R=0
 1710 LET D=D+1
 1720 IF M=40 OR RM=60 OR RM=90 OR RM=11 THEN LET L=30
 1730 GOTO 1800
 1740 IF M=2 AND Y/4=INT (Y/4) THEN LET L=29
 1750 GOTO 1800
 1760 IF M=2 THEN LET L=28
 1770 GOTO 1800
 1780 LET L=31
 1800 IF D>L THEN LET D=D-L
 1810 LET M=M+1
 1820 GOTO 1900
 1830 PRINT 
 1840 LET Z=ZH
 1850 GOTO 1350
 1900 IF M=13 THEN LET M=1
 1910 LET Z=Z+1
 1920 GOTO 1350
 1930 LET Z=Z+1
 1940 GOTO 1350
 2500 PRINT 
 2510 PRINT "IT HAS BEEN ";X-1;" DAYS OR ";(X-1)*24;" HOURS SINCE YOU WERE BORN"
 2520 LET XS=X
 2530 PRINT "OR APPROX, ";XS*24*90;" HEARTBEAT SINCE THE DAY OF YOUR BIRTH"
 2540 INPUT QR
 2550 CLEAR 
 2560 GOTO 10
 3000 STOP 
 3010 SAVE "1016%9"
 3020 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