APS101 Assignment #3

Play Words Game

Purpose

This assignment will give you practice with one- and two-dimensional arrays, graphical user interfaces (GUIs), main methods, reading from files and consoles, as well as the concepts from the first and second assignment. You will also develop a test suite.

Plan to spend a full hour reading this handout so that you thoroughly understand what we are asking for. Do this before you start programming! Take notes as you read. What classes do we want? What are the method names for each?

If you notice parts that are unclear, then please ask the instructor or post a message to the discussion board. The major changes/clarification will be posted to A3 FAQ page.

Introduction : Playing the game


Fig 1: The window  layout

The Play Words game is a computer game made up of a game window containing a rectangular grid of letters, an "Enter word" button and a display for the player's total points.


Fig 2: Starting to form the word "sane"

The goal of the game is to form words. The player selects letters by clicking the buttons representing the letters. As letters are selected, the buttons are highlighted if they are valid. A letter is valid if it is adjacent to the previous selected letter; adjacency can be horizontal, diagonal ...


Fig 3.1: Selecting 'e' as the next letter to complete forming the word. 'e' is adjacent to 'n'.

...or vertical.


Fig 3.2: Selecting 'd' as the next letter. 'd' is not adjacent to 'n' If an invalid letter is selected, all the highlighted buttons are cleared and the player must start making a new word to continue the game.


Fig 4.1: Selecting "Enter Word" to submit a word.

Once the player has finished building their word, they should select the "Enter Word" button.


Fig 4.2: Refreshing the game grid.

If the submitted word is found in the dictionary, (5*i) points are awarded for each letter of the word, where i is the index of the letter in the word) and the total points are updated accordingly. All the highlighted buttons are cleared and the letters of that word are replaced by random letters.

For example, for the word sane 30 points (i.e. s:5*0 + a:5*1 + n:5*2 + e:5*3 =30) are awarded (so you are way better off to make longer words).



Fig 5.1 , 5.2: Making an invalid word.

If the word formed is not found in the dictionary, a message pops up informing the player that their word is not valid. All the letters on the grid remain unchanged but the letters are cleared of any highlighting, and the player is penalized for up to 10 points (if the Total Points so far is >= 10 then 10 points are deducted, if Total Points <10 then it is set to 0) . The player must make another word to continue playing the game.


Fig 6: Messages

A message box pops when the player achieves enough points to move to the next level, or to win the game (see hasWon() method in PlayWords.java for more details)

In this assignment, we ask you to make your own graphical Play Words game that you can play with on your own.

Requirements

There are certain basic requirements that we will expect in your final design: sufficient testing, documentation of your code, and a good design approach to the assignment.

Testing

The product of this assignment is visual, but this doesn't mean that the testing portion of the assignment can be left out. On the contrary, most of the underlying logic of this assignment can be thoroughly tested with JUnit.

When testing, you do not have to worry about testing for malicious input (e.g. non-alphabetic characters on the grid, arrays whose dimensions don't match), but you should be prepared to handle letter grids of all sizes. Also, make sure to cover both typical and boundary conditions in your test. This means that you should not only use ordinary values to test your methods, but also values that test the limits of these methods. A few example scenarios you might want to consider:

These are just a few test conditions you should take into account. When in doubt, feel free to consult your TA or your instructor about the test cases you're considering.

Documentation

For this assignment, we expect you again to follow the style rules laid out in A2 rules .

As for Javadoc: we expect proper JavaDoc comments for:

A brief reminder: JavaDoc comments must begin with /** and end with */, and the following tags can be used to denote special roles within your comments:

We also expect non-JavaDoc comments throughout your code, especially in sections where the purpose of your code is not immediately clear.

General Design

The Play words game is composed of three major parts:

  1. The Play words game
  2. The driver for the game
  3. The window-based interface

For this assignment, we provide you with "starter code" which implements some of the PlayWords, GameDriver and GameTileListener classes. You must complete the parts missing from the provided classes, as well as write any new classes that are necessary. Assume that the code we have given you should be in the final product; this means that none of the method signatures that we have already specified should be changed in your final design.

When approaching this design, certain components are more important than others. Rather than programming the entire assignment at once, implement this assignment in stages, and make sure the current stage is working properly before moving on to the next.

The required parts are specified in the following sections.

Part 1:

The PlayWords Class

The PlayWords class represents the basic functionality of the game.

This class is responsible for performing the following operations:

  1. At creation, it initializes the instance variables used to store the current state of the game.
  2. When a letter is selected, it checks if it is a legal selection and allows the letter to letter to be selected if valid.
  3. When the user tries to enter a word, it checks if the word is in the dictionary and updates the grid layout (letters, points) accordingly.
  4. It reports information about the current state of the game when asked (whether the player has won the game, number of points reached, what the current grid layout is, etc.)

You should decide what instance variables (other than those provided) to use based on the method descriptions and starter code. Note that we have already defined the variable currentWord which is an array of Tile that stores the word selected so far (you will also implement the Tile class). Initially, it is null but it gets bigger when we call growCurrentWord(Tile) (see below).

You are required to implement the following methods for this class (note that some of these are helper methods that must be used in implementing more complex methods):

Method Name Description
PlayWords
(char[][], String)

The constructor for this class. This constructor takes in two parameters: a two-dimensional array of characters representing the game grid and a String that represents the path and name of the file that contains the dictionary. It uses the array to initialize its internal game grid. The grid represents the layout: the first dimension of the input array is assumed to be the vertical dimension of the layout (# of rows), and the second dimension of the array is the horizontal dimension of the layout (# of columns). For example, in a 4x5 array called grid, the top-left grid corner is at position (0,0), the top-right corner would be at grid[0][4], and the bottom left corner would be at grid[3][0]. The name of the dictionary file is used to load all the valid words into an array (look for the already given loadDictionary() method).

The constructor should also set all the default values for the other instance variables used.

boolean checkWord (String)

This method checks whether the given String is a valid word in the dictionary and returns true if it is, and false otherwise.

int calculatePoints ()

Returns the point value of the currentWord regardless of it being in in dictionary or not (so, it basically is just a helper that computes the sum of 5*i). if currentWord is null it returns 0.

boolean adjacentTo (Tile) This method takes in a Tile object and returns true if it is horizontally, vertically, or diagonally adjacent to the last letter selected in the current word; it returns false otherwise.
boolean growCurrentWord (Tile)

This method takes in a Tile object as a parameter. The Tile is added to the currentWord if it is adjacent to the end of it (so the array needs to be expanded), otherwise the currentWord is reset i.e. becomes null. The method returns a boolean value to indicate whether the Tile was added to the current word or not (true means successfully added).

void refreshGrid () This method updates the grid array by replacing the values in the current word by randomly generated letters.
int enterWord ()

This method constructs the word (i.e. a String) corresponding to the currentWord (you can assume currentWord is NOT null). If the word is valid (i.e. is in the dictionary), it computes the point value (a positive value) for the word and returns the value; it also updates the current total points for the game and repalces the the charateres in the grid with random ones (simply by calling refreshGrid). If the word is NOT valid (i.e. isn't in the dictionary), it computes and returns the penalty value (a number between 0 to -10), it also updates the current total points for the game. The penalty value depends on the current total points: if the total points so far is >=10 then 10 points are deducted otherwise all the total points are deducted (i.e. the player's total points will become zero). 
Note: regardless of word being valid or not, you should reset the currentWord at the end (i.e. making it null)

char[][] getGrid ()

Returns a two-dimensional array of characters that represents the current grid of letter values. The first dimension of the array represents the vertical dimension of the grid (i.e. rows), and the second dimension of the array represents the horizontal dimension of the grid (i.e. columns). The orientation of this grid should be consistent with that of the constructor's input parameter, so see that method's description for more clarification.

String toString ()

Returns a String that represents the current layout of the grid in String form. Each row of the grid is separated by a newline character '\n', and the letters are separated by spaces. For example, a grid with 3 rows and 4 columns will be represented as
String "r a k z\na f t u\ne k h g" (note that there is no '\n' for the last line) which looks like the following when printed:

r a k z
a f t u
e k h g

There should be no leading or trailing spaces in this String, and there should be NO  newline character after the final row.


You should build a tester for this class (PlayWordsTester), to make sure that it behaves the way you planned.

The Tile Class

The Tile class represents a tile clicked by the player.

You will need instance variables that represent the following information:

The letter that was clicked by the player.
The letter's row position.
The letter's column position.

You are required to implement the following methods for this class:

Method Name Description
Tile (char, int, int) The constructor for this class. This constructor takes in three parameters to initialize all the instance variables of the class.
int getRow () Returns the row position of the Tile.
int getCol () Returns the column position of the Tile.
char getContent () Returns the character at that Tile.
String toString () Returns a String that represents the Tile. For a letter "a" Tile in row 3 and column 4 the String returned should look like the following:
            "(3,4):a"

Part 2:

The Driver Class

This GameDriver class is the driver for this game. This class contains a main method, so it can be invoked from the command prompt. The game can be played in two ways:

  1. java GameDriver <pathToDictionary> fileLayout <filePath>
    where :

    <pathToDictionary> is the path and name of the file that contains the dictionary of words.
    <filePath> the location of an existing text file that contains a layout for a grid of lower-case letters.


  2. java GameDriver <pathToDictionary> random <NumRows NumCols>
    where :

    <pathToDictionary> is the path and name of the file that contains the dictionary of words.
    <NumRows NumCols> are the desired dimensions of a grid, which will contain randomly generated letters.


This class should perform the following actions:

  1. If fileLayout is selected, bring up a JFileChooser to allow the player to select a layout file. Use the <filePath> parameter passed in at the command line as the start directory for this JFileChooser.
  2. If random is selected, create a random grid of letters with the <NumRows NumCols> dimensions given on the command lines (you can use getRandomLetter() in PlayWords.java).
  3. Create a PlayWords object with the generated layout .
  4. Create a GameTileListener and a GameGUI, initializing each with the appropriate values.

Part 3:

The GUI Interface

The Graphical User Interface (GUI) is the window-based interface, which will display the game to the user in a JFrame and allow the user to play the game by clicking on JButtons to select letters or make words.

The GameGUI class

The GameGUI class inherits from the JFrame class and is for display purposes only. The window contains:

  1. A 2D grid of JButtons that reflect the state of the 2-D grid of letters from the, PlayWords game.
  2. A JButton labelled "Enter Word" that a player will select to submit a word.
  3. A JLabel that displays the player's current points.

Its main functions are to load up the grid of buttons with the letter grid when the game is started, and to update the button grid when a letter is selected or when the user submits a word. Even then, it relies on the GameTileListener class to determine when to update and what values to use.

The design of the GameGUI and its relation to the other classes is intentionally unspecified here, because this design component is left for you to decide.

To understand fully what this class does, make sure you read the last paragraph of the next class, describing how you will attach a "listener" to the GameGUI.

The GameTileListener class

This class extends the MouseAdapter class, and its basic function is to listen for mouse events. When attached to a button or window, it knows when the mouse has interacted with that component in any way, and will execute the appropriate method. Five methods are available for such purposes, in the cases where the mouse enters the component, exits the component, is pressed, is released, or is clicked.

For this assignment, you only need to concern yourself with the click action. Most of the GameTileListener class is provided for you, and contains a method that can be used to attach the GameTileListener to the GameGUI, as well as the signature and the starting line for the mouseClicked method. This method is invoked every time somebody clicks the mouse on a component that the GameTileListener is "attached" to. You are required to fill in the remaining functionality for the mouseClicked method, making it respond to the click event by manipulating the GameGUI objects appropriately.

How do you attach a GameTileListener object to the graphic component whose clicks it is listening for? Easy: check out the code in that you used in Week 10 Lab. There, a MouseAdapter class was attached to a JButton object by calling that object's addMouseListener() method. All graphic components (JFrames, JButtons) have such methods. To identify which listener it is attaching, your GameGUI class will have to take in a TileGameListener instance as a parameter in its constructor. To make sure you get this part right: read and understand the Week 10 Lab code; if necessary, build a few small JFrame/JButton classes and experiment with adding your Listener through the addMouseListener method until you're comfortable with it.

General GUI Operations

The combination of the PlayWords, GameGUI and GameTileListener components produces the overall behavior of the game. When the game is first invoked from the command line, the following connections are formed:

  1. An instance of the PlayWords object is created.
  2. An instance of the GameTileListener object is created.
  3. An instance of the GameGUI is created, using the reference to the GameTileListener object and the PlayWords object.

Once the constructors are done, the connections between the objects produce the following behavior when a player clicks on a letter or button in the GameGUI:

  1. The GameTileListener is invoked whenever a button is clicked in the GameGUI window .
  2. The GameTileListener tells the GameGUI object what selection was made.
  3. The GameGUI decides what to do with the selection and tells PlayWords object what to do.
  4. The PlayWords object tells the GameGUI how to update itself.

If the player makes a word that results in a win or going to the next level, bring up a JOptionPane with a congratulatory message to the user. A method that detects when the player has won or moved to the next level is provided for you.

Other Information

The Layout File

The layout file is a plain text file that stores any rectangular grid of lower-case letters, separated by single space characters. Each row of the grid is stored on a new line. Note: the first line of the file contains the dimensions of the grid and has the following from:
rowN colN
 where rowN and colN are the number of rows and columns of the grid.

You may assume that the grid dimensions will be greater than 1x1.

Make sure that the orientation of the grid layout is maintained when producing and updating the GUI window.

Error Conditions

Even though we assume a non-malicious player for this game, there are certain error conditions that you must anticipate.

Enhancements

WARNING: This section should only be considered if you have completed ALL of the other parts of this assignment, including testing and JavaDocs.

If you have completed the rest of the assignment, kudos will go out to students who add enhancements to their game, either in the form of extra features or more elaborate functionality. This is your chance to be creative, have fun and impress us with you imagination.

Required Files

The following files must be submitted with this assignment:

Hints and Tips