Seaman

 Zoom Name:
[The tutorial software in this segment was written new for this Fall term, so it may not work very well. If you did everything we said to do, and it doesn't behave like we said it should, it's my fault, not yours. Hit the Mentor button (or "Ask" for help in Zoom) and a Mentor will advance you manually. Oh, also some of the videos have not yet been recorded ("00 minutes") you will need to read the transcripts instead. I apologize for the inconvenience, it happens with new software, as you probably already noticed with your own code.]


Seaman Video Introduction (00 minutes) <<--- Watch this video first, then

English IDE <<--- Click this link and write your game program in the program panel.

When your top-down-design is "OK" (or if you get stuck), come back here and click this Next link to skip down to the next video.

If it's not a link yet, you might need to refresh your browser, or else click this button to call a mentor:

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 transcript (and probably come out ahead of the non-readers).

Additional discussion (TDD), not in the video.


If you are stuck, let me give you some hints, here in the next video:

Seaman Design (00 minutes) Transcript below

Additional discussion (Trees), not in the video.

Details

Each time your program structure is defined down to a new degree of detail, you should look at each line of the pseudo-code (that would be the English description you just did) and see if another layer of decomposition is justified. For example, if the first line has you printing the game rules, you can probably convert that directly to code with no additional design work.

If one or more lines are still some abstract description of more work to do, then you need to go through the process again for those lines, as if each line is the whole program. Most of the programs we give you can be fully analyzed in two or three levels. Seaman is probably ready for the next step, thinking about your data formats.

Don't forget. The first player inputs their word all at once -- we'll get to that detail shortly -- but the 2nd player part happens many times, once for each guessed letter. You need an iteration ("Repeat".."Next") around that whole subroutine, either inside the subroutine itself, or else around the call in the main code. Why don't you add that in right now, then come back and refresh this page.

Data Structures

When you are designing a program like a game, if one of your Design lines is about data input, or setting up a game board, or shuffling and dealing cards, it might be time to start thinking about appropriate data structures.

An important part of program design is choosing appropriate data types. So far we worked with numbers and text, which work automatically in the English computer and have been suitable for the small programs you worked on so far. When you get to Java, you will need to be much more intentional about your data, but Seaman is a spelling game and you need to be able to work with both whole words and also the letters that make it up, so you can start today thinking about more complex forms of data.

Words are made up of sequences of letters, and the ordinary English language we all speak has ways to talk about how words are spelled, but picking letters out of words came across more complicated than people could easily grasp. So today we will do it with arrays. You probably should start with the section on Arrays in the Variables page. If you understand it, great, skip down to the next section on "Words as Arrays" below. Otherwise we have a video that tries to explain the concept in more detail.

Arrays of Characters (00 minutes) Transcript below

Words as Arrays

You need two arrays representing the two words in this game: one to hold the word that you are comparing against, supplied by the first player, and a second array that starts out all dashes, then as the letters are guessed, the dashes are replaced, one by one, with the correctly guessed letters. If you can't figure out how to input the first word one letter at a time to load up the array for that word, I suggest you go back and review the "Arrays of Characters" video.

After you have the first player's word input working, you need to build the array of dashes, which you will print out each time before the second player makes a guess. Part of the input is counting the number of letters in the first player's word. That's how many dashes you need. You can make a second iteration to build the dashes array, or you can do it inside the same iteration as the input, after you know you have a letter, just add another dash to the second array.

Also, by now you already know how to accept the second player's guesses, one letter at a time. After you have that working (and click Done) the Mentor will open up the next Video/Transcript for scoring, which is a little more complicated.

Seaman Scoring

The actual scoring takes a little more thought. For each input letter (inside the same iteration that accepts input guesses) first you need to pick out the letters from the first player's word, one at a time -- each letter is a single array item, right? That would be another iteration -- and compare it to the letter you just got from the second player. If it matches (is equal), then you want to replace the dash in that position with the letter you just got. If you get all the way through the word without finding a single match, then you add one to the numerical score for the first player. Do you think you can do that? We will later add code to draw the Seaman stick figure after we have the game playing correctly just counting the incorrect guesses as a number.

If you get stuck, then watch this next video "Seaman Scoring". But try it first. After you graduate, when you are writing your own programs, I won't be around with videos to help you out, so you need to learn how to think about your program on your own. We will help you while you are here, but you need to try.

Seaman Scoring (00 minutes) Transcript below

ASCII Graphics

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 the graphics (or none at all) as differently named subroutines, which a minor tweak to the calling line -- or even a conditional -- will select the one you want.
 

Indexed Graphics

Now you know all about arrays in the Kitchen English programming language, so you can put all possible ASCII graphic text lines into a large array, then print them off by line number. It's a little tedious to build this array, one line at a time, but not as tedious as all those different print commands, because you only have one copy of each possible print line. The important principle here is called "code re-use" where you try to not have duplicate code in your program unnecessarily, it's considered poor form.

This is going to get complicated, so you can skip forward to the Java segment if you prefer, then come back later if you want to do serious programming -- because you need this kind of experience.

Anyway, since the boat is printed every time, no matter how much (and which part) of the seaman is being drawn, we can build each line of the display programmatically, one boat part + one seaman part. This uses extra arrays. You have maybe 12 lines of boat, they can be the first 12 lines of your print lines array.

You have nine lines of the seaman, but each line has at least two variants (draw nothing, or draw that whole line, and maybe also draw one leg or arm, or both, or just the spine, all depending on how many wrong guesses there were). So for each line of the seaman, you need seven (or eight, however many wrong guesses it takes to draw the whole seaman, plus a zero position representing no errors yet) items, line numbers in the first array for that body part in all its forms (I counted 18, you may have a different number depending on how you draw it), where zero is used to signify that no part of the seaman is drawn on that line for that number of wrong guesses.

This is where it gets complicated. Let me start you with the TDD version:

{Assume nerrs is the number of wrong guesses so far, from 0 to 6}
{Assume pLines is an array of printable text (see below)}
{Assume Sinx is an array of numbers (see below), each a line number in pLines}

"Print Seaman"
  {Calculate index for body parts}
  Repeat 12  {the total number of lines to print}
    {Build aLine = boat line # body part line}
    Print aLine
    Next
  Done

Let nerrs = 6  {test this subroutine...}
{Assume pLines and Sinx are already initialized}
Do Print Seaman

I colored the lines that you need to rewrite in green before it will run (we'll look into those shortly). Here is some of the array of boat and bodyparts. I left out about half of the data lines, because after you understand how it must work, it's a simple matter for you to fill in the rest of them. Don't forget to initialize your arrays before your test code runs.
Array pLines
  Let pLines[1] = "        /|"
  Let pLines[2] = "       / |"
...
  Let pLines[9] = "/________|"
  Let pLines[10] = "         |"
  Let pLines[11] = "______________________"
  Let pLines[12] = "\                    /"
  Let pLines[13] = "     _ "
  Let pLines[14] = "    ( )"
  Let pLines[15] = "     | "
  Let pLines[16] = "    _|_"
  Let pLines[17] = "   / |  "
  Let pLines[18] = "   / | \"
...
  Let pLines[23] = "   /    "
  Let pLines[24] = "   /   \"
  Let pLines[25] = " _/       "
  Let pLines[26] = " _/     \_"
Here pLines[15] is the seaman's neck, but the same graphic gets used for his waist and (when there are no arms) his spine, so we do not need additional copies of the same line.

Then you need another array big enough to cover all seven possible error counts (0 through 6) and all the different combinations of error number and printed line number. Each item at the front of this array selects a sequence later in the same array based on the current error count, nine items in each sequence for the nine lines that contain a body part at that level of drawing the seaman. Here, I filled in the index at the front, and the first three and last sequences, with comments explaining which parts are drawn by which lines.

Array Sinx = 8,17,26,35,44,53,62
  Let Sinx[8] = 0  {top of (no) head, nerrs=1}
  Let Sinx[9] = 0  {(no) face, nerrs=1}
  Let Sinx[10] = 0 {(no) neck, nerrs=1}
  Let Sinx[11] = 0
  Let Sinx[12] = 0
  Let Sinx[13] = 0  {(no) waist, nerrs=1}
  Let Sinx[14] = 21 {1 thigh, nerrs=1}
  Let Sinx[15] = 23 {1 knee, nerrs=1}
  Let Sinx[16] = 25 {1 foot, nerrs=1}
  Let Sinx[17] = 0  {top of (no) head, nerrs=2}
  Let Sinx[18] = 0  {(no) face, nerrs=2}
  Let Sinx[19] = 0
  Let Sinx[20] = 0
  Let Sinx[21] = 0  {no spine no hands, nerrs=2}
  Let Sinx[22] = 0  {(no) waist, nerrs=2}
  Let Sinx[23] = 22
  Let Sinx[24] = 24 {2 knees, nerrs=2}
  Let Sinx[25] = 26 {2 feet, nerrs=2}
  Let Sinx[26] = 0  {top of (no) head, nerrs=3}
  Let Sinx[27] = 0  {(no) face, nerrs=3}
  Let Sinx[28] = 15 {neck, nerrs=3}
  Let Sinx[29] = 15
  Let Sinx[30] = 15 {spine no hands, nerrs=3}
  Let Sinx[31] = 15 {waist, nerrs=3}
  Let Sinx[32] = 22
  Let Sinx[33] = 24
  Let Sinx[34] = 26 {2 feet, nerrs=3}
  Let Sinx[35] = 0  {top of (no) head, nerrs=4}
...
  Let Sinx[52] = 26 {2 feet, nerrs=5}
  Let Sinx[53] = 13 {top of head, nerrs=6}
  Let Sinx[54] = 14 {face, nerrs=6}
  Let Sinx[55] = 16 {neck, nerrs=6}
  Let Sinx[56] = 18
  Let Sinx[57] = 20 {spine+hands, nerrs=6}
  Let Sinx[58] = 15 {waist, nerrs=6}
  Let Sinx[59] = 22
  Let Sinx[60] = 24
  Let Sinx[61] = 26 {2 feet, nerrs=6}
 
So now let's think about the two parts (in green above) that you get to write. I called the printed line "aLine" but you can give it any name you like. To count the printed lines, you will need another variable -- I will call it "lino" -- which you must initialize before the repeat and then increment it inside the loop. You know how to do that. Variable aLine starts with the boat image for that line:
Let aLine = pLines[lino]
When there are no errors, or if the line number is greater than 9, you are ready to print it. Otherwise you need to concatenate (use the '#' operator) whatever body part is appropriate for this line number and this error count. The easy way is to define another variable as a body part line number, and look its initial value up in the index portion of array Sinx (outside the inner loop) then use it to index body parts inside the loop.

Some of those body part line numbers are zero, and in those cases you do not add a body part at all. That's a conditional inside a conditional, which may or may not be tricky. A simpler way is to add another line item to the pLines array,

Let pLines[27] = " "
then replace all the zero entries in the Sinx array with the new line number 27 (which tacks on a blank body part in those cases). Do you think you can do that?

There's some extra thinking to do this in English (about the same 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.
If it feels like it's too hard, don't worry, you'll get another shot at it after we get to Java. Or if you get stuck, ask a mentor for help, that's what they are here for.

Next is Java


Video Transcripts...

Seaman Introduction Transcript

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, and our graphic is a sailboat for the stick figure to stand on.

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 the Six Concepts, after which it presumably ran in the English Computer. If you missed or skipped over these informational sessions you might find the next step difficult, and if so, you should go back and review one or more of these preparational sessions:

1. (PBJ) You Already Know How (#1)
2. (PBJ) Conditionals & Input
3. (PBJ) Iteration
V. Variables
4. Calculator (#2)
5. Guessing Game (#3)
6. Rock Paper Scissors (RPS, #4)
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 never played Seaman (H---man), pause the video and go find somebody to play it with. You can't tell the computer how to do something you yourself don't understand.

Then you should think about the component parts of your program. Michael Schuff considers it helpful to
think about the known inputs: Are they single items, or is there a sequence of inputs? What needs to be set up before you can do anything with these inputs? What operations do you perform on them after they are in? Stuff like that.

Thinking about how the program is going to work is very, very important. I cannot stress it enough. You cannot write a computer program until after you understand exactly how each part of it will work. But you can understand (and write) the separate parts separately. In fact, with big programs you must do it that way, because nobody can keep the whole program in their mind all at once. Hide from view everything except the one part you are working on. The human mind can focus on seven things: one for the title, three lines to subdivide it into, leaving three more for other stuff. That's all.

The first step in the last three program designs was to break each program into two or three major parts described by a single descriptive line each. I think Seaman has two. Can you figure them out? In the English IDE, create a subroutine name for your program, then add two lines defining the major parts. Then make two more subroutines with those lines as names.

The next step is to take each part, each of these (two, or usually three, but not this time) subroutines, as if it were a whole program and subdivide it again. Where are your inputs? This is a game, do you have instructions for how to play? Where do those instructions go? What does your program do at the end of the first part?

What about the second part? Can you come up with two or three or four single items that make up the whole rest of the game, or should you be iterating over what is happening? What two or three things would be an abstract description of everything that happens inside that iteration? Pause the video and try to fill out in the IDE your main program and the two subroutines it calls. Can you do that?

If you succeeded, if when you clicked the Run button, it told you your design is OK, you are ready for the next video. If you know how to fix any problems, fix them and try again. If you are stuck, refresh the transcript page, and the Next link will take you to some additional helps.


Seaman Design Transcript: Defining the Problem

If you are flummoxed, let me give you some hints. Here are some ideas that might represent what your program needs to do -- and a few that are irrelevant (or completely wrong). You should decide which of these are major divisions of your program, which are parts of those divisions, and which of them are low-level details that don't belong in your high-level description. The ideas that belong, type them into your IDE in the order they belong, and click Run. Did it accept those ideas? If you have better ideas, summon the Mentor, and if they agree, your ideas will go into the documentation for our next batch of students -- and you will be manually advanced to the next level 
 
Add up total number of guesses and letters
Computer
Count incorrect guesses
Count letters
Decide if input is correct or not
First player
Guessing Game
Hide word from 2nd player
Human
Input dash
Input guess(es)
Input letter
Input whole word
Insert correct letter into dashes
Part One
Part Two
Play Seaman
Print dashes
Print dashes and letters
Print instructions
Print one boat part
Print one body part
Print whole picture
Repeat
Ridicule user for guessing wrong
Scoring
Second player
Third player


Each time your program structure is defined down to a new degree of detail, you should look at each line of the pseudo-code (that would be the English description you just did) and see if another layer of decomposition is justified. For example, if the first line has you printing the game rules, you can probably convert that directly to code with no additional design work.

If one or more lines are still some abstract description of more work to do, then you need to go through the process again for those lines, as if each line is the whole program. Most of the programs we give you can be fully analyzed in two or three levels. Seaman is probably ready for the next step, thinking about your data formats.
 

Arrays of Characters

"Array" is originally a military term, where the British and the French lined their armies up by rank and file, and shot their guns at each other in unison because the black powder they used made so much smoke you had to wait until everybody stopped shooting and the wind blew the smoke away before you could see to aim at the other guys. The Americans didn't fight like that, we invented guerilla war, where our guys shot from behind trees and the Brits couldn't see us even after the smoke cleared. And that was the end of arrays of soldiers, except in parades. So nobody knows what arrays are any more, and I can't say "You already know."

So think instead of a list, like a shopping list. Maybe you don't number the lines in your shopping list, but computers like numbers, so we number the lines in our list. Or rather, the computer numbers them sequentially, whether we use the numbers or not.

So let's think about how we might store a word like "HELLO" in an array, with one letter in each item of the array, like this picture. If you know the whole word when you are writing your program, you could do it in one line, like this:
Array myWord = "H","E","L","L","O"
But in the real world things are not always that convenient. Instead you might be getting the word one letter at a time, like this:
Array myWord
Print "Enter your word"
Let posn = 0
Repeat
  Input letter,1
  If letter < 'A' then Exit
  Add 1 to posn
  Let item posn of myWord = letter
  Next
Print myWord " is " posn " letters."
Notice that when this loop exits, variable posn has the size of the word that was input.

Try stepping through this in the IDE until you are pretty sure you understand it.

 
Button to open IDE


Let's say you want to reverse the letters of this word and print it with hyphens between the letters. You can pick out the letters one at a time, and pack them together with hyphens between:

Let aLine = "-"
Repeat posn {left over from first loop}
  Let letter = item posn of myWord
  Let aLine = aLine # letter # "-"
  Subtract 1 from posn
  Next
Print aLine
Notice that variable aLine is not an array, just the concatenation of the letters. You could build it as an array if you wanted:
Let item 6-posn of aLine = letter # "-"


Enough generalities about arrays and characters, how does this relate to keeping score for Seaman? That's next.



 

Seaman Scoring

You have a line item in your design where your program will be deciding if the guessed letter matches one of the letters in the first player's word. We (meaning the computer program) already know what the guess is (that was the previous line), and that it's in a variable (probably not yet named), and we are going to compare it to each letter of the original word. That would be an iteration, one of our "Six Ideas". This is why we need an array for that word, so we can pick out the letters, one at a time, to compare them to the guessed letter. You already know how to pick out an array element -- if not, go back and review Arrays in the Variables page and/or our more recent "Arrays of Characters" video or Transcript -- and you already know how to compare two variables, so all that's left is to decide what to do if the input letter is equal to the letter you picked out of the first player's word, and what to do if it is not equal (that would be an "Otherwise" line). If what you need to do is complicated or takes more than one line, make a subroutine. I called mine "ItsEqual" and "UnEqual".

Pause the video and try it now.

What we are doing here is just another level of what we have been calling "Top-Down-Design" (TDD). Here is my 'Player 2 Part' subroutine:

" Player 2 Part "
  Print dashes and letters
  Input letter
  Scoring
  Done
And this is the (subroutine) part we are designing right now:
" Scoring "
  Repeat {the number of letters in first player's word}
    Add 1 to {word position, starts at 0, now 1}
    if {the guessed letter} = {this letter in first player's word}
      then Do ItsEqual
    Next
  if {no letters changed} then Do UnEqual
Pause the video and see if you can write the two subroutines.
"ItsEqual"
  {replace dash in partial word with guessed letter}
  {remember somehow that you changed at least one letter}

"UnEqual"
  {add 1 to number of missed guesses (this will count the body parts)}
 

You still need to rewrite my {purple} comments as proper English code. Can you do that? You will need to choose names for your variables, and initialize them to zero before they are used, so the first iteration in the Repeat loop looks at the first letter, stuff like that. The only hard part is subroutine "ItsEqual", where you need to remember to change the dash in the same position as the letter that matched.

Can you figure out how to remember if you made any changes? Pause the video and try it before proceeding...

I suggest a variable, perhaps a count of each time you make a change. If it's still zero after the iteration, then you know, right? Don't forget to initialize it outside the loop.



 

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).

Next is Java


[2022 October 31]