Old version
This is the CS 112 site as it appeared on May 11, 2018.
Problem Set 2
due by 11:59 p.m. on Tuesday, February 6, 2018
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
cs112-staff@cs.bu.edu
.
Make sure to submit your work on Apollo, following the procedures found at the end of the assignment.
Part I
40 points total
This part of the assignment consists of a series of short-answer questions. You will be able to check your answers to at least some of these questions in DrJava, but we encourage you to try answering them on your own and convincing yourself of the correctness of your answers before you attempt to test them in DrJava. These questions are similar to ones that could appear on the midterms and final exam, which you will have to take without the use of a computer!
Problem 1: Understanding code that uses an array
8 points total; individual-only
Using folders
Don’t forget that we strongly encourage you to create a separate
folder for each assignment, so that you can more easily keep track
of your work. For example, you could create a folder called ps2
for your work on this assignment, and put all of the files for PS
2 in that folder.
Open up a text editor (e.g., Notepad or TextEdit) and create a
plain-text file named ps2pr1.txt
. Put all of your work for
this problem in that file.
-
(3 points) What is the output of the following lines of code?
int[] a = {3, 6, 9, 12, 15}; int[] b = {3, 6, 9, 12, 15}; int[] c = b; c[3] = 10; System.out.println(a[3] + " " + b[3] + " " + c[3]);
After giving the output, explain briefly why it makes sense.
-
(3 points) Consider the following static method, which operates on an array of integers:
public static void mystery(int[] arr) { for (int i = 0; i < arr.length / 2; i++) { int n = arr.length - 1 - i; int val = arr[n]; arr[n] = arr[i]; arr[i] = val; // What values do the variables have here, // for each value of the loop variable `i`? } }
Consider the following code fragment, which calls this method:
int[] values = {0, 1, 2, 3, 4, 5, 6, 7}; mystery(values);
Copy the table shown below into your text file for this problem, and complete it to illustrate the execution of the above method call.
mystery's variables i | n | val | arr ------------------------------------------- - | - | - | {0, 1, 2, 3, 4, 5, 6, 7} 0 | | |
We have started the table for you. The first row shows what the array looks like before the start of the
for
loop. For each value of the loop variablei
, include a row in the table that shows the values of the other variables at the end of the iteration of the loop for that value ofi
. Note that you should write the value ofarr
as an array literal that shows the current contents of the array, even though the variable itself actually holds a reference to the array. -
(2 points) After running the code fragment from part 2, we then execute the following statement:
System.out.println(Arrays.toString(values));
Do we see the original array, or do we see the changes made by the call to the
mystery()
method? Explain briefly why your answer makes sense.(Note: If you want to check your answer, you’ll need to import the
java.util
package so that you can use theArrays.toString()
method.)
Problem 2: Two-dimensional arrays
8 points total; pair-optional
This is one of only two problems in this 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.
Open up a text editor (e.g., Notepad or TextEdit) and create a
plain-text file named ps2pr2.txt
. Put all of your work for
this problem in that file.
Overview
Two-dimensional arrays in Java are extremely similar to
two-dimensional lists in Python.
In Python, a 2-D list is a list of lists:
grid = [ [2, 4], [5, 7], [8, 1] ]
In the same way, a 2-D array in Java is an array of arrays:
int[][] grid = { {2, 4}, {5, 7}, {8, 1} };
(Note: When we declare a variable for a 2-D array, the type of the
elements is followed by two pairs of square brackets: int[][]
)
Here is a comparison of other key operations for 2-D sequences:
operation |
in Python |
in Java |
---|---|---|
determining the number of rows |
|
|
determining the number of elements in row r |
|
|
determining the number of columns in a rectangular grid/matrix (in which all rows have the same length) |
|
|
accessing the element at row r, column c |
|
|
Problems
Assume that you have a variable twoD
that refers to a
two-dimensional array of integers. Here is another example of such
an array:
int[][] twoD = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
In your answers below, you may assume that the array is rectangular – i.e., that all rows have the same number of elements.
-
(2 points) Write an assignment statement that replaces the value of 6 in the above array with a value of 12.
-
(3 points) Write a code fragment that prints the values in the leftmost column of the array to which
twoD
refers. Print each value on its own line. For the array above, the following values would be printed:1 4 7
Make your code general enough to work on any two-dimensional array named
twoD
that has at least one value in each row. -
(3 points) Write a code fragment that prints the values in the anti-diagonal of the array to which
twoD
refers – i.e., the values along a diagonal line from the bottom-left corner to the upper-right corner. Print each value on its own line. For the array above, the following values would be printed:7 5 3
Make your code general enough to work on any two-dimensional array in which the dimensions are equal – i.e., the number of rows is the same as the number of columns.
Problem 3: A class that needs your help
12 points total; individual-only
Open up a text editor (e.g., Notepad or TextEdit) and create a
plain-text file named ps2pr3.txt
. Put all of your work for
this problem in that file.
Consider the following class, which is intended to serve as a
blueprint for objects that encapsulate two pieces of data: a
person’s name (which should not be allowed to have the special
value null
) and the person’s age (which must be non-negative).
public class Participant { String name; int age; }
-
(8 points) This class does not employ appropriate encapsulation. Rewrite it to prevent direct access to the internals of a
Participant
object while allowing indirect access through appropriate methods. Your rewritten version should include:- whatever changes are needed to the field declarations to prevent them from being accessed outside the class
- methods that can be used to obtain the value of each field
(call them
getName
andgetAge
) -
methods that can be used to change the value of each field (call them
setName
andsetAge
). These methods should ensure thatage
is always non-negative, and thatname
is notnull
. Attempts to assign an invalid value should produce anIllegalArgumentException
, which you can do as follows:throw new IllegalArgumentException();
-
a constructor that initializes the fields of a newly created
Participant
object to the values specified by the parameters of the constructor. Attempts to assign an invalid value should produce anIllegalArgumentException
. Take advantage of the error-checking code that is already present in the 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
Participant
class – i.e., code in a different class that usesParticipant
objects.Write a single line of client code to accomplish each of the following tasks:
-
Construct a
Participant
object for a person named Tom Brady who is 35 years old, and assign it to a properly declared variable namedqb
. -
The Tom Brady (the one who is participating in his 8th Super Bowl this week) is actually 40 years old! Change the age in the
Participant
object that you created in part (a). 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
Participant
object. As a result, you will need to make an appropriate method call to accomplish the change to the age. -
Get the name from the
Participant
object that you created in part (a), and assign it to a properly declared variable namedmvp
. Here again, you will need to make an appropriate method call.
-
Problem 4: Static vs. non-static methods
12 points total; 6 points each part; individual-only
Open up a text editor (e.g., Notepad or TextEdit) and create a
plain-text file named ps2pr4.txt
. Put all of your work for
this problem in that file.
When designing a blueprint class, we can include both non-static and static methods. A non-static method is required if the method must have access to the fields of a particular called object. However, if a method does not need a called object – i.e., if all of the information that it needs is supplied by its parameters – then we typically make it static. Non-static methods must be called on an object of the class. 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.
Consider the following simple class, which is a blueprint class
for Grade
objects that encapsulate both the number of points earned
(a floating-point number) and a late penalty, if any. The late-penalty
percentage is stored as an integer (e.g., 10 for a 10% late penalty).
public class Grade { private double points; private int latePenalty; public Grade(double pts, int penalty) { this.points = pts; this.latePenalty = penalty; } // other methods are omitted for the sake of brevity }
Assume that you are considering adding two methods to this class.
-
The first method is called
addExtraCredit
. It takes a floating-point number calledamount
and increases the points component of aGrade
object by the specified amount. It does not return anything.- What type of method should
addExtraCredit
be — static or non-static? Explain briefly. - Give an appropriate header for this method. You do not need to define the body of the method.
- 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.
- What type of method should
-
The second method is called
computePercent
. It takes two floating-point numbers – one calledpointsEarned
and another calledpossiblePoints
– and it returnspointsEarned
as a percentage ofpossiblePoints
. For example, ifpointsEarned
is 30.0 andpossiblePoints
is 50.0, the method should return 60.0, because 30.0 is 60 percent of 50.0.- What type of method should
computePercent
be — static or non-static? Explain briefly. - Give an appropriate header for this method. You do not need to define the body of the method.
- 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.
- What type of method should
Part II
60 points total
Problem 5: Array-processing methods
24 points total; 8 points each part; individual-only
In a class named ArrayMethods
, implement each of the methods
described below.
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 should not use any Java classes that we have not covered in the lecture notes.
-
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
Methods5.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.
-
Write a method with the header
public static void swapAdjacent(int[] values)
that takes a reference to an array of integers
values
and swaps adjacent pairs of elements:values[0]
withvalues[1]
,values[2]
withvalues[3]
, etc.For example, after implementing this method and compiling your
ArrayMethods
class, you should see the following when you test the method from the Interactions Pane in DrJava:> int[] a1 = {0, 2, 4, 6, 8, 10}; > ArrayMethods.swapAdjacent(a1); > a1 { 2, 0, 6, 4, 10, 8 }
(Note that if you evaluate an array variable in the Interactions Pane, DrJava is nice enough to show you the contents of the array, even though printing that same variable would show something based on the array’s memory address.)
In an odd-length array, the last element should not be moved:
> int[] a2 = {1, 2, 3, 4, 5, 6, 7}; > ArrayMethods.swapAdjacent(a2); > a2 { 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[] copyReplace(int[] values, int oldVal, int newVal)
that takes a reference to an array of integers
values
and two integersoldVal
andnewVal
, and that creates and returns a new array that is a copy of the original array, but in which all occurrences of the valueoldVal
are replaced with the valuenewVal
.Important:
-
You may not use any of the built-in methods for copying an array.
-
Your method must not modify the original array.
Examples:
> int[] a1 = {2, 5, 4, 2, 7, 4, 2}; > int[] a2 = ArrayMethods.copyReplace(a1, 4, 0); > a2 { 2, 5, 0, 2, 7, 0, 2 } > int[] a3 = ArrayMethods.copyReplace(a1, 2, -1); > a3 { -1, 5, 4, -1, 7, 4, -1 } > a1 { 2, 5, 4, 2, 7, 4, 2 }
Special case: If the parameter is
null
, the method should throw anIllegalArgumentException
. -
-
Write a method with the header
public static int maxSorted(int[] values)
that takes a reference to an array of integers and returns the length of the longest sorted sequence of integers in the array. For example:
> int[] a1 = {3, 8, 6, 14, -3, 0, 14, 207, 98, 12}; > ArrayMethods.maxSorted(a1) 4
The above call should return
4
, because the longest sorted sequence in the array has four values in it (the sequence-3, 0, 14, 207
). Note that the sorted sequence could contain duplicates. For example:> int[] a2 = {17, 42, 3, 5, 5, 5, 8, 4, 6, 1, 19}; > ArrayMethods.maxSorted(a2) 5
This call should return
5
for the length of the sequence3, 5, 5, 5, 8
.Special cases:
-
If the parameter is
null
, the method should throw anIllegalArgumentException
. -
Your method should return
0
if passed an empty array (i.e., an array of length 0). -
Your method should return
1
if passed an array with one element or an array in which all of the elements are in decreasing order. It should be possible to get a return value of 1 for these cases without needing to explicitly check for them.
-
Problem 6: Our Rectangle
class revisited
12 points total; 4 points each part; pair-optional
This is one of only two problems in this 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.
This problem asks you to modify an existing blueprint class.
The guidelines from the previous problem also apply here.
Begin by downloading this file:
Rectangle.java
, which contains a
version of the Rectangle
class that we discussed in lecture. Open
it in DrJava, and add your methods to the class that we have given you
in that file.
-
Add a non-static method named
rotate
that rotates aRectangle
object 90 degrees by swapping its width and height values. For example, if aRectangle
‘s dimensions are 10x30, then calling therotate
method would change its dimensions to 30x10.Because the method should change the internals of the called object, it doesn’t need to – and should not! – return a value.
-
Add a 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.Special case: If a
null
value is passed into the method, it should throw anIllegalArgumentException
.Important:
-
For full credit, you should take full advantage of the existing
Rectangle
methods to get the information that you need in this method. Do not reinvent the wheel! -
Make sure that you return a boolean literal (
true
orfalse
) and not the string"true"
or the string"false"
.
-
-
Add code to the bottom of the existing
main()
method that makes at least two test calls to each of your new methods.-
If the method returns a value, you should assign that value to an appropriately declared variable, and then print the value of that variable.
-
If the method does not return a value, print the
Rectangle
object both before and after each call to that method.
-
Problem 7: A blueprint class for Card
objects
24 points; individual-only
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 called Buno (pronounced B-U-no).
You can think of it as BU’s version of a popular card game whose name
does not begin with B!
The sections below outline the steps that you should take.
The guidelines from Problem 5 also apply here.
-
(0 points) Download
Card.java
, and open it in DrJava. This file includes some starter code for the class you will write. Read through this code 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. Here is the first one:
public static final int MIN_VALUE = 0;
In general, a class constant is defined near the top of the class, outside of any method. Its definition includes several key components:
-
the keyword
static
, which means that the variable belongs to the class as a whole. This distinguishes it from a field, which is a non-static variable that is inside every object of the class. Every object gets its own separate set of the fields, but there is only one copy of astatic
variable, and it is is shared by all objects of the class. -
the keyword
final
, which is what makes this variable a constant. The value that we assign to the class constant here is its final value, and we cannot assign a new value to it somewhere else. -
the type declaration, like that of any other variable
-
the variable name, which we capitalize so that it will be obvious that it is a constant
-
the initialization of the variable, which we must do here, because we can’t change a class constant outside of its definition.
We have provided two class constants. Read the accompanying comments to see what they represent.
-
-
(1 point) Add a third class constant for the maximum value that a
Card
can have, which is 9. -
(5 points) 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 (3 points)
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 (4 points)
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 (3 points)
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 (2 points)
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 (2 points)
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 (4 points)
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
- should compile after completion of part 6. If it doesn’t, check your method headers.
- tests the methods from parts 2 and 4-6
- expected output is given here
Client2.java
- should compile after completion of part 8. Do not open it before then!
- tests the methods from parts 7 and 8
- expected output is given here
Put the client programs in the same folder as your Card.java
file. Make sure not to open the clients until the necessary parts have
been completed.
In addition to using the client programs, we recommend that you perform
additional testing on your own. You can do so in the Interactions Pane,
or by adding code to one of the clients, or by adding a main
method to
the Card
class.
If you are unable to get a given method to compile, make sure to comment out the body of the method (keeping the method header and possibly a dummy return value) so that we’ll still be able to test your other methods.
Submitting Your Work
You should use Apollo to submit the following files:
- your
ps2pr1.txt
file containing your solutions for Problem 1 - your
ps2pr2.txt
file containing your solutions for Problem 2; if you worked with a partner, make sure that you each submit a copy of your joint work, and that you include comments at the top of the file specifying the name and email of your partner - your
ps2pr3.txt
file containing your solutions for Problem 3 - your
ps2pr4.txt
file containing your solutions for Problem 4 - your
ArrayMethods.java
file file containing your solutions for Problem 5 - your modified
Rectangle.java
file containing your solutions for Problem 6; if you worked with a partner, make sure that you each submit a copy of your joint work, and that you include comments at the top of the file specifying the name and email of your partner - your modified
Card.java
file containing your solutions for Problem 7
Warnings
-
Make sure to use these exact file names, or Apollo will not accept your files. If Apollo reports that a file does not have the correct name, you should rename the file using the name listed in the assignment or on the Apollo upload page.
-
Make sure that you do not try to submit a
.class
file or a file with a~
character at the end of its name. -
Before submitting your files, make sure that your BU username is visible at the top of the Apollo page. If you don’t see your username, click the Log out button and login again.
-
If you make any last-minute changes to one of your Java files (e.g., adding additional comments), you should compile and run the file in DrJava after you make the changes to ensure that it still runs correctly. Even seemingly minor changes can cause your code to become unrunnable.
-
If you encounter problems with Apollo, click the Log Out button (if you are already logged in), close your browser, and try again. If possible, you may also want to wait an hour or two before retrying. 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
Here are the steps:
- Login to Apollo, using the link in the left-hand navigation bar. You will need to use your Kerberos user name and password.
- Check to see that your BU username is at the top of the Apollo page. If it isn’t, click the Log out button and login again.
- Find the appropriate problem set section on the main page and click Upload files.
- For each file that you want to submit, find the matching upload section for the file. Make sure that you use the right section for each file. You may upload any number of files at a time.
- Click the Upload button at the bottom of the page.
- Review the upload results. If Apollo reports any issues, return to the upload page by clicking the link at the top of the results page, and try the upload again, per Apollo’s advice.
- Once all of your files have been successfully uploaded, return to the upload page by clicking the link at the top of the results page. The upload page will show you when you uploaded each file, and it will give you a way to view or download the uploaded file. Click on the link for each file so that you can ensure that you submitted the correct file.
Warning
Apollo will automatically close submissions for a given file when its final deadline has passed. We will not accept any file after Apollo has disabled its upload form, so please check your submission carefully following the instructions in Step 7 above.