COMMENT This is the complete version of the Scrabble program. 
COMMENT

( print(("Input a large integer to initialize the random number generator"
      , newline))
; read((lastrandom, newline))

; LOC INT boardsize := 0
; WHILE NOT ODD boardsize
  DO  print(("Input the boardsize (an odd number, please)", newline))
    ; read((boardsize, newline))
  OD

    # **** Now declare 'board' with 'boardsize+2' rows and columns #
    # Note that all arrays in this program will have their lower bounds
        (LWB) equal to 1 #

; LOC [1:boardsize+2,1:boardsize+2] CHAR board

; FOR i FROM 1 TO 2 UPB board DO board[1, i] := " " OD
; FOR j FROM 1 TO 1 UPB board DO board[j, ] := board[1, ] OD

    # **** Now write ".scrabble." at the centre of the board #

; LOC INT centre := (1 UPB board)%2 + 1
; board[centre,centre-5:centre+4]:=".scrabble."

; PROC print board = VOID:
    ( print(newline)
    ; TO 1 UPB board +2 DO print("*") OD
    ; print(newline)
    ; FOR i FROM 2 TO 1 UPB board -1
      DO  print(("* ",board[i, 2 : 2 UPB board -1 ], " *",newline)) OD
    ; TO 1 UPB board +2 DO print("*") OD
    ; print((newline,newline))
    )
; print board

; LOC FILE vocabulary
; open(vocabulary, "/usr/dict/words", stand in channel)
; on logical file end(vocabulary, (REF FILE f)BOOL: GOTO stop)

; PROC get word = STRING:
    ( LOC STRING s
    ; FOR i TO ROUND (next random(lastrandom)*1000)
      DO get(vocabulary, newline) OD
    ; WHILE get(vocabulary, (s, newline))
        ; s[1]>="A" AND s[1]<="Z"
      DO SKIP OD
    ; s
    )

; PRIO MAX = 4
; OP MAX = (INT a, b)INT: IF a>b THEN a ELSE b FI

; PROC firstchar = ([] CHAR piece)INT:
    (
      # **** Scans 'piece' looking for the first non-space CHAR, and 
        returns its index. If 'piece' is all spaces, it returns 
        'UPB piece +1' (as if there were a space immediately 
        after it). #

	  LOC INT index := 1
	; WHILE
		piece[index] = " " AND index < UPB piece
 	  DO index +:=1 OD
	; IF piece[index]/=" " THEN index ELSE index+1 FI


    )


; PROC fits = ([] CHAR word, piece)BOOL:
    (
      # **** Tests whether 'word' will fit over the initial part of 
        'piece'.
           First find the first non-space CHAR of 'piece'.
           If this is beyond the end of 'word' with one to spare, then 
        the fit is possible; if it is beyond, but with none to spare, 
        then it is NOT possible; otherwise, the corresponding CHAR in 
        'word' must match the CHAR from 'piece', in which case we call 
        'fit' recursively on the remainder of 'word' together with the 
        remainder of 'piece'. 
           It may be asssumed that the LWBs of 'word' and of 'piece' are 
        both 1 #

	  LOC INT first := firstchar(piece)
	; LOC INT gap := first - UPB word
	; IF gap > 1 THEN TRUE
 	  ELIF gap = 1 THEN FALSE
 	  ELIF word[first] = piece[first] THEN
		IF UPB word > 1 THEN fits(word[first+1: ],piece[first+1: ]) ELSE TRUE FI
	  ELSE FALSE FI

    )


; PROC put word = (STRING word, REF [] CHAR piece)BOOL:
    (
      # **** 'piece' is a complete row or column of 'board' (including 
        the border spaces at each end).
           The REF gives the effect of a VAR parameter in PASCAL.
           We try to 'fit' 'word' starting at every allowed position within 
        'piece', but using 'firstchar' to skip quickly past long stretches 
        of spaces.
           So, initialize an index 'start' to 1 and, each time round the 
        loop, increment it so that, if 'word' started there it would end 
        on the first non-space CHAR (increment it by 1 if this is NOT 
        possible - the infix operator MAX has been provided to assist with 
        this).
           Exit the loop if the new position of 'start' leaves no room for 
        'word' at the end of 'piece'.
           Otherwise, check that there is a space at [start-1] and see if 
        'word' 'fits' in the part of 'piece' starting at 'start' (NOTe 
        that slicing out a part of 'piece' for this purpose automatically 
        gives a [] CHAR with its LWB=1, as assumed in 'fits'). Also, it is
        quite in order to provide the STRING 'word' where 'fits' is expecting
        a [] CHAR.
           If this works, you may assign 'word' to the found place within 
        'piece', with a '.' before and after it to protect its ends. 'put 
        word' should then return TRUE. #

	  LOC INT start := 1
	; LOC BOOL fitted := FALSE
	; WHILE (UPB word < (UPB piece - start - 1) AND NOT fitted)
	  DO start := (firstchar(piece[start: ]) + start - (UPB word) - 2) MAX (start+1)
	; fitted := firstchar(piece[start: ]) <= UPB word  AND fits(word,piece[start: ]) AND piece[start-1]=" "
	  OD
	; IF fitted THEN piece[start-1:start + UPB word] := "." + word + "."
		; TRUE
	  ELSE FALSE FI
    )



; LOC STRING word := get word
; LOC INT row, column
; LOC BOOL done
; DO
        # **** Use 'put word' to try to put 'word' into each odd-numbered 
          row and each odd-numbered column (the ones with even indices 
          actually, because of the border).
             As soon as a word has been placed, use 'get word' to obtain 
          aNOTher one and 'print board'. Then continue your scan from where 
          it left off. #

	  row:=column:=2
	; WHILE done := put word(word, board[row, ])
		; NOT done AND row < boardsize + 1
	  DO row +:=2 OD
	; IF NOT done THEN 
		WHILE done := put word(word, board[ ,column])
			; NOT done AND column < boardsize + 1
		DO column +:=2 OD
	  FI
	; IF done THEN print((word," has been added.",newline))
		;print board 
	  ELSE print(("failure to add the word ",word,newline)) FI
	; word := get word
  OD
)
