--- title: "Dungeon Generator" id: 57358 type: "computer_media" slug: "dungeon-generator" url: "http://localhost/computer_media/dungeon-generator/" markdown_url: "http://localhost/computer_media/dungeon-generator.md" published_at: "2024-10-04T08:52:00+00:00" modified_at: "2026-04-03T07:58:33+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/205_DSL.png" excerpt: "A BASIC dungeon map builder lets you scatter rooms, pits, lakes, walls, and doors across a full-screen grid — then print the result." 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 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" indiv: - name: "Tony Willing" slug: "tony-willing" taxonomy: "indiv" url: "http://localhost/indiv/tony-willing/" genre: - name: "Dungeons & Dragons" slug: "dungeons-dragons" taxonomy: "genre" url: "http://localhost/type/dungeons-dragons/" media_contents: - id: 56735 title: "Timex Sinclair Public Domain Library Tape 1004" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1004/" media_type: "Program" programmers: - name: "Tony Willing" slug: "tony-willing" taxonomy: "indiv" url: "http://localhost/indiv/tony-willing/" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/09/205_DSL.png" media_type_tags: "Dungeons & Dragons" --- # Dungeon Generator This program is an interactive dungeon map generator that draws a grid-based layout on screen and lets the user populate it with rooms, pits, lakes, walls, halls, and doors. It begins by rendering a bordered play area using inverse-video digits and block characters, then iterates through seven predefined room size categories stored in a DIM’d string array R$(7,5), dispatching to GOSUB routines via the computed address VAL “100*Q+2000” to draw rooms of varying dimensions with dot-fill patterns. User-placed features (lakes, walls, halls, doors) are entered as row/column coordinates interactively, with bounds checking, and the completed map can be sent to a printer via the COPY command. The FAST mode is engaged during initialisation to speed up screen rendering. *** ## Program Analysis ### Program Structure The program divides into several clearly distinct phases: 1. **Initialisation (lines 4–78):** CLS, FAST, draw the border frame with inverse digits and a blank interior. 2. **Room placement (lines 80–220):** Define seven room-size categories in `R$`, prompt the user for counts, and dispatch to subroutines via computed GOSUB. 3. **Pit placement (lines 230–290):** Scatter inverse-video pit characters at random coordinates. 4. **Interactive feature placement (lines 300–500):** Four sequential phases for lakes, walls, halls, and doors, each using INPUT for row/column coordinates with bounds checking. 5. **Output (lines 1500–1530):** Optional COPY to printer, then STOP. 6. **Room-drawing subroutines (lines 2100–2760):** Seven subroutines, one per room size, each printing dot-filled rectangles at random positions. ### Room Size Categories The array `R$(7,5)` stores human-readable size labels displayed in the prompt at line 170. The seven entries correspond to subroutines at lines 2100–2700: | Q | R$(Q) | Subroutine | Room footprint | | --- | --- | --- | --- | | 1 | 20×30 | 2100 | 2 rows × 3 cols | | 2 | 20×40 | 2200 | 2 rows × 5 cols | | 3 | 30×50 | 2300 | 3 rows × 5 cols | | 4 | 40×60 | 2400 | 4 rows × 6 cols | | 5 | 20×20 | 2500 | 2 rows × 2 cols | | 6 | 30×30 | 2600 | 3 rows × 3 cols | | 7 | 40×40 | 2700 | 4 rows × 4 cols | Note that the size labels in `R$` use inverse-video digit characters (e.g. `%2%0%X%3%0`), making the dimensions appear highlighted on screen. The actual dot dimensions in the subroutines do not perfectly match the labels — for example, “20×30” yields a 2×3 dot block rather than 20×30 character cells, suggesting the labels are stylistic rather than literal measurements. ### Computed GOSUB Dispatch Line 200 uses `GOSUB VAL "100*Q+2000"` to dynamically compute the subroutine address from the loop variable `Q`. This is a well-known space-saving idiom: a single GOSUB replaces seven explicit IF/GOTO branches. For Q=1 through 7, the targets are lines 2100, 2200, …, 2700. Line 2000 contains a bare `STOP` as a safety guard in case Q is somehow 0, and line 2800 likewise acts as a sentinel past the last valid subroutine. ### Border Drawing Lines 5–78 construct the map border. Line 7 prints a row of inverse-video digits 0–9 repeating across 32 columns as the top border. Lines 10–30 print 20 rows of inverse spaces to fill the play area with a uniform background. Lines 40–76 use a two-pass loop (`C=1 TO 2`) with an inner loop over `A=0 TO 3` (exploiting `NOT PI = 0` and `LEN STR$ PI = 4`) to print characters `CHR$(156)` through `CHR$(159)` — block graphic characters — down both the left side (pass 1) and an offset position (pass 2, `AT A+10`). Line 78 then places an inverse zero at row 20, column 0 to close the frame. ### Interactive Placement and Bounds Checking The lake, wall, hall, and door phases each prompt the user for a row (`M`) and column (`N`). Entry of the value 86 for `M` acts as a sentinel to advance to the next phase (lines 315, 333, 370, 450). Bounds checks vary slightly between phases — for example, walls allow rows 1–20 and columns 1–30, while halls allow rows 1–20 and columns 1–31. A bounds violation silently re-presents the prompt rather than reporting an error. There is a minor anomaly in the door-placement phase: a bounds violation at line 470 jumps to `GOTO 350` (the hall prompt) rather than back to the door prompt at line 430. This means an out-of-range door entry accidentally drops the user into hall-placement mode instead of retrying the door prompt. ### Key BASIC Idioms - `SGN PI` evaluates to 1 (since PI > 0), used wherever the literal 1 would otherwise appear — saves one byte per occurrence. - `NOT PI` evaluates to 0, used for column 0 in PRINT AT statements. - `LEN STR$ PI` evaluates to 4 (length of “3.14159…” truncated to display form), used as the upper bound of the border character loop. - `VAL "number"` in numeric contexts is a standard token-saving technique on this platform. - `FAST` mode at line 5 suppresses the display refresh interrupt during the initial screen draw to speed up rendering. ### Unused / Dead Code Lines 2800–2830 are unreachable during normal execution. Line 2810 contains a `CLEAR` and line 2820 a `SAVE` with an inverse-video filename, which appear to be remnants of a development save-and-autorun stub that was never removed from the listing. ### Pit Symbol Line 280 prints `"%X"` — a single inverse-video X character — to mark pit locations. The prompt at line 230 also displays this character inline to illustrate the symbol to the user. ## Source Code ``` 0 REM % % % %D%U%N%G%E%O%N% %G%E%N%E%R%A%T%O%R% % % BY ANTHONY WILLING 3/84 4 CLS 5 FAST 7 PRINT "%0%1%2%3%4%5%6%7%8%9%0%1%2%3%4%5%6%7%8%9%0%1%2%3%4%5%6%7%8%9%0%1" 10 FOR A=SGN PI TO VAL "20" 20 PRINT "% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % " 30 NEXT A 40 FOR C=SGN PI TO 2 50 FOR A=NOT PI TO LEN STR$ PI 60 PRINT AT A,NOT PI;CHR$ (A+VAL "156") 70 IF C=2 THEN PRINT AT A+10,NOT PI;CHR$ (A+VAL "156") 75 NEXT A 76 NEXT C 78 PRINT AT 20,0;"%0" 80 DIM R$(7,5) 90 LET R$(1)="20%X30" 100 LET R$(2)="20%X40" 110 LET R$(3)="30%X50" 120 LET R$(4)="40%X60" 130 LET R$(5)="20%X20" 140 LET R$(6)="30%X30" 150 LET R$(7)="40%X40" 160 FOR Q=1 TO 7 170 PRINT AT 21,NOT PI;"HOW MANY ";R$(Q);" ROOMS?" 180 INPUT G 190 FOR B=SGN PI TO G 200 GOSUB VAL "100*Q+2000" 210 NEXT B 220 NEXT Q 230 PRINT AT 21,NOT PI;"HOW MANY PITS? (%X)" 240 INPUT G 250 FOR B=1 TO G 260 LET Z=INT (1+26*RND) 270 LET Y=INT (1+18*RND) 280 PRINT AT Y,Z;"%X" 290 NEXT B 300 PRINT AT 21,0;"PLACE YOUR LAKES (##)%8%6% %T%O% %E%N%D" 310 INPUT M 315 IF M=86 THEN GOTO 331 320 INPUT N 322 IF M>21 OR M<1 THEN GOTO 300 324 IF N>31 OR N<1 THEN GOTO 300 329 PRINT AT M,N;"##" 330 GOTO 300 331 PRINT AT 21,0;"PLACE YOUR WALLS (% )%8%6% %T%O% %E%N%D" 332 INPUT M 333 IF M=86 THEN GOTO 350 334 INPUT N 335 IF M>20 OR M<1 THEN GOTO 350 336 IF N>30 OR N<1 THEN GOTO 350 337 PRINT AT M,N;"% " 339 GOTO 331 350 PRINT AT 21,0;"PLACE YOUR HALLS (.)%8%6% %T%O% %E%N%D" 360 INPUT M 370 IF M=86 THEN GOTO 421 380 INPUT N 390 IF M>20 OR M<1 THEN GOTO 350 400 IF N>31 OR N<1 THEN GOTO 350 410 PRINT AT M,N;"." 420 GOTO 350 430 PRINT AT 21,0;"PLACE YOUR DOORS (%D)%8%6% %T%O% %E%N%D" 440 INPUT M 450 IF M=86 THEN GOTO 1500 460 INPUT N 470 IF M>20 OR M<1 THEN GOTO 350 480 IF N>30 OR N<1 THEN GOTO 350 490 PRINT AT M,N;"%D" 500 GOTO 430 1500 PRINT AT 21,0;"ENTER ""COPY"" TO COPY TO PRINTER" 1510 INPUT G$ 1520 IF G$="COPY" THEN COPY 1530 STOP 2000 STOP 2100 LET Z=INT (SGN PI+VAL "28"*RND) 2110 LET Y=INT (SGN PI+VAL "18"*RND) 2120 PRINT AT Y,Z;"..." 2130 PRINT AT Y+1,Z;"..." 2140 RETURN 2200 LET Z=INT (SGN PI+VAL "26"*RND) 2210 LET Y=INT (SGN PI+VAL "18"*RND) 2220 PRINT AT Y,Z;"....." 2230 PRINT AT Y+SGN PI,Z;"....." 2240 RETURN 2300 LET Z=INT (SGN PI+VAL "26"*RND) 2310 LET Y=INT (SGN PI+VAL "17"*RND) 2320 PRINT AT Y,Z;"....." 2330 PRINT AT Y+SGN PI,Z;"....." 2340 PRINT AT Y+2,Z;"....." 2350 RETURN 2400 LET Z=INT (SGN PI+VAL "25"*RND) 2410 LET Y=INT (SGN PI+VAL "16"*RND) 2420 PRINT AT Y,Z;"......" 2430 PRINT AT Y+1,Z;"......" 2440 PRINT AT Y+2,Z;"......" 2450 PRINT AT Y+3,Z;"......" 2460 RETURN 2500 LET Z=INT (SGN PI+VAL "29"*RND) 2510 LET Y=INT (SGN PI+VAL "18"*RND) 2520 PRINT AT Y,Z;".." 2530 PRINT AT Y+SGN PI,Z;".." 2540 RETURN 2600 LET Z=INT (SGN PI+VAL "28"*RND) 2610 LET Y=INT (SGN PI+VAL "17"*RND) 2620 PRINT AT Y,Z;"..." 2630 PRINT AT Y+SGN PI,Z;"..." 2640 PRINT AT Y+2,Z;"..." 2650 RETURN 2700 LET Z=INT (SGN PI+VAL "27"*RND) 2710 LET Y=INT (SGN PI+VAL "16"*RND) 2720 PRINT AT Y,Z;"...." 2730 PRINT AT Y+SGN PI,Z;"...." 2740 PRINT AT Y+2,Z;"...." 2750 PRINT AT Y+3,Z;"...." 2760 RETURN 2800 STOP 2810 CLEAR 2820 SAVE "1020%6" 2830 RUN ```