--- title: "Four Stroke" id: 71420 type: "computer_media" slug: "four-stroke" url: "http://localhost/computer_media/four-stroke/" markdown_url: "http://localhost/computer_media/four-stroke.md" published_at: "2026-09-09T09:01:03+00:00" modified_at: "2026-09-09T09:01:04+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/09/four-stroke.png" excerpt: "An animated four-stroke engine diagram cycles through induction, compression, ignition, and exhaust using custom-designed graphics and a piston that really moves." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "1988" slug: "year-1988" taxonomy: "post_tag" url: "http://localhost/tag/year-1988/" - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" basic: - name: "User Defined Graphics (UDG)" slug: "user-defined-graphics-udg" taxonomy: "basic" url: "http://localhost/basic/user-defined-graphics-udg/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Demo" slug: "demo" taxonomy: "genre" url: "http://localhost/type/demo/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Four%20Stroke%20(1988)(-)(TS2068)(CA)(Program).zip" tsrun_member: "Four Stroke (1988)(-)(TS2068)(CA)(Program).tap" mediadate: "1988" images: - url: "http://localhost/wp-content/uploads/2026/09/four-stroke.png" media_type_tags: "Demo" --- # Four Stroke Four Stroke Engine is an animated educational demonstration that illustrates the four stages of an internal combustion engine — induction, compression, ignition, and exhaust — using user-defined graphics (UDGs) to render a cylinder, piston, valves, and spark plug. Eleven UDGs are defined at runtime by reading DATA values and POKEing them into memory via USR. The animation loop cycles through the four strokes continuously, with the piston position controlled by a FOR-NEXT loop iterating rows 9 to 15 and back, and a PAUSE 15 delay between frames to regulate speed. A pause routine triggered by the “P” key allows the user to freeze the animation, continue with “C”, or quit with “S”. Labels for the engine components (spark plug, inlet manifold, exhaust manifold, cylinder, piston) are printed as static text around the animated diagram. *** ### Program Structure The program is organized into clearly delineated sections, each preceded by a REM comment using decorative block-graphic borders. The main flow is: 1. Lines 10–60: Title screen with flashing text, then call UDG setup subroutine. 2. Lines 70–180: Draw the static cylinder outline using PLOT/DRAW, print static labels (via subroutine at 540), and display the control hint bar. 3. Lines 190–470: Main animation loop cycling through four strokes — Induction (200–250), Compression (270–310), Ignition (330–380), Exhaust (400–460) — then GO TO 190 to repeat. 4. Lines 480–530: Pause/stop subroutine. 5. Lines 540–610: Static label printing subroutine. 6. Lines 615–830: UDG definition subroutine with DATA. 7. Line 840: SAVE with autorun. ### User-Defined Graphics Eleven UDGs are defined by the subroutine starting at line 620. The character string `a$` at line 630 lists the UDG characters in the order their DATA rows appear: `\\e\\f\\g\\h\\i\\j` form the piston body (top-left, top-middle×3, top-right, bottom-left, bottom-middle×3, bottom-right), `\\a\\b` are the connecting rod or valve graphics, `\\k` is the spark flash, `\\d` is the intake/exhaust flow indicator, and `\\c` is a valve graphic. DATA is read sequentially (8 bytes per UDG) and POKEd via `USR b$`, which resolves to the base address of that UDG’s bitmap in the system font area. Notably, many DATA lines contain `c` as a literal value (lines 740–830). Within the DATA context this is the numeric variable `c`, which is uninitialized and defaults to 0 in Sinclair BASIC. This is an intentional technique to embed zero bytes without typing “0” repeatedly — it reads as valid BASIC and evaluates to 0 at runtime. ### Animation Technique Each of the four stroke phases uses a FOR-NEXT loop on variable `n` ranging from 9 to 15 (piston descending) or 15 to 9 STEP -1 (piston ascending). On each iteration, the previous piston row is erased with spaces and the piston UDG block is reprinted at the new row, creating smooth vertical movement within the cylinder. `PAUSE 15` (roughly half a second) paces the animation; the hint line tells the user any keypress speeds it up (via INKEY$ shortcutting the PAUSE). ### Cylinder Drawing with PLOT/DRAW The cylinder walls are drawn using pixel-level PLOT and DRAW commands rather than character graphics, giving a precise outline independent of the character grid. The left wall is drawn from (96,130) and the right from (152,130), with short horizontal segments representing valve apertures. The values `NOT PI` evaluate to 0 (since PI is non-zero, NOT PI = 0 in Sinclair BASIC), so `DRAW NOT PI, -84` draws a vertical line of 84 pixels — a common idiom for embedding zero without the digit. ### Key BASIC Idioms - `NOT PI` evaluates to 0; used extensively in DRAW, PRINT AT column, and INK arguments as a compact zero literal. - `SGN PI` evaluates to 1 (since PI > 0); used in `BRIGHT SGN PI` and `INK SGN PI` to set attributes to 1 without the literal digit. - `POKE 23658,8` at line 30 enables CAPS LOCK (sets the caps-shift flag), ensuring consistent keyboard input behavior. - `RESTORE 620` at line 620 resets the DATA pointer to line 620 — since there is no DATA before line 730, this effectively resets to the first DATA line. It ensures the UDG routine works correctly if called after any prior READ. ### Pause and Stop Subroutine The pause subroutine (lines 480–530) uses `PAUSE 0` to wait indefinitely for a keypress, then checks INKEY$ for “C” (continue) or “S” (stop). The loop at line 530 (`GO TO 490`) re-enters the pause and re-issues `PAUSE 0` if neither key is pressed, preventing spurious returns. The “P” key check in the main animation loops (lines 240, 440) is a simple `IF INKEY$="P" THEN GO SUB 480`; it is only polled once per animation frame rather than continuously. ### Stroke Phase Details | Stroke | Lines | Piston Direction | Valve/Effect | | --- | --- | --- | --- | | Induction | 200–250 | Down (9→15) | Inlet valve open (`\\c`), fuel symbol (`\\d\\d`) | | Compression | 270–310 | Up (15→9) | Valve closed, label “Compression” | | Ignition | 330–380 | Down (9→15) | Spark UDG (`\\k`) with FLASH 1 | | Exhaust | 400–450 | Up (15→9) | Exhaust valve indicator (`\\d\\d`), label “Exhaust” | ### Potential Anomalies - Line 740 contains `DATA 255,0,255,0,255,0,c,c` — the trailing `c` values rely on the variable `c` being 0 (from the POKE loop at line 700 where `c` is the READ target, last assigned the final byte of the previous UDG). This is fragile but works in practice because after the first UDG is fully read, `c` holds the last byte (128 from line 730), not 0. However the DATA for UDG \\f (line 740) ends with two `c` bytes which would be 128, not 0 — this may result in slightly incorrect bitmaps for those UDGs, giving unexpected pixel rows, though the visual effect may be minor or intentional. - The “PRESS P TO PAUSE / ANY KEY TO SPEED UP” hint at line 180 is only 64 characters and wraps onto two screen rows as intended, but the P-key check is absent in the Compression and Ignition loops (lines 280–310, 340–380), meaning pausing is only possible during Induction and Exhaust strokes. ## Source Code ``` 10 REM ZX-Appeal June/88, p.15 20 \{20}\{1} REM \{20}\{0}<>four stroke engine<> 30 BORDER 1:PAPER 6:INK 2:CLS :POKE 23658,8 40 PRINT FLASH 1; PAPER 7; AT 7,14; INK 3;"FOUR"; AT 9,13; INK 1;"STROKE"; AT 11,13; INK 4;"ENGINE" 60 GO SUB 620 70 \{20}\{1} REM \{20}\{0}<><>build cylinder<><> 80 BORDER PI:PAPER 7:CLS 90 PRINT BRIGHT SGN PI; AT NOT PI,7; INK SGN PI;"FOUR STROKE ENGINE" 100 PLOT 96,130 110 DRAW 10, NOT PI:DRAW NOT PI,-10:DRAW -3, NOT PI:DRAW NOT PI,-84 120 PLOT 96,134 130 DRAW 14, NOT PI:DRAW NOT PI,-14:DRAW 28, NOT PI:DRAW NOT PI,14:DRAW 14,0 140 PLOT 152,130 150 DRAW -10, NOT PI:DRAW NOT PI,-10:DRAW 2, NOT PI:DRAW NOT PI,-84 160 PRINT INK NOT PI; AT 6,15;"\a"; AT 7,15;"\b" 170 GO SUB 540 180 PRINT AT 20, NOT PI; INK 1; PAPER 6;"********PRESS P TO PAUSE**************ANY KEY TO SPEED UP*******" 190 \{20}\{1} REM \{20}\{0} <><><>induction<><><> 200 PRINT AT 7,17; INK NOT PI;"\c"; INK 7; PAPER 1; AT 9,1;"Induction"; AT 5,10; INK 2; PAPER 7;"\d\d"; AT 5,19;" " 210 FOR n=9 TO 15 220 PRINT INK 1; PAPER 7; AT n-1,13;" "; AT n,13; PAPER 6;"\e\f\f\f\g"; AT n+1,13; PAPER 6;"\h\i\i\i\j" 230 PAUSE 15 240 IF INKEY$="P" THEN GO SUB 480 250 NEXT n 260 \{20}\{1} REM \{20}\{0}<><><>compression<><><> 270 PRINT AT 7,13; INK 0;"\c"; AT 9,1; INK 7; PAPER 1;"Compression"; AT 5,10; PAPER 7;" " 280 FOR n=15 TO 9 STEP -1 290 PRINT INK 1; AT n+2,13; PAPER 7;" "; AT n,13; PAPER 6;"\e\f\f\f\g"; AT n+1,13; PAPER 6;"\h\i\i\i\j" 300 PAUSE 15 310 NEXT n 320 \{20}\{1} REM \{20}\{0} <><><>ignition<><><> 330 PRINT AT 9,1; INK 7; PAPER 1;"Ignition " 340 FOR n=9 TO 15 350 PRINT AT 8,15; FLASH 1; INK 2; PAPER 6;"\k" 360 PRINT INK 1; AT n-1,13; PAPER 7;" "; AT n,13; PAPER 6;"\e\f\f\f\g"; AT n+1,13; PAPER 6;"\h\i\i\i\j" 370 PAUSE 15 380 NEXT n 390 \{20}\{1} REM \{20}\{0} <><><>exhaust<><><> 400 PRINT PAPER 7; AT 7,17;" "; AT 8,15;" "; AT 9,1; INK 7; PAPER 1;"Exhaust "; AT 5,19; INK 2; PAPER 7;"\d\d" 410 FOR n=15 TO 9 STEP -1 420 PRINT INK 1; AT n+2,13; PAPER 7;" "; AT n,13; PAPER 6;"\e\f\f\f\g"; AT n+1,13; PAPER 6;"\h\i\i\i\j" 430 PAUSE 15 440 IF INKEY$="P" THEN GO SUB 480 450 NEXT n 460 PRINT AT 7,13; INK 0;" " 470 GO TO 190 480 \{20}\{1} REM \{20}\{0} <><>pause routine<><> 490 PRINT AT 21,0; INK 1; PAPER 6;"*PRESS C TO CONTINUE S TO STOP**" 500 PAUSE 0 510 IF INKEY$="C" THEN PRINT AT 21,0; INK 1; PAPER 6;"********PRESS P TO PAUSE********":RETURN 520 IF INKEY$="S" THEN PRINT AT 21,0; INK 1; PAPER 6;"****HAPPY MOTORING - GOODBYE****":STOP 530 GO TO 490 540 \{20}\{1} REM \{20}\{0}<><><><>labels<><><><> 550 PRINT AT 3,13; INK 0;"spark" 560 PRINT AT 4,1; INK 0;"inlet plug exhaust" 570 PRINT AT 5,1; INK 0;"manifold" 580 PRINT AT 5,22; INK 0;"manifold" 590 PRINT AT 9,19; INK 0;"cylinder" 600 PRINT AT 19,13; INK 0;"piston" 610 RETURN 615 \{20}\{1} REM \{20}\{0}<>user defined graphics 620 RESTORE 620 630 LET a$="\e\f\g\h\i\j\a\b\k\d\c" 640 LET n=0 650 LET n=n+1 660 IF n>11 THEN RETURN 670 LET b$=a$(n) 680 FOR m=0 TO 7 690 READ c 700 POKE USR b$+m,c 710 NEXT m 720 GO TO 650 730 DATA 255,128,255,128,255,128,128,128 740 DATA 255,0,255,0,255,0,c,c 750 DATA 255,1,255,1,255,0,1,c 760 DATA 128,c,c,192,224,176,152,255 770 DATA 0,c,c,c,c,c,c,255 780 DATA 1,c,c,3,7,13,25,255 790 DATA 16,c,56,c,c,124,c,255 800 DATA 56,c,c,40,c,32,56,0 810 DATA 128,200,108,54,11,1,0,c 820 DATA 24,12,254,255,254,12,24,0 830 DATA 60,c,0,c,c,c,c,c 840 SAVE "engine" LINE 10 ```