Old version
This is the CS 112 site as it appeared on May 12, 2022.
Problem Set 3
due by 11:59 p.m. on Tuesday, February 15, 2022
Preliminaries
In your work on this assignment, make sure to abide by the collaboration policies of the course.
If you have questions while working on this assignment, please come to office hours, post them on Piazza, or email instructor.
Make sure to follow the instructions outlined at the end of Part I and Part II when submitting your assignment.
Part I
40 points total
Creating the necessary folder
-
If you haven’t already created a folder named
cs112
for your work in this course, follow these instructions to do so. -
Then create a subfolder called
ps3
within yourcs112
folder, and put all of the files for this assignment in that folder.
Creating the necessary file
Problems in Part I will be completed in a single PDF file. To create it, you should do the following:
-
Access the template that we have created by clicking on this link and signing into your Google account as needed.
-
When asked, click on the Make a copy button, which will save a copy of the template file to your Google Drive.
-
Select File->Rename, and change the name of the file to
ps3_partI
. -
Add your work for the problems from Part I to this file.
-
Once you have completed all of these problems, choose File->Download->PDF document, and save the PDF file in your
ps3
folder. The resulting PDF file (ps3_partI.pdf
) is the one that you will submit. See the submission guidelines at the end of Part I.
Problem 1: Our Rectangle
class revisited
15 points total; individual-only
Put your answers to these questions in the Problem 1 section of
your copy of ps3_partI
(see above).
Recall the Rectangle
class that we defined in lecture. (The relevant
version of this class is available here.)
-
Consider a potential non-static method named
rotate
that would rotate aRectangle
object 90 degrees by swapping its width and height values. For example, if aRectangle
‘s dimensions are 10 x 30, then calling therotate
method would change its dimensions to 30 x 10. Because the method only needs to change the internals of the called object, it doesn’t need to – and should not! – return a value.-
(1 point) What type of instance method would
rotate
be, an accessor or mutator? -
(3 points) Give an appropriate method header for this method, making sure to take into account the fact that the method is non-static. You do not need to define the body of the method.
-
-
Now consider a potential non-static method named
largerThan
that takes anotherRectangle
object and determines if the calledRectangle
object (i.e., the one on which the method is invoked) has a larger area than the otherRectangle
object – returningtrue
if the called object has a larger area andfalse
otherwise.- (1 point) What type of instance method would
largerThan
be, an accessor or mutator? - (3 points) Give an appropriate method header for this method, making sure to take into account the fact that the method is non-static. You do not need to define the body of the method.
- (1 point) What type of instance method would
-
Consider the following client code — i.e., code from another class that uses a
Rectangle
object:Rectangle r1 = new Rectangle(60, 80); System.out.println("r1's height is: " + r1.height); r1.width = r1.width + 20; System.out.println(r1); // print the new dimensions
Because our
Rectangle
class employs appropriate encapsulation, this code fragment will not compile.- (2 points) Explain what problems are present in the code fragment that prevent it from compiling.
- (5 points) Rewrite the fragment to eliminate those problems while maintaining the intended functionality of the original version. Don’t make any unnecessary changes.
Problem 2: A class that needs your help
11 points total; individual-only
Consider the following class, which is intended to serve as a blueprint for objects that encapsulate two pieces of data: an odd integer and a positive real number:
public class ValuePair { int a; double b; public double product() { return this.a * this.b; } }
-
(7 points) This class does not employ appropriate encapsulation. In section 2-1 of
ps3_partI
, revise the class to prevent direct access to the internals of aValuePair
object while allowing indirect access through appropriate methods. Your revised version should include:- whatever steps are needed to prevent direct access to the fields
- accessor methods that can be used to obtain the value of each field
- mutator methods that can be used to change the value of each
field. These methods should ensure that
a
is always odd, and thatb
is greater than 0.0. Attempts to assign an invalid value should produce anIllegalArgumentException
. - a constructor that takes values for
a
andb
and initializes the fields using those values. Attempts to assign an invalid value should produce anIllegalArgumentException
. Take advantage of the error-checking code that is already present in the mutator methods that you defined for changing the values of the fields.
No other methods are required.
-
(4 points) Now imagine that you’re writing client code for your revised
ValuePair
class – i.e., code in a different class that usesValuePair
objects.For each of the following tasks, write a single line of client code to accomplish the task:
-
Construct a
ValuePair
object for the pair (7, 15.5), and assign it to a properly declared variable namedvp1
. -
Change the integer value in the
ValuePair
object that you created in part (a), giving it a value of 25. You should not create a new object; you should change the internals of the existing object.Important: As a result of your changes from part 1, clients no longer have direct access to the fields in a
ValuePair
object. As a result, you will need to make a method call to change the appropriate field. -
Get the real-number value in the
ValuePair
object that you created in part (a), and assign it to a properly declared variable namedb1
. Here again, you will need to make an appropriate method call. -
Now imagine that you are given a second
ValuePair
object that has been created by someone else and that has been assigned to the variablevp2
. Change the integer value invp2
, giving it a value that is 2 more than its current value.
-
Problem 3: Static vs. non-static
14 points total; individual-only
When designing a blueprint class, we have seen that we can include both static and non-static variables. Static variables (also known as class variables) belong to the class as a whole. Non-static variables (also known as instance variables or fields) belong to individual objects of the class; each object gets its own copy of those variables.
We have also seen that a blueprint class can include both static and non-static methods. A non-static method (also known as an instance method) is required if the method must have access to the fields of a particular called object. However, if a method doesn’t need a called object – i.e., if all of the information that it needs is supplied by its parameters or by the static variables of the class – then we typically make it static. In the same way that static variables are also known as class variables, static methods are sometimes referred to as class methods.
Whether a method is static or non-static has an impact on how we call
it. Non-static methods must be called on an object of the class (e.g.,
r1.area()
, where r1
is a reference to a Rectangle
object). Static methods may be called on an object of the class, but
it is better style to call them using the name of the class instead.
Imagine that we are defining a class called Grade
that will serve as
a blueprint for objects that encapsulate the raw score and the
possible late penalty associated with a given grade. For example, to
create a Grade
object that represents a grade with a raw score of
85.5 and a late penalty of 20%, we would write:
Grade g = new Grade(85.5, 20);
An initial implementation of this class can be found here.
-
(4 points) Imagine that we want to modify the existing
Grade
class so that eachGrade
object has an associated category — aString
that is either"assignment"
,"quiz"
, or"exam"
. In addition, we want to keep track of how manyGrade
objects have been created for each of the three categories. What variables (static and/or non-static) would we need to add to theGrade
class as part of our implementation of these changes?In section 3-1 of
ps3_partI
, we have included a table that you should complete to describe the necessary variables. For each of your proposed variables, you should specify:- its type and name (make it descriptive!)
- whether it will be static or non-static
- a brief description of its purpose, and why it needs to be static or non-static.
As an example, we have filled in the first row of the table to describe the existing
rawScore
field. You should add the descriptions of your proposed new variables. You may not need all of the rows in the table. -
(4 points) Now let’s say that we want to add a method called
setCategory
that takes in a category string and uses it to change the category of the calledGrade
object.- What type of method should
setCategory
be — static or non-static? Explain briefly. - Assume we have a
Grade
object whose current category is"quiz"
. The professor who assigned the grade has decided to make the associated test worth more, so we need to callsetCategory
to change the grade’s category to"exam"
. During that method call, what changes will the method need to make to the values of the variables that you proposed above? Be as specific as possible.
- What type of method should
The remaining sections of this problem consider two other new methods
for the Grade
class – methods that do not involve the grade’s
category.
-
(3 points) Now let’s say that we want to add a method called
waiveLatePenalty
. It takes no parameters, and it sets the late penalty of aGrade
object to 0.- What type of method should
waiveLatePenalty
be — static or non-static? Explain briefly. - Give an example of how you would call this method from
outside the
Grade
class. If you need aGrade
object to call the method, assume that the variableg
represents that object, and that the object has already been created. However, you should only useg
if doing so is absolutely necessary.
- What type of method should
-
(3 points) Finally, let’s say that we want to add a new method called
computeRaw
. It takes two parameters — adouble
calledpct
and anint
calledpossiblePoints
— and it computes and returns the raw score that would be obtained if a student earnedpct
percent of the points represented bypossiblePoints
. In other words, it converts a percentage grade to a raw score. For example, ifpct
is 80.0 andpossiblePoints
is 50, the method should return 40.0, because 40 is 80 percent of 50.- What type of method should
computeRaw
be — static or non-static? Explain briefly. - Give an example of how you would call this method from
outside the
Grade
class. If you need aGrade
object to call the method, assume that the variableg
represents that object, and that the object has already been created. However, you should only useg
if doing so is absolutely necessary.
- What type of method should
Submitting your work for Part I
Note: There are separate instructions at the end of Part II that you should use when submitting your work for that part of the assignment.
Submit your ps3_partI.pdf
file using these steps:
-
If you still need to create a PDF file, open your
ps3_partI
file on Google Drive, choose File->Download->PDF document, and save the PDF file in yourps3
folder. -
Login to Gradescope by clicking the link in the left-hand navigation bar, and click on the box for CS 112.
-
Click on the name of the assignment (
PS 3: Part I
) in the list of assignments on Gradescope. You should see a pop-up window labeled Submit Assignment. (If you don’t see it, click the Submit or Resubmit button at the bottom of the page.) -
Choose the Submit PDF option, and then click the Select PDF button and find the PDF file that you created. Then click the Upload PDF button.
-
You should see a question outline along with thumbnails of the pages from your uploaded PDF. For each question in the outline:
- Click the title of the question.
- Click the page(s) on which your work for that question can be found.
As you do so, click on the magnifying glass icon for each page and doublecheck that the pages that you see contain the work that you want us to grade.
-
Once you have assigned pages to all of the questions in the question outline, click the Submit button in the lower-right corner of the window. You should see a box saying that your submission was successful.
Important
-
It is your responsibility to ensure that the correct version of every file is on Gradescope before the final deadline. We will not accept any file after the submission window for a given assignment has closed, so please check your submissions carefully using the steps outlined above.
-
If you are unable to access Gradescope and there is enough time to do so, wait an hour or two and then try again. If you are unable to submit and it is close to the deadline, email your homework before the deadline to
cs112-staff@cs.bu.edu
Part II
60 points total
Problem 4: Array-processing methods
35 points total; individual-only
Getting started
-
If you haven’t already done so, create a folder named
ps3
for your work on this assignment. You can find instructions for doing so here. -
In VS Code, select the File->Open Folder or File->Open menu option, and use the resulting dialog box to find and open the folder that you created for this assignment.
-
Select File->New File, which will open up an empty editor window.
-
Select File->Save, and give the new file the name
ArrayMethods.java
. -
In the new file, create a class called
ArrayMethods
. In that class, take the steps described below. -
In addition, we highly recommend adding a
main
method to your class that makes test calls to your methods. Don’t forget to importjava.util
so that you can use theArrays.toString
method in your tests.
Important guidelines:
-
Your methods must have the exact headers that we have specified, or we won’t be able to test them. Note in particular that the case of the letters matters.
-
If you are asked to write a method that returns a value, make sure that it returns the specified value, rather than printing it.
-
You may not use any Java classes that we have not covered in the lecture notes.
-
While you are encouraged to use
Arrays.toString()
when testing your methods, you must not use it inside the methods themselves. In addition, you must not use any other methods from theArrays
class. -
Each of your methods should be preceded by a comment that explains what your methods does and what its inputs are. You should also include a comment at the top of the file, similar to the one that we included in
Methods7.java
from Problem Set 1. -
More generally, use good programming style. Use appropriate indentation, select descriptive variable names, insert blank lines between logical parts of your program, and add comments as necessary to explain what your code does. See the coding conventions for more detail.
The methods
-
Include the following declaration at the beginning of your class, immediately after the class header:
public static final String[] DAY_NAMES = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
It declares a variable called
DAY_NAMES
that refers to an array of strings that you will use in one of your methods.The syntax that we are using to declare this variable makes it a class constant. Declaring a variable to be static means it has class-level scope and can be accessed by any method written in the class. Declaring a variable to be final means that it is a constant that cannot be modified by code elsewhere in the program.
By convention, when declaring a class constant, we capitalize the entire variable name. Doing so makes it easier for readers of our code to recognize that the variable is a constant—and to know that they can find its value at the top of the class.
-
Write a method with the header
public static int getDayNum(String day)
that takes a reference to a string and returns the index of that string in the array referred to by the class constant
DAY_NAMES
that you declared above. For example:getDayNum("Sunday")
should return 0, because"Sunday"
has an index of 0 in theDAY_NAMES
array.getDayNum("Wednesday")
should return 3, because"Wednesday"
has an index of 3 in theDAY_NAMES
array.
Important notes:
-
If the parameter is
null
or the string is not found in the array, the method should return-1
. -
The method should work correctly regardless of the case of the letters in the string that is passed in. For example, the inputs
"Monday"
,"monday"
, and"MoNDaY"
should all produce the same result. To do so, you should take advantage of theequalsIgnoreCase
method from theString
class. -
Your method should work even if we change the contents of the
DAY_NAMES
array. In other words, you should write code that processes an arbitrary array ofString
objects calledDAY_NAMES
, and you should not make any assumptions about the strings found in that array.
-
Write a method with the header
public static void swapNeighbors(int[] values)
that takes a reference to an array of integers
values
and swaps pairs of elements that are “neighbors” of each other:values[0]
withvalues[1]
,values[2]
withvalues[3]
, etc.For example, if you add the following test code to your
main
method:int[] a1 = {0, 2, 4, 6, 8, 10}; swapNeighbors(a1); System.out.println(Arrays.toString(a1));
you should see the following output:
[2, 0, 6, 4, 10, 8]
In an odd-length array, the last element should not be moved. For example, if you run these statements:
int[] a2 = {1, 2, 3, 4, 5, 6, 7}; swapNeighbors(a2); System.out.println(Arrays.toString(a2));
you should see:
[2, 1, 4, 3, 6, 5, 7]
Special case: If the parameter is
null
, the method should throw anIllegalArgumentException
. -
Write a method with the header
public static int[] copyWithCeiling(int[] values, int ceiling)
that takes a reference to an array of integers
values
and an integerceiling
, and that creates and returns a new array based onvalues
in which all elements greater thanceiling
are replaced by the valueceiling
.Important:
-
You may not use any of the built-in methods for copying an array.
-
You must not modify the original array.
For example:
int[] a3 = {2, 5, 6, 3, 7, 4, 1}; int[] a4 = ArrayMethods.copyWithCeiling(a3, 4); System.out.println(Arrays.toString(a4));
should display:
[2, 4, 4, 3, 4, 4, 1]
Special case: If the first parameter is
null
, the method should throw anIllegalArgumentException
. -
-
Write a method with the header
public static int mostOccur(int[] arr)
that takes a reference to a sorted array of integers and returns the value that occurs most often in the array. For example, consider this array:
int[] arr = {1, 2, 3, 3, 8, 8, 8, 8, 11, 11, 11, 14, 19, 19};
The method call
mostOccur(arr)
should return8
, because8
is the value that occurs most often in the array, appearing four times.The array is guaranteed to be in sorted order. For full credit, you should not use another array as part of your solution, and you should not perform more than one scan through the array from left to right.
Special cases:
-
If two or more values tie for the most occurrences, return the one that comes first. For example, if we added an extra
11
to the array shown above – giving that value four occurrences as well – the method should still return8
, because8
comes before11
in the array. -
If all of the values occur exactly once, or if there is only one element, the first element should be returned. You should not need separate code to check for these cases.
-
If the parameter is
null
, or if the array has a length of 0, the method should throw anIllegalArgumentException
.
Important: You must not modify the original array.
-
-
Write a method with the header
public static int find(int[] arr1, int[] arr2)
that takes two arrays containing sequences of integers and that returns the index of the first occurrence of the first sequence in the second sequence, or
-1
if the first sequence does not appear in the second sequence. For example, suppose that you have these arrays:int[] list1 = {1, 3, 6}; int[] list2 = {1, 3, 5, 8, 12, 1, 3, 17, 1, 3, 6, 9, 1, 3, 6};
then the call
find(list1, list2)
should return 8 because the sequence of values stored inlist1
appears inlist2
starting at index 8. Notice thatlist1
actually appears twice inlist2
, starting at position 8 and starting at position 12. Your method should return the first such position.If the first sequence is not contained in the second sequence, then the method should return
-1
. For example, iflist2
had the same values as before butlist1
stored{12, 1, 3, 6}
, then the callfind(list1, list2)
should return-1
becauselist1
is not contained inlist2
.Special case: If either parameter is
null
or has a length of 0, the method should throw anIllegalArgumentException
.Important: You must not modify the original arrays.
Problem 5: A blueprint class for Card
objects
25 points; pair-optional
This is the only problem of the assignment that you may complete with a partner. See the rules for working with a partner on pair-optional problems for details about how this type of collaboration must be structured.
In this problem you will create a class called Card
that serves as a
blueprint for objects that can be used to represent a single playing
card for a card game in which cards have both colors and numeric values.
The sections below outline the steps that you should take.
The guidelines from Problem 4 also apply here.
Getting started
-
Download the following file:
Card.javaMake sure to put it in your
ps3
folder. If your browser doesn’t allow you to specify where a file should be saved, try right-clicking on its link above and choosing Save as... or Save link as..., which should produce a dialog box that allows you to choose the correct folder for the file. -
In VS Code, select the File->Open Folder or File->Open menu option, and use the resulting dialog box to find and open the folder that you created for this assignment. (Note: You must open the folder; it is not sufficient to simply open the file.)
The name of the folder should appear in the Explorer pane on the left-hand side of the VS Code window, along with the name of the file that you downloaded.
-
Click on the name
Card.java
, which will open an editor window for that file. You will see that we’ve given you the beginnings of the class. -
Read over the starter code in
Card.java
before continuing — including all of the comments that we have provided.You will note that we have provided two class constants – global variables whose value cannot change. Read the accompanying comments to see what they represent.
Implementing the rest of the class
-
Add a third class constant for the maximum value that a
Card
can have, which is 9. -
Add a static method called
isValidColor
. It should take the name of a color as a parameter, and it should returntrue
if the specified color is valid (i.e., if it is one of the colors listed in theCOLORS
array), andfalse
otherwise. For example:isValidColor("red")
should returntrue
, because “red” appears in theCOLORS
arrayisValidColor("orange")
should returnfalse
, because “orange” does not appear in theCOLORS
array.
Notes:
- The case of the letters matters. For example,
isValidColor("Red")
should returnfalse
, because"Red"
begins with an upper-caseR
, and the version in theCOLORS
array begins with a lower-caser
. - You may not use any built-in methods to determine whether
the color is in the
COLORS
array. Rather, you should write the code needed to process this array and see if the color is present. - In addition, you should not make any assumptions about the
actual values in the
COLORS
array. If we change the set of colors, your method should still work. - This method is a helper method that will be used by one or more of the other methods that you write.
- This method (unlike the others you will write) is static, because it does not need to access the fields in the object. Rather, we pass it all of the information that it needs as a parameter.
-
Define the fields
EachCard
object should encapsulate two pieces of state:- the card’s color (a string)
- the card’s value (an integer).
For example, here is what a
Card
object representing a red 7 would look like in memory:(To simplify matters, we have shown the string “red” inside the field, even though in reality the memory address of the string would be stored.)
For now, you only need to define the fields, making sure to protect them from direct access by client code. In subsequent sections, you will write constructors that assign values to the fields, and that ensure that only valid values are allowed.
-
Implement mutators for the fields
Next, add the following mutator methods:-
setColor
, which takes aString
representing a color and sets the value of theCard
object’scolor
field to the specified color. Attempts to assign an invalid color should produce anIllegalArgumentException
. Take advantage of yourisValidColor
method when checking for invalid colors. -
setValue
, which takes an integer and sets the value of theCard
object’svalue
field to the specified number. Attempts to assign an invalid value (one that is outside the range specified by theMIN_VALUE
andMAX_VALUE
constants) should produce anIllegalArgumentException
.
Make sure that your methods are non-static, because they need access to the fields in the called object. Use the class constants when checking for invalid values.
-
-
Implement a constructor
Next, add a constructor that takes a string for theCard
‘s color and an integer for theCard
‘s value (in that order), and initializes the values of the fields. Your constructor should call the mutators that you defined in part 3 so that you can take advantage of the error-checking code that is already present in those methods. -
Implement accessors for the fields
Next, define the following accessor methods:getColor
, which returns the string representing theCard
object’s color.getValue
, which returns the integer representing theCard
object’s value.
Make sure that your methods are non-static, because they need access to the fields in the called object.
Once you have completed parts 1–6, you can test them using the first client program that we’ve given you. See below for more detail.
-
Define the
toString
method
Write atoString
method that returns aString
representation of theCard
object that can be used when printing it or concatenating it to aString
. We discuss this type of method in the lecture notes, and we provide an example in ourRectangle
class. The returnedString
should be of the formcolor value
(e.g.,"blue 3"
or"red 10"
). -
Define methods for comparing
Card
objects
Finally, define the following two instance methods for comparingCard
objects:-
matches
, which takes anotherCard
object as a parameter and returnstrue
if the calledCard
object matches the color and/or value of the otherCard
object, andfalse
if it doesn’t match either the color or the value. If a value ofnull
is passed in for the parameter, the method should returnfalse
. -
equals
, which takes anotherCard
object as a parameter and determines if it is equivalent to the called object, returningtrue
if it is equivalent andfalse
if it is not equivalent. TwoCard
objects should be considered equivalent if their color and value are the same. If a value ofnull
is passed in for the parameter, the method should returnfalse
.
-
Client programs and testing your code
To help you in testing your Card
class, we have created two sample
client programs:
Client1.java
- make sure to save it in your
ps3
folder - tests the methods from parts 2 and 4-6
- should only try to run it after completion of part 6.
- if you get errors in
Client1.java
, check your method headers inCard.java
- expected output is given here
- make sure to save it in your
Client2.java
- make sure to save it in your
ps3
folder - tests the methods from parts 7 and 8
- should only try to run it after completion of part 8.
- expected output is given here
- make sure to save it in your
In addition to using the client programs, we recommend that you perform additional testing on your own by adding code to one of the clients.
Submitting your work for Part II
Note: There are separate instructions at the end of Part I that you should use when submitting your work for that part of the assignment.
Pair-optional problem
If you chose to work on Problem 5 with a partner, both you and your partner should submit your own copy of your joint work, along with your individual work on Problem 4.
You should submit only the following files:
ArrayMethods.java
Card.java
Make sure that you do not try to submit a .class
file or a file
with a ~
character at the end of its name.
Here are the steps:
-
Login to Gradescope as needed by clicking the link in the left-hand navigation bar, and then click on the box for CS 112.
-
Click on the name of the assignment (
PS 3: Part II
) in the list of assignments. You should see a pop-up window with a box labeled DRAG & DROP. (If you don’t see it, click the Submit or Resubmit button at the bottom of the page.) -
Add your files to the box labeled DRAG & DROP. You can either drag and drop the files from their folder into the box, or you can click on the box itself and browse for the files.
-
Click the Upload button.
-
You should see a box saying that your submission was successful. Click the
(x)
button to close that box. -
The Autograder will perform some tests on your files. Once it is done, check the results to ensure that the tests were passed. If one or more of the tests did not pass, the name of that test will be in red, and there should be a message describing the failure. Based on those messages, make any necessary changes. Feel free to ask a staff member for help.
Note: You will not see a complete Autograder score when you submit. That is because additional tests for at least some of the problems will be run later, after the final deadline for the submission has passed. For such problems, it is important to realize that passing all of the initial tests does not necessarily mean that you will ultimately get full credit on the problem. You should always run your own tests to convince yourself that the logic of your solutions is correct.
-
If needed, use the Resubmit button at the bottom of the page to resubmit your work. Important: Every time that you make a submission, you should submit all of the files for that Gradescope assignment, even if some of them have not changed since your last submission.
-
Near the top of the page, click on the box labeled Code. Then click on the name of each file to view its contents. Check to make sure that the files contain the code that you want us to grade.
Important
-
It is your responsibility to ensure that the correct version of every file is on Gradescope before the final deadline. We will not accept any file after the submission window for a given assignment has closed, so please check your submissions carefully using the steps outlined above.
-
If you are unable to access Gradescope and there is enough time to do so, wait an hour or two and then try again. If you are unable to submit and it is close to the deadline, email your homework before the deadline to
cs112-staff@cs.bu.edu