--- title: "4 Way Rotate" id: 70749 type: "computer_media" slug: "4wrotate" url: "http://localhost/computer_media/4wrotate/" markdown_url: "http://localhost/computer_media/4wrotate.md" published_at: "2026-08-23T15:08:15+00:00" modified_at: "2026-08-23T16:59:02+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/08/4w-rotate.png" alt: "4wrotate screen" excerpt: "Rotate any user-defined graphic character 90 degrees in place — this BASIC program reads, transforms, and rewrites UDG pixel data live in memory." 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: "Demo" slug: "demo" taxonomy: "genre" url: "http://localhost/type/demo/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/4wrotate%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" tsrun_member: "4wrotate.tap" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/08/4w-rotate.png" alt: "4wrotate screen" media_type_tags: "Demo" --- # 4 Way Rotate This program rotates a user-defined graphic (UDG) character 90 degrees and writes the transformed pixel data back into UDG memory. The user selects a UDG by letter (“a” through “u”), and the program reads its 8×8 pixel bitmap from RAM using PEEK, stores it in a two-dimensional array Z(8,8), then recomputes the rotated byte values and POKEs them back with POKE. A DATA block at lines 1000–1040 preloads UDG “a” with an F-shaped pattern (bytes 252,128,128,248,128,128,128,252) to serve as a demonstration. After rotation, the new glyph is displayed on-screen using block graphic characters, and the program loops back to allow repeated rotations. *** ### Program Structure The program divides into three functional sections: 1. **Setup and UDG preload (lines 1000–1040):** A `FOR`/`READ`/`POKE` loop loads eight bytes into UDG “a”, providing a ready-made test character. 2. **Input and validation (lines 1–6):** The user is prompted to enter a UDG letter. A boundary check on line 6 is intended to restrict input to “a”–”u”. 3. **Rotation engine and display (lines 10–155):** The core algorithm reads pixel bits from UDG RAM, stores them in a 2D array, then writes the 90-degree-rotated result back and displays it. ### Rotation Algorithm The rotation proceeds in two passes. The first pass (lines 40–90) PEEKs each of the eight bytes of the selected UDG starting at `USR A$`, and decodes individual pixel bits by repeatedly subtracting powers of two (starting from 128, halving each iteration). Each bit is stored in array `Z(Q,W)` where `Q` is the column index (1–8) and `W` is the row index counting down from 8 to 1, effectively transposing the bit matrix. The second pass (lines 100–140) iterates over rows of `Z`, accumulates each row back into a byte by multiplying set-bit positions by descending powers of two, and POKEs the result into UDG RAM. This achieves a 90-degree clockwise rotation of the character bitmap. ### Key BASIC Idioms - `LET A=USR A$` on line 10 retrieves the RAM address of the UDG corresponding to the entered letter, using the built-in `USR` function with a string argument. - The bit-extraction loop uses successive halving of `X` (128, 64, 32, … 1) and a conditional subtraction to test each bit without bitwise operators, a common technique in Spectrum BASIC. - `POKE C,A` on line 140 writes the reconstructed rotated byte directly into UDG memory, immediately affecting how the character renders. - Line 130 prints a block graphic `█` character for set pixels, giving a visual preview of the rotated glyph. ### Bugs and Anomalies | Location | Issue | | --- | --- | | Line 6 | The validation condition `IF A$<"a" OR "a">"u"` is incorrect. The second operand should be `A$>"u"`; as written, `"a">"u"` is always false, so only the lower bound is enforced. Any letter after “a” passes without an upper-bound check. | | Line 155 | `GO TO 10` jumps back into the rotation loop rather than to the input prompt (line 5), re-running the rotation on the same character infinitely without asking for new input. Line 160 is unreachable under normal flow. | | Line 160 | `IF "R"="N"` is a literal string comparison that is always false; it should presumably read `IF R$="N"`. | | Lines 1000–1040 | This subroutine is never called from the main program; it must be run first manually or invoked via `GO SUB` from the command line to preload UDG “a”. | ### Notable Techniques Using `DIM Z(8,8)` as an intermediate pixel store avoids the need for any machine code; the entire rotation is accomplished in pure BASIC with arithmetic. The approach of saving the original UDG address in variable `C` at line 10 and advancing `C` in the write-back loop (line 140) mirrors the read-loop pointer `A`, keeping the two passes symmetric and avoiding address recalculation. ## Source Code ``` 1 INK 7: PAPER 0: BORDER 0 2 PRINT TAB 8;"ROTATE CHARACTER"''' 5 PRINT TAB 5;"GO TO GRAPHICS MODE !!!": PAUSE 180: CLS : INPUT "CHARACTER TO BE ROTATED ? "; LINE A$ 6 IF A$<"a" OR "a">"u" THEN GO TO 5 10 LET A=USR A$: LET C=A 20 LET Q=1: LET W=8 40 DIM Z(8,8): FOR D=1 TO 8 50 LET X=128: LET B=PEEK A 60 FOR F=1 TO 8 70 IF (B-X)>=0 THEN LET B=B-X: LET Z(Q,W)=1 80 LET X=X/2: LET Q=Q+1 90 NEXT F: LET Q=1: LET W=W-1: LET A=A+1: NEXT D 100 FOR X=1 TO 8: LET A=0: LET B=128 110 FOR Y=1 TO 8 120 IF Z(X,Y)=0 THEN PRINT " ";: GO TO 140 130 LET A=A+B: PRINT "█"; 140 LET B=B/2: NEXT Y: POKE C,A: LET C=C+1: PRINT : NEXT X 150 PRINT : PRINT "LOOK AT THE NEW GRAPHIC '";a$;"'!"'''' 155 PAUSE 120: CLS : GO TO 10 160 INPUT "Y OR N ";R$: CLS : IF R$="Y" THEN GO TO 5: IF "R"="N" THEN STOP 170 STOP 1000 FOR n=USR "a" TO USR "a"+7 1010 READ user: POKE n,user 1030 NEXT n 1040 DATA 252,128,128,248,128,128,128,252 ```