CS 1502: JAVA! Programming Assignment #2 - Spring 1999.

Program Title:   Making That Special Connection
Assigned:        April 2, 1999
P2 Program Due:  April 16, 1999

Files Provided:
o p2.nfo              - this file
o TestIC.class        - a test interface for your program
o TestIC.html         - Documentation for TestIC
o stylesheet.css      - Style sheet for TestIC documentation

Learning Objectives:
o Array instantiation/initialization
o 'for' loops for array iteration
o Model-View-Controller (MVC)

GAME OVERVIEW:

Most people are probably familiar with the game of Connect-4, but we'll
go through it anyways just to make sure.  The game bears a slight
resemblance to tic-tac-toe, but adds many fun twists.

The board is an 8 by 8 grid of spaces where the pieces will be played.
Two players alternatingly drop their colored pieces into each of the
columns, where they fall all the way to the bottom, landing on the
bottom row of the board or on top of another piece.  The objective of
the game is to get 4 of your pieces in a row before your opponent.  "In
a row" can mean vertically, horizontally, or diagonally.  For instance:

|   | X | O | O | X |   |
0   1   2   3   4   5   6   7

If the board looked like this, and it was O's turn, it would be a smart
move to drop into column 5 to block the diagonal Connect-4 that X is
about to get....

|   | X | O | O | X |   |
0   1   2   3   4   5   6   7

OK, so now O has successfully blocked X's attempt to win the game.  But
now X must deal with the same situation.  O is about to get a vertical
Connect-4 in column 5.  If X is to keep O from winning the game, he
should also go into column 5.

And so on.

This action-packed intensity lasts the entire length of the game!
Situations can arise where the entire board is filled and nobody has won
yet.  This is a tie, something tic-tac-toe players should be familiar
with.

Now that you're familiar with the game, let's get you familiar with the
data structure you'll need for the board.

ARRAYS OVERVIEW:

Arrays are simply matrices.  They are static data structures which can
have any number of dimensions and any size in any direction, but after
the array is created, it cannot be resized.  (That's why they are called
a "static" data structure.)

You will need to declare your array in the instance variable section of
your class so all of the class's methods can access it.  An array
declaration looks like:

private Donut[] boxOfDonuts = new Donut [ MAXDONUTS ];

It's a poor idea to hard code the size into the array declaration.  Use
a constant to specify the maximum elements.  The initial size of our
array will be 10.  (Note: One may also see the above line of code
written as:

private Donut boxOfDonuts[] = new Donut [ MAXDONUTS ];

Both lines are equally legal.)

A two dimensional array is similar in notation, except the brackets []
are replaced by double brackets [][]:

private Soda[][] TwelvePack = new Soda[3][4];
private Soda TwelvePack[][] = new Soda[3][4];

What you are actually creating here is not a 2-D array, but an array of
arrays.  You may wonder which of these brackets refers to the X
direction and which the Y direction ( have we created 3 rows and 4
columns or 3 columns and 4 rows? ).  Well, actually it doesn't matter as
long as you are consistent when you are referring to the array.

Also emphasized in this program is array initialization.  This is very
different from array instantiation.  Instantiating the array, which are
what the above lines of code do, simply declares the array.  Every
element in the array is initially null, so any attempt to access
anything in there will result in an error (NullPointerException to be
specific).  This is why we also initialize arrays, which puts a default
object in each spot in the array, so attempts to access the array will
not cause the program to die.

Let's also make you familiar with MVC...

MVC OVERVIEW:

A primary concept of Computer Science is an acronym, MVC, which stands
for Model-View-Controller.  What this refers to is dividing your program
into the functional part (model), the interface (view), and the input
(controller).

We will be partially implementing this idea in our program.  Why, you
ask?  Well, P6 this quarter will be giving your Connect-4 game a
graphical interface, and we want to completely eliminate duplication of
code.

In this case, though, we will be combining the Viewer and the Controller
into one class, the AsciiInterface class.  We'll get into the specifics
in a second, but it is important to realize that the driver will have no
references to println (besides debug statements) or util.readXXXX().
The game will have no knowledge of the interface type (ASCII or
graphical), and the interface will have no idea what game we're playing!

Since you'll be writing the driver first, and not worrying about the
interface until later in the program, we have provided the TestIC class
to test out your program with.  Use this as your interface until you get
the part of the program where you write your AsciiInterface.  The method
calls to TestIC are _identical_ to the calls in AsciiInterface.

To help you use the TestIC class, we have provided some Javadoc
documentation for the class.  If you open the TestIC.html file in a
browser, you will get a list of all of the method headers in this class
in the same format as the Sun API on their website.  The documentation
is fairly straight-forward.  One hint is to remember that

java.lang.String     -means-     String

PROGRAM WALKTHROUGH:

You'll need to create a P2.java file and create a class P2 inside it:

public class P2 {

(Don't forget your header.)  We'll first need some instance variables to
hold stuff:

private char turn;
private TestIC Bob;
private char[][] Board = ???

You should be able to fill in the ???'s by yourself.

To have your program work with the supplied code, you'll need your board
to use what is called "column-major" order.  That is, the board is done
like this:

Board[x][y]

rather than:

Board[row][column]

which is dramatically different.  If your program acts in strange ways,
check that you are using x/y, not row/column format.

We will have five methods and a constructor in the driver to set up the
board and play the game.  Let's go through them one by one.

main

public static void main ( String argv[] ) {

P2 myP2 = new P2();

We'll give you this one cause we're nice guys!  All it does is
call the constructor of P2.

constructor

public P2 ()

This is a pretty simple module (five lines to be exact).  It will
first set the initial turn to 'X' or 'O' (your choice).

Next it will instantiate the TestIC, Bob, and pass it a reference
to the Board:

Bob = new TestIC( Board );

For initially testing your program, you will use the TestIC
provided with the project.  After you have completed this class,
you will be writing an AsciiInterface yourself.

After the turn is set, a call to initBoard() should be made to
initialize the board array.  Next a call to playGame() is in order
to actually run the game.

Finally, a call to System.exit(0) will end the program after
playGame() finishes.

initBoard

private void initBoard ()

This method should loop through the array, probably using nested
'for' loops like this:

for ( int j=0 ; j<ROWS ; j++ ) {
for ( int i=0 ; i<COLS ; i++ ) {

At each item in the array, it should set the char there to a space
just so something is there, but when it's printed out it should
look blank.

playGame

private void playGame ()

This method, just as our MVC idea dictates, will have no
references to util.readXXX() or System.out.println().  All it will
do is loop indefinitely doing:

1) calling drawBoard() in the TestIC class:

Bob.drawBoard( turn );

2) calling getInput() from the TestIC class:

int input = Bob.getInput();

3a) if the input is -1, then call System.exit(0);
3b) otherwise addPiece() is called to add the piece.

If addPiece() returns true, then the piece was successfully
added and the turn should be changed; checkForWin() should be
called to see if someone won on that move.

If addPiece() returned false, then the piece was not added
successfully (column didn't exist or the column was full) and
so the turn should not be changed and we loop back to the
beginning.  Before you loop back, though, send printMessage()
in the TestIC the String:

Invalid Input. Try Again.

4) If checkForWin() returned true, then we have a winner!  Send
the TestIC method printMessage() the String:

"Player X is a winner"    or
"Player O is a winner"    depending on who won

Then exit the loop and let the method end.  This should let the
call to System.exit(0) in the constructor be called, so the
program will end at this point.

addPiece

private boolean addPiece ( int column )

This is most certainly one of the two hardest methods. The input
to the method is the column where the user chose to drop their
piece.  The value should be checked to see if it is higher than
the number of rows, or lower than 0.  If either of these occurs,
addPiece() must return false.

If the column is a valid choice, you must check to see if it is
full.  If the top row of this column has something other than a
space in it, then it is full.  Return false.

OK, now we're ready to add the piece assuming we haven't returned
false yet.  You need to loop down the column, checking to see if
the space is occupied by something other than a space.  If so,
then add the char representing the user's turn to the row ABOVE
where you are.  If you reach the bottom row, then just add the
char there.

Finally, so that your program will work correctly with TestIC,
number the top row as zero and the bottom as seven.

At the end of this method, return true to tell the calling method
that everything worked OK.

checkForWin

private boolean checkForWin ()

This is the other tough method.  To make things a bit easier,
we're not going to require checking for diagonal Connect-4's, just
horizontal and vertical ones.  We'll save diagonal for P6 =)

You need to split this task up.  You can't check for vertical AND
horizontal Connect-4's on one pass.  First do the horizontal.
You'll need that nested 'for' loop like before, and you'll need to
loop across each row one by one, keeping a tally of how many of
the current turn's pieces you've come across.

The idea is pretty simple.  Declare a temp int at the beginning of
the method.  When you come to a spot in the array, check to see if
its value matches the "turn" character.  If so, add one to temp.
If not, set temp to 0.  Before you go to the next spot, check if
temp is equal to 4 yet.  If it is, you can return true right then
and there!  If not, move on.

At the end of each row, you need to reset temp to 0 so you don't
count Connect-4's that wrap to the next row on the other side!

Do the same thing for the vertical checking, except go down the
columns instead of the rows (i.e., reverse the 'for' loop order
in your nesting).

Don't forget the closing curly brace to your class.

And finally you're done with your Connect-4 internal workings.  You can
test your progress as you go along by using the TestIC class distributed
with this package.

ASCIIINTERFACE

We'll now go through the AsciiInterface class.  This class has only
three methods and one constructor, so it should be a breeze!  You need
to obviously create an AsciiInterface.java file and put the class
declaration (and header) at the top.

Next, so you can test out the AsciiInterface with your P2, you will need
to change the instance variable at the top of P2.java from

private TestIC Bob;       to

private AsciiInterface Bob;

You also need to change your instantiation call within P2's constructor.

As long as you write your class with the same method names as we suggest
below, your calls to Bob will be valid whether it is to a TestIC or
AsciiInterface.

You'll need one instance variable, a double array of char's to hold a
copy of the board you'll get from the driver ( i.e.  private char[][]
Board ).

Constructor

public AsciiInterface ( char[][] newBoard )

This method is just two lines, the first is to copy the newBoard
parameter to the instance variable "Board".  The second is to
print out a greeting by sending printMessage() the String:

Welcome to Spring 99 Program 2

drawBoard

public void drawBoard ( char turn )

This method prints the board out to the screen.  The output should
look like the output from the TestIC class:

|   | X | O | O | X |   |
0   1   2   3   4   5   6   7

Try to keep the spacing pattern shown above.  Each column is three
spaces wide and the character centered within it.  Also put the
numbers at the bottom ( 0 to 7 ) so the users can easily tell
which column is which.  Also don't forget the turn indicator:

Player X please choose a column

printMessage

public void printMessage ( String msg )

It doesn't get much simpler than this!  We'll even give you the
entire method right here!

System.out.println ( msg + "\n" );

Tough, eh?

getInput

public int getInput ()

Here's another simple method.  All you need to do is call
readInteger() in the util class, convert the Integer to an int,
and return the int.  (See p1.nfo if you get stuck on this part.)

And you've completed the requirements for a 100%.  Though the code for
this assignment is much longer than your previous program, it is very
simple coding.  Use debug statements in your loops, and take things one
method at a time, and you should finish in no time =)

HINTS AND TIPS:

DEBUG

Debugging (finding programming boo-boo's) is a tough problem, even for
experienced programmers.  But simple little tricks like a DEBUG flag can
be of ENORMOUS use.  Here's what you do:

First, declare a constant at the top of the file:

private static final boolean DEBUG = true;

Then, drop lines like the following in your code at critical points:

if (DEBUG) System.out.println ( "My variable is now " + myVar );

Since booleans are inherently true or false anyways, there is no need to
formally say (DEBUG==true), though it does not hurt.  Don't feel
embarrassed to use this extensively.  This is considered one of the most
useful ways to find bugs.

Remember to set your DEBUG flag to false to check your outputs with FC
or DIFF, and certainly before you turn your code in.

I REPEAT:  TURN DEBUG OFF BEFORE TURNING YOUR CODE IN.

From this point onward in CS1502 programs, you are required to use
if(DEBUG) code at least a few times (hopefully more) per assignment, and
you will be penalized for not having DEBUG code.

UTIL Error

If you're getting errors about an unknown variable named "util" or a
ClassDefNotFound error, make sure you have a copy of util.java in the
same directory as your P2.java.

Comments

Simply put, if you do not comment your code, we will bring wrath upon
your program grade.  Well, maybe not 'wrath', but it won't be pretty.

Each method should have a header similar to the comments from P1's code,
each instance variable should be commented, and any code that is not
obvious should be explained briefly in a comment.

This is the program where we start taking the "Programming Style" part
of the Requirements section _seriously_.

Invalid Input

For this program, you only have to worry a little about invalid input.
If the user enters 27 as the column choice, you should gracefully print
out about that message about invalid input and, like the instructions
for playGame() say, loop back and ask the user for the input again.

But if you try to input a letter, for instance, into util.readInteger()
your program will crash.  Don't worry about this.  Assume that the user
will enter a number.

Programming Style on Checklist

The requirement checklist below may seem intimidating right now.  Keep
the style neat and in good form.  Don't feel pressured to document every
single ling, but just write the code neatly and you'll do fine.  Note
that the section 2 (Software Design) is only a generic template; each
program will have a specific point breakdown for software design.  This
is detailed on each program's cover sheet (which you will get back with
your graded program), but not necessarily laid out for you in the .nfo
files.  Just like inline commenting, if you follow good OO design
practices, then you will do fine, but we've got to draw the line
somewhere to let you guys figure some things out on your own.  If you
are confused on design, then, as always, ask your TA.

COMPILERS:

As a reminder, assure that your program compiles and runs as expected
under Sun's JDK 1.2

EXTRA CREDIT:

Sorry, no extra credit is available for this assignment.

REQUIREMENT CHECK LIST:

IMPLEMENTATION:

For 35/70 (50%):
- Compiles with Sun JDK 1.1.7
- All P2 Class methods implemented
- Game displays properly using the TestIC
- Game plays using the TestIC
- Game does not randomly crash

For 50/70 (71%): Everything for 50%, plus:
- Horizontal and vertical Connect-4's detected properly
- Game ends on a Connect-4

For 70/70 (100%): Everything for 71%, plus:
- AsciiInterface Class methods implemented correctly
(input taken correctly, game plays and displays properly)
- Columns labeled

PROGRAMMING STYLE:

0.  Code Format
-code easy to read and understand
-includes student's name
-DEBUG code implemented

1.  Documentation
-every method and constructor has a method header, including
pre- and post-conditions if any
-has description of any parameters and return values using
@param and @return tags
-inline code documentation on non-obvious code segments

2.  Software Design
-minimal duplication of code/behavior
-no direct access to instance variables except within the
class where they reside
-uses constants rather than hard-wiring values
-uses good variable names
-demonstrates proper object oriented design

PROGRAM RESTRICTIONS:

These are the restrictions for this program.  You MUST do the
following:

o Your driver must be called P2.java.
o You must implement the required methods and classes.
o You may add any additional method(s) or variable(s) as you see
fit.

TURNIN:

o  Files to be turned in (Be sure to ftp the files in ascii):

P2.java
AsciiInterface.java

o  Files NOT to turn in (You shouldn't have altered these, so we
already have them.):

TestIC.class
TestIC.html
stylesheet.css
util.java

o  How to turnin:
o  You mail e-mail your work to dagon@cc.gatech.edu.
Please join all the files into a single attachment,
perhaps as a .zip file.