--- title: "Clock" id: 56850 type: "computer_media" slug: "clock-3" url: "http://localhost/computer_media/clock-3/" markdown_url: "http://localhost/computer_media/clock-3.md" published_at: "2024-09-29T07:30:34+00:00" modified_at: "2026-04-03T07:58:50+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/318_Clk.png" excerpt: "A fully animated analogue clock that draws hour markers trigonometrically and moves its hands using a hand-coded Bresenham line algorithm — all in BASIC." 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: "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/" genre: - name: "Home" slug: "home" taxonomy: "genre" url: "http://localhost/type/home/" media_contents: - id: 56738 title: "Timex Sinclair Public Domain Library Tape 1007" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1007/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/09/318_Clk.png" media_type_tags: "Home" --- This program implements an analogue clock display, drawing a clock face with numbered hour positions and animating minute and hour hands. The clock face is drawn using trigonometric positioning (COS and SIN with PI) to place digits 1–12 around a circle, switching to FAST mode during rendering. Line-drawing between two points is handled by a Bresenham-style integer line algorithm in the subroutine at line 1000, which uses SGN and ABS to step along the major axis while accumulating error in variable S. The minute hand is erased and redrawn each tick using PLOT/UNPLOT controlled by the variable P, with timing regulated by POKE 16437 and a PEEK busy-wait loop plus PAUSE 219. Time is input in HHMM format, with the hours variable H computed from hundreds digits and incremented at the 15- and 45-minute marks. *** ## Program Analysis ### Program Structure The program is divided into several logical sections: 1. **Initialisation (lines 12–22):** Accepts time in HHMM format, decodes hours and minutes, and pre-computes the initial hour-hand position in `H`. 2. **Clock face drawing (lines 24–65):** Clears screen, switches to FAST mode, plots hour digits 1–12 using trigonometry, then returns to SLOW mode. Sets the interrupt counter via `POKE 16437,250`. 3. **Main animation loop (lines 70–240):** Alternates between erasing the old minute-hand position (via `GOSUB 1000` with `P=0`) and drawing the new one (`P=1`), with the hour hand drawn at each tick via `GOSUB 310`. 4. **Hour-hand subroutine (lines 310–380):** Draws a line from the centre (27,22) to the hour-hand endpoint using the Bresenham subroutine. 5. **Save stub (lines 490–510):**`CLEAR`, `SAVE`, and `RUN` for persistence. 6. **Line-drawing subroutine (lines 1000–1260):** A general integer Bresenham line-draw routine controllable via `P` (1=PLOT, 0=UNPLOT). ### Time Input and Decoding Time is entered as a four-digit integer in HHMM format (e.g. 1430 for 2:30 PM). Line 16 extracts hours: `H=2*INT(T/100)` — note the factor of 2, which converts 12-hour clock hours into half-hour units matching the half-PI step used in the hour-hand calculation. Lines 18–22 strip the hour part, leaving minutes in `T`, then add 1 to `H` if past the quarter-hour and again if past the three-quarter mark, giving a coarse hour-hand position in 30-minute increments. ### Clock Face Rendering The hour numerals are positioned using: - Row: `10 - 10*COS(D/6*PI)` - Column: `13 + 10*SIN(D/6*PI)` This maps D=1..12 evenly around a circle using `PRINT AT` in character coordinates. The clock face is rendered in FAST mode (line 26) to avoid slow screen updates, then SLOW is restored (line 60) before animation begins. ### Timing Mechanism Timing is achieved through a combination of hardware manipulation and busy-waiting. `POKE 16437,250` sets the ZX81 frame counter (FRAMES system variable at address 16437) to 250. The loop at line 230 polls `PEEK 16437` until it falls below 241, effectively waiting approximately 9 frame intervals (~9/50 s). `PAUSE 219` at line 235 then waits a further 219 frames, giving a combined delay approximating one minute per tick of the minute hand — though this is a rough approximation rather than a precise real-time second counter. ### Bresenham Line Algorithm (lines 1000–1260) The subroutine implements a Bresenham-style integer line algorithm. It accepts start point (`A`,`B`) implicitly set to (27,22) — the screen centre — and endpoint (`C`,`D`). Key variables: | Variable | Role | | --- | --- | | `U`, `V` | dx, dy from centre to endpoint | | `O`, `L` | SGN of dx, dy (step direction) | | `Z`, `Q` | Major-axis step (0 or SGN) | | `M`, `N` | Major and minor axis lengths | | `S` | Bresenham error accumulator, initialised to M/2 | | `P` | 1 = PLOT, 0 = UNPLOT | The algorithm swaps axes if the vertical span is larger than the horizontal (lines 1080–1120), ensuring it always steps along the longer dimension. Error accumulation occurs at line 1170 (`S=S+N`), with the diagonal step taken when `S≥M`. Note that lines 1040 (`LET Z=SGN U`) and 1130 (absent — the label after the conditional block) reveal a minor structural issue: line 1040 initialises `Z` to `SGN U`, but this is immediately overridden by line 1090 (`LET Z=0`) if the vertical span dominates, so the initialisation at 1040 is only effective when M≤N is false — which is correct behaviour. However, there is no line 1130 in the listing (the FOR loop at 1150 follows directly), indicating the `GOTO 1130` at line 1080 jumps to line 1140 as the next available line — a standard ZX81 BASIC behaviour where GO TO targets the nearest line at or above the specified number. ### Hand Erase-Redraw Cycle The animation loop erases the previous minute-hand position before drawing the new one. At line 80, `P` is set to 0 (UNPLOT mode) and the old endpoint (`X`,`Y`) is used to call the line subroutine, erasing the hand. Then `P=1` and the new endpoint is computed and plotted. The hour hand (subroutine at line 310) is drawn after each minute update but is never explicitly erased, relying on the clock-face redraw (GOTO 24 at line 260) when the hour changes. ### Notable Idioms and Anomalies - The factor of 2 in `H=2*INT(T/100)` and the use of `H/12*PI` for the hour-hand angle means the hour hand completes a half-turn (`PI` radians) per 12 increments of `H` — correctly placing it at the top (12 o’clock) when H=0 and at the bottom (6 o’clock) when H=12. - The minute-hand angle uses `T/30*PI`, mapping 0–59 minutes to 0–~2PI correctly. - Lines 140 and 260 handle the quarter-hour increments of the hour hand: at T=16 or T=46 (just past the quarter and three-quarter marks), the program jumps to line 250, increments `H`, and redraws the full clock face. - The `CLEAR` at line 490 before the SAVE is unusual; it would erase all variables before saving, meaning the saved program starts fresh on load. ## Source Code ``` 12 PRINT " INPUT TIME" 14 INPUT T 16 LET H=2*INT (T/100) 18 LET T=T-100*INT (T/100) 20 IF T>15 THEN LET H=H+1 22 IF T>45 THEN LET H=H+1 24 CLS 26 FAST 30 FOR D=1 TO 12 40 PRINT AT 10-10*COS (D/6*PI),13+10*SIN (D/6*PI);D 50 NEXT D 60 SLOW 65 POKE 16437,250 70 GOTO 150 80 LET P=0 90 LET C=X 100 LET D=Y 110 GOSUB 1000 120 LET T=T+1 130 IF T=60 THEN LET T=0 140 IF T=16 OR T=46 THEN GOTO 250 150 LET P=1 160 LET L=T/30*PI 170 LET X=27+18*SIN L 180 LET Y=22+18*COS L 190 LET C=X 200 LET D=Y 210 GOSUB 1000 220 GOSUB 310 230 IF PEEK 16437>241 THEN GOTO 230 235 PAUSE 219 240 GOTO 80 250 LET H=H+1 260 GOTO 24 310 LET P=1 320 LET A=27 330 LET B=22 340 LET G=H/12*PI 350 LET C=27+12*SIN G 360 LET D=22+12*COS G 370 GOSUB 1000 380 RETURN 490 CLEAR 500 SAVE "1031%8" 510 RUN 1000 LET A=27 1002 LET B=22 1008 LET U=C-A 1010 LET V=D-B 1020 LET O=SGN U 1030 LET L=SGN V 1040 LET Z=SGN U 1050 LET Q=0 1060 LET M=ABS U 1070 LET N=ABS V 1080 IF M>N THEN GOTO 1130 1090 LET Z=0 1100 LET Q=SGN V 1110 LET M=ABS V 1120 LET N=ABS U 1140 LET S=INT (M/2) 1150 FOR I=0 TO M 1160 IF P=1 THEN PLOT A,B 1165 IF P=0 THEN UNPLOT A,B 1170 LET S=S+N 1180 IF S