--- title: "Biorhythms and Day Of The Week" id: 56663 type: "computer_media" slug: "biorhythms-and-day-of-the-week" url: "http://localhost/computer_media/biorhythms-and-day-of-the-week/" markdown_url: "http://localhost/computer_media/biorhythms-and-day-of-the-week.md" published_at: "2024-09-22T23:31:36+00:00" modified_at: "2026-04-03T07:59:02+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/BIORHY.png" excerpt: "A three-cycle biorhythm plotter that maps Physical, Emotional, and Intellectual rhythms across any month using only character-cell graphics and sine arithmetic." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "Softsync" slug: "softsync" taxonomy: "post_tag" url: "http://localhost/tag/softsync/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" indiv: - name: "Ron Oblander" slug: "ron-oblander" taxonomy: "indiv" url: "http://localhost/indiv/ron-oblander/" genre: - name: "Entertainment" slug: "entertainment" taxonomy: "genre" url: "http://localhost/type/entertainment/" media_type: "Cassette" programmers: - name: "Ron Oblander" slug: "ron-oblander" taxonomy: "indiv" url: "http://localhost/indiv/ron-oblander/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Biorhythms%20and%20Day%20Of%20The%20Week%20%281982%29%28Ron%20Oblander%29%28TS1000%29%28US%29%28Program%29.zip" mediadate: "1982" producer_company: - id: 11319 title: "Softsync, Inc." type: "company" url: "http://localhost/company/softsync/" images: - url: "http://localhost/wp-content/uploads/2024/09/BIORHY.png" - url: "http://localhost/wp-content/uploads/2024/09/Cass-2.jpg" - url: "http://localhost/wp-content/uploads/2024/09/Cover_Front.jpg" - url: "http://localhost/wp-content/uploads/2024/09/Cover_Rear.jpg" - url: "http://localhost/wp-content/uploads/2024/09/DoW.png" related_products: - id: 11928 title: "Biorhythms" type: "product" url: "http://localhost/product/biorhythms-2/" media_type_tags: "Entertainment" --- This program calculates and displays biorhythm charts for a given birth date and target month, plotting Physical (23-day), Emotional (28-day), and Intellectual (33-day) cycles on a 32×24 character screen grid. The user enters birth date and desired month, and the program computes the number of elapsed days to determine each cycle’s phase using sine functions scaled to row positions. Input validation checks for impossible month numbers, day values over 31, and target dates before the birth year. The chart uses FAST mode for calculation, then switches to SLOW for display, with optional COPY output to a ZX Printer and navigation keys to step forward by month or restart entirely. A POKE to address 16418 is used to control the printer buffer/display area. *** ## Program Analysis ### Program Structure The program is organized into a clear sequence of phases: 1. **Data entry (lines 2–67):** Prompts for birth date, target month/year, printer choice, and a 4-letter name. 2. **Leap-year detection (lines 77–165):** Computes the number of days remaining in the birth year after the birth date (`DA1`). 3. **Elapsed-year accumulation (lines 250–315):** Counts days between end of birth year and start of target year (`DA2`), correctly inserting 366-day years for leap years. 4. **Days-into-target-month (lines 320–404):** Adds the cumulative day-of-year for the target month’s start (`DA3`). 5. **Phase calculation (lines 405–424):** Computes `DAYT` (total elapsed days) and derives display row offsets `FUDGP`, `FUDGE`, `FUDGI` for each cycle’s first day in the target month. 6. **Array filling (lines 745–946):** Runs in `FAST` mode, filling 32-element arrays `P()`, `E()`, `I()` with screen row values (0–20) for each day. 7. **Display (lines 690–727, 952–967):** Renders the chart frame, axis labels, month name, and plots `P`, `E`, `I` characters at computed positions. 8. **Navigation (lines 990–1066):** Allows advancing to the next month, restarting, or stopping. ### Day-Count Arithmetic The total elapsed days from birth to the start of the target month is built from three components: - `DA1`: days remaining in the birth year after the birth date (lines 80–135 for non-leap, 155–160 for leap January/February). - `DA2`: sum of days in all complete years between birth year+1 and the target year (lines 260–315), with leap years yielding 366. - `DA3`: cumulative day offset to the start of the target month within the target year (lines 325–380), with a +1 correction at line 395 if the target year is a leap year and the month is March or later. The combined total `DAYT = DA1 + DA2 + DA3 - 1` (line 405) gives the number of days from the birth date to the first day of the target month. ### Biorhythm Phase and Screen Mapping Lines 422–424 compute the display column offset for day 1 of the target month within each cycle: - `FUDGP` (Physical, period 23): `INT(.5 + 22 - (DAYT/23 - INT(DAYT/23))*23)` - `FUDGE` (Emotional, period 28): `INT(.5 + 27 - (DAYT/28 - INT(DAYT/28))*28)` - `FUDGI` (Intellectual, period 33): `INT(.5 + 32 - (DAYT/33 - INT(DAYT/33))*33)` The fractional part of `DAYT/period` gives the phase offset, which is subtracted from the period length and rounded to find how many days remain in the current cycle at the month boundary. The sine functions in the array-fill loops then use this offset to place the plotted character at the correct screen row. ### Array Filling and Sine Scaling The array-fill loops (e.g., lines 755–805 for Physical) use two nested strategies: - Forward fill: for day index `P`, compute column `X = FUDGP + P`; if `X ≤ 31`, set `P(X+1) = 11 - 5*SIN(P/11.5*PI)` (descending half of cycle). - Backward fill: if `X > 31`, iterate backwards from the fudge offset to fill the ascending half using `P(XX+1) = 11 + 5*SIN(Q/11.5*PI)`. The centre row is 11 (midpoint of the 0–20 usable display range). Amplitude scaling is ±5 rows for Physical, ±7 for Emotional, ±9 for Intellectual, matching the relative importance traditionally assigned to each rhythm. ### Notable Techniques - **FAST/SLOW switching:**`FAST` (line 76, 745) is used during calculation to suppress screen updates and speed up the sine-heavy array fills; `SLOW` (line 690) is restored for display. - **POKE 16418:** Used at line 406 (set to 0) and line 968 (set to 12). Address 16418 is the system variable `DF_SZ`, the number of lines in the lower display area. Setting it to 0 suppresses the lower screen during calculation; restoring it to 12 after plotting is unusual — the normal value is 2 — and may be an attempt to extend the display or manage COPY output. - **COPY for printer output:** Line 970 conditionally issues `COPY` based on the user’s initial `A$="Y"` choice, sending the screen to a ZX Printer. - **Looping navigation:** Lines 1061–1066 increment `BMN`, handle year rollover, and jump back to line 76 (FAST mode re-entry) to recalculate for the next month without re-entering the birth date. - **Array variable name collision:** The program uses `P` both as a scalar loop variable (lines 755, 952) and as an array `P()` (line 750). BASIC resolves these as distinct entities, but the practice is potentially confusing. ### Bugs and Anomalies - **DA validation is incomplete:** The check at line 57 only rejects `DA > 31`; days 29–31 are accepted for February, and day 31 is accepted for 30-day months. This can produce slightly incorrect day counts. - **BYR=YR check (line 255):** The program stops if the birth year equals the target year (line 257), but allows target years only one year ahead of birth without issue. However, the user could enter a target month/year in the birth year but a later month — this would produce incorrect results rather than being caught. - **32-element vs 31-day arrays:** Arrays are dimensioned to 32 (line 750–752) and the fill loop runs to 32, but only 31 elements are ever plotted. This is harmless but wastes a small amount of memory. - **Leap-year detection uses two-digit year:**`LY = (YR/4) - INT(YR/4)` works correctly for years divisible by 4 within the two-digit range, but would misidentify year 00 (2000) as a leap year coincidentally correctly, and year 00 (1900) — also correctly, since 1900 was not a leap year but the program has no century handling. - **Month name PRINT statements (lines 701–712):** Several month names are missing a comma before the closing quote (e.g., `"FEBRUARY"""` vs `"JANUARY,"""`), leading to inconsistent formatting in the display header. ### Variable Summary | Variable | Purpose | | --- | --- | | `A$` | Printer flag (“Y”/”N”) | | `MN, DA, YR` | Birth month, day, two-digit year | | `BMN, BYR` | Target month and year for display | | `N$` | User’s name (4 letters) | | `DA1` | Days remaining in birth year after birth date | | `DA2` | Days in complete years between birth and target | | `DA3` | Day-of-year offset for start of target month | | `DAYT` | Total elapsed days from birth to target month | | `FUDGP/FUDGE/FUDGI` | Phase column offsets for P/E/I cycles | | `P(), E(), I()` | Screen row arrays for each cycle’s 31 days | | `LY, LYY` | Leap-year fraction test and next leap year | ## Source Code ``` 1 REM BIORHYTHM 2 PRINT "PROGRAM TO CALCULATE BIORHYTHMS FOR GIVEN MONTHS WHEN ZX81 IS PROVIDED WITH BIRTHDATE. COPYRIGHT-RONALD G. OBLANDER, ANN ARBOR,MICHIGAN 1982" 3 PRINT "IF PRINTER OUTPUT IS DESIRED, ENTER ""Y"",IF NOT ""N""";"--"; 4 INPUT A$ 5 PRINT A$ 6 PRINT "ENTER MONTH OF BIRTH IN NUMERICAL FORM";"--"; 10 INPUT MN 11 PRINT MN 15 PRINT "ENTER DAY OF MONTH OF BIRTH--"; 20 INPUT DA 21 PRINT DA 25 PRINT "ENTER LAST TWO DIGITS OF YEAR OF BIRTH";"--"; 30 INPUT YR 31 PRINT YR 35 PRINT "ENTER MONTH OF BIORHYTHMS DESIRED";"--"; 36 INPUT BMN 37 PRINT BMN 42 PRINT "ENTER LAST TWO DIGITS OF YEAR OF BIORHYTHMS";"--"; 43 INPUT BYR 44 PRINT BYR 52 IF BYR12 THEN GOTO 61 55 IF BMN<1 THEN GOTO 61 56 IF BMN>12 THEN GOTO 61 57 IF DA>31 THEN GOTO 63 58 GOTO 65 59 PRINT "BIORHYTHMS BEFORE BIRTH ARE INVALID DUMMY-RERUN" 60 STOP 61 PRINT "INVALID MONTH NUMBER DUMB-BELL -RERUN" 62 STOP 63 PRINT "INVALID DAY NUMBER, IDIOT -RERUN" 64 STOP 65 PRINT "ENTER NAME(4 LETTERS ONLY)--"; 66 INPUT N$ 67 PRINT N$ 76 FAST 77 LET LY=(YR/4)-INT (YR/4) 78 LET LYY=(INT (YR/4)+1)*4 79 IF LY=0 THEN GOTO 150 80 IF MN=1 THEN LET DA1=366-DA 85 IF MN=2 THEN LET DA1=335-DA 90 IF MN=3 THEN LET DA1=307-DA 95 IF MN=4 THEN LET DA1=277-DA 100 IF MN=5 THEN LET DA1=246-DA 105 IF MN=6 THEN LET DA1=216-DA 110 IF MN=7 THEN LET DA1=186-DA 115 IF MN=8 THEN LET DA1=154-DA 120 IF MN=9 THEN LET DA1=123-DA 125 IF MN=10 THEN LET DA1=93-DA 130 IF MN=11 THEN LET DA1=62-DA 135 IF MN=12 THEN LET DA1=32-DA 140 GOTO 250 150 IF MN>=3 THEN GOTO 90 155 IF MN=1 THEN LET DA1=367-DA 160 IF MN=2 THEN LET DA1=336-DA 165 GOTO 250 250 LET DA2=0 255 IF YR=BYR THEN GOTO 257 256 GOTO 260 257 PRINT "BIORHYTHMS IN YEAR OF BIRTH CANNOT BE CALCULATED-SORRY" 258 STOP 260 LET YR1=YR+1 265 IF YR1=BYR THEN GOTO 320 270 IF YR1=LYY THEN GOTO 305 280 LET DA2=DA2+365 285 LET YR1=YR1+1 290 IF YR1=BYR THEN GOTO 320 295 IF YR1=LYY THEN GOTO 305 300 GOTO 280 305 LET DA2=DA2+366 310 LET LYY=LYY+4 315 GOTO 285 320 IF YR1=LYY THEN GOTO 385 325 IF BMN=1 THEN LET DA3=0 330 IF BMN=2 THEN LET DA3=31 335 IF BMN=3 THEN LET DA3=59 340 IF BMN=4 THEN LET DA3=90 345 IF BMN=5 THEN LET DA3=120 350 IF BMN=6 THEN LET DA3=151 355 IF BMN=7 THEN LET DA3=181 360 IF BMN=8 THEN LET DA3=212 365 IF BMN=9 THEN LET DA3=243 370 IF BMN=10 THEN LET DA3=273 375 IF BMN=11 THEN LET DA3=304 380 IF BMN=12 THEN LET DA3=334 381 GOTO 405 385 IF BMN>2 THEN GOTO 395 390 GOTO 325 395 LET DA2=DA2+1 400 GOTO 325 405 LET DAYT=-1+DA1+DA2+DA3 406 POKE 16418,0 422 LET FUDGP=INT (.5+22-(DAYT/23-INT (DAYT/23))*23) 423 LET FUDGE=INT (.5+27-(DAYT/28-INT (DAYT/28))*28) 424 LET FUDGI=INT (.5+32-(DAYT/33-INT (DAYT/33))*33) 425 GOTO 745 690 SLOW 691 PRINT AT 11,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % " 692 IF BMN=12 OR BMN=1 OR BMN=3 OR BMN=5 OR BMN=7 OR BMN=8 OR BMN=10 THEN PRINT AT 10,0;" 1111111111222222222233" 693 IF BMN=12 OR BMN=1 OR BMN=3 OR BMN=5 OR BMN=7 OR BMN=8 OR BMN=10 THEN PRINT AT 12,0;" 1234567890123456789012345678901" 694 IF BMN=4 OR BMN=6 OR BMN=9 OR BMN=11 THEN PRINT AT 10,0;" 111111111122222222223" 695 IF BMN=4 OR BMN=6 OR BMN=9 OR BMN=11 THEN PRINT AT 12,0;" 123456789012345678901234567890" 696 IF BMN=2 THEN PRINT AT 10,0;" 1111111111222222222" 697 IF BMN=2 THEN PRINT AT 12,0;" 1234567890123456789012345678" 699 PRINT AT 0,0;"*******BIORHYTHMS FOR ";N$;"******" 700 PRINT AT 1,4;"FOR MONTH OF "; 701 IF BMN=1 THEN PRINT "JANUARY,""";BYR; 702 IF BMN=2 THEN PRINT "FEBRUARY""";BYR; 703 IF BMN=3 THEN PRINT "MARCH,""";BYR; 704 IF BMN=4 THEN PRINT "APRIL,""";BYR; 705 IF BMN=5 THEN PRINT "MAY,""";BYR; 706 IF BMN=6 THEN PRINT "JUNE,""";BYR; 707 IF BMN=7 THEN PRINT "JULY,""";BYR; 708 IF BMN=8 THEN PRINT "AUGUST,""";BYR; 709 IF BMN=9 THEN PRINT "SEPTEMBER,""";BYR; 710 IF BMN=10 THEN PRINT "OCTOBER,""";BYR; 711 IF BMN=11 THEN PRINT "NOVEMBER,""";BYR; 712 IF BMN=12 THEN PRINT "DECEMBER,""";BYR; 713 PRINT AT 23,0;"******BIRTHDATE:";MN;"/";DA;"/";YR;"******" 717 PRINT AT 21,2;"P";"=PHYS ";"E";"=EMOT ";"I";"=INTEL" 718 FOR S=2 TO 9 719 PRINT AT S,0;"%+" 720 PRINT AT S+11,0;"%-" 721 NEXT S 722 PRINT AT 22,6;"% % % % % =CRITICAL DAY" 723 PRINT AT 9,0;"%D" 724 PRINT AT 10,0;"%A" 725 PRINT AT 11,0;"%T" 726 PRINT AT 12,0;"%E" 727 GOTO 952 745 FAST 750 DIM P(32) 751 DIM E(32) 752 DIM I(32) 755 FOR P=0 TO 32 760 LET X=FUDGP+P 765 IF X>31 THEN GOTO 780 770 LET P(X+1)=11-5*SIN (P/11.5*PI) 775 GOTO 805 780 FOR Q=1 TO 31 785 LET XX=FUDGP-Q 790 IF XX<0 THEN GOTO 815 795 LET P(XX+1)=11+5*SIN (Q/11.5*PI) 800 NEXT Q 805 NEXT P 815 FOR E=0 TO 32 820 LET X1=FUDGE+E 825 IF X1>31 THEN GOTO 840 830 LET E(X1+1)=11-7*SIN (E/14*PI) 835 GOTO 865 840 FOR F=1 TO 31 845 LET XXX=FUDGE-F 850 IF XXX<0 THEN GOTO 900 855 LET E(XXX+1)=11+7*SIN (F/14*PI) 860 NEXT F 865 NEXT E 900 FOR I=0 TO 31 905 LET X2=FUDGI+I 910 IF X2>31 THEN GOTO 925 915 LET I(X2+1)=11-9*SIN (I/16.5*PI) 920 GOTO 946 925 FOR G=1 TO 36 930 LET X3=FUDGI-G 935 IF X3<0 THEN GOTO 947 940 LET I(X3+1)=11+9*SIN (G/16.5*PI) 945 NEXT G 946 NEXT I 947 CLS 948 GOTO 690 952 FOR P=1 TO 31 953 PRINT AT P(P),P;"P" 954 NEXT P 962 FOR P=1 TO 31 963 PRINT AT E(P),P;"E" 964 NEXT P 965 FOR P=1 TO 31 966 PRINT AT I(P),P;"I" 967 NEXT P 968 POKE 16418,12 970 IF A$="Y" THEN COPY 990 PRINT AT 0,0;"PRESS N-FOR NEXT MONTH, R-FOR RESTART (DIFFERENT BIRTHDATE) ORS-FOR STOP. " 991 IF INKEY$="" THEN GOTO 991 992 LET U$=INKEY$ 993 IF U$="N" OR U$="R" OR U$="S" THEN GOTO 998 994 PRINT AT 0,0;"INVALID ENTRY -- REENTER. " 995 PAUSE 30 996 PRINT AT 0,0;" " 997 GOTO 990 998 IF U$="N" THEN GOTO 1061 999 IF U$="R" THEN GOTO 1010 1000 STOP 1010 CLS 1011 GOTO 2 1061 LET BMN=BMN+1 1062 IF BMN<=12 THEN GOTO 76 1063 LET BMN=BMN-12 1064 LET BYR=BYR+1 1066 GOTO 76 ```