--- title: "Mental Mania" id: 55103 type: "computer_media" slug: "men-man" url: "http://localhost/computer_media/men-man/" markdown_url: "http://localhost/computer_media/men-man.md" published_at: "2024-06-16T14:43:39+00:00" modified_at: "2026-03-30T21:43:38+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A five-disc Tower of Hanoi challenge with joystick support, colorful block-graphic discs, a 100-move limit, and a printer-ready move history." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" - name: "Games" slug: "games" taxonomy: "category" url: "http://localhost/category/software/games/" 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/" indiv: - name: "James DuPuy" slug: "james-dupuy" taxonomy: "indiv" url: "http://localhost/indiv/james-dupuy/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 54965 title: "ISTUG Public Domain Library 5" type: "computer_media" url: "http://localhost/computer_media/istug-public-domain-library-5/" media_type: "Program" programmers: - name: "James DuPuy" slug: "james-dupuy" taxonomy: "indiv" url: "http://localhost/indiv/james-dupuy/" mediadate: "1984" images: - url: "http://localhost/wp-content/uploads/2024/06/SCR-20260329-nglv.png" - url: "http://localhost/wp-content/uploads/2024/06/SCR-20260329-nggu.png" media_type_tags: "Game" --- # Mental Mania Tower of Hanoi puzzle game for five discs across three pegs. The player must move all five discs from peg 1 to peg 3 without placing a larger disc on a smaller one, within a 100-move limit. Disc graphics are built from block-graphic strings stored in a DIM’d string array `d$(5,10)`, with each disc rendered in a different INK color using `INK (6-P(N,O))`. The game supports both keyboard input (keys 1–3) and joystick input via the `STICK` function, reading directional values 1, 4, and 8. A high-score tracker persists across replays, and completed move sequences can be printed via `LPRINT` and `COPY`. *** ## Program Analysis ### Program Structure The program is organized into clearly labeled subroutines and sections separated by `REM` statements. Execution begins at line `1110` (initialization), which is reached via `GO TO 1110` at line `20`. After initialization, control flows to `140` (instructions/input setup), then into the main game loop starting at line `210`. 1. **Lines 1100–1270:** Initialization — POKE keyboard repeat, set high score, define disc strings, populate peg array, draw screen. 2. **Lines 30–130:** Display subroutines — draw pegs (`GO SUB 40`) and draw all discs (`GO SUB 60`). 3. **Lines 140–190:** Pre-game setup — instructions, joystick/keyboard selection, border drawing. 4. **Lines 200–530:** Main game loop — move input, validation, array update, win check. 5. **Lines 540–680:** Move validation subroutines — “FROM” check (`GO SUB 550`) and “TO” check (entered via `GO TO 620`). 6. **Lines 690–780:** Joystick input handlers for source and destination peg selection. 7. **Lines 800–930:** Win routine, move printing via LPRINT. 8. **Lines 940–1000:** Lose/quit routine and restart prompt. 9. **Lines 1010–1090:** Instructions and joystick briefing subroutines. ### Data Representation The three pegs and five disc positions are stored in a two-dimensional array `P(3,5)`, declared as `DIM p(PI,5)` — an interesting idiom that uses `PI` (≈3.14159) as the first dimension, which is truncated to 3 by BASIC’s integer conversion. Each cell holds the disc number (1–5) occupying that slot, or 0 for empty. At initialization, all five discs are placed on peg 1: `FOR N=SGN PI TO 5: LET P(1,N)=N: NEXT N`. Disc graphics are stored in `d$(5,10)`, a string array where each element is a 10-character string composed of block graphics (`\::` = █ and `\` = space). Disc 1 is the narrowest (2 block pairs wide) and disc 5 the widest (5 block pairs), creating a visual taper. They are rendered with `INK (6-P(N,O))`, giving each disc a distinct color based on its disc number. ### Key BASIC Idioms - `SGN PI` is used as a constant for `1` throughout all `FOR` loops (e.g., `FOR N=SGN PI TO 5`), saving a byte over the literal `1`. - `DIM p(PI,5)` exploits the fact that BASIC truncates the floating-point value of PI to the integer 3 for array dimensions. - `POKE 23609,25` at line `1110` sets the keyboard repeat speed (system variable REPDEL), reducing key-repeat delay for more responsive input. - The “TO” error-check subroutine is entered via `GO TO 620` rather than `GO SUB`, meaning it falls through directly to `GO TO 430` (store moves) — a structured-fall-through technique avoiding an explicit `RETURN`. - Move history is accumulated in the string variable `M$` by concatenation: `LET M$=M$+A$+"-"+B$+":"`, building a human-readable log for printing. ### Joystick Support Joystick input is handled via the `STICK` function (`|`), called as `|(1,1)` to read joystick port 1. Direction values used are: | STICK value | Direction | Mapped peg | | --- | --- | --- | | 4 | Left | 1 | | 1 | Up | 2 | | 8 | Right | 3 | When joystick mode is active (`LET st=1`), lines `690–730` and `740–780` handle “FROM” and “TO” peg selection respectively, branching back into the keyboard-input flow at lines `290` and `380` once a valid direction is detected. The `X` key remains the quit key in joystick mode. ### Screen Layout and Graphics The three pegs are drawn using `PLOT`/`DRAW` commands in the subroutine at line `40`, with each peg consisting of a 4-pixel-wide, 42-pixel-tall vertical bar. The UDG character `\a` is programmed at line `1140` with the alternating byte pattern `170,85,170,85,170,85,170,85` (binary `10101010`/`01010101`), producing a checkerboard or hatched fill used in the peg labels row at line `1240`. An outer border rectangle is drawn at line `1260` and a second inner rectangle is added on win at line `800` using `OVER 1` to erase the outer border cleanly. ### Win and Lose Conditions The win check at lines `480–520` iterates over peg 3 slots, incrementing `S` each time `P(3,G)=G` (i.e., disc *G* is in slot *G* of peg 3, meaning discs are stacked in correct order 1–5). If `S=5`, all five discs are correctly placed and the win routine fires. The 100-move limit is enforced at line `240`; exceeding it redirects to the lose routine at line `950`. The high-score variable `hs` is initialized to `100` and updated only when the player wins in fewer moves than the previous best. ### Bugs and Anomalies - At line `70`, the loop variable is written as lowercase `n` (`FOR n=SGN PI TO 5`) but the body references uppercase `N` (`PRINT AT N,1,,`). Sinclair BASIC treats variable names case-insensitively for numeric variables, so this works correctly. - Line `130` closes two nested loops with `NEXT O: NEXT n` — again mixing case for `n`/`N`, which is harmless. - The instructions text at line `1030` contains a grammatical error: “move all 5 of the discs one at a time” is split mid-word as “at a” on separate print lines due to fixed-width layout packing, but this is purely cosmetic. - At line `450`, the condition `IF N=1` uses `N`, but `N` at this point in the flow holds whatever value it last had in the display loop (line `80`–`130`). The intent appears to be checking whether the destination slot is position 1 (top of peg), but the variable being tested is the loop counter rather than the insertion index. The correct placement logic relies on the “TO” subroutine’s loop variable `N` from lines `630–670`, which exits with `N` set to the first empty slot — making this effectively check if slot 1 is empty (first position on peg), which works correctly in practice but is fragile. - The `COPY` command at line `880` performs a screen dump to printer before the `LPRINT` statements at lines `890–910`, meaning the printed output shows a screen snapshot followed by the text move log. ## Source Code ``` 10 REM "MEN MAN" by J.G.DuPuy 11/23/84 20 GO TO 1110 30 REM DRAW PEGS 40 FOR B=0 TO 3: PLOT PL+B,128: DRAW 0,42: NEXT B: RETURN 50 REM DRAW DISCS 60 LET PL=-34 70 FOR n=SGN PI TO 5: PRINT AT N,1,,: NEXT n 80 FOR N=SGN PI TO 3: LET PL=PL+80: GO SUB 40 90 FOR O=SGN PI TO 5 100 IF P(N,O)=0 THEN GO TO 130 110 PRINT AT O,1+((N-1)*10); INK (6-P(N,O));D$(P(N,O)) 120 BEEP .05,P(N,O)+10 130 NEXT O: NEXT n: RETURN 140 PRINT AT 16,10; FLASH 1;" STOP THE TAPE!": BEEP .5,0: BEEP .5,10: INPUT "Do you want intructions?(Y/N)"; LINE z$: IF z$="y" THEN GO SUB 1010 150 PRINT AT 16,10;" " 160 INPUT "Enter:J-Joy stick,K-keys(1-3)"; LINE z$: LET st=0: IF z$="j" THEN LET st=1: GO SUB 1080 170 PLOT 0,22: DRAW 255,0: DRAW 0,52: DRAW -255,0: DRAW 0,-52 180 PRINT AT 14,17;"BEST SCORE:";hs 190 IF st THEN PRINT AT 18,6;"LEFT=1, UP=2, RIGHT=3" 200 REM MAIN PROGRAM 210 LET M=M+1 220 PRINT AT 16,1,, 230 PRINT AT 14,1;"MOVE:";M 240 IF m>100 THEN PRINT AT 16,1;"You have gone over you limit!": BEEP 1,-10: PAUSE 30: GO TO 950 250 PRINT AT 16,1;"FROM?(1-3):"; 260 IF st THEN GO TO 690 270 LET A$=INKEY$: IF A$="x" THEN GO TO 950 280 IF A$>"3" OR A$<"1" THEN GO TO 270 290 IF INKEY$<>"" THEN GO TO 290 300 PRINT A$;: BEEP .1,27 310 IF st AND |(1,1) THEN GO TO 310 320 LET D=VAL A$: GO SUB 550 330 IF Z THEN PRINT AT 16,1;"NOTHING THERE TO TAKE!": BEEP .5,-20: PAUSE 30: GO TO 220 340 PRINT " / TO?(1-3):"; 350 IF st THEN GO TO 740 360 LET B$=INKEY$: IF B$="x" THEN GO TO 950 370 IF B$>"3" OR B$<"1" THEN GO TO 360 380 IF INKEY$<>"" THEN GO TO 380 390 PRINT B$: BEEP .1,30 400 IF b$=a$ THEN PRINT AT 16,1;"A RATHER STUPID MOVE!!! ": BEEP .5,-20: PAUSE 30: GO TO 220 410 LET E=VAL B$: GO TO 620 420 REM STORE MOVES 430 LET M$=M$+A$+"-"+B$+":" 440 REM UPDATE POSITION ARRAY 450 LET P(D,I)=0: IF N=1 THEN LET P(E,N)=FR: GO SUB 60: GO TO 480 460 LET P(E,N-1)=FR: GO SUB 60 470 REM CHECK PEG#3 FOR WIN 480 LET S=0 490 FOR G=SGN PI TO 5 500 IF P(3,G)=G THEN LET S=S+1 510 NEXT G 520 IF S=5 THEN GO TO 800 530 GO TO 210 540 REM "FROM"SETUP&ERROR CHECK 550 DIM F(5) 560 FOR I=SGN PI TO 5 570 IF P(D,I)=0 THEN GO TO 590 580 LET F(I)=P(D,I): LET Z=0: LET FR=F(I): RETURN 590 NEXT I 600 LET Z=1: RETURN 610 REM "TO"SETUP & ERROR CHECK 620 DIM T(5) 630 FOR N=SGN PI TO 5 640 IF P(E,N)=0 THEN GO TO 670 650 LET T(N)=P(E,N): IF T(N)0 THEN GO TO 430 670 NEXT N 680 GO TO 430 690 IF |(1,1)=4 THEN LET a$="1": GO TO 290 700 IF |(1,1)=1 THEN LET a$="2": GO TO 290 710 IF |(1,1)=8 THEN LET a$="3": GO TO 290 720 IF INKEY$="x" THEN GO TO 950 730 GO TO 690 740 IF |(1,1)=4 THEN LET b$="1": GO TO 380 750 IF |(1,1)=1 THEN LET b$="2": GO TO 380 760 IF |(1,1)=8 THEN LET b$="3": GO TO 380 770 IF INKEY$="x" THEN GO TO 950 780 GO TO 740 790 REM WIN ROUTINE 800 PLOT OVER 1;0,22: DRAW OVER 1;255,0: PLOT OVER 0;0,24: DRAW 0,-20: DRAW 255,0: DRAW 0,20: PRINT AT 18,1;"GOOD GOING! YOU GOT IT!",AT 19,1;"IT TOOK YOU : ";M-1;" MOVES. " 810 IF m-1"y" THEN RETURN 870 INPUT "Turn printer on, press ENT "; LINE z$ 880 COPY 890 LPRINT "NUMBER of MOVES: ";M-1 900 LPRINT ' 910 LPRINT M$ 920 LPRINT ' 930 RETURN 940 REM LOSE ROUTINE 950 PRINT AT 20,1;"I guess I wiped your mind!!";AT 21,1;"Ha! Ha! Ha!" 960 FOR n=SGN PI TO 20: BEEP .1,0-n: NEXT n 970 GO SUB 860 980 REM RESTART GAME 990 INPUT "Want to play again?(Y/N):";z$: IF z$<>"n" THEN GO TO 30 1000 STOP 1010 REM INSTRUCTIONS 1020 PRINT AT 16,0,, 1030 PRINT AT 12,0;"The object of the game is to move all 5 of the discs one at atime so that you end up with all5 at 3 in the same order as 1 isnow in the least number of movesbut You can't put a larger disc on top of a smaller disc! Enter an ""X"" if you want to quit." 1040 PRINT "BEWARE, You only have 100 moves!" 1050 INPUT "Press enter to start. "; LINE z$ 1060 FOR x=12 TO 20 1070 PRINT AT x,0,,: NEXT x: RETURN 1080 PRINT AT 12,0;"You have elected to use the JOY STICK. To move, LEFT=1, UP=2and RIGHT=3. X key to stop." 1090 INPUT "Press enter to start ";z$: FOR v=12 TO 16: PRINT AT v,0,,: NEXT v: RETURN 1100 REM INITIALIZE 1110 POKE 23609,25 1120 LET hs=100 1130 BORDER 1: PAPER 7: LET m=0: INK m: BRIGHT 1: CLS 1140 FOR n=m TO 7: READ a: POKE USR "\a"+n,a: NEXT n 1150 DATA 170,85,170,85,170,85,170,85 1160 CLS : DIM p(PI,5): LET m$="": DIM d$(5,10) 1170 LET d$(1)="\ \ \ \ \::\::" 1180 LET d$(2)="\ \ \ \::\::\::\::" 1190 LET d$(PI)="\ \ \::\::\::\::\::\::" 1200 LET d$(4)="\ \::\::\::\::\::\::\::\::" 1210 LET d$(5)="\::\::\::\::\::\::\::\::\::\::" 1220 FOR N=SGN PI TO 5: LET P(1,N)=N: NEXT N 1230 REM SET UP SCREEN 1240 PRINT AT 6,m;"\a\a\a\a\a1\a\a\a\a\a\a\a\a\a2\a\a\a\a\a\a\a\a\a3\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a" 1250 PRINT ' INK m;" M E N T A L M A N I A" 1260 PLOT m,87: DRAW 255,m: DRAW m,88: DRAW -255,m: DRAW m,-88 1270 GO SUB 60: GO TO 140 1280 CLEAR : SAVE "MEN MAN" LINE 10 ```