Computer Science
15-111 (Sections A & B), Spring 2007
Homework #4.2
Due: Mon
5-Feb-2007 at 8:00pm (online submission).
Place these
programs in hw4.2.zip. Remember to just
submit your .java files, and not your .class files, random .jpg files, or miscellaneous
Eclipse or other IDE-related files.
1. Gaussian Elimination with Partial Pivoting
(This is a verbose question, but with very little code to write in the
end. –DK)
In class, we wrote a simple version of GaussianElimination.java. First, carefully review the lecture notes
(which describe how the algorithm works) and then study the code – you are
responsible for it!
While this code is useful for learning purposes, it is not a very good solver
of linear systems of equations. For
example, it is easy enough to make it crash by giving it an unsolvable system:
// Unsolvable system (two parallel lines)
private static double[][] unsolvableSample
= {
{ 1, 1, 1 }, // x + y = 1
{ 1, 1, 2 } // x + y = 2
(these lines are parallel)
};
When our solver runs on this example, it produces the “solution”:
x = -Infinity
y = Infinity
Not a good situation! But it is perhaps
tolerable because we at least are dealing with an unsolvable system (though it
would be nice to handle this case more deftly than we presently do!). Here, however, we’ll consider a worse flaw.
Consider the following system:
private static double[][] thisWorks = {
// x = 3, y = 2, z = 1
{ 4, 0, 3, 15 }, // 4x + 0y + 3z =
15
{ 0, 1, 2, 4 }, // 0x + 1y + 2z = 4
{ 5, 6, 0, 27 } // 5x + 6y + 0z = 27
};
Our program handles this system just fine.
Great! Unfortunately, what
happens if we simply rearrange the
first two equations? Naturally, this
does not change the problem at all, so we should expect the same answer. Well, try it.
Start with this:
private static double[][] thisFails = {
// x = 3, y = 2, z = 1
{ 0, 1, 2, 4 }, // 0x + 1y + 2z = 4
{ 4, 0, 3, 15 }, // 4x + 0y + 3z =
15
{ 5, 6, 0, 27 } // 5x + 6y + 0z = 27
};
And when you run it, you see that something went terribly wrong, and our answer
is that x, y, and z all equal NaN (“Not A Number”). Yikes!
What happened? Well, the first thing our
solver does is try to place a “1” in the first coefficient of the first
equation (that is, in c[0][0]). It does this
by dividing the first equation by whatever value is there. This is done in this code:
// 1. set c[row][row] equal to 1
double factor = c[row][row];
for (int col=0; col<cols;
col++)
c[row][col]
/= factor;
But what happens if
“factor” is zero (0) – which is precisely the case here (see the 0 in the
top-left corner of our array)? Then we
divide by zero! If the division were
integer division, our program would throw an exception and crash right
there. But since it is double division,
instead the answer is NaN (“Not A Number”) and the computation proceeds despite
being hopelessly broken.
Your task is to fix this problem, at least for most cases. To do this, copy GaussianElimination.java to
a new file, GaussianWithPartialPivoting.java. In that file, you will implement partial
pivoting.
What is Partial Pivoting?
As we just observed, when the element on the diagonal is a 0, we cannot divide
to make it equal 1. In this case, we
find the first non-zero element in the same column but below this element (so,
in a higher row, since rows increase as we move down), and then we swap the two
rows (so we are pivoting about this
element). This places a non-zero element
on the diagonal so we can continue our algorithm. Interestingly, if there is no non-zero
element below the offending diagonal element, then we are in an unsolvable case
(either there are no solutions, as with parallel lines, or there are infinitely
many solutions, as when solving two lines that are in fact the same line). So you can print out a reasonable message in
this case, rather than continue “solving” the unsolvable system.
In the example above, your code would see that c[0][0] equals 0, and would
search downwards, noting that c[1][0] equals 4, and so would swap rows 0 and 1, which produces a solvable
problem (we know this since we solved it above!).
Remember that we do not use == for doubles (why not?), so you cannot have code
that reads:
if (factor == 0) …
Instead, you have to
test if factor is very nearly
zero. That is, if its absolute value
(Math.abs) is less than some value epsilon,
which should be a very small number (how small? 10-10? 10-20? You decide!).
Demonstrate that your partial pivoting code works on the example above, and
provide another example where the original code fails and the partial pivoting
code succeeds, but where the failure does not occur in the first column (as it
did here) but in a subsequent column during the solution process. Include this example in your solution.
2. Bullseye!
Starting from BasicGUI.java, write a program, BullseyeApp.java,
that draws the following bullseye pattern:
Your BullseyeApp should extend IntroCsApplication, and it should create an
instance of Bullseye, that extends IntroCsComponent, as such:
public class
BullseyeApp extends IntroCsApplication {
public static void main(String[] args)
{ new BullseyeApp(); }
public void init() {
add(new Bullseye());
}
}
class Bullseye extends IntroCsComponent {
// your code goes here!
}
Note that this pattern must abide by the following:
a. It must be enclosed in a blue
square.
b. It must have 5 concentric circles,
alternating red and black, with the innermost circle being red, with the
outermost circle exactly fitting inside the square, and each consecutive
circle’s radius different by a constant.
c. The square must be centered in the
window at all times (even after resizes).
d. The square’s side changes with
resizes. To find the square’s side
length S:
A = the lesser of the window’s width and its height
B = the smaller of 250 and A/2
S = the smallest multiple of 10 at least as large as B
(Thought question: why is it convenient
for the square’s side length to be a multiple of 10?)
3. Drag and Resize
Starting from BasicGUI.java, write a program, DragAndResizeApp.java,
that draws a simple 50x100 orange rectangle originally placed at (10,10), and
has two buttons, “Drag” and “Resize”, as such:
Remember to use “addButtons()” to add the buttons! These buttons switch between Drag mode and
Resize mode, where the application starts by default in Drag mode.
In Drag Mode:
When in Drag Mode, mouse presses inside the rectangle will begin a “drag”
operation, where the rectangle moves with the mouse and stops moving at the
mouse up.
Note #1: Mouse presses outside the
rectangle have no effect. Do not start a
drag operation in this case!
Note #2: You must keep the mouse
positioned in the same part of the rectangle throughout this operation. So if the user clicks in the lower-right
corner of the rectangle, for example, the mouse will remain in the lower-right
corner of the rectangle throughout the drag operation.
Note #3: At least 10 pixels of each
dimension of the rectangle must always stay in the window during a drag. So as you move off the right edge, for instance,
the left of the rectangle cannot exceed (window’s width – 10). Also, for example, as you move off the top
edge (heading up), the bottom edge
(not the top edge!) of the rectangle cannot be less than 10.
In Resize Mode:
When in Resize Mode, mouse presses within 5 pixels in each dimension from any
corner of the rectangle will begin a “resize” operation, where that corner of
the rectangle moves with the mouse (with the opposite corner never moving) and
stops resizing at the mouse up.
Note #1: Mouse presses beyond 5 pixels
in either dimension from a corner have no effect.
Note #2: Do not resize either dimension
of the rectangle to less than 10 pixels, and do not “flip” the rectangle if the
user drags beyond the opposite corner.
Note #3: Do not resize the rectangle
beyond the visible portion of the window.
Note that it is possible that a rectangle is already partly offscreen
(due to a prior drag) at the start of a resize.
This is ok, and that portion of the rectangle will remain offscreen
throughout the resize.
4. Simple Game
Again starting from BasicGUI.java, write SimpleGame.java, which is (not
surprisingly) a simple game. There is a
ball that moves (on a timer) back and forth across the top of the window. There is a paddle that moves in response to
left and right arrows back and forth across the bottom of the window. When the user hits the space bar, a
projectile is fired up the screen towards the ball. If it hits the ball, the user scores points,
and if it misses, the user loses points.
Show the points at all times.
Have the user win or lose at reasonable times. Clicking with the mouse anywhere at any time
will start the game over.
This game is underspecified. Even
in such a simple game, there are plenty of decisions you need to make. Make good ones! You will be graded on correctness (matching
the description above), but also on how nice your Graphical User Interface
(GUI) is, as well as how stylistic your code is. Don’t go too overboard, though, since you
should save your energy for the bonus, time and interest permitting!
5. Little Bonus (up to 5 points, or ½ letter grade): Pong
Make a game of
Pong, where you play an air-hockey-like paddle game against a computer
opponent. How does Pong work? It’s easy to find sample Pong applets on the
web (for a randomly-chosen example, try: http://www.xnet.se/javaTest/jPong/jPong.html). Note: as
will be the case with many of our assignments, it is also easy enough to find
actual source code on the web for Pong.
Remember the course policy: if
you are to submit a Pong program for this course, then you may not look at Pong
source code until after you have submitted your own code! In any case, this is meant as a “little
bonus”, so don’t make the problem too hard.
6. Big Bonus (up to 10 points, or one full letter grade): NxN Tic-Tac-Toe
You have everything
you need to write a decent tic-tac-toe game.
Start with a 3x3 game. Users
should take turns, and they should click where they want to move. Your code should determine when there is a
win or a tie and display a message for a short while then restart the next
game. Always display the score, too. Also, have a few buttons: “larger”, “smaller”, and “reset”. Larger and smaller should change the size of
the board while always keeping it square.
Each time you click “larger”, the board size should increase by 1 in
each dimension (3x3 to 4x4, then 4x4 to 5x5, etc). Smaller does this in reverse. Don’t allow boards smaller than 3x3 or larger
than 10x10. Finally, you should pick an
interesting rule for how to win an NxN game, since 3-in-a-row is too easy for,
say, 6-by-6, but 6-in-a-row may be too hard.
You decide. Have fun with this!