- What are the minium requirements for this assignment?
- How do I read from a file?
- How can I print in evenly spaced columns?
- How can I make a formatted string with evenly spaced columns?
- How do I create/use/edit/modify arrays for this project?
- What’s the deal with Exceptions?
- How do I write to a file?
- How do I write formatted text to a file?
- How can I dynamically resize an array?
-
What are the minimum requirements for this assignment?
- In general you must have at least a console-based application that:
- is stable - i.e. won’t crash if the user mis-types commands
- can collect a reasonable set of statistics for a basketball game a good baseline to use would be: points, rebounds, assists, and steals.
- Can print out a well-formatted box score for both teams once the game is over.
You will also have to include some minimal documentation that explains how to use the program.
That’s pretty much it.Moving away from the bare minimum:
- It’s helpful to understand what the value of this program really is: good statistics for basketball games are difficult to come by for high school coaches. Beyond the accuracy of the statistics, ease of use by a trained scorekeeper, and the ability to generate clean, well-formated reports is what’s really valuable.
- A user shouldn’t have to modify any code in order to set up a new game between two new teams. I.e. setting the home team and visitor team is something that the user should be able to do — don’t hard code it.
- For an application like this, it’s very nice to get some sort of confirmation that a command was executed properly. For example, a portion of a console session might look like this:
bbsp$> fga H 21 2 #21 - 2 pts Home: 2 Visitor: 0 bbsp$> fga H 15 3 #15 - 3 pts Home: 5 Vistor: 0 bbsp$> rbe H 14 ERROR: did not understand 'rbe' bbsp$> reb 14 ERROR: usage: reb HorV num etc.
- Having multiple print/save options is good. Be able to print more than just a box score. How about a human-readable log of all the game events? For example, if the command was entered: fga H 21 2, this could be entered in a game log as: “Field Goal: U-High #21-Jenkins(4 pts) [H: 8 V: 6]” For more inspiration, here is a game log for a recent bulls game.
Along with printing these things to the console, the user should be able to same them as plain text files.
Anything that your program can print to the console should be able to be written to a text file (named by the user). - Having an option to print the report in html would be EXTREMELY useful (and not too difficult) as coaches are often asked to update their team’s websites with scores and statistics. (XML is another option here if you want to experiment with that).
- Basketball is played in Quarters - 4 quarters to a game. Our program (right now) cannot hook up to the actual game clock. Your program should be able to keep track of points by quarter - both player and team points. After the game you should be able to generate a scoring-by-quarter report.
- You should be able to undo the last command that was executed. You may need this if you type a command that’s valid, but the data you entered turns out to be wrong. (Sometimes this can’t be helped - you think a player scored a 3 point shot, then the refs confer and decide it was only a 2). Being able to undo more than one command would be even better - you could keep an array of the last 20 commands, for example, and provide the ability to undo any of them. Of course, why not just keep the whole history?
- Better still, would be the ability to pick and choose which commands to undo. Think of it this way: Each command you enter represents an event that happened in the game. You could number each event in the order it occured. You could add a print feature that could show you a range of events. For example: “print history 20″ would show you the last 20 commands that were entered, or “print history 20-30″ would show you the 20th through 30th events that occurred in the game. You could then pick one to edit, or undo, or whatever. For example: “undo 32″ might undo the 32nd event. Or “replace 32 fga H 21 2″ would effectively undo the 32nd event, and put a new fga H 21 2 in its place. (WARNING: this could be complicated).
- Ideas abound. If you think of something and you’re not sure about it, just ask on the list.
- How do I read from file?
- How do I print in evenly-spaced columns?
- How can I make a string with evenly spaced columns?
- How do I create/use/modify Arrays?
- What’s the deal with Exceptions?
- How do I write to a file?
- How do I write formatted text to a file?
- How can I dynamically resize an array?
Simple, use Scanner. The Scanner class can be used to read strings out of a file as well as from the keyboard. The trick is that you have construct a “File” object for the Scanner to use and there’s some minutia involved in getting it to work. Here’s the code - I’ll explain it below:
import java.util.*; import java.io.*; ... Scanner S = null;
try{
File F = new File("path/to/myFile.txt");
S = new Scanner(F);
}
catch(FileNotFoundException e){
throw new RuntimeException(e);
}
String line = "";
while(S.hasNext()){
line = S.nextLine();
//do stuff with "line"
}
S.close();
Let’s look at the first chunk first, which is how you have to construct a Scanner from a file. The problem is that in order to use a file the Scanner must confirm that a file exists. If it doesn’t exist the Scanner cannot proceed so it throws an Exception, but it is NOT a runtime exception. Non-runtime exceptions must be “caught” or you must declare that you program will throw them. This is java’s way of ensuring that you know what you’re getting yourself into. As such, we must introduce the try-catch block. This is a way that you can handle exceptions on your own. The block essentially says “Hey Java, try this…and redirect any exceptions to the catch block.”
Scanner S = null;
//declare S outside of try-catch block, otherwise it wouldn't exist
//after we performed the try.
try{ //Hey Java, try this...
File F = new File("path/to/myFile.txt");
//Make a File object out of the given path
S = new Scanner(F);
//Attempt to make a Scanner on the given file -- this is the line
//that would throw an exception.
}
catch(FileNotFoundException e){
//Hey java, I know that a FileNotFoundException might be
// thrown so I'm catching it here.
throw new RuntimeException(e);
// This is what I'm doing with the exception. I
// don't have to throw a RuntimeException...I could
// just print an error message to the screen and
// continue on. But in this example I do want my
// program to crash if the file isn't found, so I make
// a new RuntimeException out of the exception that I
// caught and throw it.
}
Now let’s look at the second part of the program which actually uses the Scanner that was constructed from the file. When you use Scanner to read from a file, you can think of it as a person sitting at the keyboard who knows exactly what you want entered and can type it as fast as you can ask for it. Typically, data files are formatted in some way that makes parsing them easier. For example, a data file for a team in our basketball program might look like this:
Foobars 14,Franke, B.,3,5,10 12,Davis, B.,4,9,5 ...
This file isn’t intended to be read by humans. It’s formatted for the convenience of our program. So, the first line might be the team name and subsequent lines might be a line for each player where each data element is separated by commas : num, Name, fga, fgm, reb
(Actually at the beginning of a game, all of the stats would be 0’s so you’d really just need the name and number).
Let’s look at the code:
String line = "";
//it's good form to declare variables outside of a loop
while(S.hasNext()){
//The scanner checks to see if there's more stuff in the file.
//If there is, hasNext() returns true. Thus, this loop will stop
//when the Scanner reaches the end of the file.
line = S.nextLine();
//read the nextLine out of the file -- this is the same as reading
//the next line from the keyboard. You can use any of Scanner's
//"next" methods to read the next item of data out of a file.
//For example: nextInt() attempts to read the next characters in the
//file and parse them as an int. If the next token can't be parsed as
//an int the program will crash.
//For our stats program we might want to parse the line in order to construct some players.
String[] parts = line.split(","); //split the line at each comma
someTeam.add(new Player(parts[1], parts[0]);
}
You’ll want to use System.out.printf(….);
Printf hails from the “C” family of languages the “f” stands for “format.” Printf allows you to compose a “format string” using special characters to represent variables that should be plugged in. Here are some examples:
int foo = 7;
System.out.printf("The value of foo is: %d wasn't that fun?n", foo);
Printf looks for “format” characters within the string - these characters are prefixed with a “%”. In the example above “%d” means a decimal value (for an int it will print the number with no decimal afterwards). After the format string, you must supply printf with a comma-separated list of the variables you want plugged into the format characters.
EXAMPLE 2:
int foo1 = 5, foo2=7;
System.out.printf("Foo1=%d, Foo2=%d and Foo1/Foo2=%f", foo1, foo2, ((double)foo1/foo2));
Here my format string has 2 %d’s in it and one %f, so I must supply printf with 3 variables (or computed values) to plug into to those spots. %f means “floating point” value — i.e. a non-integer decimal number.
Printf also allows you to control how many characters of a variable actually get printed. For example, if you have a long decimal value in a double, you can control how many digits of the decimal get printed.
double foo = 5.14287142857142857;
System.out.printf("The value of foo is: %10.5f", foo);
This will print the string:
The value of foo is: 5.14285
In our formatting string %10.5f means “print a minimum 10 characters of the floating point number that are on the left-side of the decimal, and a max of 5 characters on the right side of the decimal. The 10 effectively “pads” the number with spaces. What you’re really saying is: “Print some float using 16 characters. (10 on the left, a decimal point and 5 on the right).”
Useful formats that might need are:
%d - use for integers
%f - use for doubles
%s - use for Strings
%c - use for chars
%b - use for boolean (will print “true” or “false”);
For more information:
The java documentation is HERE but it’s kind of long read.
This tutorial goes more in depth.
The trick here is to use a class from java.util called Formatter. You should read about formatted output in general using printf in the question above. You could use this code to make a method in your Player class that returns a formatted string of that player’s stats. Here is the commented code:
//Make a StringBuffer which is a more flexible kind of String
StringBuffer buf = new StringBuffer();
//construct a Formatter whose output will go into the String buffer
Formatter F = new Formatter(buf);
//Produce a line of formatted text (assuming these variables exist)
F.format("%10s %2s %3d %3d %3d %3d", playerName, playerNum, fga, fgm, pts, reb);
//get a String out of the StringBuffer
String line = buf.toString();
//You can now do anything with that string - print it to the terminal, write it to a text file, etc.
Brief notes about arrays:
HOW TO MAKE:
1. Player[] list;
//declare 'list' to be an array of type Player
2. list = new Player[30];
// initialize 'list' to be an array large enough to hold 30 players.
3. Player[] list = new Player[30];
//combining 1 and 2 onto one line.
4. int var = 50;
Player[] list = new Player[var];
// here use a variable to initialize the length of the list.
HOW TO ACCESS:
1. int len = list.length;
// every array holds a variable 'length' that tells you how many
// slots there are in the array.
2. list[0] = new Player("Baker", 14);
// assign index 0 of the array to be a new Player object.
3. Player temp = new Player("Baker", 14);
list[1] = temp;
// any player variable is just a reference to a Player.
// You can assign the reference into a slot in the array. Here, index 1.
4. Player p = list[0];
// Similarly, a slot in the array just holds a reference to
// a Player. This line gets the 0th player out of 'list'
// and assigns it to p.
5. list[0].getName();
// since list[0] IS A Player reference, you can call methods
// directly on some slot in the array.
HOW TO DO THINGS TO EVERY ELEMENT OF AN ARRAY:
For loops, of course!
for(int i=0; i<list.length; i++){
System.out.println(list[i]);
}
You don’t have to just print it out. You could do anything you want. What the for-loop does is allows you to gain access to each player in the list. If you’re looking for a certain player by name, you can write an if-statement that checks:…
public Player findByName(String nameToFind){
for(int i=0; i<list.length; i++){
if(list[i]!=null && list[i].getName().equals(nameToFind)){
return list[i];
}
return null;
}
Note that in the code above, I’m looking at each possible slot in the array. But each slot might not have a player in it. If I attempt to run getName() on a null reference I will get the dreaded NullPointerException. So in my if-statement BEFORE I check the name of the player I must check to make sure that the slot I’m looking at isn’t null. If it is null, the rest of the if-statement is ignored since the first part of the expression would evaluated to false, it would make the whole expression false. Ensured that the slot at index i has a Player in it, I can safely call the getName() method and check to see if it’s equal to the name I’m looking for. If it is, I return the Player object. If the loop finishes and I haven’t returned a player yet, my method returns null to indicate that no player with the supplied name was found.
EXAMPLE 2:
Here’s another example that shows something you could do with an array of players….Calculate the team field goal percentage. I’ll let the method speak for itself:
public class Team{
private Player plist; //will be filled by constructor.
...
public double teamfgp(){
int fgaTotal=0, fgmTotal=0; //vars for sum of all players
for(int i=0; i<plist.length; i++){
if(plist[i]!=null){//make sure there is a player in slot i
fgaTotal += plist[i].getFga(); //add to total fga
fgmTotal += plist[i].getFgm(); // add total fgm
} }
// do the calculation and return return ((double)fgmTotal) / (double)fgaTotal)) * 100.0;
}
Exceptions are actually a rather large sub-topic unto themselves. I would recommend reading the Sun Java Tutorial on Exceptions which is quite good (Exceptional even :)). Here is a link to the middle of the tutorial, which I think is a good starting point for you (and is what I’m going to summarize below) : Exceptions — The Controversy. You can go forward and backward in the tutorial to find out more.
Exceptions:
In Java there are two kinds of Exceptions - “checked” and “unchecked.” Unchecked exceptions are the ones you’re used to - the ones that get reported when your program crashes while it’s running - NullPointerException, NumberFormatException, ArrayIndexOutOfBoundsException, etc.
But there is another class of Exception that we have to introduce in order to read and write from files and these are so-called “checked” exceptions. Checked exceptions are ones that you must deal with in your code. The idea is that “those who call a method must know about the exceptions that a method can throw so that they can decide what to do about them. These exceptions are as much a part of that method’s programming interface as its parameters and return value.”
The bottom line:
Checked exceptions tend to be errors that a program should reasonably be able to recover from, for example a FileNotFoundException. Unchecked Exceptions tend to be errors from which a program cannot recover, e.g. divison by zero, accessing a null object, accessing an array index that’s out of bounds, etc. These RuntimeExceptions are usually the result of a bug in the program or programmer error.
EXAMPLE: to handle checked exceptions, you must use a try-catch block in order to try the segment of code that might throw the exception and to handle it if it does.
File F = new File("path/to/some/file.txt");
Scanner S = null; //declare S here so that it's available
// outside of try-catch afterward
try{
S = new Scanner(F);
}
catch(FileNotFoundException e){
System.out.println("Could not find file: "+F);
System.out.pritnln("Error was: "+e);BB
}
// now do stuff with Scanner
// MAKE SURE IT'S NOT NULL!
The code above will prevent a program from crashing if a File that you’re trying to scan doesn’t actually exist. In the context of the BasketBall Stats program this code might appear inside a command that allows the user to load a team roster from a file. You’d want to report that you couldn’t find the file, and stop executing the command at that point. But you wouldn’t want to crash the program.
Easy. Use FileWriter. You can avoid reading this if you want to just read the documentation.
How to use FileWriter. The example should be self-explanatory:
FileWriter F;
try{
F = new FileWriter("path/to/file");
F.write("Hey this is line\n"); //notice line break.
F.write("Another line. \n");
F.close();
}
catch(IOException e){
System.out.println("Couldn't write to file.");
}
If you want to append to a file that already exists you can use the other constructor:
FileWriter F = new FileWriter("path/to/file", true);
Using this constructor any “writes” will be done to the end of the file.
It is possible to open an existing file and write into the middle of it, or at any offset you like, but to learn more you’ll have to read the java API or experiment on your own.
This is also easy but unfortunately, it’s just different from the basic file writing described above. You can use a class called ‘Formatter’ which allows you print formatted text to any destination - the terminal, a file, etc. I’ll give an example here of how to print to a file. You should have read the FAQ entry on printf above. Here is a code segment that should explain all.
Formatter formFile;
try{
formFile = new Formatter("someFileName.txt");
}
catch(FileNotFoundException e){ // handle exception }
int fga=10, fgm = 5, pts = 11;
formFile.format("%5d %5d %5d\n", fga, fgm, pts);
formFile.flush();
formFile.close();
There is no built-in feature to do this. If you need more slots for elements in your array, you need to make an array that’s bigger and copy over all of the elements from the old one. Here is code to do it…assume an array of, say, Players.
Player[] plist = new Player[10]; //old array
//now let’s say you need to make it bigger…
Player[] plist2 = new Player[plist.length*2]; //new array that’s twice as big
for(int i=0; i<plist.length; i++){
plist2[i] = plist[i]; //copy each element from plist into plist2
}
plist = plist2; //re-assign plist to point to the new list