Several questions came up yesterday:
We learned about reading from standard input at the beginning of Session 11, in particular in the section called Working with Standard Input and Output as Files. (Imagine that!!) Take a look at the Session 11 version of Echo.java, and then the Sign and Squish programs we wrote later in the session. Sign and Squish read only from standard input.
If you don't avail yourself of the lecture notes and example code that I provide you, then programming assignments will seem much harder than they actually are!
By the way, you can also use command-line arguments to accept inputs that configure the game as a whole. This might work well for selecting the number of stones to use for the game, and maybe even for who goes first.
Command-line arguments and input obtained from a BufferedReader both come as Strings. And there is a big difference between "15" 15.
Fortunately, the Integer class gives us a convenient way to convert a String into an int:
anInt = Integer.parseInt( aString );
This method will convert any String whose characters make up an integer value into the equivalent int. If given "15", it will return 15.
If you give Integer.parseInt() a String that does not correspond to a legal int, it will throw an exception:
Exception in thread "main" java.lang.NumberFormatException: For input string: "foo" at java.lang.NumberFormatException.forInputString (NumberFormatException.java:48) at java.lang.Integer.parseInt(Integer.java:426) at java.lang.Integer.parseInt(Integer.java:476) at ExceptionDemo01.main(ExceptionDemo01.java:5)
A NumberFormatException is just what it says: an exception caused when an expression that is expected to be in the format of a number is not. It is one of those unchecked exceptions that Java does not require us to catch. (The I/O methods in our readers and writers throw checked exceptions that we must account for before the program will compile.)
In the past, we have seen that we can use a throws clause to "throw" the exception up to whoever called the method. That works fine in cases where we don't have any particular reason to deal with the exception immediately. But if we want, say, to recognize an error in user input, the we do want to deal with the exception. In such cases, we can use a try...catch... clause. For example:
try { System.out.println( Integer.parseInt(args[0]) + 1 ); } catch (NumberFormatException ex) { System.err.println( "\"" + args[0] + "\" is not an integer!" ); }
This code catches the exception and prints an error message. But what if we want to force the user to enter another input value? You can do something like this:
while ( true ) try { inputString = in.readLine(); valueToIncrement = Integer.parseInt( inputString ); break; } catch (NumberFormatException ex) { System.err.println( "\"" + inputString + "\" is not an integer!" + "\nPlease try again:" ); }
This loop will keep trying to read a legal value, and break only when it succeeds. When it catches an exception, it prints and error message and continues.
Almost none. Your main() method should create an object, maybe two, and send a message to an object. All real work should be done by an object. We first encountered this idea in Session 11, in the form of substitutable objects for doing I/O. We can and should do the same thing!
Patient: "Doctor, it hurts when I do this."Doctor: "Don't do that."
All semester I have encouraged you to start small, to take small steps. Never once have we designed a multiple-class solution before writing any tests and code. I don't imagine that most you will feel very comfortable trying to implement a four-, five-, or six-class solution to this assignment without feeling overwhelmed.
So don't do that. If your design is too complex to implement easily as it is, then start with a smaller design. One class. One behavior. Write a test. Write the code. Then add another behavior. And do it again.
Again, this isn't new advice. many of you ran into a similar problem on Homework 2, and I gave you some advice at the top of Session 7. Start simple. Take small steps.
Any other questions?
Let's grow our first graphical Java program a simple BallWorld. And let's walk the walk, starting small and taking small steps:
Your reading assignment is to study the several versions of this growing program, including the last version: a BallWorldFrame that has a Ball, which is a Disc that moves itself.
Ideas to consider;
How do we test one of these graphical objects?
How do we test one of these objects? Actually, this question came up in the context of Homework 5, too:
I think I've successfully made a "cannot be tested" class... Everything in this class has to do with getting input from the user and accessing that input. I can't think of any single way to write a test for this, unless I set the tests up to test a specific value and enter that exact value as input.I know you love tests, but how can you test random input?
You don't have "random" input. You have arbitrary input. (... great session on randomness at my conference last week ...) So did our bowling game. Notice that we were able to test that class quite thoroughly, considering all of the interesting cases we could think of: open frames, spares, and strikes; in early frames and in the 10th.
We can do the same thing in Nim. For example, we might ask the user to pick up some stones. The user may enter a legal number of stones, or not. What shoule we test? The boundary cases of 0 and 3 are interesting. "Ordinary" legal value. Illegal values in both directions. These tests are really for the methods that receive and use the user's inputs.
Separate
the methods that read from the user
from
the methods that use the information.
This will make your code testable. Test the methods that use the information. If a method does nothing but use a Java snippet that we know reads a String from System.in, then we can trust BufferedReader.readLine() to do its job.
This approach makes your program better, too. If we ever want to change how the program interacts with the user, we will be able to replace only the methods that do interaction. The code that uses the information will stay the same! And if those methods are in different objects, then our program allows us to substitute new interaction objects without changing the "guts" of the Nim game!
Testing graphical applications is a bit tougher. How do we know that the program painted the ball at the right location in the window? Idea: Use a Graphics object that can tell us what we need to know...