![]() |
Problem Set 8 Due on Tuesday, April 8 |
The purpose of this problem set is to give you experience with iteration (tail recursion, while loops, and for loops) and list of lists. In Task 1, you will use list of lists to determine all the different ways to make change for a given amount of money. In Task 2, you will use iteration to manipulate lists. In Task 3 you will use iteration to create pictures of nested boxes.
All code for this assignment is available in the ps8_programs folder in the cs111d download directory on puma.
ChangeMaker.java
file from Task 1.
Partition.java
file from Tasks 2b, 2c, 2d, and 2e;
NestedFrames.java
file from Task 3b;
ps8_programs
folder. In particular,
ChangeMaker
subfolder should
contain your final version of ChangeMaker.java
.
Partition
subfolder should
contain your final version of Partition.java
.
NestedFrames
subfolder should
contain your final version of NestedFrames.java
.
Lists of lists are useful data structures for holding lists of possibilities. We can use them to hold the list of all subsets of a set of numbers like we saw in lecture. We could also use them to hold a list of all permutations of a list of numbers, using an approach similar to computation of string permutations considered in the previous problem set. In this problem, we will use lists of lists to represent all the possible ways of making change for a given amount of money given an unlimited number of coins with certain denominations. Some examples are given below (assume all values are in cents).
Amount to change | Denominations | Ways to Make Change |
---|---|---|
5 | [5,1] | [[5], // 1 nickel [1, 1, 1, 1, 1] // 5 pennies ] |
16 | [10,5,1] | [[10, 5, 1], // 1 dime, 1 nickel, and 1 penny [10, 1, 1, 1, 1, 1, 1], // 1 dime and 10 pennies [5, 5, 5, 1], // 3 nickels and 1 penny [5, 5, 1, 1, 1, 1, 1, 1], // 2 nickels and 6 pennies [5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], // 1 nickel and 11 pennies [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] // 16 pennies. ] |
Your goal is to formulate a strategy that will list all the possible
ways to make change for a given amount of money with a list of possible
coin denominations provided in descending order of value. You will be completing
the method makeChange
of the ChangeMaker
class.
The skeleton for the method is provided below:
public static IntListList makeChange (int amount, IntList coins)
Returns a list of possible ways to make change foramount
using the coin denominations in the listcoins
. Assume the integers incoins
are in descending order of value.
Complete this problem by fleshing out the definition of makeChange
in the ChangeMaker.java
file within the ChangeMaker
folder.
ChangeMaker.mcp
project is configured so that it
tests makeChange
on a number of test cases when you
run the project.
The correct output for the test cases is provided at the end of this problem
description. You need to get the same number of ways to make change and the same ways to
make change as listed, but you may list the ways to make change in any order and may list
the coins in any order.
makeChange
involves working with IntList and IntListList
lists, we can no longer just use list methods and operators without the class name because Java
won't know which method we want (i.e. do we want the one that applies to the IntList or
the IntListList class?). Instead, we must specify the name of the class with the
method (e.g. IntList.prepend
or IntListList.prepend
). However,
specifying the full name of the class makes the code harder to read so we have provided you with
the following "shortcut" way to refer to IntList
and
IntListList
methods and operators for doing this problem.
IntList Methods (IL) | IntListList Methods (ILL) |
---|---|
IL.empty IL.prepend IL.head IL.tail IL.isEmpty IL.toString IL.fromString IL.length IL.append IL.postpend |
ILL.empty ILL.prepend ILL.head ILL.tail ILL.isEmpty ILL.toString ILL.fromString ILL.length ILL.append ILL.postpend ILL.mapPrepend |
Note that the IntListList
operations include the
mapPrepend
method discussed in lecture. It is defined as:
public static IntListList mapPrepend (int n, IntListList L) { if (ILL.isEmpty(L)) { return L; } else { return ILL.prepend (IL.prepend(n, ILL.head(L)), mapPrepend(n, ILL.tail(L))); } }
Correct Test Case Answers
---------------------------------------------------- There are 1 ways to make change for 5 cents using [5]: [[5] ] ---------------------------------------------------- There are 1 ways to make change for 5 cents using [10, 5]: [[5] ] ---------------------------------------------------- There are 1 ways to make change for 10 cents using [5]: [[5, 5] ] ---------------------------------------------------- There are 2 ways to make change for 10 cents using [10, 5]: [[10], [5, 5] ] ---------------------------------------------------- There are 1 ways to make change for 15 cents using [5]: [[5, 5, 5] ] ---------------------------------------------------- There are 2 ways to make change for 15 cents using [10, 5]: [[10, 5], [5, 5, 5] ] ---------------------------------------------------- There are 0 ways to make change for 16 cents using [10, 5]: [] ---------------------------------------------------- There are 2 ways to make change for 5 cents using [5, 1]: [[5], [1, 1, 1, 1, 1] ] ---------------------------------------------------- There are 3 ways to make change for 10 cents using [5, 1]: [[5, 5], [5, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ] ---------------------------------------------------- There are 4 ways to make change for 10 cents using [10, 5, 1]: [[10], [5, 5], [5, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ] ---------------------------------------------------- There are 4 ways to make change for 15 cents using [5, 1]: [[5, 5, 5], [5, 5, 1, 1, 1, 1, 1], [5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ] ---------------------------------------------------- There are 6 ways to make change for 15 cents using [10, 5, 1]: [[10, 5], [10, 1, 1, 1, 1, 1], [5, 5, 5], [5, 5, 1, 1, 1, 1, 1], [5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ] ---------------------------------------------------- There are 6 ways to make change for 16 cents using [10, 5, 1]: [[10, 5, 1], [10, 1, 1, 1, 1, 1, 1], [5, 5, 5, 1], [5, 5, 1, 1, 1, 1, 1, 1], [5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ] ---------------------------------------------------- There are 13 ways to make change for 26 cents using [25, 10, 5, 1]: [[25, 1], [10, 10, 5, 1], [10, 10, 1, 1, 1, 1, 1, 1], [10, 5, 5, 5, 1], [10, 5, 5, 1, 1, 1, 1, 1, 1], [10, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5, 5, 5, 5, 5, 1], [5, 5, 5, 5, 1, 1, 1, 1, 1, 1], [5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ] ---------------------------------------------------- There are 60 ways to make change for 56 cents using [25, 10, 5, 1]: [[25, 25, 5, 1], [25, 25, 1, 1, 1, 1, 1, 1], [25, 10, 10, 10, 1], [25, 10, 10, 5, 5, 1], [25, 10, 10, 5, 1, 1, 1, 1, 1, 1], [25, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [25, 10, 5, 5, 5, 5, 1], [25, 10, 5, 5, 5, 1, 1, 1, 1, 1, 1], [25, 10, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [25, 10, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [25, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [25, 5, 5, 5, 5, 5, 5, 1], [25, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1], [25, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [25, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [25, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [25, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 10, 10, 10, 10, 5, 1], [10, 10, 10, 10, 10, 1, 1, 1, 1, 1, 1], [10, 10, 10, 10, 5, 5, 5, 1], [10, 10, 10, 10, 5, 5, 1, 1, 1, 1, 1, 1], [10, 10, 10, 10, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 10, 10, 5, 5, 5, 5, 5, 1], [10, 10, 10, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1], [10, 10, 10, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 10, 10, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 10, 10, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 10, 5, 5, 5, 5, 5, 5, 5, 1], [10, 10, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1], [10, 10, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 10, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 10, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 10, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 10, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1], [10, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1], [10, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1], [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1], [5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ]
The following partitionIter
method takes an integer named
pivot
and a list of integers named L
and
partitions the list into two lists:
L
less than pivot
.
L
greater than or equal to pivot
.
The two resulting lists are returned in a two-element IntListList
--
i.e., a list of two integer lists.
public static IntListList partitionIter (int pivot, IntList L) { return partitionTail(pivot, L, IL.empty(), IL.empty()); } public static IntListList partitionTail (int pivot, IntList list, IntList lesses, IntList greaters) { if (IL.isEmpty(list)) { return twoLists(lesses, greaters); } else if (IL.head(list) < pivot) { return partitionTail(pivot, IL.tail(list), IL.prepend(IL.head(list), lesses), greaters); } else { return partitionTail(pivot, IL.tail(list), lesses, IL.prepend(IL.head(list), greaters)); } }
Because the program manipulates both IntList
and IntListList
objects, it is necessary to distinguish the list operations for these
different kinds of lists. As in Task 1, we will use IL.
to prefix
IntList
operations and ILL.
to prefix
IntListList
operations. To make the code more readable, we
use the following helper method:
public static IntListList twoLists (IntList L1, IntList L2) { return ILL.prepend(L1, ILL.prepend(L2, ILL.empty())); }
partitionTail
method is a tail recursive method that
specifies an iteration in four state variables named
pivot
, list
, lesses
, and
greaters
. Any iteration can be characterized by how the
values of the state variables change over time. Below is a table with
four columns, one for each state variable of the iteration described
by partitionTail
. Each row represents the values of the
parameters to a particular invocation of partitionTail
.
pivot | list | lesses | greaters |
Suppose that the list A
has the printed representation
[7,2,3,5,8,6,1]
. Fill in the above table to show
the parameters passed to successive calls to partitionTail
in the computation that begins with the
invocation partitionIter(5, A)
. There are more rows shown here than you need, so you should draw only
as many rows as you need to in your table.
partitionWhile
while
loop.
Flesh out the following code skeleton of a partitionWhile
method that
behaves just like the above partitionIter
method except that it uses a
while
loop rather than tail recursion to express the same iteration
as partitionTail
.
public static IntListList partitionWhile (int pivot, IntList L) { // Replace this stub return ILL.empty(); }
Notes:
partitionWhile
method in the file Partition.java
within the
Partition
folder.
IntList
operations from IntListList
operations. The prefix
IL.
will be used for the former and ILL.
for the latter.
while
loop has the syntax
while (test-expression) { body-statements }
while
loop
to implement the iteration implied by the iteration table.
The body of this loop may contain any Java statements, including
conditionals, but should not contain other while
loops.
Partition.mcp
project invokes the main
method of the Partition
class, which will run the methods of
this task on various test cases. You should study the results of
the test cases in the Java console window to verify
that the results are what you expect.
partitionFor
partitionTail
and
partitionWhile
can also be expressed via a
for
loop whose index variable is the list
state variable. Flesh out the skeleton of the following method
so that it expresses the partitioning iteration with a
for
loop:
public static IntListList partitionFor (int pivot, IntList L) { // Replace this stub return ILL.empty(); }
Recall that a Java while
loop has the syntax
for (init-statement; test-expression; update-statement) { body-statements }
The above for
loop is
equivalent to the following
while
loop:
init-statement; while (test-expression) { body-statements; update-statement; }
partitionRec
partitionIter
method, elements in the two
returned lists are in a relative order opposite to their relative
order in the original lists. For instance, partitioning the list
[1, 4, 8, 3, 6, 7, 5, 2]
about the pivot 6 yields the lists
[2, 3, 4, 1]
and [7, 6, 8]
.
Suppose that we want the resulting lists to have the same relative
order as in the original list. If we are provided with an IntList
reversal
method IL.reverse
, we can easily accomplish this by reversing the two
lists before gluing them together. That is, we can
change the line
return twoLists(lesses, greaters);within
partitionTail
to be
return twoLists(IL.reverse(lesses), IL.reverse(greaters));
An alternative to using IL.reverse
to achieve this behavior is
to define a non-tail-recursive version of partitionIter
that we will call partitionRec
. Flesh out the
following skeleton of partitionRec
, which partitions the elements
of a list about the pivot but maintains the relative order of the
elements in the resulting lists:
public static IntListList partitionRec (int pivot, IntList L) { if (IL.isEmpty(L)) { return twoLists(IL.empty(), IL.empty()); } else { IntListList subresult = partitionRec(pivot, IL.tail(L)); // replace the following stub: return ILL.empty(); } }
Notes:
partitionRec
should be a self-contained non-tail-recursive method
that should not invoke any of the other partitioning methods
mentioned in this problem.
The "Rec" in the name "partitionRec" stands for "Recursive",
and is intended to suggest a non-tail-recursive method.
partitionRec
method is tested by the main
method of the Partition
class.
quicksort
To sort the elements of a list, partition the elements of the tail of the list around its head into result lists that we'll call lesses and greaters. Then result of sorting the whole list can be obtained by appending the result of sorting lesses to the result of prepending the head of the list to the result of sorting greaters.
For example, if the initial list is [5, 2, 8, 3, 6, 7, 1, 4]
,
then partitioning the tail of the list around the head (5) yields:
lesses = [4, 1, 3, 2] greaters = [7, 6, 8]
By wishful thinking, sorting lesses
will yield [1, 2, 3, 4]
and sorting greaters will yield [6, 7, 8]
.
The result of sorting the original list is the result of appending
[1, 2, 3, 4]
to the result of prepending 5
to
[6, 7, 8]
.
Flesh out a method with header public static IntList quicksort (IntList L)
that uses this idea to sort the elements of a list. You may use IL.append
to append two lists and any of the above partitioning methods to partition a list.
The quicksort
method is tested by the main
method of the Partition
class.
It turns out that quicksort, true to its name, is one of the fastest algorithms for sorting a list. If you take CS230 and CS231, you will learn (among other things) much more about various sorting algorithms and how to compare them in terms of efficiency.
In this problem you will use iteration in to draw two-colored nested frame patterns like those shown below:
Each of the four patterns consists of concentric rectangular frames that have the same thickness and alternate between two colors. In the above example, each target has 10 nested frames, each of whose thicknesses is 1/20 of the dimensions allocated to the pattern. (When the thickness is 1/(2*nestingLevels), the frames will evenly fill the alloted Picture space)
In Picture World, each rectangular frame pattern can be drawn as a sequence of concentric filled rectangles, where the rectangles are draw from the outside in. You have been provided with the following method for creating a centered rectangular picture:
public Picture centeredRect (double fraction, Color c)
Returns a rectangle filled with color c that is centered in the picture canvas in which it is drawn. The width and height of the rectangle are each the given fraction of the enclosing picture canvas's width and height. The fraction argument must be between 0 and 1.
For example, using this method, here is a recursive implementation of the nested frame pattern:
public Picture nestedRec(int level, double thickness, Color c1, Color c2) { if (level == 0) { return empty(); } else { return overlay(nestedRec(level - 1, thickness, c2, c1), centeredRect(2*level*thickness, c1)); } }
Here, level
is the number of nested
frames, thickness
represents the thickness of
each frame edge as a fraction of the dimensions allocated to the pattern,
c1
is the outermost
color, and c2
is the color that
alternates with c1
. In the code that you are given,
when nestedRec
is initially invoked, the thickness
argument is initially 1/(2 * initlevel
), where initlevel
is the initial level number.
The nestedRec
method
accumulates a final picture that consists of level
centered rectangles overlayed on top of
one another. Note how each level of the recursion decrements level
by 1 and swaps c1
and c2
(so that c2
is the outermost color in the
nested subpicture). This strategy is not a tail recursive one,
since there is still a pending overlay
operation to be performed after the recursion returns.
In the rest of this problem, you will expore three iterative strategies for expressing the nested box pattern. You will start by creating an iteration table for the nested boxes.
level
, thickness
, c1
, and c2
)
as well as a Picture
variable that contains the "answer so far" for the current iteration
state. You may also want to include an extra column that contains the picture
that will be used in combination with the current answer to generate the next answer in
the next row of the iteration table. This extra column should have pictures
that can be created from the other state variables and the Picture
methods
that are available to you (including centeredRect
).
Draw your iteration table for a process that produces the same picture
as the following invocation, but does so in an iterative manner
than a non-tail-recursive one:
Turn this in with the hardcopy of your assignment.nestedRec(4,0.125,Color.blue,Color.green);
NestedFrames.java
within the folder
NestedFrames
in the ps8_programs
folder:
public Picture nestedIter(int n, double thickness, Color c1, Color c2) { // This method contains the initial call to nestedTail, which does all the work. return nestedTail(n, thickness, c1, c2, empty()); } public Picture nestedTail(int n, double thickness, Color c1, Color c2, Picture ans) { // nestedTail should be a tail recursive method that returns a Picture // that is the nested frames pattern. // Replace the following stub by a correct definition. return empty(); } public Picture nestedWhile(int n, double thickness, Color c1, Color c2) { // Use a while loop to accumulate and return a Picture // that is the nested frames pattern. // Replace the following stub by a correct definition. return empty(); } public Picture nestedFor(int n, double thickness, Color c1, Color c2) { // Use a for loop to accumulate and return a Picture // that is the nested frames pattern. // Replace the following stub by a correct definition. return empty(); }
Your task is to flesh out the three methods
nestedTail
, nestedWhile
,
and nestedFor
so that they
yield the same picture as nestedRec
,
but do so via the iterative process exemplified
in your iteration table from Part a.
You can test your methods by executing the
NestedFrames.html
applet. This will give you a
window like that displayed at the beginning of this problem. By
selecting an integer in the rightmost choice box, you can change the
nesting level of the patterns. Your code does not have to take care
of calculating the initial thickness; this calculation is already performed
by the testing enviroment.
The patterns are arranged as follows inside the
NestedFrames
Applet window:
nestedRec
.
nestedIter
.
nestedWhile
.
nestedFor
.
In your definitions, pay attention to the following notes:
while
loop has the syntax
while (test-expression) { body-statements }
and a Java for
loop has the syntax
for (init-statement; test-expression; update-statement) { body-statements }
A Java for
loop is
equivalent to the following
while
loop:
oinit-statement; while (test-expression) { body-statements; update-statement; }
level
by 1. You should not decrement
level
by 2!nestedRec
method provided. That is, none of the
methods may invoke any of the other methods for which you are writing
the code in this problem, nor may they invoke the nestedRec
method.