Seaman

(ToC)


There was a very popular pencil and paper game school-aged children played to hone their spelling skills, but it seems to have fallen into disfavor. A number of alternatives have cropped up, which are basically the same rules but different graphics. Seaman is one of them.

This is a two-player game: one person chooses a word and draws out dashes for each letter of that word (so the other player knows how long it is, but not the word itself. This second person tries to guess the word, one letter at a time. The first player fills in the correct letters, and adds a body part to a stick figure for each incorrect guess. When the stick figure is fully drawn, the first player wins; otherwise if the word is fully spelled, the second player wins.

The program you will write today is the scorekeeper for two human players. The first player enters a word, then the second player begins to type in single letters under the computer's supervison. At first the computer will merely keep a numerical score, but after that is working, the program can also draw the stick figure.

By this time, you should have already worked your way through PBJ, Calculator, Guessing Game, and RPS. You should already be familiar with the process of defining your computer program in English, then converting every part of that description into one of the Five Concepts, after which it should run in the English Computer. If you missed or skipped over these informational sessions and you find the next step difficult, you might go back and review one or more of these preparational sessions:

1. You Already Know How
2. Conditionals & Input
3. Iteration & Variables
4. Calculator
5. Guessing Game
6. Rock Paper Scissors
Three times you watched me go from a vague idea to runnable code, and once you did it yourself, four different programs in all.

Now you get to do another one on your own. Click this button to open our "Integrated Development Environment" in a new window, which you can position to one side or above or below the instructions in this page:

 
Button to open IDE


If you don't know how to begin, Watch this video to see if it helps:

Seaman Video Introduction (5 minutes) Transcript below


If you are doing fine, but don't know how to extract a single character from a whole word, Watch this video (and/or read the transcript):

Get Character from English Word (3 minutes) Transcript below
If you have the setup working, but are unsure how to do the Seaman scoring, Watch this video to see how to extract and compare individual letters (or read the transcript):
Seaman Scoring (3 minutes) Transcript below


After you have a simple numerical scoring working for Seaman, Watch this video for an introduction to ASCII graphics (or read the transcript):

ASCII Graphics (3 minutes) Transcript below
You can make your implementation of ASCII graphics into a separate part of your program by making it into a Subroutine, which you can do several different versions of of the graphics (or none at all) as differently names subroutines, which a minor tweak to the calling line -- or even a conditional -- will select the one you want. This next video introduces the idea of Subroutines in this context, and joins it with the other Five Concepts as an essential element of programming:
Subroutines (5 minutes) Transcript


If you have an English description of your game, but you do not know how to turn it into lines of "Five Concepts" items, Raise your hand in Zoom to get a Mentor to look at your description and suggest a way forward.

If each line of the English description of your game already begins with one of the keywords in the Reference section from the English IDE, but your program misbehaves when you try to run it, Watch this video to see if it helps:

Debugging Video (0 minutes) (Transcript) [This video and transcript are not ready yet]
If you didn't see anything in the video to help your situation, Raise your hand in Zoom to get a Mentor to look at your program and suggest a way forward.

When your game runs, Raise your hand in Zoom to continue.

If you are like me and prefer to read at your own pace instead of whatever pace set in some video, You can read the transcripts here.


Video Transcript: 7a. Seaman: Defining the Problem

Seaman is a game played between two people. You will write a program that keeps score between those two people. The game has two parts, with the second part repeated until the word is spelled or the stick figure is fully drawn.
1a. Word Input (1st player) &
1b. Presentation (to 2nd player)

2a. Letter Input (2nd player)
2b. Scoring (counting, by computer)

I suggest you read through all four segment descriptions below before you start to code, because later design decisions affect earlier parts of the code. Software design is often like that. In other sciences it is called "Irreducible Complexity" = the idea that the whole system is non-functional if any single critical component is left out or non-functional. For unit testing (testing individual components in isolation, which is a good idea) you can stub in the missing components, but of course the whole system does not work without them.
 

Word Input

Presumably with the second player not looking, the program invites the first player to enter a word. Later in the program (the presentation and the scoring) you will need to know how long the chosen word is. When you do this later in Java, you will use arrays (numbered sequences of data) to hold the first player's word and the second player's guessed letters, but arrays are not a normal English language concept and therefore also not in the English programming language. Instead we can hold the data in whole text strings (think "words"), then pick out the letters one at a time using a very unEnglish "hack" -- in English, when you "hack away at" something, it is understood to be cutting imprecisely or clumsily; in programming the noun "hack" has come to mean an awkward quick-fix piece of code, not particularly well-done -- which this hack corresponds to library routines in Java, but only remotely resembles anything in the English language. This will be explained in another video (Transcript), "Get Character from English Word."

It is possible to input the first player's word in a single Input command, and then count the letters in it, but you already know how to input the letters one at a time and then concatenate them into a single word while counting the number of letters:

Let theWord = ""
Let guessWd = ""
Let nLets = 0
Repeat
  Input letter 1
  If letter < "A" then Exit
  Let theWord = theWord # letter
  Add 1 to nLets
  Next
Repeat 33 {to clear screen}
  Print " "
  Next

Presentation

Before you can begin the play, you need to know how many letters there are in the word, which is done in your input loop. Then you need to build a row of dashes the same length, either after the fact, in a loop (iteration) for that purpose:
Repeat nLets
  Let guessWd = guessWd # "_"
  Next
Print guessWd
or else include that one line inside the Input loop (above). Then you print that line before and after each time the second player guesses a letter. Of course you only print it once inside the guess loop, but if you print it after the user has guessed, then you need to print it also before the loop starts. If you print it inside the loop, but before the second player guesses, then you must print the final result after the loop is done, or else place your loop exit (either too many wrong guesses, or else the word is correctly guessed, see Scoring below) in the middle, after printing the word but before you accept another input (see Letter Input below).
 

Letter Input

The second player will be guessing the letters of the word one at a time, in an iteration. First they must see the guessed word so far (initially all dashes), plus the current score -- either the number of wrong guesses, or else the graphical presentation of the partial stick figure (or both) -- then they input their next guess, and the program must look through the original word to see if any of its letters match, and if so, replace the corresponding dash in the guessWd with the correct (just now guessed) letter. There may be multiple matches, like for example the "L" in "HELLO", or there may be none. If there are no matches, we add to the error count (later we will also draw a stick figure, see "ASCII Graphics").

The iteration ends when either the whole word has been guessed, or else the stick figure has been fully drawn (or the count reaches 6 or whatever number of body parts there are).


Video Transcript: 7b. Seaman Scoring

The Letter Input iteration ends when either the whole word has been guessed, or else the stick figure has been fully drawn (or the count reaches 6 or whatever number of body parts there are). After the player has entered a guessed letter, you need a second iteration to step through the initial word to see if that letter matches of the letters in it. Extracting that letter will be explained in another video (Transcript), "Get Character from English Word," or (better) you can figure it out yourself from the Kitchen English Reference Manual, Character command.

Replacing the corresponding dash in guessWd is probably easiest to understand if you simply reconstruct it in a new variable (here: nuly), then copy it back:

Let nuly = ""
Let offs = 0
Let seen = 0
Repeat nLets
  Character looky = theWord,offs  {get next letter from original word}
  Character prio = guessWd,offs  {get corresponding letter as guessed}
  Add 1 to offs
  if looky=letter then Add 1 to seen  {replace letter in guessWd}
    Otherwise Let looky = prio     {preserve previous guess or dash}
  Let nuly = nuly # looky
  Next
Let guessWd = nuly           {this is now updated guess}
If seen>0 then {score match}
If seen=0 then {score no-match}
Knowing when the whole word has been guessed is probably simplest if you keep a separate count of the correctly guessed letters (perhaps counting down from the original word size nLets, or else counting up until the number of correct letter substitutions matches the total). Note that this count must survive the inner letter-check iteration, that is, you need a separate counter variable for the total, different from the seen counter inside the letter-check loop.

If you still have trouble, Raise your hand in Zoom to get a Mentor to look at your program and suggest a way forward.


Video Transcript: 7c. Get Character from English Word

Seaman is a word game that depends on guessing the individual letters of a word, then showing those guesses within a row of dashes representing the unguessed letters. Picking out those individual letters is not the kind of thing one often has reason to say in ordinary speaking English, so there is not a natural way to say it in our programming version of English. Most programming languages (including Java, when you get to it) can do these same things in about the same way, but then those languages don't pretend to resemble English at all!

If you look at the Quick Reference panel of the English IDE page, in the lower right corner is the Character command linked to its definition in the Kitchen/English Reference page. You probably should become comfortable with reading command definitions like this one, because it is the definitive way for programmers to understand the tools they work with. For our purposes today, we want to write something like this:

Character letter = theWord,offs
where theWord is the word you want a letter from, and offs is the zero-based offset (= the number of letters to the left to skip over) in that word.

To replace a letter in a particular position in the word you can use the Substring command to extract the left and right context, then put the three together:

Substring left = theWord,0,offs
Substring right = theWord,offs+1,nLets {or any large number}
Let theWord = left # letter # right
Less complicated for Seaman, where you always walk through the whole word anyway, is to build a replacement copy as you go:
Let nuly = ""
Let offs = 0
Repeat nLets
  Character letter = theWord,offs
  Add 1 to offs
  {maybe change it, then put it back..}
  Let nuly = nuly # letter
  Next
Let theWord = nuly

Video Transcript: 7d. ASCII Graphics

Seaman is derived from a much older game with simple graphics. Wrong guesses result in a stick figure of a guy being drawn, part by part. When the full figure is drawn, the guessing stops. For non-technical reasons we replaced the traditional apparatus (but not the stick figure) with the outline of a sailboat, which is almost as easy to draw as the previous environment.

The drawing depends on a monospaced font, which is common in computer output, partly for historical reasons, but probably also because ASCII graphics and space-tabbed tables are so common and depend only on the equal spacing of the characters. ASCII (pronounced "ASS-key") was the original American Standard Code for Information Interchange, which became included as the first 128 characters in the ISO standard that replaced it. Here is our stick figure fully drawn:

     _
    ( )
    _|_
   / | \
  /  |  \
     |
    / \
   /   \
 _/     \_


There is an obvious partition of this figure into six body parts -- head, spine, two arms, and two legs -- which six wrong letter guesses will fully draw. You could, if you wanted more latitude, separate off the shoulders and two feet, and perhaps a hat. The point is that this character can be entirely drawn with special characters from your keyboard, spaced out by the spacebar.

We can similarly draw a sailboat for him to stand on (hence the name "Seaman" which is also a pun on "see, [a] man"):

          /|     _
         / |    ( )
        /  |    _|_
       /   |   / | \
      /    |  /  |  \
     /     |     |
    /      |    / \
   /       |   /   \
  /________| _/     \_
  ______________________
  \                    /


The characters you use for this are the spacebar, the forward slant (next to the shift key on most QWERTY keyboards) the backward slant and vertical bar (on the same key, next to the backspace) the left and right parentheses (shift-9 and shift-0) and the underscore (shift-hyphen, usually between the zero and the equals/plus keys). For drawing halftone (gray-scale) images you can use the period or back-accent to fill a light gray, and "#" (shift-3) or "@" (shift-2) or capital-M for near-black, with other keys to supply mid-tone ranges between.

Basically you write the horizontal lines of the image into character string constants in your program, which you print out as needed:

Print "          /|     _"
Print "         / |    ( )"
Print "        /  |    _|_"
Print "       /   |   / | \"
Print "      /    |  /  |  \"
Print "     /     |     |"
Print "    /      |    / \"
Print "   /       |   /   \"
Print "  /________| _/     \_"
Print "  ______________________"
Print "  \                    /"


The body parts are not drawn until after the requisite number of guess errors; you can use conditionals to print those lines either with the body parts or without -- in some cases (like the arms) there are four versions of the line: one with no body, one with only the spine, and the other two with one or two arms -- or else you can construct variable strings conditionally, then always print the same strings (as modified by the addition of body parts).

We do not have arrays in the Kitchen English programming language, but when you get to Java you can put all possible lines into a large constant array, then print them off by line number. You can still do something like that in the English computer if you use a subroutine -- see the video on Subroutines, or read the transcript -- with a sequence of conditional assignments, like this

"IxTxt"
  let txt = ""
  if ix=1 let txt = "          /|"
  if ix=2 let txt = "         / |"
  ...
  if ix=4+5+8 let txt = "    ( )"
  ...
  Done
and then call it be presetting the parameter variable (here: ix) then printing the subroutine result, or else compositing several results into one line:
let ix = row
let line = txt
let txt = ""
if nerrs>0 if row<10 repeat 1
  let ix = row*4+nerrs+8
  IxTxt
  let line = line # txt
  next
Print line


Again when we get to Java, you can put the reference indexes to these lines into a second array variable [or additional indexed lines in your subroutine], so that you don't waste a lot of table space on duplicated strings. It's messy in English (it's messy in Java too), but it looks so cool to show off to your programmer friends -- non-programmers simply won't understand why it's cool, sort of like people who see nothing funny about the T-shirt that reads:

There are 10 kinds of people in the world,
Those who understand binary,
and those who don't.
The first indexed fetch is a line of equally spaced index numbers, so you can use a Substring command to pick off 2-digit index numbers to go fetch the actual strings. If it feels like it's too hard, don't worry, you'll get another shot at it after we get to Java.

I have not given you much sample code here because I think you can write it all yourself. If you get stuck, ask a mentor for help, that's what they are here for.
 

[2021 August 31a]