This program calculates and displays biorhythm charts for three cycles — Physical (23 days), Emotional (28 days), and Intellectual (33 days) — based on a user-supplied date of birth and today’s date. Date validation at line 1000 checks string length, delimiter placement, and digit validity before converting the DD.MM.YY input into a day-count using month-length data encoded in the string `m$` as ASCII offset values (e.g., `CODE m$(m)-20` yields the number of days in month `m`). Leap year correction is applied when the year is divisible by 4 and the accumulated day count has passed February. The chart is plotted using PLOT and SIN with a scaling factor of 20 pixels amplitude, and month boundaries are marked by vertical tick lines driven by the same `m$` encoding used during date parsing.
Program Structure
The program is divided into four logical sections:
- Lines 10–90: Setup, color attributes, and input loop for birth date and today’s date.
- Lines 100–340: Cycle calculation and chart rendering including sine-wave plotting and month-boundary markers.
- Lines 1000–1550: Subroutine that validates a date string and converts it to an absolute day number stored in
n. - Line 2000–2010: Error handler that sets flag
x=1and prints a flashing “INVALID DATE” message.
The m$ Encoding Trick
The string m$="303232332323" at line 20 encodes month lengths in a compact form. Each character’s ASCII code minus 20 yields the number of days in that month: '3' = 51−20 = 31, '0' = 48−20 = 28, '2' = 50−20 = 30. This avoids a DATA statement or array, and the same string is reused both in the date-to-day conversion (lines 1090–1530) and in the month-boundary tick-mark loop (lines 300–330).
Date Validation Subroutine (Lines 1000–1550)
The subroutine performs several layered checks before attempting numeric conversion:
- Exact length of 8 characters (line 1010).
- Dots at positions 3 and 6 (line 1020).
- Digit characters at positions 1–2, 4–5, and 7–8 via a loop stepping by 3 (lines 1030–1050).
- Non-zero day, month, and year, and month ≤ 12 (line 1070).
An anomaly exists at line 1090: it calculates the days in month m into n (including leap-day adjustment for February), but this value is immediately overwritten by LET n=0 at line 1500 without being used. The intent was likely to validate that the day number does not exceed the month length, but that check was never implemented — so invalid days such as 31 in April pass silently.
Day-Count Calculation
Lines 1500–1550 sum month lengths for all months before m, add a leap-year correction if the accumulated count has passed day 59 (end of February), then add the day-of-month and an approximation of prior complete years using INT (365.25*(y-1)). This gives a relative Julian-style day number sufficient for computing the difference between two dates. The two-digit year y means dates in different centuries are not distinguished, though this is typical for the era.
Biorhythm Calculation and Plotting
Line 130 derives cycle periods: b(1)=23, b(2)=28, b(3)=33, matching Physical, Emotional, and Intellectual cycles. Line 140 computes c(j), the phase offset (days into the current cycle). The sine wave is plotted at line 230:
PLOT INK j; k, SIN((k + 2*c(j)) * PI / b(j)) * 20 + ((4-j)*48-28)
The factor 2*c(j) in the argument shifts the curve horizontally so the chart’s left edge represents the current date. Each cycle is drawn in a different INK color (1=blue, 2=red, 3=green) and centered on its own horizontal baseline at vertical positions 20, 68, and 116 pixels respectively.
Month Boundary Markers (Lines 300–330)
A second pass over all 256 x-coordinates draws short vertical tick marks at month boundaries. Variable d accumulates 0.5 per pixel column and is compared against CODE m$(m)-20 (days in month m). When the threshold is exceeded, d resets and m advances. Note that d is also used as the day-of-month variable in the date parsing subroutine (line 1060), so if the chart section is reached, d retains whatever value was left from parsing. This is benign because d is effectively initialized to a small value before the comparison matters, but it is a variable reuse that could cause confusion.
Notable Techniques and Anomalies
- The typo “Pleasr” (missing ‘e’) in the PRINT statement at line 30 is a cosmetic bug in the original listing.
- Error handling uses a flag variable
xrather than structured error trapping, with GO TO 2000 used as a shared error exit from multiple validation points. - The
DIM n$(3,12)at line 100 allocates fixed-length strings; “Physical” (8 chars), “Emotional” (9), and “Intellectual” (12) are padded to 12 by the DIM, so labels display correctly without manual padding. - Line 1090 computes a value into
nthat is immediately discarded by line 1500’sLET n=0, representing an incomplete validation or refactoring artifact.
Content
Source Code
10 INK 2:BORDER 6:PAPER 6:BRIGHT 1:CLS
20 LET m$="303232332323"
30 PRINT TAB 11;"BIORHYTHM"'''''"Pleasr enter dates in the form:"''' TAB 11;"DD.MM.YY"
40 INPUT "Enter your date of birth ";d$
50 GO SUB 1000:IF x THEN GO TO 40
60 LET b=n:LET b$=d$
70 INPUT "Enter today's date ";d$
80 GO SUB 1000:IF x THEN GO TO 70
90 LET n=n-b:IF n<0 THEN GO SUB 2000:GO TO 70
100 DIM n$(3,12):LET n$(1)="Physical":LET n$(2)="Emotional":LET n$(3)="Intellectual"
110 DIM b(3):DIM c(3)
120 FOR j=1 TO 3
130 LET b(j)=18+5*j
140 LET c(j)=n-b(j)* INT (n/b(j))
150 NEXT j
200 CLS :PRINT TAB 11;"BIOCHART"''"D.O.B.:";b$;"Today:";d$
210 INK 7:FOR j=1 TO 3:PLOT 0,j*48-28:DRAW 255,0:PRINT INK j; AT j*6-2,2;n$(j):NEXT j
220 FOR j=1 TO 3:FOR k=0 TO 255
230 PLOT INK j;k, SIN ((k+(2*c(j)))* PI/b(j))*20+((4-j)*48-28)
240 NEXT k:NEXT j
300 FOR j=0 TO 255
310 LET d=d+.5
320 IF d> CODE m$(m)-20 THEN LET d=.5:FOR k=1 TO 3:PLOT j,k*48-30:DRAW 0,5:NEXT k:LET m=m+1:IF m>12 THEN LET m=1
330 NEXT j
340 STOP
1000 LET x=0:PRINT AT 15,10;" ":REM 12 spaces
1010 IF LEN d$ <>8 THEN GO TO 2000
1020 IF d$(3) <>"." OR d$(6) <>"." THEN GO TO 2000
1030 FOR j=1 TO 7 STEP 3
1040 IF d$(j)<"0" OR d$(j)>"9" OR d$(j+1)<"0" OR d$(j+1)>"9" THEN GO TO 2000
1050 NEXT j
1060 LET y= VAL d$(7 TO ):LET m= VAL d$(4 TO 5):LET d= VAL d$( TO 2)
1070 IF y=0 OR d=0 OR m=0 OR m>12 THEN GO TO 2000
1080 LET l=0:IF y/4= INT y/4 THEN LET l=1
1090 LET n= CODE m$(m)-20+(m=2 AND l=1)
1500 LET n=0
1510 FOR j=1 TO m-1
1520 LET n=n+ CODE m$(j)-20
1530 NEXT j
1540 IF l=1 AND n>59 THEN LET n=n+1
1550 LET n=n+d+ INT (365.25*(y-1)):RETURN
2000 LET x=1
2010 PRINT INK 2; FLASH 1; AT 15,10;"\{16}\{2}INVALID DATE":RETURN
9000 SAVE "BIORHYTHMS" LINE 0
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
