--- title: "Rotate Character" id: 71244 type: "computer_media" slug: "rotate-character" url: "http://localhost/computer_media/rotate-character/" markdown_url: "http://localhost/computer_media/rotate-character.md" published_at: "2026-08-30T19:55:26+00:00" modified_at: "2026-08-30T19:55:27+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/08/rotate-character.png" alt: "Rotate Character screen" excerpt: "This program reads any user-defined graphic character, transposes its 8×8 bit matrix, and POKEs the rotated result back into memory for instant display." 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: "Utility" slug: "utility" taxonomy: "genre" url: "http://localhost/type/utility/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Rotate%20Character%20%28198x%29%28-%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/08/rotate-character.png" alt: "Rotate Character screen" media_type_tags: "Utility" --- # Rotate Character Rotate Character reads a user-defined graphic (UDG) character entered in graphics mode, extracts its 8×8 pixel bitmap by PEEKing the eight bytes from USR memory, transposes the bit matrix into a two-dimensional array, then rebuilds and POKEs the rotated bitmap back into the UDG’s memory location. The pixel extraction loop unpacks each byte bit-by-bit using successive halving of an initial value of 128, storing results in a DIM Z(8,8) array. The transposed matrix is then repacked into bytes and displayed using block graphic characters alongside the POKE operation. Lines 1000–1040 preload UDG “a” with a sample character (the DATA values 252,128,128,248,128,128,128,252) so the program has a ready-made graphic to demonstrate the rotation effect. *** ### Program Structure The program divides into three logical sections: 1. **Setup and input (lines 1–6):** Sets display colors, prints a title, prompts the user to enter a UDG letter (a–u) in graphics mode, and validates the input. 2. **Rotation engine (lines 10–150):** Extracts the 8×8 bitmap via PEEK, stores it in a 2-D array, transposes it, repacks bytes, POKEs them back, and displays the result. 3. **UDG preloader (lines 1000–1040):** Seeds UDG “a” with a sample L-shaped character so the user has an immediate test case. ### Input Validation Bug Line 6 contains a logical error in the validation condition: ``` 6 IF A$<"a" OR "a">"u" THEN GO TO 5 ``` The second operand of `OR` should be `A$>"u"`, not the constant expression `"a">"u"`. Because `"a">"u"` is always `0` (false), the upper-bound check is never performed. Any string less than `"a"` correctly re-prompts, but characters beyond `"u"` are silently accepted, potentially PEEKing and POKEing beyond the UDG area. ### Bitmap Extraction (Lines 40–90) `DIM Z(8,8)` allocates an 8×8 numeric array. The outer loop iterates over the 8 rows (bytes) of the UDG; the inner loop unpacks each row bit-by-bit. Starting with `X=128` and halving after each bit, the code subtracts `X` from the current byte value when the result is non-negative — the standard ZX Spectrum bit-test idiom. The extracted bit (1 or 0) is stored at `Z(Q,W)` where `Q` is the column index (1–8) and `W` counts down from 8 to 1, achieving a 90° transpose. ### Bitmap Repacking and Display (Lines 100–140) The second double loop reads the transposed array row by row. For each set bit it accumulates a byte value using `A=A+B` (where `B` starts at 128 and halves), mirrors a block graphic character (`\::` — the full block █) to the screen, and otherwise prints a space. After each row, `POKE C,A` writes the new byte directly into UDG RAM and advances pointer `C`. ### Key Variables | Variable | Role | | --- | --- | | `A$` | UDG letter entered by user | | `A` | Current PEEK address (walks through 8 UDG bytes) | | `C` | Base POKE address (saved copy of USR A$) | | `Z(8,8)` | Intermediate transposed bit matrix | | `Q, W` | Column and row indices into Z during extraction | | `X, B` | Bit-weight accumulators (128→1) in extraction and repacking | ### Continuation Loop (Lines 155–170) After displaying the rotated graphic, line 155 prompts the user to delete graphics mode and press Y or N. Line 160 contains a second typo: `IF "R"="N"` should be `IF R$="N"`. Because the string constant `"R"` never equals `"N"`, the N branch never triggers; instead, execution falls through to the unconditional `STOP` at line 170, which coincidentally produces the correct behavior but for the wrong reason. ### UDG Preloader (Lines 1000–1040) Lines 1000–1040 are not called from the main program flow — they must be run separately (e.g., `RUN 1000`) to seed UDG “a” with the sample shape before testing the rotation routine. The DATA values `252,128,128,248,128,128,128,252` define a bold capital F or similar rectilinear form. ### Notable Techniques - Using `USR A$` to obtain the RAM address of a named UDG is idiomatic and avoids hard-coding system addresses. - The bit-extraction method (subtract powers of two from 128 downward) is a common ZX Spectrum BASIC approach since there is no bitwise AND operator in standard BASIC. - Storing intermediate bits in a floating-point array `Z(8,8)` is simple but memory-intensive; a machine code routine could perform the same transpose in microseconds. - The block graphic `\::` (█) used for display gives a visual 8×8 preview of the rotated character at PRINT resolution. ## Source Code ``` 1 INK 7:PAPER 0:BORDER 0 2 PRINT TAB 8;"ROTATE CHARACTER"''' 5 PRINT "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 PRINT "Now delete GRAPHICS mode. Press Y to continue - or N to stop" 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 ```