Hanshan

Developer(s): Tim Hartnell
Date: 1984
Type: Program
Platform(s): TS 2068
Tags: Art

Hanshan generates pseudo-haiku poetry in the style of the Tang Dynasty Buddhist hermit poet Hanshan (Cold Mountain), combining randomly selected single words and short phrases from built-in DATA statements. The program uses three distinct print patterns, each with varying TAB indentation, to create staggered verse layouts that mimic the visual structure of translated Chinese poetry. Sound effects are triggered probabilistically using RND comparisons, producing three different BEEP sequences at random intervals between verses. Two string arrays, W$(20,12) for single words and S$(20,26) for short phrases, are dimensioned and populated from DATA at initialization. The main loop runs indefinitely via GO TO 40, calculating the subroutine address as R*50+40 to dispatch to one of three pattern routines.


Program Structure

The program is organized into clearly delineated sections separated by REM comments. Execution begins at line 15 with display setup, then calls the initialization subroutine at line 250 before entering an infinite loop at line 40. The loop picks a random pattern number and dispatches to one of three poetry-formatting subroutines, optionally triggers sound, then repeats.

LinesPurpose
10–15Title REMs and display attribute setup
20–80Main control loop
100–130Pattern One subroutine
150–180Pattern Two subroutine
200–230Pattern Three subroutine
250–350Initialization: arrays and DATA loading
360–620DATA: 20 single words, 20 short phrases

Subroutine Dispatch via Arithmetic

Line 50 uses the expression GO SUB R*50+40 where R is 1, 2, or 3, yielding target lines 90, 140, or 190 respectively. Since those line numbers do not actually exist, the interpreter jumps to the next available line in each case: 100, 150, and 200. This is a well-known technique for computed subroutine dispatch without requiring an explicit IF chain.

Array Design

Two fixed-length string arrays are declared at line 280: W$(20,12) holds 20 single words each up to 12 characters, and S$(20,26) holds 20 short phrases each up to 26 characters. Both are filled sequentially from DATA at lines 290–340. Random selection from either array uses the idiom INT(RND*20)+1 to produce a uniform integer in the range 1–20.

Poetry Output Patterns

Each of the three subroutines applies a distinct TAB indentation scheme to simulate the staggered visual layout of translated classical verse:

  • Pattern One (lines 100–130): Two words joined by "..." on the first line, a tabbed word with leading dots on the second, and a tabbed phrase on the third.
  • Pattern Two (lines 150–180): A phrase at column 0, a phrase with trailing "..." at column 3, and a phrase at column 6 — a simple stepped indent.
  • Pattern Three (lines 200–230): A word at column 3, a phrase at column 0, then a combined word and phrase joined by ", " at column 3.

Sound Generation

Lines 60–68 implement three independent probabilistic BEEP sequences, each governed by a separate RND threshold:

  • Line 60: Triggered when KK > 0.65 (35% probability); plays a four-note ascending motif with a randomly offset pitch range using DD=RND*20-5.
  • Line 65: Triggered when KK < 0.4 (40% probability); plays a five-iteration descending/ascending pattern. Note that when 0.4 ≤ KK ≤ 0.65, neither of these fires.
  • Line 68: An independent check (RND < 0.7, 70% probability) plays a simple chromatic run from −5 to 5 semitones.

The variable KK is sampled once at line 60 and reused at line 65, meaning lines 60 and 65 are mutually exclusive only within the 0.4–0.65 band; below 0.4, both could fire (KK < 0.4 also satisfies the complement of KK > 0.65). In practice, when KK < 0.4, line 60’s condition is false, so only line 65 fires.

Display Initialization

Line 15 sets up the display using BRIGHT 1, FLASH 0, INK 7, PAPER 1, and BORDER 1 — a white-on-blue color scheme. BRIGHT is set to 1 then immediately reset to 0, which has no lasting visual effect. CLS and CLEAR prepare the screen and memory before initialization.

Notable Anomalies

  • The DATA at line 400 contains "WINDING" twice, so that word has a doubled probability of selection — likely a copy-paste oversight.
  • Line 70 uses PRINT '' (two apostrophes) to emit two blank lines between stanzas, creating visual breathing room.
  • The RANDOMIZE call at line 270 seeds the random number generator without an argument, using the system clock for a fresh seed each run.

Content

Appears On

Related Products

Related Articles

Related Content

Image Gallery

Source Code

   10 REM "HANSHAN" by Tim Hartnell
   12 REM RESET 1984
   15 CLS : CLEAR : BRIGHT 1: FLASH 0: INK 7: PAPER 1: BRIGHT 0: BORDER 1
   20 GO SUB 250: REM Initialize
   30 REM Choose pattern
   40 LET R=INT (RND*3)+1
   50 GO SUB R*50+40
   60 LET KK=RND: IF KK>.65 THEN LET DD=RND*20-5: FOR G=DD TO DD+5: BEEP .1,3: BEEP .1,7: BEEP .1,-4: BEEP .1,G/2: NEXT G
   65 IF KK<.4 THEN FOR G=1 TO 5: BEEP .1,-7: BEEP .1,G*3: BEEP .2,-2: BEEP .5,3: NEXT G
   68 IF RND<.7 THEN FOR G=-5 TO 5: BEEP .1,G: NEXT G
   70 PRINT ''
   80 GO TO 40
   90 REM *** Pattern One ***
  100 PRINT W$(INT (RND*20)+1);"...";W$(INT (RND*20)+1)
  110 PRINT TAB 5;"....";W$(INT (RND*20)+1)
  120 PRINT TAB 8;S$(INT (RND*20)+1)
  130 RETURN 
  140 REM **  Pattern Two  **
  150 PRINT S$(INT (RND*20)+1)
  160 PRINT TAB 3;S$(INT (RND*20)+1);"..."
  170 PRINT TAB 6;S$(INT (RND*20)+1)
  180 RETURN 
  190 REM *** Pattern Three ***
  200 PRINT TAB 3;W$(INT (RND*20)+1)
  210 PRINT S$(INT (RND*20)+1)
  220 PRINT TAB 3;W$(INT (RND*20)+1);", ";S$(INT (RND*20)+1)
  230 RETURN 
  240 REM ******************
  250 REM * INITIALIZATION *
  260 CLS 
  270 RANDOMIZE 
  280 DIM W$(20,12): DIM S$(20,26)
  290 FOR J=1 TO 20
  300 READ W$(J)
  310 NEXT J
  320 FOR J=1 TO 20
  330 READ S$(J)
  340 NEXT J
  350 RETURN 
  360 REM ***** DATA *****
  370 REM * SINGLE WORDS *
  380 DATA "SCURRYING","TREADING","GRAZING","WITHERED","CHISELLED"
  390 DATA "MUFFLED","FLANKED","WRITHED","BENDING","TWISTING"
  400 DATA "HAMMERED","HANGING","WINDING","WINDING","CLEAREST"
  410 DATA "EARTHWARD","CATARACT","SACRIFICIAL","SLIPPERY","ASUNDER"
  420 REM * SHORT PHRASES *
  430 DATA "IN THE COOL STREAM"
  440 DATA "NODDED IN CLUSTERED GRACE"
  450 DATA "WAVES OF COOLNESS"
  460 DATA "OUT FROM THE DEEPEST"
  470 DATA "SULLEN,SULLEN"
  480 DATA "IN THE BLACK DARKNESS"
  490 DATA "I TAKE YOUR POEMS"
  500 DATA "I PUT OUT THE LAMP"
  510 DATA "MY SHORT SPAN RUNS OUT"
  520 DATA "THOSE THAT ARE LEFT"
  530 DATA "MEN OF LEARNING"
  540 DATA "MEN OF ACTION"
  550 DATA "I HURRY FORWARD"
  560 DATA "WHY SHOULD YOU WASTE"
  570 DATA "WHEN SHALL WE MEET"
  580 DATA "LITTLE SLEEPING"
  590 DATA "AND MUCH GRIEVING"
  600 DATA "FOR THESE FEW STEPS"
  610 DATA "NOW AT DUSK"
  620 DATA "I HAVE DONE WITH PROFIT"

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top