$29.99
Specification 7 - Recursion
General Assignment Requirements
The purpose of this assignment is to practice writing recursive algorithms.
In this assignment you will implement nine recursive methods. Some of the methods (1 - 3) use recursion to solve problems that could just as easily (if not more easily) be solved using simple iteration (for loops or while loops), but you will use recursion for the experience.
Some of the methods still need a normal loop like the recursive backtracking examples shown in class. (Such as the determining the space taken up by files and the N Queens examples done in class. Those were both examples of recursive backtracking that used for loops to iterate through choices at a certain point.) The tester code will be placed in a class named RecursiveTester. Turn in Recursive.java and RecursiveTester.java individually. (No jar file.)
In the past some students have found playing visual programming games that require the use of recursion helpful. Two examples are LightBot (flash version here) and the CargoBot iPad game.
Files:
File
Responsibility
Source Code
Recursive.java.
Provided by me and you
Source Code
RecursiveTester.java. Contains test cases for methods in Recursive.java.
Provided by you and me.
Utility Class
DrawingPanel.java A class for creating simple graphics windows. You need this class for the triangle and carpet problems.
Provided by me.
Utility class
Stopwatch.java. A class for calculating elapsed time when running other code.
Provided by me.
Documentation
Javadoc for the Recursive class, the DrawingPanel class, and the Graphics class. Graphics is a standard Java class. (You do no have to call any methods on DrawingPanel. I already included the code to get the Graphics object. You will make calls on the Graphics object, notably setColor anddrawLine)
Provided by me.
The provided file Recursive.java contains nine methods you will complete. For each method you complete, clearly state the base case and recursive step for each method.
The provided file RecursiveTester.java contains a number of tests of the methods in Recursive.java. Some of these tests may be incorrect. Find and fix any incorrect tests. Your implementation of Recursive.java must pass these tests. Add at least 3 tests for each method other than the triangle and carpet methods to RecursiveTester.java. (21 total tests) When you turn in the file delete the provided tests and just include your tests.
Submission: Fill in the header in the RecursiveTester.java and Recursive.java files.. Replace <NAME with your name. Note, you are stating, on your honor, that you did the assignment on your own or with a single partner.
Create a zip file name a7.zip [case sensitive! Do not name the file A7.zip!] with your RecursiveTester.java and Recursive.java files. The zip file must not contain any directory structure, just the required file.
See this page for instructions on how to create a zip via Eclipse.
Turn in a7.zip via your Canvas account to programming assignment 7.
Ensure you files are named RecursiveTester.java and Recursive.java. Failure to do so will result in points off.
Ensure RecursiveTester.java and Recursive.java are part of the default package. Do not add a package statement to either file.
Ensure your zip has no internal directory structure. When the file is unzipped no directories (folders) are created. (Note, the built in unzip feature of some versions of Windows and Apple OS X "help" by adding a directory when you unzip with the same name as the file. The unzip we use on the CS Linux system does not do this. Neither do unzip programs such as 7zip.)
Ensure you submit the assignment under Programming Assignment 7 in Canvas.
If you resubmit your file you must first delete the previous versions, otherwise Canvas renames the file. See this page for instructions.
Checklist: Did you remember to:
review and follow the general assignment requirements?
work on the assignment with at most one other person?
fill in the headers in RecursiveTester.java and Recursive.java?
ensure your methods in Recursive.java pass the tests in RecursiveTester.java and add your own tests? Delete the old tests after you are sure you pass them. Add at least 3 tests for each method other than the triangles and carpets methods.
turn in your a7.zip file with your Java source code files (RecursiveTester.java and Recursive.java) to Canvas before 11 pm, Monday, March 26?
Individual Problem Descriptions from Recursive.java:
1. Binary Conversion
public String getBinary(int N)
(Simple Recursion) Write a method to recursively creates a String that is the binary representation of an int N.
Here is an example. The binary equivalent of 13 may be found by repeatedly dividing 13 by 2. If there is a remainder a 1 gets concatenated to the resulting String otherwise a zero gets concatenated to the resulting String. (The tricky part is figuring out the right time and place to do the concatenation.)
13 / 2 = 6 r 1
6 / 2 = 3 r 0
3 / 2 = 1 r 1
1 / 2 = 0 r 1
13 in base 2 is 1101. The method returns the String "1101".
2. Reversing a String
public String revString(String target)
(Simple Recursion) Write a recursive method that returns a String that is the reverse of the input String.
System.out.println( recursiveObject.revString("Calvin and Hobbes"));
would return a String equal to this: "sebboH dna nivlaC"
3. nextIsDouble
// pre: data != null
public int nextIsDouble(int[] data){
(Simple Recursion) This methods returns the number of elements in data that are followed directly by double that element. For example, the given array {1, 2, 4, 8, 16, 32, 64, 128, 256} the method would return 8. The elements 1, 2, 4, 8, 16, 32, 64, and 128 are all followed directly by double their value. Give the array {1, 3, 4, 2, 32, 8, 128, -5, 6} the method would return 0. No element in the array is followed directly by double that element. Given the array {1, 0, 0, -5, -10, 32, 64, 128, 2, 9, 18} the method would return 5. The elements 0, -5, 32, 64 and 9 are all followed directly by double their value.
Write a helper method that is sent the array and the current position or index in the array. That is where the actual recursion takes place. The public method shown above simply kicks off the recursion.
4. Phone Mnemonics
public ArrayList<String listMnemonics(String number)
(From Thinking Recursively by Eric Roberts.) On most ancient telephone keypads the letters of the alphabet are mapped to various digits as shown in the picture below:
In order to make their phone numbers more memorable, service providers like to find numbers that spell out some word (called a mnemonic) appropriate to their business that makes that phone number easier to remember. For example, the phone number for a recorded time-of-day message in some localities is 637-8687 (NERVOUS). Write a method listMnemonics that generate all possible letter combinations that correspond to a given number, represented as a string of digits. This is a recursive backtracking problem, but you are trying to find all the "solutions", not just one. In fact you are trying to find all possible Strings, not just Strings that are actual "words".
For example, if you call
ArrayList<String result = recursiveObject.listMnemonics("623")
your method shall generate and return an ArrayList containing the following 27 possible letter combinations that correspond to that prefix:
MAD MBD MCD NAD NBD NCD OAD OBD OCD
MAE MBE MCE NAE NBE NCE OAE OBE OCE
MAF MBF MCF NAF NBF NCF OAF OBF OCF
Note, the order of the Strings in the ArrayList is unimportant.
Use the following helper method:
public String digitLetters(char ch)
This method returns the letters associated with a given digit.
Create a helper method that does most of the real work:
private void recursiveMnemonics(ArrayList<String result, String mnemonicSoFar, String digitsLeft)
The ArrayList named result is used to store completed mnemonics. mnemonicSoFar is the String that has been built up so far based on various choices of letters for a digit. Initially it is the empty String. digitsLeft consists of the digits from the original number that have not been used so yet. Initially digitsLeft is the entire phone number. (Or collection of digits.)
To kick off the recursion you call method recursiveMnemonics from listMnemonics:
ArrayList<String result = new ArrayList<String();
recursiveMnemonics(result, "", number); // when starting the mnemonic is the empty string
return result;
It should come as no surprise a website exists that does this kind of thing, but checks the results against a dictionary: http://www.phonespell.org/
5. Sierpinski triangles
Write a method to draw a Sierpinski triangle, a famous fractal. Sierpinski triangles are fractals named after Wacław Sierpiński. Here is an example
Here is another example.
A Sierpinski triangle is draw using two methods, a kickoff / starter method and the recursive method. Here is the header of the starter method:
/**
* Create a DrawingPanel and place Sierpinski triangles in it. The lower
* left corner should be 20 pixels from the left edge of the window
* and 20 pixels from the bottom of the window.
* @param windowSize 20
* @param minSideLength 4
* @param startingSideLength minSideLength
*/
public void drawTriangles(int windowSize, int minSideLength, int startingSideLength)
NOTE: In most computer graphics coordinate systems, x increases as you move to the right (as you would expect) but y increases as you move DOWN. (Not up as you are use to.)
The parameters of this method specify the size of the window that contains the triangles, the minimum side length and the initial side length. This method is already complete. It creates a DrawingPanel object, gets the Graphics object for that DrawingPanel, and then calls the recursive helper method that actually draws the triangles. (DrawingPanel is not a standard Java class. You must download it from this web page.) Here is the header of the recursive helper method that you will complete:
public void drawTriangles(int minSideLength, double currentSideLength, double x1, double y1, Graphics g)
The parameters for this method are the minimum side length, the current length of a side, and a set of coordinates for the lower left corned of an equilateral triangle.
The algorithm for drawing a Sierpinski triangle is:
-if the currentSideLength is less than or equal to the minSideLength, then draw the triangle. Note, the length of the triangle and the coordinates are doubles. When you actually draw a triangle you will have to cast these to ints. (Base Case)
-else create three smaller Sierpinski triangles that are half the size of the original by making three recursive calls to drawTriangle(the private one). In the recursive case you don't draw anything with the graphics objects. You simply make recursive calls to drawTriangle with new coordinates and side length.
The lower left corners of these three Sierpinski triangles are located at:
the original x1, y1.
the midpoint of the line segment going from x1, y1 to the top of the triangle
the midpoint of the horizontal line segment starting at x1, y1.
Use trigonometry to determine the value of y2. The other coordinates are easy to figure out:
x3 = x1 + 0.5 * length of side
y3 = y1
x2 = x1 + 0.25 * length of side
y2 = y1 - sqrt(3) * length of side / 4. (Note, this is for the recursive case, not the base case.)
When you reach the base case you will use the Graphics object to actually draw the lines. The method passes doubles until it reaches the base case when you will have to cast to int. There shall not be large, noticeable gaps between triangles.
You can use the drawLine method on the graphics object passed as a parameter to draw the outline of the "small" triangle. The drawLine method accepts 4 ints, which are the endpoints of the line segment to draw. Alternatively, you may use the fillPolygon method. Either approach is acceptable. The examples above just draw the outlines of the triangles. here are example of filling the polygons. Here are some examples with the triangles filled in.
minSideLength = 100
minSideLength = 15
6. Sierpinksi Carpet
Create a method to draw a Sierpinski carpet. Here is an example:
The carpet is created via the following algorithm.
- if the length of the square is less than or equal to the limit value do nothing.
- else (the length of the square must be greater than the limit value) divide the square into a 3 by 3 grid which will contain 9 sub squares. "Cut out" the middle square and then create a Sierpenski carpet in the 8 remaining sub squares.
The middle square is "cut out" by drawing a white rectangle.
I have provided the starter method. You must supply the method to complete the carpet. The header for the method to actually draw the carpet is:
private static void drawSquares(Graphics g, int size, int limit, double x, double y)
Use the fillRect method from the Graphics class. Here is its signature.
fillRect(int x, int y, int width, int height)
Fills the specified rectangle.
Recall point 0, 0 is at the top, left of the drawing panel and y increases as you go down (not up).
Complete the following method:
public static void drawSquares(Graphics g, int size, int limit, double x, double y){
Again, the x and y coordinates are passed as doubles. When you call the fillRect method cast the x and y coordinates to ints.
Here is an extreme Carpet with min size set to 1:
7. SudokoSolver
Complete a method that solves a given Sudoko puzzle. The public method is
public static int[][] getSudokoSolution(int[][] startBoard) {
The starting board must be a 9 by 9 matrix that only contains values 0 through 9. Cells that store a zero are open cells that must be filled in with a value between 1 and 9. Cells in startBoard that store a value between 1 and 9 may not be changed.
I have provided all of the non-recursive helper methods you need to check if a particular set up is legal or not. In particular the digitsOkay method determines if there are any repeats of values between 1 and 9 in any rows, columns, or mini matrices.
You must write the recursive solver method and call it from the getSudokoSolution method.
8. Water flowing off a map.
/*pre: map != null, map.length 0, map is a rectangular matrix, 0 <= row < map.length,
0 <= col < map[0].length
post: return true if a drop of water starting at the location specified by row, column can reach the edge of the map, false otherwise.
*/
public boolean canFlowOffMap(int[][] map, int row, int col)
In this problem an area of land is represented as a 2D array of ints. The value at each element represents the elevation of that point on land. The higher the elevation, the higher the number, the lower the elevation the lower the number. So a flat plain at an elevation of 100 feet above sea level looks like this:
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
100
A river flowing through a 200 foot gorge looks like this. Cells that make up the river are shaded gray and yellow.
100
99
200
200
200
200
200
200
200
200
200
98
200
200
200
200
200
200
200
200
200
97
96
200
200
200
200
200
200
200
200
200
95
200
200
200
85
84
83
200
200
200
94
93
92
200
86
200
82
200
200
150
200
200
91
200
87
200
81
200
200
200
200
200
90
89
88
200
80
200
200
150
100
200
200
200
200
200
79
200
200
200
200
200
200
200
200
200
78
77
200
200
200
200
200
200
200
200
200
76
Method canFlowOffMap has a parameter that represents a map of elevations as 2D array of ints. It also has parameters that represent the starting location of a drop of water on the map.
The drop of water can move to one of the four adjacent cells (above, below, left, and right of the current cell) if the elevation in that cell is less than the elevation of the current cell.
Water in any cell on the edge of the map can flow off the map.
In other words water in a cell on the border of the map is assumed to be able to flow off the map regardless of the cells around it.
In the first example, the plain, water in any cell not on the border of the 2d array, cannot flow to any other cell because all adjacent cells because all the elevations are the same. Water on any of the bordering cells could flow off the map. In the second example if a drop of water started at the cell at row 2, column 2 (the yellow cell with a value of 96) it could eventually flow off the map by following the river. (Each segment of the river is one foot lower than the previous.)
Recall that water on the border can also flow off. So in the second example if we started at the cell in row 3, column 0 (the red cell with a value of 200) then we can flow off the map. The elevation in that cell is 200. The water can't flow to any of the other cells adjacent to it, but that doesn't matter because that cell is on the border and so if start there I can flow off the map.
If the starting cell is row 3, column 1 (the blue cell with a value of 200), the water can flow off the map. That cell has an elevation of 200. The water can't flow west or south because those cells are also at 200. But the water can flow north or east to the cells in the river. (the water falls off the bank into the river) and then off the map via the river.
Finally the cell at row 6, column 1 (the green cell with a value of 200) can't flow off the map. It tries north and dead ends. It can't move east or west. It can try south, but eventually dead ends.
When thinking about the problem it may help to think that off the edge of border rows and columns is an infinitely deep canyon. So if you are on a border of the map, (row 0 , column 0, last row, or last column) then you can flow off the map. (Base case?)
canFlowOffMap returns true if a drop of water starting at the location specified by row, column can reach the edge of the map, false otherwise.
9. Creating fair teams.
// pre: numTeams = 2, abilities != null, abilities.length = numTeams
/* post: return the minimum possible difference between the team with the maximum ability and the team with the minimum ability. Every team must have at least one member and every person (ability score) must be assigned to some team. The return value will must be greater than or equal to 0.
*/
In this question you are passed an int that represents the number of teams we want to form from a group of people. You are also passed an array of ints that represents the ability scores of all of the individuals we want to assign to teams. (It could be athletic ability, IQ, artistic ability, etc.) Abilities can be positive or negative. A team's total ability is simply the sum of the ability scores of the people assigned to that team.
The goal of this method is to find the minimum possible difference between the team with the maximum total ability and the team with the minimum total ability. The constraints are everyone (represented by a value in the array named abilities) must be placed on a team and every team must have at least one member.
You must create the helper method. You must keep track of multiple things such as which element in the abilities array you are currently considering (or which people have already been assigned to a team), what the total ability score is for each team, as well as some way of ensuring each team has at least one member. (You could simply track the number of members per team.)
For example if we have the following abilities: [1, 2, 3, 4, 5, 6, 7] and want to form three teams the min difference possible between the team with the maximum total ability and the team with the minimum total ability is 1. Your program does not need to show what the members of each team are but in this example the minimum possible difference is created by having 2 teams with a total ability of 9 and 1 team with 10. (min 9, max 10). There are multiple ways of doing this with these values one of which is:
Team 1: 1 + 3 + 6 = 10
Team 2: 2 + 7 = 9
Team 3: 4 + 5 = 9
In this problem there is a lot to do when you reach the base case. You must ensure every team has at least one person on it (or it is an invalid set up), and if it is a valid set up find the min and max team ability scores. If the setup is invalid you must return some value to indicate the set up was invalid. (-1 perhaps? Integer,MAX_VALUE?)