--- title: "Patterns" id: 64746 type: "computer_media" slug: "patterns-3" url: "http://localhost/computer_media/patterns-3/" markdown_url: "http://localhost/computer_media/patterns-3.md" published_at: "2026-03-07T14:47:07+00:00" modified_at: "2026-03-30T21:44:38+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/03/patterns.png" excerpt: "Draw a 16×16 pixel pattern, watch it spin through four rotations encoded as UDGs, then scroll it freely around the screen." 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 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Graphics" slug: "graphics" taxonomy: "genre" url: "http://localhost/type/graphics/" media_contents: - id: 64715 title: "Miscellaneous Programs" type: "computer_media" url: "http://localhost/computer_media/miscellaneous-programs/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/03/patterns.png" media_type_tags: "Graphics" --- # Patterns This program lets the user draw a 16×16 binary pixel pattern on screen, then animates it by repeatedly rotating the pattern 90 degrees and encoding each row into UDG (User Defined Graphics) characters. The 16×16 grid is entered cell by cell using key “1” for a filled pixel or any other key for blank, with FLASH and BRIGHT attributes highlighting the current cell. The encoded pattern is displayed as a 2×2 block of UDGs that can be scrolled around the screen using keys 5, 6, 7, and 8. The rotation is performed in BASIC by transposing the matrix into a second string array B$ and copying back into A$, repeating four times to cycle through all orientations. SAVE at line 440 uses the expression `PI` (≈3.14159, truncated to 3) as the auto-start line number, which is a known memory-optimisation trick. *** ## Program Structure The program is organised into several logical phases controlled by `GO SUB` calls: 1. **Initialisation (line 280 → 360–430):** Clears the screen, prints instructions, draws a 16×16 grid with `PLOT`/`DRAW`, and sets up variables including `N1=1`, `DIM A$(16,16)`, and `DIM B$(16,16)`. 2. **Pattern entry (lines 300–350):** Iterates over every cell of the 16×16 grid, flashes the cursor, waits for a keypress with `PAUSE 0`, records “1” or space, and prints a block character if “1” was pressed. 3. **UDG encoding and rotation loop (lines 20–120):** Iterates four times (B = 144, 148, 152, 156), encodes eight rows of A$ into four UDGs per iteration using `FN C`, then rotates the grid 90° using B$ as a buffer. 4. **Playback / movement (lines 130–230):** Plays a brief ascending/descending beep sequence, then enters an event loop reading keys 5/6/7/8 to move and redisplay the 2×2 UDG block. ## UDG Encoding — FN C The function defined at line 380 converts an 8-character substring of A$ into a single UDG byte:`DEF FN C(L$) = (128 AND L$(1)="1") + (64 AND L$(2)="1") + ... + (1 AND L$(8)="1")` Each of the eight characters in the substring contributes its positional bit-weight if and only if it equals `"1"`. This exploits the Spectrum BASIC convention that boolean `AND` returns the left operand if the condition is true, or 0 otherwise, producing a clean bitmap byte without any explicit branching. ## 90-Degree Rotation Lines 90–120 perform an in-place 90° clockwise rotation of the 16×16 string matrix. The algorithm uses B$ as a scratch buffer: - `LET B$(I,J) = A$(J, 17-I)` — reads the transposed and column-reversed element (equivalent to a 90° clockwise rotation). - `LET A$(I) = B$(I)` — copies each row of B$ back into A$ immediately after computing it. This rotation is applied inside the outer `FOR B=144 TO 159 STEP 4` loop, so all four 90° rotations (0°, 90°, 180°, 270°) are encoded into UDG slots 144–159 successively before the display phase begins. ## UDG Layout Each orientation of the pattern occupies four consecutive UDGs covering a 2×2 character cell (16×16 pixels): | B value | UDGs used | Orientation | | --- | --- | --- | | 144 | \a \b / \c \d (144–147) | 0° | | 148 | 148–151 | 90° | | 152 | 152–155 | 180° | | 156 | 156–159 | 270° | The encoding fills the top-left quadrant (rows 0–7, cols 0–7) into the first UDG, top-right into the second, bottom-left into the third, and bottom-right into the fourth, using the `9 TO` string slice to select the right half of each row. ## Movement Dispatch — Computed GO SUB Lines 180–200 implement a four-way keypress dispatcher without an `IF` chain:`LET B=(10 AND T$="5")+(20 AND T$="6")+(30 AND T$="7")+(40 AND T$="8")` Only one term is non-zero at a time, giving B a value of 10, 20, 30, or 40. `GO SUB 230+B` then jumps to line 240, 250, 260, or 270 respectively — each subroutine sets the active UDG base (`CH`) and adjusts the screen position (`R`, `C`) with clamped arithmetic before returning. ## Notable Idioms and Techniques - `NOT PI` evaluates to `NOT 3.14159… = 0`, used as a zero literal in `FOR I=NOT PI TO 7` and elsewhere. This saves bytes over typing `0` in some tokenised forms. - `N1=1` is set once at line 370 and reused throughout as a numeric constant, saving tokenised space compared to repeated literal `1`s, particularly inside the long `DEF FN` at line 380. - Boundary clamping uses boolean arithmetic: e.g. `C=C-2*(C>2)` subtracts 2 only when C is already greater than 2, avoiding `IF` statements. - `SAVE "PATTERNS" LINE PI` at line 440 saves with auto-start line 3 (INT of PI), which does not correspond to a program line and will simply run from line 10 — a harmless quirk. - The grid-drawing routine (lines 390–420) uses `PLOT`/`DRAW` for the border lines and `PRINT … OVER 1` for the horizontal interior lines, mixing pixel and character graphics. ## Source Code ``` 10 GO SUB 280 20 FOR B=144 TO 159 STEP 4 30 FOR I=NOT PI TO 7 40 POKE USR CHR$ (B)+I,FN C(A$(I+N1)) 50 POKE USR CHR$ (B+N1)+I,FN C(A$(I+N1,9 TO )) 60 POKE USR CHR$ (B+2)+I,FN C(A$(I+9)) 70 POKE USR CHR$ (B+3)+I,FN C(A$(I+9,9 TO )) 80 NEXT I 90 FOR I=N1 TO 16: FOR J=N1 TO 16 100 LET B$(I,J)=A$(J,17-I) 110 NEXT J: LET A$(I)=B$(I) 120 NEXT I: NEXT B: CLS 130 FOR I=R TO 20 STEP 2: BEEP .075,I: NEXT I 140 FOR I=I TO R STEP -2: BEEP .075,I: NEXT I 150 PRINT " USE 5,6,7,& 8 TO MOVE PATTERN" 160 PRINT AT R,C;"\a\b";TAB C;"\c\d" 170 LET T$=INKEY$ 180 LET B=(10 AND T$="5")+(20 AND T$="6")+(30 AND T$="7")+(40 AND T$="8") 190 IF NOT B THEN GO TO 170 200 GO SUB 230+B 210 PRINT AT R,C;CHR$ CH;CHR$ (CH+N1) 220 PRINT AT R+N1,C;CHR$ (CH+2);CHR$ (CH+3) 230 GO TO 170 240 LET CH=148: LET C=C-2*(C>2): RETURN 250 LET CH=152: LET R=R+2*(R<19): RETURN 260 LET CH=144: LET R=R-2*(R>2): RETURN 270 LET CH=156: LET C=C+2*(C<29): RETURN 280 CLS : PRINT "PLEASE FILL THIS 16X16 SQUARE. USE ""1"" TO PAINT AND ANY OTHER KEY FOR A BLANK" 290 GO SUB 360 300 FOR I=N1 TO 16 310 FOR J=N1 TO 16: LET R=5+I: LET C=7+J 320 PRINT AT R,C; FLASH N1; BRIGHT N1; OVER N1;" ": PAUSE 0: LET A$(I,J)=INKEY$ 330 PRINT AT R,C; FLASH 0; BRIGHT N1; OVER N1;" " 340 IF A$(I,J)="1" THEN PRINT AT R,C;"█" 350 NEXT J: NEXT I: LET R=10: LET C=15: RETURN 360 PRINT AT 6,8; 370 LET N1=1: DIM A$(16,16): DIM B$(16,16) 380 DEF FN C(L$)=(128 AND L$(N1)="1")+(64 AND L$(2)="1")+(32 AND L$(3)="1")+(16 AND L$(4)="1")+(8 AND L$(5)="1")+(4 AND L$(6)="1")+(2 AND L$(7)="1")+(1 AND L$(8)="1") 390 FOR I=NOT PI TO 128 STEP 8 400 PLOT 64,128-I: DRAW 128,0 410 PLOT 64+I,128: DRAW 0,-128 420 IF I<128 THEN PRINT TAB 8; BRIGHT N1; OVER N1;" " 430 NEXT I: RETURN 440 SAVE "PATTERNS" LINE PI ```