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.
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.
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.
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.
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.
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:
"Print Seaman"
Let nerrs = 6 {test this subroutine...}
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.
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,
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:
Next is Java
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:
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:
Then you should think about the component parts of your
program. Michael Schuff considers it helpful to
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.
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.
Try stepping through this in the IDE until you are pretty
sure you understand it.
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:
"UnEqual"
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.
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:
We can similarly draw a sailboat for him to stand on (hence
the name "Seaman" which is also a pun on "see, [a] man"):
Basically you write the horizontal lines of the image
into character string constants in your program, which you print out as
needed:
Next is Java
[2022 October 31]
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.
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.
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.
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.
{Assume nerrs is the number of wrong
guesses so far, from 0 to 6}
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.
{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}
{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
{Assume pLines and Sinx are already
initialized}
Do Print SeamanArray pLines
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.
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] = " _/
\_"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.
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 are 10 kinds of people in the world,
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.
Those who understand binary,
and those who don't.
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.
1. (PBJ) You Already Know
How (#1)
Three times you watched me go from a vague idea to runnable
code, and once you did it yourself, four different programs in all.
2. (PBJ) Conditionals & Input
3. (PBJ) Iteration
V. Variables
4. Calculator (#2)
5. Guessing Game (#3)
6. Rock Paper Scissors (RPS,
#4)
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.
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.
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 dashesPart 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.
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
Notice that when this loop exits, variable posn
has the size of the word that was input.
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."
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 = "-"
Notice that variable aLine is not an array, just the concatenation
of the letters. You could build it as an array if you wanted:
Repeat posn {left over from first loop}
Let letter = item posn of myWord
Let aLine = aLine # letter # "-"
Subtract 1 from posn
Next
Print aLineLet 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".
" Player 2 Part
"
And this is the (subroutine) part we are
designing right now:
Print dashes and letters
Input letter
Scoring
Done" Scoring
"
Pause the video and see if you can write the two subroutines.
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"ItsEqual"
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.
{replace dash in
partial word with guessed letter}
{remember somehow
that you changed at least one letter}
{add 1 to number
of missed guesses (this will count the body parts)}
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.
_
( )
_|_
/ | \
/ | \
|
/ \
/ \
_/ \_
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.
/| _
/ | ( )
/
| _|_
/
| / | \
/
| / | \
/
| |
/
| / \
/
| / \
/________| _/ \_
______________________
\
/
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.
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).