Note
Documents that describe what a programmer is supposed to do are calledspecs
(specifications
), requirements
, or (in the case of such documents in the context of courses) instructions
.This is the multi-page printable view of this section. Click here to print.
specs
(specifications
), requirements
, or (in the case of such documents in the context of courses) instructions
.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.
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.
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
Letter.java
Implement the class and methods according to the UML and specifications below.
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.
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.
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”
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.
The default no-argument constructor should create a hand of MAX_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.
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.
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.
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.
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.
This method should return the value at the given index
in the hand.
This method should return the size the hand was initialized to.
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.
Project Part | Weight |
---|---|
Checkstyle | 20% |
Correctness | 80% |
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.
module-info.java
and DO create separate folders for source and class files).
3. Activate Checkstyle
for this assignment.src
folder.Refresh
to see the new files in Eclipse.Letter
class in your project.return
some artificial value (e.g. return 0;
or return null;
, return false;
) for now.// TODO: replace this with real code
or // FIXME: implement this method
.Letter
class.Format
from the Source
menu in Eclipse).Letter
class.Hand
.) Create the Hand
class in your project.return
some artificial value (e.g. return 0;
or return null;
, return false;
) for now.// TODO: replace this with real code
or // FIXME: implement this method
.javadoc
comments to the Hand
class.Format
from the Source
menu in Eclipse).Hand
class, and neither in this project at all.Run As
-> JUnit Test
.Letter
classaccessors
(also called getters
) first.equals
methodtoString
methodHand
classaccessors
(also called getters
) first.toString
methodinsert
methodremove
methodindexOf
methodPlayScrabble
Run As
-> Java Application
.main
method and run that. In this project that should only be PlayScrabble
.Run As
-> JUnit Test
.*** 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!
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.
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:
error
error_paid
warning
manual
identified
notfound
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.
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:
-
(a space, a dash, and a space).Google
, WAVE
, SortSite
, or ASLint
) followed by :
(a colon and a space)
(a space).-
(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:
Content
notfound
notfound
error_paid
notfound
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.
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:
filename
: The path to the file to which the results
should be written.format
: The format string for the final line of the output.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:
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 AccessibilityAssessment
s 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 AccessibilityAssessment
s 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
Note: the expected output for this case does not include:
Keyboard - Google: notfound WAVE: notfound SortSite: notfound ASLint: notfound - Dropdown navigation - only the top level items receive focus
showAllFailed
This method takes no parameters, and returns an ArrayList
containing the AccessibilityAssessment
s 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 AccessibilityAssessment
s to a file named showAllFailed.txt
followed by a summarizing statement in the format specified below.
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 AccessibilityAssessment
s 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.
PA2
.AccessibilityAssessment
.AccessibilityResults
.AccessibilityAssessment
AccessibilityResults
AccessibilityAssessment
objects and add them to the ArrayList
.AccessibilityAssessment
s 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.Scanner
hasNextLine()
, it might be helpful to extract less than a full line at a time , at least at first.saveResults
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.
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:
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.
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.
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.
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.
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 roundedname: String
- the name of the product typecost: 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.
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.
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 product
s are required to
make sure it is full and returns the number of product
s it took to fill the slot
.
load(Product product, int count)
This method loads the slot
with up to count new product
s in an
attempt to fill the slot
and returns the number of product
s 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.
toString()
methods.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.
DEFAULT_SIZE
: int = 15
โ the default size for a VendingMachine
, used primarily by the default constructortotalProfit
: int
โ this models the total profit for all of the VendingMachine
s 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 product
s 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 product
s 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 slot
s in the VendingMachine
.VendingMachine()
The default constructor creates a VendingMachine
with DEFAULT_SIZE
empty Slot
s.
VendingMachine(int size)
Creates a VendingMachine
with the indicated number of empty Slot
s.
VendingMachine(int size, Product product)
Creates a VendingMachine
with size
Slot
s 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 cost
s 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 profit
s 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.
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
. DrinkMachine
s 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.
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
public
method) minus the COOLING_CHARGE
to the profit
values.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.
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.
productList
: ArrayList
โ contains the list of product
s 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.
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.
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
product
s from every slot
of every VendingMachine
owned by the company.
Returns the totalProfit
of all of the VendingMachines
.
Submission for this assignment is divided into two parts that should be completed in order.
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.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.
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.
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
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:
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.
You will need to download the following files to handle the drawing window and the main game loop:
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.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: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.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:
Point
class is an encapsulation of a two-dimensional location that uses rectangular screen coordinates.Pose
class is a subclass of Point that includes heading/orientation information (an angular measure).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.Point
, Pose
, and Vector2D
are immutable classes (just like String
). The use of immutable classes can help to avoid subtle bugs that result from accidentally aliasing mutable objects.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:
You can try out BounceGame
by changing lines ~38-39 of GameDriver.java
as follows:
// Playable game = new AsteroidsGame();
Playable game = new BounceGame();
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.
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.
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).
getters
don’t actually start with the prefix “get”. Usually these would be those accessors for a boolean
instance variable such as isDestroyed()
.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:
See Collisions and Scoring below.
The Asteroids must fulfill the following requirements:
StdDraw
pen radius of .002.AsteroidSize is an enum that represents the size of an asteroid. It has three values:
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
.
Enemy saucers must fulfill the following requirements:
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.
GameUtils.drawPoseAsTriangle
method do draw the ship to the screen.turnLeft()
, turnRight()
, and thrust()
methods.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.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.AsteroidsGame.handleKeyboardInput()
.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.
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.
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.
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.
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 Star
s 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 Star
s that are positioned randomly on the screen.
This method should create 100 new Star
s 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
.
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.
This method should add the given enemy to all the appropriate ArrayLists in AsteroidsGame.
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!)
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.
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.
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.
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.
For the purposes of collision checking, the game elements can be divided into three categories.
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:
Seems too large to include here. Click the button below to view the UML diagram in a new tab.
Larger ViewBounceGame.java
and GameDriver.java
to see what a game looks like (try running these!)GameDriver
is set up to use AsteroidsGame
and that you have properly downloaded all the provided files to your Eclipse project.Drawable
and Updatable
interfacesGameElement
abstract classupdate
methodStar
classdraw
methodAsteroidsGame
:newStars()
method to create 100 randomly-placed Star
snewStars()
in the startGame() methoddraw()
method to:StdDraw
docs or code, or take a peek ๐ at how BounceGame
does it)Drawable
s. (๐ Hint: Take a look at how the update()
method updates all the Updatable
s)update()
that invoke handleCollisions
, removeDestroyedBullets
, and removeDestroyedEnemies
are commented out for now (you’ll need these in Part 3)Star
class.NumericDisplay
classNumericDisplay
class.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
Drawable
Updatable
GameElement
Star
NumericDisplay
Star
, NumericDisplay
, and GameElement
pass our unit testsShipTest
BulletTest
ShipTest
and BulletTest
against our reference solution expecting:Ship
, Bullet
Ship
Bullet
ShipTest
BulletTest
GameElement
Ship
and Bullet
pass our unit testsGameElement
Updatable
Drawable
Star
NumericDisplay
Ship
ShipTest
Bullet
BulletTest
Enemy
Asteroid
Saucer
AsteroidSize
AsteroidsGame
Star
NumericDisplay
Ship
Bullet
Asteroid
Saucer
AsteroidsGame
AsteroidSize
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”).
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
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.
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.
Before you can start working on the components, you need to learn a little bit about the system.
People in Purple wants the system to work with the following area around and including the JMU campus.
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.
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.Extraterrestrial.java
file, this image should not be in the src
folder.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.
As you saw in (all of the
๐ท๏ธ command line labs including:) the ArrayList Lab , the File I/O Lab , and the Enum Lab , you can configure Eclipse to provide command line arguments by modifying the run configuration as outlined on the wiki .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.
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.
You must submit (using Gradescope):
Area
class. In addition to the specs implied by the UML diagram,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)|
+-------------------+
String
with a field width of 3
(padded with spaces when necessary)|
+-------------------+
|( 0, 0) + 512 |
| (512, 512)|
+-------------------+
+-------------------+
|(256, 320) + 64 |
| (320, 384)|
+-------------------+
Sensor
class, called it LoggingSensor
scanLog
to a new
HashMap
.override
the scan
method to call the base class scan
method, and then add the result to the scanLog
.override
toString
to return (only) a String
representation of the scanLog
.ExtraterrestrialLocator
class to:LoggingSensor
class (rather than the regular Sensor)toString
of the LoggingSensor
after the search is complete.You must submit (using Gradescope):
Area
LoggingSensor
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:
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.
Correctness (OfficialTests): 25 points (Partial Credit Possible)
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.
You may find the following suggestions helpful.
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).
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;
}
}
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:
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).
The visualization of the scanning process can both help and hinder testing and debugging. For your convenience:
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.
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.
By the time you complete this assignment you should have learned many things, including but not limited to the following โbig pictureโ issues.
Thanks to the CS 159 F'22 team (esp. Dr. Bernstein!) for their work in an earlier version of this assignment.
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”).
Area.toString()
- Area
to use int
s rather than Point
- 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
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.
The following classes are provided via pa5.jar, and you should not modify them:
The Java Runtime Environment itself provides the Point
class.
ExtraterrestrialLocator
LoggingSensor
instead of a Sensor
.