This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Programming Assignments

2-week Assignments

1 - Project 1 - Shortcut Scrabble

Due Feb 3 - Shortcut Scrabble is a simplified version of Scrabble…
'SCRABBLE' spelled out on what looks like a single row of a scrabble board to match the description of 'Shortcut Scrabble' that follows in the assignment.

Introduction

This assignment is intended to be a chance for you to review concepts from CS149 by completing a miniature PA (Programming Assignment). You will implement two of the classes to play Short Cut Scrabble. Scrabble is a game where players get a set, or “hand”, of wooden pieces, each one with a letter and point value on it. On their turn the player forms a word using some of the letters from their hand and places them on the board. The board has places for the wooden pieces, marked with special symbols, some of which will have a “multiplier” effect on the letter point value that is played in that location. In the real Scrabble , the board is a large square and letters must be played in such a way that each word connects to the others that have been played similar to a crossword puzzle. In Short Cut Scrabble, the board is just a single horizontal strip and a player just plays by inserting their word on the board to get points.

You should implement the two classes, Letter.java and Hand.java, from the UML diagram below. The other classes shown, Board.java and PlayScrabble.java are provided for you, along with tests for each of the classes you should implement.

Provided Files (no modifications are expected or permitted)

Implementation

  1. PlayScrabble.java
  2. Board.java

Tests

Other than only the slightest modifications (to help the autograder award/deduct points) these are precisely the tests that the autograder (gradescope) will use to test your code. You should run these tests to make sure your code is working correctly before submitting your code to gradescope.

  1. LetterTest.java
  2. HandTest.java

UML Diagram

classDiagram
class PlayScrabble:::providedCodeNoEdit
    <<utility>> PlayScrabble
    PlayScrabble: +main(args String[])$ double
class Board:::providedCodeNoEdit
  Board: -Letter[] board
  Board: -int[] pointMult
  Board: +Board(multiplier int[])
  Board: +getLetter(index int) Letter
  Board: +getPointMult(index int) int
  Board: +getBoardScore() int
  Board: +play(letter Letter, index int) boolean
  Board: +getLetterScore(index int) int
  Board: +toString() String
class Hand
  Hand: +int MAX_SIZE{ =8 readonly}$
  Hand: -Letter[] hand
  Hand: -int size
  Hand: +Hand(size int)
  Hand: +Hand()
  Hand: +getSize() int
  Hand: +getLetter(index int) Letter
  Hand: +insert(letter Letter, index int) boolean
  Hand: +remove(index int) Letter
  Hand: +indexOf(letter char) int
  Hand: +toString() String
class Letter
  Letter: -char letter
  Letter: -int points
  Letter: +Letter(letter char, points int)
  Letter: +getLetter() char
  Letter: +getPoints() int
  Letter: +equals(other Letter) boolean
  Letter: +toString() String
PlayScrabble -- Board
PlayScrabble -- Hand
Hand -- Board
Hand -- Letter
Board -- Letter

Part 1 - Create Letter.java

Implement the class and methods according to the UML and specifications below.

Letter Constructor and Accessors

The Letter constructor and accessors should be implemented to initialize the character and points with the constructor parameters as shown. You can assume that the arguments passed to the constructor parameters will be correct. In other words, no parameter checks are required.

equals

The equals method should return true if both the character and the point value associated with this letter are equal to the character and point value of the other letter.

toString

The toString method should return a String describing the letter consisting of “Letter: " with one space after the colon followed by the character, another space, then “Points: " followed by the points. For example the String returned by a Letter with letter assigned ’t’ and points assigned 3 will be: “Letter: t Points: 3”

Part 2 - Create Hand.java

Implement the class and methods according to the UML and specifications below. When implementing these methods make sure to avoid code duplication by using other methods in the class as appropriate.

Hand

The default no-argument constructor should create a hand of MAX_SIZE.

Hand(int size)

This constructor should create a hand of size. If size is less than zero, a hand of size zero should be created. If size is greater than MAX_SIZE a hand of MAX_SIZE should be created.

insert

If index is within range and there is not another letter in the hand at index, the letter should be inserted into the hand at index and return true. If those conditions do not hold, false should be returned.

remove

If index is within range, the letter at index should be removed from the hand (the location set to null) and the letter that was at index returned. If there is no letter at index, return null.

toString

This method should return a String consisting of the following for each letter in the hand: index followed immediately by a colon, then a space, then the Letter toString followed by a semicolon, and a final space. If there is no letter at index, i.e. the location is null, then insert a dash ‘-’ where the letters toString would be printed.

indexOf

This method should search through the hand and return the index of the first occurrence of letter. If the letter is not in the hand, return -1.

getLetter(int index)

This method should return the value at the given index in the hand.

getSize

This method should return the size the hand was initialized to.

Submission and Grading

You should never start design or construction until you completely understand the project.

You should start by carefully reading the project specifications. (In general it is a good idea to print a paper copy so that you can take notes and perform calculations as you read.)

Implement all of the classes (in accordance with the specifications, perhaps informed by the Implementation Advice above) and submit them to gradescope .

You are not required to submit tests for these classes.

Grading

Project PartWeight
Checkstyle20%
Correctness80%

You may submit to Gradescope an unlimited number of times.

Since nobody will be looking over your shoulder, you can use any process that you would like to use. However, it is strongly recommended that you use the process described here.

Get Started

  1. ๐Ÿ“– Read and ๐Ÿง  understand the entire assignment.
    • to each their own and all, but if your metacognitive skills are anything like mine were(n’t) ๐Ÿ˜ฌ when I was taking a similar class back in my day, you may find it worthwhile to print the specs out and read them with a pen ๐Ÿ–‹๏ธ or highlighter in hand ๐Ÿ“. This is also makes for a convenient tool ๐Ÿ› ๏ธ with which to accost your favorite TA or instructor ๐Ÿ‘ฉโ€๐Ÿซ with questions in the hallway, strolling campus, or wherever you find them ๐Ÿฅท (“Office Hours” are always great of course).
  2. ๐Ÿ“ Write down any questions you have about the assignment.
    • if you have any questions about the assignment, ask your classmates, TA, or instructor.
  3. If you’ve gotten to this step in the process at least 5 days before the assignment’s deadline ๐Ÿ—“๏ธ, you basically gave yourself bonus points ๐ŸŽ‰.
  4. Create a project for this assignment named pa1. ( Remember , do NOT create a module-info.java and DO create separate folders for source and class files). 3. Activate Checkstyle for this assignment.
  5. Add the provided code to your project, directly in the src folder.
    • You may need to right click on the project and choose Refresh to see the new files in Eclipse.

Stub it out

  1. Create the Letter class in your project.
    • it should contain all of the methods (with appropriate signatures), each of which should return some artificial value (e.g. return 0; or return null;, return false;) for now.
      • Note: you may wish to add a comment in the code any time you write code that you intend to replace later. For example, you might write // TODO: replace this with real code or // FIXME: implement this method.
  2. Add the <code>javadoc</code> comments to the Letter class.
    • For reference on javadoc syntax, take a look at the provided classes.
  3. Ensure your file has no checkstyle errors (you’ll likely want to take advantage of the autoformatter here by choosing Format from the Source menu in Eclipse).
  4. At this point, there should be no errors (Java nor Checkstyle) in your Letter class.
  5. (repeat the above for Hand.) Create the Hand class in your project.
    • it should contain all of the methods (with appropriate signatures), each of which should return some artificial value (e.g. return 0; or return null;, return false;) for now.
      • Note: you may wish to add a comment in the code any time you write code that you intend to replace later. For example, you might write // TODO: replace this with real code or // FIXME: implement this method.
  6. Add the javadoc comments to the Hand class.
    • For reference on javadoc syntax, take a look at the provided classes.
  7. Ensure your file has no checkstyle errors (you’ll likely want to take advantage of the autoformatter here by choosing Format from the Source menu in Eclipse).
  8. At this point, there should be no errors (Java nor Checkstyle) in your Hand class, and neither in this project at all.

Run the unit tests

  1. run the unit tests for the project.
    1. right-click on the project int he sidebar of eclipse
    2. choose Run As -> JUnit Test.
    3. you should see that all or most of the tests fail.

Implement the Letter class

  1. add the fields listed in the UML diagram.
  2. add the ๐Ÿšœ constructor listed in the UML diagram.
  3. add the methods listed in the UML diagram.
    1. write the accessors (also called getters) first.
      • note: did you notice the Checkstyle error about missing javadoc comments for these methods? (no, you didn’t because if you wrote these methods according to the specifications, and have Checkstyle configured correctly, it will not complain about missing javadoc comments for these methods ๐Ÿ˜. If you’re curious about why, check out <code>allowMissingPropertyJavadoc</code> in the CHeckstyle docs )
    2. write the equals method
    3. write the ๐Ÿงต toString method

Implement the Hand class

  1. add the fields listed in the UML diagram.
  2. add the ๐Ÿšœ constructors listed in the UML diagram.
  3. add the methods listed in the UML diagram.
    1. write the accessors (also called getters) first.
    2. write the ๐Ÿงต toString method
    3. write the insert method
    4. write the remove method
    5. write the indexOf method

Test with the driver class: PlayScrabble

  1. right-click on the project and choose Run As -> Java Application.
    • Eclipse will look for which class has the main method and run that. In this project that should only be PlayScrabble.
  2. You should see output similar to the depiction in a later section.
  3. Notice that the game waits for you to type a number or letter and then press enter after each to continue its work.

Ensure that all of the provided tests pass

  1. Run the unit tests for the project.
    1. right-click on the project int he sidebar of eclipse
    2. choose Run As -> JUnit Test.
  2. you should see that all of the tests pass (in which you already know the score you will get from Gradescope! ๐Ÿ’ฏ)

Help

Example Game

*** Welcome To Shortcut Scrabble ***

=========================================================
The board:
Entries:     --------
Multipliers: 31211213
Points: 0


Your hand:
0: Letter: v Points: 3; 1: Letter: u Points: 4; 2: Letter: n Points: 2; 3: Letter: y Points: 0; 4: Letter: g Points: 3; 5: Letter: i Points: 0; 6: Letter: m Points: 3; 7: Letter: a Points: 0; 
=========================================================

Where would you like to move? (0-7, 8 to quit)
0
What letter would you like to play?
v
Played Letter: v Points: 3 at position 0

=========================================================
The board:
Entries:     v-------
Multipliers: 31211213
Points: 9


Your hand:
0: -; 1: Letter: u Points: 4; 2: Letter: n Points: 2; 3: Letter: y Points: 0; 4: Letter: g Points: 3; 5: Letter: i Points: 0; 6: Letter: m Points: 3; 7: Letter: a Points: 0; 
=========================================================

Where would you like to move? (0-7, 8 to quit)
1
What letter would you like to play?
y
Played Letter: y Points: 0 at position 1

=========================================================
The board:
Entries:     vy------
Multipliers: 31211213
Points: 9


Your hand:
0: -; 1: Letter: u Points: 4; 2: Letter: n Points: 2; 3: -; 4: Letter: g Points: 3; 5: Letter: i Points: 0; 6: Letter: m Points: 3; 7: Letter: a Points: 0; 
=========================================================

Where would you like to move? (0-7, 8 to quit)
2
What letter would you like to play?
i
Played Letter: i Points: 0 at position 2

=========================================================
The board:
Entries:     vyi-----
Multipliers: 31211213
Points: 9


Your hand:
0: -; 1: Letter: u Points: 4; 2: Letter: n Points: 2; 3: -; 4: Letter: g Points: 3; 5: -; 6: Letter: m Points: 3; 7: Letter: a Points: 0; 
=========================================================

Where would you like to move? (0-7, 8 to quit)
3
What letter would you like to play?
n
Played Letter: n Points: 2 at position 3

=========================================================
The board:
Entries:     vyin----
Multipliers: 31211213
Points: 11


Your hand:
0: -; 1: Letter: u Points: 4; 2: -; 3: -; 4: Letter: g Points: 3; 5: -; 6: Letter: m Points: 3; 7: Letter: a Points: 0; 
=========================================================

Where would you like to move? (0-7, 8 to quit)
4
What letter would you like to play?
g
Played Letter: g Points: 3 at position 4

=========================================================
The board:
Entries:     vying---
Multipliers: 31211213
Points: 14


Your hand:
0: -; 1: Letter: u Points: 4; 2: -; 3: -; 4: -; 5: -; 6: Letter: m Points: 3; 7: Letter: a Points: 0; 
=========================================================

Where would you like to move? (0-7, 8 to quit)
8

Bye!

2 - Project 2 - Accessibility Assessments Analysis

Due Feb 17 - Analyzing the ability of automated accessibility checkers to detect problems on websites.

Introduction

In order to evaluate systems or tools, we often use benchmarks . These are often a collection of assessments on which new and existing tools compete to perform well. For this assignment, we will be looking at the results of multiple tools (or “checkers”) that were run on a benchmark created by the United Kingdom’s Government Digital Services to test accessibility checkers. An accessible page is one that is usable by people with disabilities, many of whom will be accessing the web with assistive technologies such as screen readers or dictation software . The benchmark includes series of assessments, each with a single introduced error. These assessments are grouped into categories with other related assessments.

These assessments have been run on 13 different accessibility checkers and the full results have been made publicly available. For this assignment, we will use the a11yCheckersResults.txt file that contains the results of the assessments for only 4 of the 13 checkers.

a11yCheckersResults.txt format

The file is organized such that each line contains the results for one assessment organized as follows:

[category] [google result] [wave result] [sortsite result] [aslint result] [assessment description]

The first 5 parts of a line (the [1] category and [2-5] result of the assessment for each checker) are all a single “word”. The last part of the line is the assessment description, and it is of variable length.

The result of the assessment for each checker is a single word that indicates the result of the assessment. The 6 possible results are:

  1. error
    • the issue was properly found
  2. error_paid
    • the issue was properly found in the paid version
  3. warning
    • the tool only gave a warning
  4. manual
    • the tool required the user to check
  5. identified
    • The tool noticed the issue, but didn’t give a warning
  6. notfound
    • The tool failed to identify the issue

For instance, the line for the test that is used to see if a person can visually determine which element has keyboard focus looks like this:

Keyboard notfound notfound error error Keyboard focus is not indicated visually

This line indicates that the assessment is in the Keyboard category of assessments, the error was not detected by the Google or WAVE tools, but was detected by SortSite and ASLint.

In this PA, you will write code to read in the assessment results list and then use them to analyze different information about the assessments.

Part 1 - AccessibilityAssessment

You are to design and implement a class named AccessibilityAssessment, which stores the category and description of the assessment and the results of the assessment for the four checkers. The constructor for the class should take all 6 pieces of information as parameters and store those values in fields. It should have accessor methods for each value, e.g., getCategory, getDescription, getGoogleResult, etc. It should also have a toString method which presents a readable format of the results of the assessment.

classDiagram
class AccessibilityAssessment
AccessibilityAssessment: -String category
AccessibilityAssessment: -String googleResult
AccessibilityAssessment: -String waveResult
AccessibilityAssessment: -String sortsiteResult
AccessibilityAssessment: -String aslintResult
AccessibilityAssessment: -String description
AccessibilityAssessment: +AccessibilityAssessment(category String, googleResult String, waveResult String, sortsiteResult String, aslintResult String, description String)
AccessibilityAssessment: +getCategory() String
AccessibilityAssessment: +getDescription() String
AccessibilityAssessment: +getGoogleResult() String
AccessibilityAssessment: +getWaveResult() String
AccessibilityAssessment: +getSortsiteResult() String
AccessibilityAssessment: +getAslintResult() String
AccessibilityAssessment: +toString() String
AccessibilityAssessment: +equals(other Object) boolean
AccessibilityAssessment: +passed(checkerPartialName String) boolean

Constructor

The constructor is not required to validate its parameters. It should simply store the parameters in the corresponding fields.

toString(): String

This method should return a (1-line) String with the following information:

  1. The category of the assessment followed immediately by - (a space, a dash, and a space).
  2. The results of the assessment for each checker (in the order presented in the UML diagram and the constructor parameters) formatted as follows:
    1. The name of the checker (i.e. Google, WAVE, SortSite, or ASLint) followed by : (a colon and a space)
    2. The result of the assessment for the checker (from the previously enumerated list of valid result String values), followed by (a space).
  3. The description of the assessment, preceded by - (a dash and a space).

equals(other: Object): boolean

This method should return true if the other object is an AccessibilityAssessment object with the same category, description, and checker results (for all 4 checkers) as this object. It should return false otherwise.

passed(checkerPartialName: String): boolean

This method should return true when the checker whose (case-insensitive) name contains checkerPartialName had a result of error or error_paid. It should return false otherwise. For example let’s say this AccessibilityAssessment object is representing the 2nd line of the provided a11yCheckersResults.txt file, which reads:

Content notfound notfound error_paid notfound Plain language is not used

In this case, we should have created an AccessibilityAssessment object with the following values:

  • category: Content
  • googleResult: notfound
  • waveResult: notfound
  • sortsiteResult: error_paid
  • aslintResult: notfound
  • description: Plain language is not used

So if we call passed("google") on this object, it should return false because the Google checker did not find an error. If we call passed("sortsite") on this object, it should return true because the SortSite checker found an error (in the paid version). If we call passed("wave") on this object, it should return false because the WAVE checker did not find an error. If we call passed("lint") on this object, it should return false because the ASLint checker did not find an error.

Part 2 - AccessibilityResults

The file a11yCheckersResults.txt as been provided for you, which contains the information about assessments used by the UK Government Digital Services to evaluate accessibility checkers. Each line in the file contains the information about a single assessment organized as described previously. You are to design and implement a class named AccessibilityResults that reads in the assessment information from a file of this format, stores them in an ArrayList of AccessibilityAssessment objects, and provides methods for accessing that information. When you are reading in the information, make sure that you are storing the values in the most appropriate types. Your implementation of AccessibilityResults should conform to the following UML diagram as well as the detailed specifications that follow. Note: you may assumes that none of the parameters will be null.

classDiagram
class AccessibilityResults
AccessibilityResults: -ArrayList~AccessibilityAssessment~ assessments
AccessibilityResults: +AccessibilityResults(filename String)
AccessibilityResults: +numTests() int
AccessibilityResults: +saveResults(filename String, format String, results ArrayList~AccessibilityAssessment~)
AccessibilityResults: +showTestResults(details String) ArrayList~AccessibilityAssessment~
AccessibilityResults: +showByCategory(category String) ArrayList~AccessibilityAssessment~
AccessibilityResults: +showAllFailed() ArrayList~AccessibilityAssessment~
AccessibilityResults: +passing(name String, category String) ArrayList~AccessibilityAssessment~
AccessibilityResults: +numPass(name String, category String) int
AccessibilityResults: +getAll() ArrayList~AccessibilityAssessment~

In particular, this class should have the following methods:

constructor

This method should take the filename as a parameter and should read in the file of accessibility assessments. The constructor should parse each line in the file to create AccessibilityAssessment instances and store them in the assessments ArrayList. The constructor should use try-catch exception handling to print an error message if an invalid filename is found. The error message should be formatted as follows: File not found: filename (where filename is the name of the file that was passed in as a parameter).

numTests

This method takes no parameters and returns the number of assessments that are stored in the ArrayList.

getAll

This method takes no parameters and (as already documented int he UML diagram above) returns an ArrayList. This ArrayList should contain all of the AccessibilityAssessment objects that were read in from the given file by the AccessibilityResults constructor.

saveResults

This method expects 3 parameters:

  1. filename: The path to the file to which the results should be written.
  2. format: The format string for the final line of the output.
  3. results: the ArrayList of AccessibilityAssessment objects to be written.

This method should write each of the AccessibilityAssessment objects in the results ArrayList to its own line of the file specified by filename. These lines should be formatted according to the AccessibilityAssessment’s toString. The final 2 lines of the file should be:

  1. an empty line
  2. a line formatted according to the format parameter. This line will be passed a integer to support messages like, Total tests matching: 10 or Total tests failed: 51.

Use try-catch exception handling to print an error message if an invalid filename is found. The error message should be formatted as follows: File not found: filename (where filename is the name of the file that was passed in as a parameter).

showTestResults

This method takes assessment details (or a portion of the details) as a parameter, and both returns an ArrayList of AccessibilityAssessments that match (or contain) that detail (should be case insensitive) in either the category or description and writes those matches to a file (named as showTestResults-<details>.txt) followed by a summarizing message. The summarizing message should read as follows. For example, if the information from a11yCheckersResults.txt was read in and stored in a AccessibilityResults object named a11y, then a11y.showTestResults("Colour") should write the following to the file named showTestResults-Colour.txt:

Colour/Contrast - Google: notfound WAVE: notfound SortSite: notfound ASLint: manual - Colour alone is used to convey content 
Colour/Contrast - Google: error WAVE: error SortSite: error_paid ASLint: notfound - Small text does not have a contrast ratio of at least 4.5:1 so does not meet AA 
Colour/Contrast - Google: error WAVE: error SortSite: error_paid ASLint: notfound - Large text does not have a contrast ratio of at least 3:1 so does not meet AA 
Colour/Contrast - Google: error WAVE: error SortSite: error_paid ASLint: notfound - Small text does not have a contrast ratio of at least 7:1 so does not meet AAA 
Colour/Contrast - Google: error WAVE: error SortSite: error_paid ASLint: notfound - Large text does not have a contrast ratio of at least 4.5:1 so does not meet AAA 
Colour/Contrast - Google: notfound WAVE: notfound SortSite: notfound ASLint: notfound - Focus not visible 
Links - Google: notfound WAVE: notfound SortSite: notfound ASLint: notfound - Identifying links by colour alone
Forms - Google: notfound WAVE: notfound SortSite: notfound ASLint: manual - Errors identified by colour only
Forms - Google: warning WAVE: error SortSite: error ASLint: error - Errors identified with a poor colour contrast
HTML - Google: notfound WAVE: notfound SortSite: notfound ASLint: notfound - Inline style adds colour

Total tests matching: 10

showByCategory

This method takes a category (or a portion of the category) as a parameter, and returns an ArrayList of all of the AccessibilityAssessments that match (or contain) that category (should be case insensitive). It writes these matches to the file named showByCategory-<category>.txt. As before, the number of matching assessments should be displayed at the end. For example, if the information from a11yCheckersResults.txt was read in and stored in a AccessibilityResults object named a11y, then a11y.showByCategory("navigation") and a11y.showByCategory("nav") should write files containing the following (in files named showByCategory-navigation.txt and showByCategory-nav.txt, respectively ):

Navigation - Google: notfound WAVE: notfound SortSite: notfound ASLint: notfound - Inadequately-sized clickable targets found

Total tests matching: 1

showAllFailed

This method takes no parameters, and returns an ArrayList containing the AccessibilityAssessments that all checkers failed (i.e. an assessment is only shown if Google, WAVE, ASLint, and SortSite all failed it, and if even one of the checkers passed the assessment, it is not shown). The method will alsop write these AccessibilityAssessments to a file named showAllFailed.txt followed by a summarizing statement in the format specified below.

For example, if the information from a11yCheckersResults.txt was read in and stored in a AccessibilityResults object named a11y, then a11y.showAllFailed() should write the following to showAllFailed.txt:

Content - Google: notfound WAVE: notfound SortSite: notfound ASLint: notfound - Content identified by location
...
HTML - Google: notfound WAVE: notfound SortSite: notfound ASLint: notfound - Inline style adds colour
HTML - Google: notfound WAVE: notfound SortSite: notfound ASLint: notfound - PRE element without CODE element inside it

Total tests failed: 51

passing

This method takes two parameters, the checker name and category, and returns an ArrayList of assessments that had a result of either error or error_paid. The method will also write these AccessibilityAssessments to a file named passing-<checker>-<category>.txt followed by a summarizing statement in the format specified below. (Note this method should work with a partial checker name or partial category name and should be case insensitive). For example, if the information from a11yCheckersResults.txt was read in and stored in a AccessibilityResults object named a11y, then a11y.passing("Goog","") should write something like the following excerpt to passing-Goog-.txt:

...
Colour/Contrast - Google: error WAVE: error SortSite: error_paid ASLint: notfound - Small text does not have a contrast ratio of at least 4.5:1 so does not meet AA
...

Total tests matching: 23

numPass

This method takes two parameters, the checker name and category, and returns the number assessments that had a result of either error or error_paid. (Note this method should work with a partial checker name or partial category name and should be case insensitive). For example, if the information from a11yCheckersResults.txt was read in and stored in a AccessibilityResults object named a11y, then a11y.numPass("Goog","") should return 23 and a11y.numPass("lint","htm") should return 2.

Avoid redundancy and be conservative in your use of fields - if a data value does not need to persist over the life of the object, declare it to be local to the method that needs it.

  1. Create a new project in Eclipse called PA2.
  2. Write and test AccessibilityAssessment.
  3. Write and test AccessibilityResults.

AccessibilityAssessment

  1. Define the instance variables
  2. Write the constructor (if you wish, Eclipse can be helpful in generating a first draft of the constructor).
  3. Write the accessors (“getters”). (Again, if you wish, Eclipse can be helpful in generating these methods.)
  4. Test the constructors and accessors.
  5. Write the equals method. (Again, if you wish, Eclipse can be helpful in generating this a first draft of this method.)
  6. Test the equals method.
  7. Write a test for what the toString method should do. (you should be failing this test right now)
  8. Write the toString method. If you wrote your test well, you should be passing the test when you’re done with this method.

AccessibilityResults

  1. Define the instance variable
  2. Write the constructor
    1. Probably begin by having your constructor manually create a few AccessibilityAssessment objects and add them to the ArrayList.
    2. Once you have that working, you can start working on reading the AccessibilityAssessments from a file. Perhaps as you move into this step, you should create a smaller version of the data file, (maybe just make a copy of a11yCheckerResults.txt and delete all but the first 6 or so lines) until you’re happy with how it’s working, and then move on to the full file.
  3. Write saveResults
    • note that this method is is early in the instructions, especially that it’s before other methods that should… write… results… to a file.

Additional Resources

JDK Scanner class

The Scanner class in the Java Development Kit (JDK) is useful for reading in data. It can help parse data from the command line as well as from a file. Take a look at the Scanner javadoc and also at the ArrayList lab (particularly in the Editor class) and the File I/O lab for examples of how to use the Scanner class.

JDK String methods

You may find several of the Java Development Kit’s String methods useful in this assignment. Here are some links to the documentation for a few of these methods:

  1. https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html#contains(java.lang.CharSequence)
  2. https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html#format(java.lang.String,java.lang.Object...)
  3. https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html#toLowerCase()

3 - Project 3 - Violet's Vending Venture

Due Mar 3 - Simulate business decisions for your friend Violet’s Vending Venture.

Introduction

Your friend Violet and her family are considering starting a vending machine business. To make sure it will be profitable, they have decided to keep it simple and plan! The planning part is where you get involved. She wants you to create a program that will allow her to simulate some of the possibilities of their business decisions. The goal is to have a program that represents the different kinds of vending machines they currently intend to operate with the possibility of adding different machine types in the future. The program will simulate the machines and model the profit of each machine and the whole business (the sum of the profit of all the machines). You both realize that this means a program that uses inheritance to represent different kinds of vending machines which will make the code simpler, more flexible, and easier to maintain.

Together you decide that you will largely model profit. First to consider is the individual machine profit so that you can tell if individual machine locations are profitable. Second is the total profit of the whole business. Violet also decides that she wants to model a basic machine with only one kind of product that doesn't require anything special to operate first. But, she will consider two other kinds of machines that have a bit more sophistication in their functionality. Specifically she will want to add a drink machine, where the whole machine is still filled with the same product, but now each product will have an added cost charged to it for the refrigeration. Both the basic machine and the drink machine will require exact change. The last machine she wants to model is a traditional snack machine. It requires no refrigeration, but each slot in the machine will be loaded with a different snack product which could have a different cost, and it will return change when something is bought. In support of this vision, you have come up with the UML diagram below.

Submission and Honor Code

Submissions should be made by the due dates listed on Canvas. There are no late submissions unless specified by your instructor otherwise. The Gradescope results will reflect the no late submissions policy. Only the latest submission to Gradescope will be graded and code that does not compile will receive a 0, so please be careful with last minute submissions. Your final grade will be determined largely by correctness as determined by your Gradescope score, but documentation, and overall code quality will also be considered.

Though you are encouraged to discuss concepts with peers, teaching assistants and the instructor, the source code you submit should be your own work and something you could replicate on your own. Representing someone (or something) else's work as your own, in any form, constitutes an honor code violation. Directly copying or using the same code is an honor code violation. It is also a violation of the honor code to "render unauthorized assistance to another student by knowingly permitting him or her to copy all or a portion of an examination or any work to be submitted for academic credit." That means that you can be written up for an Honor code violation if you share your code with someone else, even if you wrote it completely on your own. If you violate the University Honor Code, you will receive a reduced or failing grade for the assignment or other penalties may be imposed and the violation will be reported to the Honor Council.

Individual instructors may have additional requirements. Please consult the syllabus for your section for details.

Learning Outcomes

  • Implement a UML diagram that uses inheritance.
  • Correctly implement examples of overriding and overloading.
  • Correctly predict via simulation the interaction of objects from an inheritance hierarchy.
  • Implement a program that makes use of ArrayLists.

UML Diagram

The connectors in the UML diagram below now include inheritance. Recall, this tutorial: UML Tutorial

Implement the class and methods according to the UML and specifications below.

Part 1 - Create Product.java and ProductTest.java

The Product class models an individual item type in a vending machine. Each product has a name, cost. and price. Note that cost is the cost of the product to the vending machine company. Price is the price that the vending machine will charge the customer. Violet has said that she is unwilling to deal with anything but quarters, dollar bills, and debit cards so all prices are kept divisible by 25 cents. Costs to the vending machine company can be any penny value. All of the get methods perform the expected operation.

Data

Note: cost and price are both integers. All money in the vending machine is represented as cents to enable simpler math and eliminate rounding issues.

  • ROUND_PRICE: int - the value in cents to which all prices will be rounded
  • name: String - the name of the product type
  • cost: int
  • price: int

Product()

The default constructor will create an instance of a product with a name of "Generic", a cost of ROUND_PRICE = 25 cents and a price of twice the ROUND_PRICE.

Product(String name, int cost, int price) throws IllegalArgumentException

This constructor takes the name, cost, and price as parameters and sets the instance variables appropriately. Null string names or negative cost or price should throw an IllegalArgumentException. Prices should be rounded to the next ROUND_PRICE cents above the amount given if the amount given if not already divisible by ROUND_PRICE. Note: if the price given is not greater than the cost, the price should be the next ROUND_PRICE-divisible-value that is greater than the cost.

toString()

The toString() method will return a String of the instance variables of the class exactly as shown below. Assuming a name of "M&Ms", cost of $1.02, and a price of $1.25, toString() would return:

Product: M&Ms Cost: 1.02 Price: 1.25.

Note: the cost and price are kept in cents so the toString() method will need to transform the values into the right format.

Part 2 - Create Slot.java and SlotTest.java

The Slot class models a slot in the vending machine. Slots are loaded from the rear, and purchases are removed from the front. This ensures that the items that have been in the machine the longest are sold before newly added items.

Data

  • SLOT_SIZE: int = 10 - the maximum number of products that a slot in the vending machine can hold.
  • products: ArrayList<Product> - models the actual products that are in the slot. Removing the one at the front models buying one of the products in the slot and all of the others are moved forward similar to an actual vending machine.

Slot()

The Slot() constructor creates an empty array list of products.

Slot(Product product)

This constructor creates a new slot that is filled with SLOT_SIZE of product.

load(Product product)

This method loads the slot with however many new products are required to make sure it is full and returns the number of products it took to fill the slot.

load(Product product, int count)

This method loads the slot with up to count new products in an attempt to fill the slot and returns the number of products it used.

nextProduct()

This method returns a reference to the next product available for purchase. If the slot is empty this method will return null.

buyOne()

This method simulates the purchase of one item from the perspective of the slot. That means no money is dealt with here, rather the slot is checked to make sure there is product to buy and then one product is removed from the front of the ArrayList modeling the slot. If a product is successfully removed from the slot, it is returned, otherwise null is returned.

toString()

The toString() method returns a String exactly like the one below for a slot with 10 M&M products. Items should start with the front slot and end with the rear slot.

SlotCount: 10 of
Product: M&Ms Cost: 1.02 Price: 1.25.
Product: M&Ms Cost: 1.02 Price: 1.25.
Product: M&Ms Cost: 1.02 Price: 1.25.
Product: M&Ms Cost: 1.02 Price: 1.25.
Product: M&Ms Cost: 1.02 Price: 1.25.
Product: M&Ms Cost: 1.02 Price: 1.25.
Product: M&Ms Cost: 1.02 Price: 1.25.
Product: M&Ms Cost: 1.02 Price: 1.25.
Product: M&Ms Cost: 1.02 Price: 1.25.
Product: M&Ms Cost: 1.02 Price: 1.25.

Resources

  1. ChangeMakingMachineTest.java
  2. DrinkMachineTest.java
  3. SimulatorTest.java
  4. SnackMachineTest.java
  5. TestingConstants.java
  6. VendingMachineTest.java

Part 3 - Create VendingMachine.java and test it.

The VendingMachine class is a simple vending machine. Exact change is required so it is assumed if someone is buying something they have inserted the right amount of money or have used a debit card. The get methods return the appropriate instance variable values.

Data

  • DEFAULT_SIZE: int = 15 โ€“ the default size for a VendingMachine, used primarily by the default constructor
  • totalProfit: int โ€“ this models the total profit for all of the VendingMachines together. It is the sum of the price of every product bought from all of the machines minus the sum of the cost of all the products ever put in all of the machines. Note that it is protected in the UML diagram so it is accessible to classes that inherit from this class.
  • machineProfit: int โ€“ this models the long term profit for this particular machine. It is the sum of the price of every product bought from this machine minus the sum of the cost of all the products ever put in this machine. Note that it is protected in the UML diagram so it is accessible to classes that inherit from this class.
  • slots: Slot[] โ€“ this array models the array of slots in the VendingMachine.

VendingMachine()

The default constructor creates a VendingMachine with DEFAULT_SIZE empty Slots.

VendingMachine(int size)

Creates a VendingMachine with the indicated number of empty Slots.

VendingMachine(int size, Product product)

Creates a VendingMachine with size Slots each full of product.

load()

Loads an empty or partially empty VendingMachine with a Generic product (i.e. the product obtained using the default constructor of the Product class.) Makes appropriate adjustments to machineProfit and totalProfit by subtracting costs from profit values.

load(int slotNum, int count, Product product)throws IllegalArgumentException

Loads the slot indicated by slotNum with product until it is full or until count is reached. Makes appropriate adjustments to machineProfit and totalProfit by subtracting costs from profit values. Throws an IllegalArgumentException if the slotNum is out of bounds, the count is less than or equal to zero, or if the product is null.

nextProduct(int slotNum)throws IllegalArgumentException

Returns a reference to the next available product in the indicated slot or null if the slot is empty. Throws an IllegalArgumentException if the slotNum is out of bounds.

buy(int slotNum)throws IllegalArgumentException

Models buying one item from the slot number indicated. Makes appropriate adjustments to machineProfit and totalProfit by adding the price to the profit values. Throws an IllegalArgumentException if the slotNum is out of bounds. Returns false if there is no product to buy.

resetTotalProfit()

This method resets the totalProfit static instance variable to zero. This is useful when testing to make sure that different method tests start out in a known state for the static variable so the final value can be computed without knowing the order of the test runs.

toString()

Returns a String representing the VendingMachine, each slot, the machineProfit and totalProfit exactly as shown below for a 2-slot VendingMachine filled with Generic product where nothing has been bought (so the profits are negative).

Vending Machine
SlotCount: 10 of
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
SlotCount: 10 of
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Product: Generic Cost: 0.25 Price: 0.50.
Total Profit: -5.00 Machine Profit: -5.00.

Part 4 - Create DrinkMachine.java and test it.

The drink machine inherits from the general VendingMachine described above. The only additions are a constant for the cooling charge and a different buy method which will affect the profit for the machine and the total profit differently than in the general VendingMachine. DrinkMachines will assess a charge for keeping the drink cold when the drink is purchased. This charge impacts the cost of the product to the vending machine company. It does not impact the price for the customer.

Data

  • COOLING_CHARGE: int = 10 โ€“ this models the ten-cent charge assessed to each drink when it is purchased to account for the refrigeration costs of the drink machine.

DrinkMachine()

Performs the same action for the DrinkMachine as VendingMachine().

DrinkMachine(int size, Product product)

Performs the same action for the DrinkMachine as VendingMachine(int size, Product product).

buy(int slotNum) throws IllegalArgumentException

Models buying one item from the slot number indicated. Throws an IllegalArgumentException if the slotNum is out-of-bounds. Makes appropriate adjustments to machineProfit and totalProfit by adding the price

Part 5 - Create ChangeMakingMachine.java and test it.

The change-making machine will add the functionality of being able to pay with cash and potentially get change back. The change will just be returned as an integer value in cents, but the amount paid in will be determined by the number of quarters and dollars that are entered.

ChangeMakingMachine()

Performs the same action for the ChangeMakingMachine as VendingMachine()

ChangeMakingMachine(int size)

Performs the same action for the ChangeMakingMachine as VendingMachine(int size).

ChangeMakingMachine(int size, Product product)

Performs the same action for the ChangeMakingMachine as VendingMachine(int size, Product product)

buy(int slotNum, int quarters, int dollars)throws IllegalArgumentException

Models buying one item from the slot number indicated. Throws an IllegalArgumentException if the slotNum is out of bounds or if quarters or dollars are negative. Computes the amount of money put into the machine in quarters and dollars, returning -1 if there is not enough money to buy the product and returning the positive difference or โ€œchangeโ€ if there is any. Makes appropriate adjustments to machineProfit and totalProfit by adding the price to the profit values if the buy is successful.

Part 6 - Create SnackMachine.java and test it.

The snack machine will inherit from the ChangeMakingMachine. The difference is it will have an additional instance variable of an array list of products which will indicate the type of product each slot should contain and itโ€™s load method will fill each slot completely with the particular product the slot contains, making appropriate adjustments to the profit tallies.

Data

  • productList: ArrayList โ€“ contains the list of products for each slot in the SnackMachine. The first position in the productList corresponds to the product in the first slot in the slots array.

SnackMachine(ArrayList pList)

This constructor initializes the productList of the SnackMachine and creates a new snack machine where each slot is full of the product indicated in the matching position in the productList. The size of the snack machine is just the length of the productList.

load()

This load method completely fills each slot in the snack machine with the appropriate product. As a slot is filled, the total cost of the items is subtracted from the profit tallies.

Part 7 - Create Simulator.java and test it.

The simulator will provide a means of simulating a small business of vending machines. The vending machines of the business are stored in an array list. Vending machines can be added to the list using the provided method to simulate the growth of a business. Simulation of the business โ€œrunningโ€ and selling product is done by simulating a specific number of products being bought from every slot of every vending machine in the business and returning the totalProfit of all of the vending machines in cents.

Data

  • vmList: ArrayList โ€“ models the list of vending machines owned by the company

Simulator(ArrayList vmList)

Instantiates a Simulator

addVM(VendingMachine vm)

Adds the VendingMachine indicated by vm to the end of the list of vending machines owned by the company.

simulate(int pCount)

Simulates buying pCount products from every slot of every VendingMachine owned by the company. Returns the totalProfit of all of the VendingMachines.

Submission

Submission for this assignment is divided into two parts that should be completed in order.

  1. PA3-A (10%): Readiness Quiz
    • In order to complete Part A you should first carefully read the project specification. Once you feel confident that you have a good grasp of the project requirements, log into Canvas and complete the Part A quiz. YOU MUST ANSWER ALL QUESTIONS CORRECTLY TO GET ANY CREDIT FOR THIS PART. You may take the quiz as many times as necessary.
  2. PA3-B (25%): For this part you must submit your Product.java, ProductTest.java, Slot.java, and SlotTest.java to Gradescope. Your test classes should provide 100% branch coverage for the classes they test. For this part you will have unlimited submissions.
  3. PA3-C (65%): For this part you must submit .java files for all of the classes, Product.java, Slot.java, VendingMachine.java, DrinkMachine.java, ChangeMakingMachine.java, SnackMachine.java, and Simulator.java files to Gradescope. Note that you will need to use the test classes provided under Resources above to test your code before submitting to Gradescope. There will be a deduction of 1%/ea for every submissions beyond ten.

Code submitted for Parts B and C must conform to the course style guide.

Submission Penalties

Part C will include a penalty for excessive Gradescope submissions. You are allowed ten submissions with no penalty. There will be a deduction of 1%/ea for every submissions beyond ten.

  1. Follow the order of the parts as outlined above.
  2. Develop incrementally, testing as you go.
    • As you build up to Test-Driven Development, you should supplement your efforts with at least a main method (either in one of the classes you’re already writing or perhaps better in a separate “driver class”). Since Part 1 says to create the Product class, your driver class should have something that tests whether this is working:
    • // you must know by know that you're not going to get me to write the main method for you
      // especially when eclipse is so eager to help
      Product p = new Product("Coke", 75);
      Product q = new Product();
      System.out.println(p.getName()); // aside from this being a nice thing to print
      System.out.println(p.getPrice());// these lines might also make good places
      System.out.println(q.getName()); // to put breakpoints so that you can use the debugger inspect
      System.out.println(q.getPrice());// the Product objects created by your constructors
      

4 - Project 4 - Absolutely Seriously Totally Ecstatically Really Outrageously Incredibly Dope Spacerocks (not Asteroids ยฎ๏ธ)

Due Apr 14 - Implement a classic game of space rocks.

Introduction

You have a friend who is really into retro video games. One of their favorites is the Atari classic, Asteroids . Since you are in CS 159 and becoming a super-awesome programmer, you decide to put your skills to the test and create a special version of Asteroids for your friend to play. What a thoughtful gift!

Thus, the goal of this project is to implement your own playable version of Asteroids, called “Generic Space Rock Shooter” (to avoid copyright infringement ๐Ÿค“). You will need to exercise your growing knowledge of object-oriented concepts, including inheritance, abstract classes, polymorphism, and interfaces.

Your game will look a little something like Dr. Sprague’s version:

Learning Outcomes

  • Interpret UML diagrams that include inheritance, abstract classes, and interfaces
  • Use inheritance and polymorphism to reduce code duplication and simplify implementation
  • Create abstract classes and subclasses that implement abstract methods
  • Create, implement, and use interfaces
  • Write and utilize enum types

Provided Code

We have given you some code to assist you in your game development adventure! THe following files will let you draw and animate objects on the screen, as well as handle coordinates and angles that may be difficult.

StdDraw, GameDriver, and Playable

You will need to download the following files to handle the drawing window and the main game loop:

  1. ๐Ÿ“„ StdDraw.java (DO NOT MODIFY) Updated Monday March 27 at noon โ€ผ๏ธ
    • All of the graphics for this application will be handled by the StdDraw library developed by Robert Sedgewick and Kevin Wayne at Princeton University. This library is not particularly powerful or full-featured but it makes it easy to develop simple graphical applications in Java.
    • Note: For Spring 2023, we are using patched version of this class that adds a getLastDraw() method. This method returns a String representation of the last thing that was drawn to the screen. This is useful for testing your code. You can use this method to check that your code is drawing the correct things to the screen. For example, if you want to test that your Ship is drawing a triangle, you can check that the last thing drawn to the screen is a triangle. This is a very simple way to test your code.
  2. ๐Ÿ“„ GameDriver.java (use for testing)
    • The GameDriver is the entry point for the project. It contains the main method. This class contains helpful constants (that you can use) and a main method which initializes a Playable game and provides the main game loop. Any game that you wish to run must implement the following Playable interface:
  3. ๐Ÿ“„ Playable.java (DO NOT MODIFY) Updated Monday March 27 at noon โ€ผ๏ธ
    • The Playable interface includes an “update” method that should update the state of all game elements at each time step (called a frame in animation and game design), and a “draw” method that should re-draw game elements after they have been updated. Your code will be tested using the driver above.

GameUtils, Point, Pose, Vector2D

In Asteroids (and many other games), some objects will have a location on the screen (in XY coordinates) as well as an orientation they will face (aka rotation angle). Certain objects will also need to move around and have velocities (represented by a 2D vector).

In the video above, you can see that the ship has a location and orientation. Notice also that sometimes the ship is moving in a direction other than it is facing. This is because the ship has a velocity vector that is different from its orientation.

We have provided the following four classes to help represent these types of data:

  1. ๐Ÿ“„ Point.java
    • The Point class is an encapsulation of a two-dimensional location that uses rectangular screen coordinates.
  2. ๐Ÿ“„ Pose.java
    • The Pose class is a subclass of Point that includes heading/orientation information (an angular measure).
    • notice especially the Pose.move method which will be useful for moving objects around the screen.
  3. ๐Ÿ“„ Vector2D.java
    • The Vector2D class represents a two-dimensional vector. Vectors of this sort may be visualized as arrows with both a direction (or heading) and a length (or magnitude). Vectors may be used in this application to represent both the velocities and accelerations of game elements.
  4. ๐Ÿ“„ GameUtils.java
    • Contains utility methods for working with the classes above. In particular, it includes a method for drawing a triangle for a particular Pose (which will you must use when drawing the Ship).
      • note: if you look at the implementation of GameUtils.drawPoseAsTriangle, you will find that it uses StadDraw.polygon internally. Therefore if you're testing Ship, you should take advantage of StdDraw.getLastDraw() to check that the correct polygon was drawn.

Other Provided Files

  1. ๐Ÿ“„ AsteroidsGame.java
  2. ๐Ÿ“„ TestHelpers.java
  3. ๐Ÿ“„ TestStar.java (Updated Thursday 3/30 at 4:15 PM)
  4. ๐Ÿ“„ TestNumericDisplay.java (Updated Thursday 3/30 at 4:15 PM)

Example Game

The GameDriver class is organized so that it will support any game that implements the Playable interface. The following two classes provide an example of a very simple “game” that implements Playable and makes use of some of the helper classes provided above:

  1. ๐Ÿ“„ BounceGame.java Updated Monday March 27 at noon โ€ผ๏ธ
  2. ๐Ÿ“„ Ball.java

You can try out BounceGame by changing lines ~38-39 of GameDriver.java as follows:

// Playable game = new AsteroidsGame();
Playable game = new BounceGame();

Game Design

There are a lot of parts that go into creating a Generic Space Rock Shooter game. To help you, we’ve started AsteroidsGame.java for you, which handles the main game loop and simple keyboard input.

Updatable and Drawable

These simple interfaces each require only 1 method (update and draw, respectively). The AsteroidsGame class will use these interfaces to update and draw the game elements. You will need to implement these interfaces in your game elements.

GameElement

The GameElement class is an abstract class that implements the Updatable and Drawable interfaces (this means every GameElement is responsible not only for storing its own data [“state”], but also for [1] maintaining that data via its update method and [2] drawing itself). It also provides a few instance variables that will be useful to all game elements. You will need to extend this class in your concrete game elements. Implement this class based on the UML diagram (getters with no specification below should be simple one-line getters that return the instance variable of the same name).

update()

At each time step, a GameElement should update its position based on its current velocity. A GameElement should also “wrap” around the edges of the game screen when moving:

  • For instance, if (after applying velocity) the element flies off the right side of the screen (its X coordinate is greater than the width of the screen), the X position should be changed to 0 instead to make it re-appear on the left side of the screen.
  • Likewise, if the element flies off the left side of the screen (its X coordinate is less than 0), it should reappear on the right side of the screen.
  • GameElements should also wrap around the top and bottom edges of the screen.

checkCollision(GameElement other)

See Collisions and Scoring below.

Asteroid

The Asteroids must fulfill the following requirements:

  1. Asteroids (and all other non-filled game elements) must be drawn using the default StdDraw pen radius of .002.
  2. The initial location of each asteroid must be generated randomly. Positions must be selected uniformly from the entire game screen.
  3. The direction of motion for each asteroid must be drawn uniformly from the interval [0, 2ฯ€).
  4. Asteroids must maintain a constant speed of one pixel per time step.
  5. The location of asteroids must “wrap” at the edges of the game screen. For example, when an asteroid departs from the left side of the screen, it must reappear in the corresponding location on the right side of the screen.
  6. Asteroids must be displayed as open circles.
  7. Asteroids come in three different sizes, each with a different point value, see AsteroidSize below.

AsteroidSize

AsteroidSize is an enum that represents the size of an asteroid. It has three values:

  • SMALL: radius of 10 pixels, worth 200 points when destroyed.
  • MEDIUM: radius of 20 pixels, worth 100 points when destroyed.
  • LARGE: radius of 30 pixels, worth 50 points when destroyed.

AsteroidSize also has a static method called randomSize() that will return a random AsteroidSize based on the probabilities specified in the Initialization section. This method must have a 50% chance of returning AsteroidSize.LARGE and a 25% chance of returning AsteroidSize.SMALL or AsteroidSize.MEDIUM.

Saucer

Enemy saucers must fulfill the following requirements:

  1. Saucers must be displayed as open rectangles with a width of 20 pixels and a height of 10 pixels.
  2. The initial location of each saucer must be generated randomly. Positions must be selected uniformly from the entire game screen.
  3. The initial direction of motion for each saucer must be drawn uniformly from the interval [0, 2ฯ€).
  4. Saucers must maintain a constant speed of 2 pixels per time step.
  5. On each time step a saucer must select a new direction of motion with probability .05. The direction of motion must be drawn uniformly from the interval [0, 2ฯ€).
  6. The location of the saucer must not “wrap” at the edges of the game screen. Saucers must disappear permanently when they exit the screen.
  7. Saucers are worth 400 points when destroyed.
  8. The radius of a Saucer should be defined based on the details in Collisions and Scoring.

Ship (Updated Thursday 4/6 at 4:40 PM)

The Ship class is a GameElement that represents the player’s ship. It is responsible for drawing the ship and updating its position based on the current velocity . You will need to implement this class based on the UML diagram (getters with no specification below should be simple one-line getters that return the instance variable of the same name).

The player’s ship must also fulfill the following requirements.

  1. The initial pose of the ship must be at the center of the game screen pointing upward.
  2. The ship must be represented as an open isosceles triangle with a base of 10 pixels and a height of 20 pixels. You may use the GameUtils.drawPoseAsTriangle method do draw the ship to the screen.
  3. The movements of the ship must be controlled through the turnLeft(), turnRight(), and thrust() methods.
  4. TURNING: If turnLeft() is called, the ship must be turned .1 radians to the left. If turnRight() is called the ship must be turned .1 radians to the right. Note that you don’t need to worry about keeping heading values within the range 0 to 2ฯ€. All of the provided heading-related methods will perform correctly for values outside of this range.
  5. THRUST: If thrust() is called, a thrust must be applied to the ship’s current velocity (note: thrust() should not modify the ship’s position). The ship must be pushed in the direction of its current Pose heading, with a speed of .1 pixels/time step. Because the ship is floating in outer space, this means that its new velocity must now be a combination of its previous velocity plus the thrust. You may use methods from the Vector2D class (consider especially the add method of Vector2D) to help with this.
  6. FRICTION: The ship must slow down over time. Every time update is called (aka one time step), after the ship’s position is updated, the speed of the ship must be decreased by .02 pixels/time step. (hint: speed is defined as the magnitude of velocity)
  7. The location of the ship must “wrap” at the edges of the game screen.
  8. The radius of the ship (because it is not a circular object) should be defined based on the details in Collisions and Scoring.

Bullet

  1. Bullets must be displayed as filled circles with a radius of 1.5 pixels.
  2. Bullets must be created at the current position of the ship each time the user presses the space bar, as handled by AsteroidsGame.handleKeyboardInput().
  3. Bullets must move at a constant speed of 20 pixels per time step.
  4. The direction of the bullet’s motion must match the heading of the ship at the time the bullet is fired.
  5. Bullets must exist for a maximum of 20 time steps (calls to update). After 20 time steps, the bullet should be set to be destroyed.
  6. The location of bullets must also “wrap” at the edges of the game screen.

Stars

  1. Stars must be displayed as closed circles with a radius of 1 pixel.
  2. The initial location of each star must be generated randomly. Positions must be selected uniformly from the entire game screen.
  3. Stars must remain stationary.

Scoreboard (Updated Thursday 3/30 at 4:15 PM)

The text for the player’s score must be left-aligned 10 pixels from the left edge of the game screen and 20 pixels from the top. The numeric score must be prefixed by the string “Score: “. The score must be initialized to 0.

If you look in the constructor for AsteroidsGame.java, you can see how NumericDisplay is used to present the score.

Lives Remaining (Updated Thursday 3/30 at 4:15 PM)

The text for the number of lives remaining must be left-aligned 10 pixels from the left edge of the game screen and 40 pixels from the top. The number of lives must be prefixed by the string “Lives: “. The number of lives remaining must be initialized to 3.

AsteroidsGame (UPDATED Tuesday 4/12 at 3 PM)

The AsteroidsGame class is a Playable class that is responsible for the main game loop and keyboard input. It is also responsible for creating and updating the game elements. We provide a starter version of this class for you, but you will need to implement several methods and modify some of the existing methods. Start by downloading the following file, and then as you proceed through this assignment, work toward your implementation meeting the specifications as outlined below and in the UML diagram.

There are four ArrayLists that handle the objects in the game: drawElements, updateElements, shipAndBullets, and enemies. Objects that are put in drawElements and updateElements should be drawn and updated every time step, respectively. The other two lists, shipAndBullets and enemies are used for collisions. Collisions between game elements should be handled through the methods handleCollisions(), removeDestroyedBullets(), and removeDestroyedEnemies().

This class should also follow the specifications outlined in Game Logic. For instance, AsteroidsGame is also responsible for keeping track of the score and increasing it when enemies are destroyed.

AsteroidsGame() Constructor

Like most constructors, this one initializes its instance variables, but it stops short of creating the game elements. Rather it delegates that responsibility to the startGame() method, which is called by GameDriver. As provided, this class initializes a few of its instance variables, but you will need to ensure all of the instance variables are initialized. Refer to the UML diagram to make sure you have included all the instance variables and methods.

startGame()

This method is responsible for creating the various game elements that are required for the beginning of the game. As you progress through the different parts of the assignment, you will revisit this method to add in new game elements. In Part 1, you need to create the Stars and store references to them to ensure they are drawn (perhaps it would be best to rely on the private helper method here). The game should begin with 100 Stars that are positioned randomly on the screen.

newStars()

This method should create 100 new Stars at random positions on the screen and store their references such that they will be drawn. It should rely on the provided randomXPosition() and randomYPosition() static methods in AsteroidsGame.

newShip()

This method should create a new Ship instance and assign it to the corresponding instance attribute. It should also add the ship to all the appropriate ArrayLists.

addEnemy(Enemy enemy)

This method should add the given enemy to all the appropriate ArrayLists in AsteroidsGame.

newEnemies()

This method should create 10 asteroids of random sizes as determined by the probabilities in AsteroidSize and add them to all the appropriate ArrayLists in AsteroidsGame. (hint: there’s a couple methods that you’ve already written that you could use here!)

handleCollisions()

This method is responsible for checking if objects collide in the game. You should loop through each enemy in the enemies list and check if it collides with the ship or any of the bullets currently in the game. If a collision occurs, both objects should be set to be destroyed.

removeDestroyedBullets()

This method should go through shipAndBullets and check if each bullet needs to be destroyed (it’s destroyed attribute was set to true). If a bullet needs to be destroyed, then it should be removed from all ArrayLists that it was added to.

removeDestroyedEnemies()

This method should go through the enemies list and check if each enemy needs to be destroyed. If an enemy needs to be destroyed, then it should be removed from all ArrayLists that it was added to.

Game Logic

Initialization

When the game starts, the ship must be present on the game screen along with 100 stars, the two numeric displays and 10 asteroids. It is not necessary to guarantee that the the ship is safe from asteroids when the game starts. If the ship appears inside an asteroid, that’s just bad luck for the player.

The size of each asteroid must be determined randomly when it is created. Each asteroid must have a 50% chance of being large and a 25% chance of being small or medium.

There must be no saucers on the initial game screen. A new saucer must be added to the game screen on each time step with a probability of .002. Note that this means there may occasionally be more than one saucer present on the game screen. Again, it is possible for saucers to appear in a location that will cause an immediate collision with the ship.

Collisions and Scoring

For the purposes of collision checking, the game elements can be divided into three categories.

  1. Stars and the numeric display values - These elements are not subject to collisions.
  2. Ship and Bullets - Elements in this category are able to collide with asteroids and saucers.
  3. Asteroids and Saucers - Elements in this category are able to collide with the ship and bullets.

It is not necessary to perform pixel-level collision detection. Instead, you should perform approximate collision detection by associating each game element with an appropriate collision radius.

For the case of the circular elements (Asteroids and Bullets) this should match the radius of the element. For the case of non-circular objects (Ship and Saucers) this radius should be chosen to be half the length of the longest axis of the element. For example, the ship’s longest axis is 20 pixels, so the collision radius should be 10 pixels. A collision should occur whenever two objects are near enough that the circles defined by their collision radii overlap.

Whenever a collision occurs, both elements involved in the collision must be destroyed and removed from the screen. The player’s score must be increased by the point value associated with the Asteroid or Saucer that was involved in the collision.

If the player’s ship is destroyed, and the player has remaining lives, then a new ship should be created at the starting location.

If the player loses all three lives, then no future game updates must occur: the game screen must freeze. The Lives Remaining indicator must read 0 and the score should reflect the final collision that caused the game to end.

Any time the player manages to destroy all of the Asteroids and Saucers on the game screen, a new “level” should begin: the correct number of new asteroids must appear at randomly selected locations. The position of the ship and the position of the stars should not be modified.

The following UML diagrams depict the classes you will need to implement the game:

UML Diagram

Seems too large to include here. Click the button below to view the UML diagram in a new tab.

Larger View

Part 1

  1. Go over the provided files to understand what they do
    • Especially take a look at BounceGame.java and GameDriver.java to see what a game looks like (try running these!)
  2. Make sure GameDriver is set up to use AsteroidsGame and that you have properly downloaded all the provided files to your Eclipse project.
  3. Create the Drawable and Updatable interfaces
  4. Create the GameElement abstract class
    • Implement the update method
  5. Create the Star class
    • Declare the attributes and implement the constructor
    • Implement the draw method
    • In AsteroidsGame:
      1. add code in the newStars() method to create 100 randomly-placed Stars
      2. invoke newStars() in the startGame() method
      3. add code in the draw() method to:
        1. set StdDraw’s pen color to white (read the StdDraw docs or code, or take a peek ๐Ÿ‘€ at how BounceGame does it)
        2. draw all the Drawables. (๐Ÿ‘€ Hint: Take a look at how the update() method updates all the Updatables)
      4. ensure that the lines in update() that invoke handleCollisions, removeDestroyedBullets, and removeDestroyedEnemies are commented out for now (you’ll need these in Part 3)
    • Run the game and test your starfield!
  6. Run the provided tests for your Star class.
  7. Create the NumericDisplay class
  8. Run the provided tests for your NumericDisplay class.

Part 2

  1. Create the Ship class stubs
  2. Write the test class for the Ship class (you may want to review the GameUtils methods to support your work here.)
    • Name it ShipTest
  3. Create the Bullet class stubs
  4. Write the test class for the Bullet class
    • Name it BulletTest
  5. Complete the implementation of the Ship class
    • Implement the attributes and constructor
    • Implement the draw method
    • Implement methods to control the ship (turnLeft, turnRight, thrust)
  6. In AsteroidsGame, implement method to add a ship and handle movement
    • You should be able to run the game and test it at this point
    • Add code to AsteroidsGame to shoot a bullet when the spacebar is pressed

Part 3

  1. Create the Enemy abstract class
  2. Create the AsteroidSize enum class that represents the three different sizes and point values
  3. Create the Asteroid class
    • Implement the attributes, constructor, and method stubs
    • Implement the draw method
    • Implement update to have the asteroid move each frame
  4. In AsteroidsGame, implement newEnemies() to add 10 randomly sized asteroids
  5. Add collision handling to AsteroidsGame
    • You will need to check every Enemy to see if it collides with a Bullet or Ship
    • Objects that collide should be destroyed
    • Enemies that are destroyed should update the score
  6. Create the Saucer class

Submitting

As usual you will submit the parts of this assignment to Gradescope. There will be 4 different assignments on Gradescope, dividing this assignment as follows

  1. Part 1 - ๐Ÿ—“๏ธ Monday April 3
    • Submit:
      1. Drawable
      2. Updatable
      3. GameElement
      4. Star
      5. NumericDisplay
    • Autograder:
      1. deducts for checkstyle issues
      2. Your implementation of Star, NumericDisplay, and GameElement pass our unit tests
  2. Part 2A - ๐Ÿ—“๏ธ Wednesday April 5
    • Submit:
      1. ShipTest
      2. BulletTest
    • Autograder:
      1. deducts for checkstyle issues
      2. Runs your ShipTest and BulletTest against our reference solution expecting:
        • 90% coverage of Ship, Bullet
        • all tests passing
  3. Part 2B - ๐Ÿ—“๏ธ Monday April 10
    • Submit:
      1. Ship
      2. Bullet
      3. ShipTest
      4. BulletTest
      5. GameElement
    • Autograder:
      1. deducts for checkstyle issues
      2. Your Tests should have 100% coverage of your implementation, and all of the tests should pass
      3. Your implementation of Ship and Bullet pass our unit tests
  4. Part 3 - ๐Ÿ—“๏ธ Friday April 14
    • Submit:
      1. GameElement
      2. Updatable
      3. Drawable
      4. Star
      5. NumericDisplay
      6. Ship
      7. ShipTest
      8. Bullet
      9. BulletTest
      10. Enemy
      11. Asteroid
      12. Saucer
      13. AsteroidSize
      14. AsteroidsGame
    • Autograder:
      1. deducts for checkstyle issues
      2. Your implementation of the following pass our unit tests:
        • Star
        • NumericDisplay
        • Ship
        • Bullet
        • Asteroid
        • Saucer
        • AsteroidsGame
        • AsteroidSize

Change Log

Many software projects undergo changes over time. This section documents the changes made to this assignment over time. The most recent changes are listed first (this is called “reverse chronological order”).

  1. Add additional method descriptions for AsteroidsGame -
  2. Add reference to AsteroidSize probabilities under AsteroidSize -
  3. Updated Part 3 to list the classes that must pass tests, and added language to Ship thrust -
  4. Revise wording for Ship thrust and friction -
  5. Put instructions for Ship together -
  6. Added hints for Ship radius -
  7. Updated Part 2A language to not require coverage of GameElement, and add guidance on use of existing code in StdDraw, Pose, and GameUtils -
  8. Updated Tests and spec to use textLeft instead -
  9. Update TestStar and TestNumericDisplay to fix issue with JUnit -
  10. Added TestHelpers and due dates for sub-parts -
  11. Update Part 1 -
    • Provide TestStart and TestNumericalDisplay
    • Add instructions about modifications to AsteroidsGame
  12. Publish remaining specs -
  13. Updated `AsteroidsGame.java`
    • provide random helpers
    • provide beginning of `update()`
    • provide beginning of `startGame()` stub
  14. Initial Draft so you can get rolling on Part 1 -

4.1 - A.S.T.E.R.O.I.D.S. UML

โ†–๏ธ Back to specs

classDiagram
direction BT

class Updatable {
  <<interface>>
  +update()
}

class Drawable {
  <<interface>>
  +draw()
}

class GameElement:::italics {
  <<abstract>>
  #Pose pose
  #Vector2D velocity
  #double radius
  #boolean destroyed
  +GameElement(pose Pose, velocity Vector2D, radius double)
  +getPose() Pose
  +getVelocity() Vector2D
  +getRadius() double
  +isDestroyed() boolean
  +setDestroyed(destroyed boolean)
  +checkCollision(other GameElement) boolean
  +update()
}
GameElement ..|> Updatable
GameElement ..|> Drawable

class Ship
Ship: +int SHIP_WIDTH {readOnly=10}$
Ship: +int SHIP_HEIGHT {readOnly=20}$
Ship: +double SHIP_TURN {readOnly=0.1}$
Ship: +double SHIP_MOVE {readOnly=0.1}$
Ship: +double FRICTION {readOnly=0.02}$
Ship: +Ship()
Ship: +turnLeft()
Ship: +turnRight()
Ship: +thrust()
Ship: +update()
Ship: +draw()
Ship --|> GameElement

class Bullet 
Bullet: +double BULLET_RADIUS {readOnly=1.5}$
Bullet: +int BULLET_SPEED {readOnly=20}$
Bullet: +int BULLET_DURATION {readOnly=20}$
Bullet: -int counter
Bullet: +Bullet(pose Pose)
Bullet: +update()
Bullet: +draw()

Bullet --|> GameElement

class Enemy:::italics {
  <<abstract>>
  #int points
  +Enemy(speed double, radius double, points int)
  +getPoints() int
}
Enemy --|> GameElement

class AsteroidSize {
  <<enumeration>>
  SMALL
  MEDIUM
  LARGE
  -int radius
  -int points
  -AsteroidSize(radius int, points int)
  +getRadius() int
  +getPoints() int
  +randomSize()$ AsteroidSize
}
AsteroidSize <.. Asteroid

class Asteroid 
Asteroid: +int ASTEROID_SPEED {readOnly=1}$
Asteroid: +Asteroid(size AsteroidSize)
Asteroid: +draw()

Asteroid --|> Enemy

class Saucer 
Saucer: +int HALF_WIDTH {readOnly=10}$
Saucer: +int HALF_HEIGHT {readOnly=5}$
Saucer: +int SAUCER_SPEED {readOnly=2}$
Saucer: +int SAUCER_POINTS {readOnly=400}$
Saucer: +double SPAWN_PROB {readOnly=0.002}$
Saucer: +double TURN_PROB {readOnly=0.05}$
Saucer: +Saucer()
Saucer: +update()
Saucer: +draw()

Saucer --|> Enemy

class Star
Star: -Point location
Star: +int STAR_RADIUS {readOnly=1}$
Star: +Star(x double, y double)
Star: +getLocation() Point
Star: +draw()
Star ..|> Drawable

class NumericDisplay {
  -String prefix
  -int value
  -Point location
  +NumericDisplay(xPos int, yPos int, prefix String, value int)
  +getLocation() Point
  +getValue() int
  +setValue(value int)
  +draw()
}
NumericDisplay ..|> Drawable
classDiagram
class Playable {
  <<interface>>
  +update()
  +draw()
  +startGame()
}
class AsteroidsGame
AsteroidsGame: +int LIVES {readOnly=3}$
AsteroidsGame: -ArrayList~Drawable~ drawElements
AsteroidsGame: -ArrayList~Updatable~ updateElements
AsteroidsGame: -ArrayList~GameElement~ shipAndBullets
AsteroidsGame: -ArrayList~Enemy~ enemies
AsteroidsGame: -Ship ship
AsteroidsGame: -NumericDisplay score
AsteroidsGame: -NumericDisplay lives
AsteroidsGame: +AsteroidsGame()
AsteroidsGame: +addEnemy(enemy Enemy)
AsteroidsGame: -newStars()
AsteroidsGame: -newEnemies()
AsteroidsGame: -newShip()
AsteroidsGame: -handleKeyboardInput()
AsteroidsGame: +update()
AsteroidsGame: +draw()
AsteroidsGame: +handleCollisions()
AsteroidsGame: +removeDestroyedBullets()
AsteroidsGame: +removeDestroyedEnemies()
AsteroidsGame: +startGame()
AsteroidsGame: #randomXPosition()$ double
AsteroidsGame: #randomYPosition()$ double
AsteroidsGame: #randomHeading()$ double
AsteroidsGame ..|> Playable

5 - Project 5 - People in Purple Extra Terrestrial Locator

Due Apr 28 - The People in Purple ยฎ Extraterrestrial Locator.

Learning Objectives

This assignment is designed to help you learn about recursive thinking, programming using recursion, and working with different kinds of Collections and other abstract data types.

Overview

As you may have heard, James Madison University has been working hard to give extraterrestrials (including Arcturans, Arquillians, Ballchinians, Boov, Colossi, Daleks, Druidians, Ewoks, Flora, Gorg, Hutts, Krylorians, Kylothians, Mawgs, Oods, Raxacoricofallapatorians, Remoolians, Sontarans, and Wookies) the opportunity to study on campus. However, for a variety of reasons related mostly to their psychologies, many extraterrestrials have a habit of getting lost on campus. So, JMU has created a super-secret group, named People in Purple, that monitors them (with their permission, of course).

Since their physiologies tend to interfere with the operation of both wearable devices and mobile telephones, PIP has purchased a remote sensor from the (fictitious) company Sciontific, that can determine if a particular extraterrestrial is in a given square area (of any size). They have asked you to create an algorithm that can use this sensor to determine a particular extraterrestrial’s location within a small tolerance, and to incorporate it into an application named the Extraterrestrial Locator.

The relationship between all of the components that comprise the Extraterrestrial Locator are illustrated in the following detailed UML class diagram.

Components in purple are part of the Java libraries, components in green were written by the GUI development team, components in orange were written by other developers, and components in black are to be written by you for this assignment. The Point class is in the package java.awt. All of the other classes are in the default package.

Background Information

Before you can start working on the components, you need to learn a little bit about the system.

Acronyms

EL
Extraterrestrial Locator
JMU
James Madison University
PIP
People in Purple

About the JMU Campus

People in Purple wants the system to work with the following area around and including the JMU campus.

JMU Campus

PiP have divided this area into a grid that has 512 cells on a side. Cell (0,0) is at the upper left corner of this area and cell (511,511) is at the lower right corner of this area.

PiP have divided this area into a grid that has 512 cells on a side. Cell (0,0) is at the upper left corner of this area and cell (511,511) is at the lower right corner of this area.

About the Sensor

The sensor that People in Purple has purchased from Sciontific is very sophisticated, but has limitations.

First, though the sensor can determine if a particular extraterrestrial is in any square area, it can’t determine exactly where the extraterrestrial is. Hence, you must design and implement an algorithm that can identify the 1x1 cell that contains the extraterrestrial if it is, in fact, in the campus area. (Note: A particular extraterrestrial can be in at most one 1x1 cell.)

Second, it can only perform 50 scans on a single charge. Hence, since there are 262,144 cells on campus, the algorithm they originally thought they would use to locate an extraterrestrial (i.e., using a nested loop that scans all 262,144 of the 1x1 cells) does not work.

Provided Files

  1. pa5.jar
    • this jar includes the Sensor and SensorDisplay classes, but you will not see their source code. You don’t need to interact with the SensorDisplay class yourself. You can find the documentation for the Sensor class below.
    • Remember, you’ll need to add the .jar to the build path: How to import .jar files
  2. ExtraterrestrialLocator.java
  3. jmu.png
    • you should put this one in the eclipse project folder for your PA5, but unlike the Extraterrestrial.java file, this image should not be in the src folder.

The Existing Class: Sensor

Other programmers at People In Purple have created the Sensor and SensorDisplay classes that interact with the physical sensor and can be used to visualize the results. They are in the provided jar file.

You need only use the Sensor class (the Sensor class uses the SensorDisplay class). The scan() method in this class is passed the square to scan (where x and y are the upper-left corner of the square and width is the width and height of the square). It returns -width if the extraterrestrial is not in the square and width if the extraterrestrial is in the square. The checkSystem() method returns a two-line String that describes the result of the scan. The first line will be "Power constraint satisfied" if 50 or fewer scans were used and will be "Power constraint violated" otherwise. The second line will be "Strongest signal at location" if your ELgorithm found the extraterrestrial at the correct location and will be "No signal" if your ELgorithm does not find the extraterrestrial at the correct location. They have also written the main class.

The main method is passed one required and one optional argument. Argument 0, which is required, is a String containing the name of the extraterrestrial to search for. Argument 1, which is optional, is an integer that controls the amount of time between scans (in milliseconds), which is useful when visualizing the search process. If you want to visualize the results on the aerial photograph of the campus area, you will also need the aerial photo of the JMU campus (see provided files above), which must be in your project directory/folder. When searching for Stitch with a non-zero scan time, the application will look something like the following while it is in the process of searching.

In this visualization, the gray areas are those that did not contain the extraterrestrial of interest, the purple lines are used to delineate the area that is currently being scanned, and the purple square (which flashes briefly), indicates the area that is currently being scanned.

Part 1

The Class to be Written

You must write the ELgorithm class.

The search() method in this class is called by the main() method in the (provided) ExtraterrestrialLocator to initiate a search in the area defined by the parameters 0, 0, 512. Hence, the search() method is responsible for doing the work of locating the extraterrestrial (thought it can, of course, call other methods). This method must return null if the extraterrestrial is not in the area of interest and must return a Point object with the coordinates of the 1x1 cell containing the extraterrestrial if it is in the area of interest.

Submission

You must submit (using Gradescope):

  1. Your implementation of the ELgorithm class.
  2. You must not submit any other classes; the Sensor class will be available on Gradescope.
  3. There is no limit on the number of submissions and no penalty for excessive submissions.

Part 2

  1. Write the Area class. In addition to the specs implied by the UML diagram,
    1. override toString to return a String representation of this Area. If this Area had a starting x of 160, a starting y of 192, and a width (and height) of 32, then the String representation would be (note the leading newline):
      
      +-------------------+
      |(160, 192) +  32   |
      |         (192, 224)|
      +-------------------+
      
      • all 5 of the numbers displayed here are inserted into the String with a field width of 3 (padded with spaces when necessary)
      • the commas always have at least 1 space after them regardless of the numbers that follow
      • 3 spaces follow the width before the |
      • 9 spaces precede the opening parenthesis of the ending coordinates
      • See below for examples where some of the numbers do not have 3 digits.
        
        +-------------------+
        |(  0,   0) + 512   |
        |         (512, 512)|
        +-------------------+
        
        
        +-------------------+
        |(256, 320) +  64   |
        |         (320, 384)|
        +-------------------+
        
  2. Create a new specialization of the Sensor class, called it LoggingSensor
    1. Its constructor (summarized in the UML diagram) should rely on its base class constructor to initialize most things, but it should also initialize the new instance variable scanLog to a new HashMap.
    2. It should override the scan method to call the base class scan method, and then add the result to the scanLog.
    3. It should override toString to return (only) a String representation of the scanLog.
  3. Modify the ExtraterrestrialLocator class to:
    1. use the LoggingSensor class (rather than the regular Sensor)
    2. print the toString of the LoggingSensor after the search is complete.

Submission

You must submit (using Gradescope):

  1. Your implementation of these classes:
    1. Area
    2. LoggingSensor
  2. You must not submit any other classes; the Sensor class will be available on Gradescope.
  3. There is no limit on the number of submissions and no penalty for excessive submissions.

Grading

Your code will first be graded by Gradescope and then by the Professor. The grade you receive from Gradescope is the maximum grade that you can receive on the assignment

Your code must compile, all class names and method signatures must comply with the specifications, and your code must have no style defects for you to receive any points on this assignment. Gradescope will then grade your submission as follows:

Part 1

Correctness (OfficialTests): 75 points (Limited Partial Credit Possible) Given the nature of this assignment, your grade from Gradescope will be either a 0, 37, or 75, and a 37 is fairly unlikely. In other words, your code must be correct for you to receive any points from Gradescope on this part of the assignment.

Part 2

Correctness (OfficialTests): 25 points (Partial Credit Possible)

Manual Grading

After the due date, the Professor may manually review your code. At this time, points may be deducted for inelegant code, inappropriate variable names, bad comments, etc.

Suggestions

You may find the following suggestions helpful.

Allocating Time

Almost all of your time on this assignment should be spent thinking; very little time should be spent typing/compiling/etc. It is very unlikely that you will discover an algorithm that works through trial and error (i.e., try something, compile, test, make a change, repeat).

Getting Started

Before you start thinking about building a full-fledged ELgorithm, you might want to play around a little bit. For example, here’s a ELgorithm that scans the whole area and then scans some cells around I81. (Note: As it turns out, this algorithm will find Omastar.)

import java.awt.Point;
public class ELgorithm {
  private Sensor sensor;
  public ELgorithm(Sensor sensor) {
    this.sensor = sensor;
  }
  public Point search(int x, int y, int width) {
    int resultOfScan;
    Point resultOfSearch;
    resultOfSearch = null;
    // Check the whole area
    resultOfScan = sensor.scan(x, y, width);
    if (resultOfScan < 0) // The extraterrestrial isn't in the area
    {
      resultOfSearch = null;
    }
    else // The extraterrestrial is in the area so let's search some more
    {
      // Try some cells around I81
      for (int xx=300; xx<340; xx++)
      {
        resultOfScan = sensor.scan(xx, 323, 1);
        if (resultOfScan == 1)
        {
          resultOfSearch = new Point(xx, 323);
          break;
        }
      }
    }
    return resultOfSearch;
  }
}

Approach

This assignment will be much easier to complete if your algorithm is recursive. Indeed, it is possible to write a recursive algorithm that contains surprisingly few lines (though your algorithm, like mine, may have more than that). Remember that there are two parts of a recursive algorithm:

  1. The part of the algorithm that handles the “easy” (or “base”) case.
  2. The part of the algorithm that moves “difficult” cases toward the “easy” case (i.e., the refinement part of the algorithm).

The first thing to think about is how to define the “easy”/“base” case. To do so, suppose your ELgorithm calls the scan() method in the Sensor class. When is its job really easy? (Note: There may be more than one easy case.) The second thing to think about is what you need to do to refine other cases (i.e., take hard cases and move them closer to the easy case).

Testing and Debugging

The visualization of the scanning process can both help and hinder testing and debugging. For your convenience:

  • The scan time controls the speed of the visualization. Longer scan times will make it easier for you to see what your ELgorithm is doing, shorter scan times will make the program run faster.
  • You can disable the GUI window completely with a scan time of 0.

The following extraterrestrials are known to frequent the JMU campus: Beeblebrox, Chewbacca, Fourarms, Groot, Kang, Neelix, Omastar, and Stitch. In other words, your ELgorithm must find all of these extraterrestrials. You can also test the system using UL, LL, UR and LR (fake extraterrestrials that are at the upper-left, lower-left, upper-right, and lower-right corners). Alf, on the other hand, is never on campus.

Questions to Think About

You don’t have to submit your answers to these questions, but you should try to answer them because they will help you determine whether or not you understand some of the important concepts covered in this assignment.

  1. Why weren’t your required to find the exact location of the extraterrestrials (rather than the 1x1 cell containing them)?
  2. Could the search() method in the ELgorithm class return an int[] rather than a Point? What is the advantage of returning a Point?
  3. Why were square areas used rather than rectangular areas?

Looking Back - The Big Picture

By the time you complete this assignment you should have learned many things, including but not limited to the following โ€œbig pictureโ€ issues.

  • Some problems are much easier to solve using recursion.
  • Solving problems using recursion requires a different way of thinking.

Acknowledgements

Thanks to the CS 159 F'22 team (esp. Dr. Bernstein!) for their work in an earlier version of this assignment.

Change Log

Many software projects undergo changes over time. This section documents the changes made to this assignment over time. The most recent changes are listed first (this is called “reverse chronological order”).

  1. Added to spec for Area.toString() -
  2. Corrected spec (and UML) for Area to use ints rather than Point -

5.1 - PiP UML

โ†–๏ธ Back to specs

classDiagram


class Sensor:::providedCodeNoEdit {
  +Sensor(etName String, scanTime int)
  +checkSystem() String
  +scan(x int, y int, width int) int
}

ExtraterrestrialLocator -- ELgorithm : constructs
ExtraterrestrialLocator -- Sensor : constructs
ExtraterrestrialLocator .. LoggingSensor : constructs
Sensor -- ELgorithm : uses
Sensor -- SensorDisplay : uses
LoggingSensor --|> Sensor
ELgorithm -- Point : constructs
class Point:::jdk {
  +int x
  +int y
  +Point(x int, y int)
}

class ExtraterrestrialLocator:::starter {
  <<main>>
  +main(args String[])$
}

class SensorDisplay:::providedCodeNoEdit

class ELgorithm {
  -Sensor sensor
  +ELgorithm(sensor Sensor)
  +search(x int, y int, width int) Point
}

class LoggingSensor:::part2 {
  +LoggingSensor(etName String, scanTime int)
  +scan(x int, y int, width int) int
  +getScanLog() Map~Area_COMMA_Boolean~
  +toString() String
}

LoggingSensor : -Map~Area, Boolean~ scanLog


class Area:::part2 {
  -int x
  -int y
  -int width
  +Area(x int, y int, width int)
  +getX() int
  +getY() int
  +getWidth() int
  +toString() String
}

LoggingSensor -- Area : constructs

7 Classes

The seven classes depicted in the UML diagram include some code provided in the Jave Runtime Enviroment, other classes you should create or modify, and other classes still will not be necessary until Part 2 of the assignment.

Provided (gray background)

The following classes are provided via pa5.jar, and you should not modify them:

  1. SensorDisplay
  2. Sensor

JRE (black background)

The Java Runtime Environment itself provides the Point class.

Should Create (lavender background)

  1. ELgorithm

Part 2 (dotted borders)

Should Create (dotted borders, lavender background)

  1. Area
  2. LoggingSensor

Should Modify (dotted borders, gray background)

  • ExtraterrestrialLocator
    1. change this class to construct a LoggingSensor instead of a Sensor.
    2. add a last line to main that is executed when the Extraterrestrial is found and prints the scan log.