This assignment has two major portions. The first involves reading and understanding a substantial piece of code that we provide to you. In addition, you are expected to document this code (and to turn in your documented version with the writeup for problem set). That portion of the assignment emphasizes:
emphasizes the following topics:
You should read through this entire assignment and complete the Lab preparation section before coming to lab. You will find it very much to your advantage to understand the code in the first portion of the assignment before coming to lab. Some portions of the Post Lab write-up also require your thinking about them before and during the laboratory portion of the assignment.
As per policy, you are encouraged to discuss this assignment in detail with your classmates, but you are required to do the write-up on your own. You may get comments from other students on all portions of your write-up before turning it in, if you wish. Please include the names of anyone with whom you collaborate, in any way, on this assignment, and indicate the nature of the collaboration. [Failure to include this information is a violation of the collaboration policy.]
This assignment is due at the beginning of class on Friday, 22 October.
The laboratory project for this week is a very simple four-function calculator. We have constructed the calculator's GUI (graphical user interface). Its functionality is documented in the interface Calculator (in the package calculator). Note that a Calculator is only a graphical interface; there is no intelligence connecting button presses to actions.
We have also provided you with a largely undocumented piece of code called CalculatorState. An instance of the CalculatorState class provides valuable functionality for a particular Calculator. Your written assignment this week involves reading and understanding this code and writing complete documentation for it. In lab, your mission will be to write the logic controller that connects the Calculator GUI with the CalculatorState smarts in appropriate ways.
Your assignment is to read through and understand the code that we have written. You will discover that the code is completely undocumented. You will demonstrate your understanding of the code to us by providing us with a complete set of documentation for the ButtonHandler files. What you turn in should be a complete set of documentation for the code that we have written.
You may work closely with other students to understand the code in this assignment. In fact, explaining the code to a friend is a good way to figure out whether you understand it yourself. You can locate other students in the class by mailing to the class list or zephyring to the class. (See the general information handout for further details.) It may also be useful to have someone read through your documentation just as you would have someone proofread your paper.
You should, however, make certain that the documentation you turn in was written entirely by you. You should also list anyone you discussed this problem set with and briefly describe the nature of your interactions.
Before you embark on your documentation of the CalculatorState class, it pays to get to know the Calculator interface.
You should begin by examining the Calculator interface (attached). (You may also want to take a look at the javadoc file generated from that interface, also attached.) It defines everything that you'll need to know about a Calculator. In particular, it contains three kinds of declarations:
The first things defined in Calculator.java are the "buttonID constants": Calculator.OP_ADD, Calculator.OP_SUB, Calculator.OP_MUL, Calculator.OP_DIV, Calculator.EQUALS, Calculator.DOT, and Calculator.CLEAR.
These are all static, i.e., accessible as parts of the Calculator interface: e.g., Calculator.OP_ADD. They are also final, i.e., they cannot be changed. Finally, they are all of type int.
All of these constants are distinct from one another and from the numbers 0 through 9; it is intended that the numbers 0 through 9 serve as buttonIDs for their respective buttons, although they have not been given symbolic names. (In this case, 0 through 9 are actually meaningful, not arbitrary, names!)
An additional constant, Calculator.NO_OP, is not a buttonID but is provided for convenience.
Each Calculator object has its own getText and setText methods for interacting with the Calculator's display. (Note that the display, and these methods, operate using Strings, not a numeric type such as int.) Their signatures are as follows:
public String getText(); public void setText( String s);
getText() returns the String currently displayed on that Calculator's screen. Unlike getButton(), getText() doesn't wait for something to happen (e.g., for the value to change) before returning it; it just tells you what text is currently being displayed.
setText replaces any currently displayed text with its single argument, a String.
Every Calculator object also has its own getButton method:
public int getButton();
The int returned is a buttonID indicating which of the buttons was pressed: one of 0 through 9, or one of the buttonIDs defined in the Calculator interface. Each time that the getButton method is called, it returns the next button pressed. So, if the calculator's user presses 3 + 4 =, your object's first call to your Calculator's getButton() method will return 3. The next call to getButton() will return Calculator.OP_ADD. The third call will return 4, and the fourth call will return Calculator.EQUALS. Then, if you call your Calculator's getButton method again, it will wait for another button to be pressed before returning.
getButtonLabel is a method that takes a buttonID as an argument and returns a (single-character) String suitable for labeling that button. This is particularly useful if you want to print a number or operator, e.g., on the calculator's screen.
In reading the code for CalculatorState, you should also familiarize yourself with the following method signatures.
We've provided you with a coercion routine which takes a String and returns a floating point (double) decimal number:
double cs101.util.Coerce.StringTodouble( String s );
(Remember that in Java, double (the primitive data type) and Double (the object) are two different kinds of things.)
In fact, it is built out of two java.lang.Double methods:
public static Double Double.valueOf( String s ); public double Double.doubleValue;
You can use these methods directly if you prefer.
To produce a String from a double, you can use:
public static String String.valueOf( double d );
and from an int:
public static String String.valueOf( int i );
To figure out whether a char or String appears in a given String, use
public int String.indexOf( int ch); public int String.indexOf( String str);
Your job is to understand and document the CalculatorState class. Note that the CalculatorState is only connected to the Calculator gui directly through CalculatorState's constructor. The two classes have very limited interactions, mostly centering around the Calculator's display. In lab, you will add a class that provides a better connection between instances of these two classes.
Execution of this code begins when a new CalculatorState( Calculator gui ) is created. What actually happens? Continue this way through the code until you have defined all of the objects in the system. Now imagine that your CalculatorState's handleNumKey method is called. What happens then? Try calling handleOperation next, then handleNumKey again, then handleEquals. Follow through the execution of that code, too. Don't forget to write down how the various fields of objects change.
You can figure all of this out using pictures, people, or the computer. You may want to try several of these methods. Which ever approach you take, don't try to jump ahead, guessing what things will do. Instead, work slowly and carefully through the code in a step by step manner. Continue experimenting with the execution of this system of objects until you are confident that you understand how it works.
You may want to begin by drawing pictures of the various kinds of objects in this system. For example, you might take some index cards and put one object on each. Draw the first CalculatorState on an index card. List its fields and the values assigned to each. If a field refers to another object, you can write long squiggly lines to connect them, or you can be more creative. For example, I like to glue in the pointer with a piece of string or yarn. Alternately, you can simply assign each index card a unique identifier and use that to refer to the object.
Alternately, you could get together with a group of friends and play-act the changing of the objects. You may even want to do this in a classroom where there's a big blackboard for scratch work. (This idea may sound silly, but it is actually quite effective.)
When you feel that you have an adequate understanding of what the code does and of what the various pieces of the system do, you should begin to work on your documentation.
[CHECK-IN] Before you come to lab, you will need to have read and understood the CalculatorState class. You may want to write an interface that describes the contract you will rely on from CalculatorState. You should in any case have a written description of what CalculatorState does and what role its various methods play. This should be comparable to the documentation of Calculator (the interface or the javadoc) or to the documentation above.
In addition to an understanding of what the CalculatorState class can do for you, you will need to actually go in and write documentation for this class. You do not need to bring your fully documented CalculatorState class to lab with you for checkin, but you will need this for your final writeup.
[TURN-IN] The documentation for CalculatorState should include:
In documenting the code, you should follow the conventions of the Design Project:
It should be possible to read your documentation and understand what the code is doing -- and why -- almost without reading the code itself.
You may wish to edit the code files that we have provided directly, i.e., to write your documentation as comments in the file.
We recommend that you complete the finger exercises and lab preparation in cooperation with classmates. As always, a neat write-up of the finger exercises should be turned in along with your completed laboratory.
You should complete the coding part of following two exercises before coming to lab.
[CHECK-IN, TURN-IN] Write a class that can be used as the startup class for a program. Remember that Java's contract is that it starts at a method matching
public static void main( String args );
In Code Warrior, this class must be identified as the Java target.
Your class's main method should do something, just to let us know it is there. You may find the cs101.io.Console class useful to accomplish this. If you want to use cs101.io.Console, you should
at the top of your java file. (Otherwise you will have to refer to Console by its full name.)
[TURN-IN] Document your class, indicating what it does, how it works, and why it works the way that it does. See the style sidebars on class and method documentation for more detail.
[CHECK-IN, TURN-IN] Create a simple self-animating object class. The basic properties of a self-animating object are that it:
For example, instances of your animate object class might read a line from the console and write it back to the console.
You may want to use the java charts on program files and on classes as reference. Code on which you may want to build includes
To use this provided class and interface, you will probably want to import the appropriate packages or files at the top of your file.
[CHECK-IN, TURN-IN] Q. What import statements would you need to include to use AnimatorThread and Animate? How could you refer to them without an import statement?
[TURN-IN] Document your class, indicating what it does, how it works, and why it works the way that it does. See the style sidebars on class and method documentation for more detail.
You do not need to run the week's program before coming to lab, since you surely know what a calculator does. However, a simple implementation is available on Athena, which you can run by typing the following on an Athena Sun workstation (assuming that you have successfully set up your account to run java. E-mail the course staff for help.)
athena % java calculator.RunCalc
Your target should be to design and build a calculator that can handle simple arithmetic on one-digit numbers. This assignment is written to guide you through a variety of stages in the development of the calculator; the project is open-ended and you will certainly leave lab with further ideas for the additional calculator functionality.
Specifically, you will implement an active object class which will interact with a Calculator object to respond to the user. The Calculator can do such things as figuring out which button the user presses, and managing redrawing, displaying, and other various things that happen on your computer screen. However, it does not actually know how to interpret these button presses, or what answer to display. That is your object's job.
For this lab, you will need to define an active (i.e., animate) object class that will interact with the Calculator object. You may rely on both a Calculator and a CalculatorState, provided that you conspire to have these objects available for your class. Your object's job is to tell the Calculator exactly what to do, such as recognizing and appropriately responding to the user's button presses. You will presumably find a CalculatorState a useful helper in this task.
In lab, you will be writing a class that will interact with an instance of the Calculator object, and serve as a controller for it. You should name your class ButtonHandler, and it should be a self-animating active object (much like the class you created for the Balancer lab). At each point in time, your class should ask the Calculator for the next button pressed, and then, if appropriate, perform any desired computations and update the Calculator's display. (Needless to say, it should also update its own internal state appropriately at each step.)
You will also be writing a class that has a main method, so that your program can get started. Your main class should work with your controller class (as well as with the Calculator and CalculatorState objects that you will need).
As usual, you should follow an incremental design strategy -- keeping the end goal (a working calculator) in mind, but starting with simple implementations first. Before going to lab, think about how you would implement the following:
A simple test that will help ensure that your infrastructure is working is to simply echo each button pressed back to its Calculator's screen. (Of course, you can also use Console.println, but echoing to the calculator is so much cooler!) You can start by echoing back the buttonIDs (which are ints) as they are handed to you, but you'll get prettier results if you use getButtonLabel method, which provides you with more informative String names for the non-numeric buttons.
Once you've gotten echoing to work, you can start to build in some logic. At this point, you can now try to design a simple controller that relies straightforwardly on the CalculatorState object that you've been given. This is the target point of the problem set.
A useful feature to have is a reset feature -- that is, a certain button or sequence of button presses that will bring your calculator back into a known state.
Write code that will allow you to reset your calculator.
Q. How would you make the calculator reset (i.e., call the reset() method you have defined in your class) when then the CLEAR button is pressed, but not at any other time?
If you have additional time, experiment with that calculator program and see whether you can get it to behave badly. If so, write this up and turn it in with your writeup. You may also augment the existing CalculatorState behavior. The following additional features may be of interest, if you have the time. Most or all of them will require modifying, extending, or overriding the CalculatorState class.:
Remember, don't try to implement too a complex calculator all at once. Break it down into pieces that you can test independently, and test them thoroughly before moving on to the next step. In each case, be sure that your logic can handle any button press at any time. Think of examples that your code should work on, as well as examples where it might not behave as you would like. Write these examples down and experiment with them in lab.
As always, you should draft your code before coming to lab.
Your code should define a class whose instance should arrange to have access to a Calculator and to a CalculatorState. It should be a self-animating object, i.e., it should have its own AnimatorThread. At each point in time, it should gobble up a button press (by calling the Calculator object's getButton() method) and, if appropriate, update the Calculator's display.
You will also be responsible for defining some startup code that will allow your class to be instantiated.
You need to bring your finger exercises, preliminary documentation of the CalculatorState class, code draft, and development plan with you to lab. You will not be checked in without them. You should also have read the entire problem set and be prepared to discuss an implementation strategy before you arrive.
Before you begin work on the calculator directly, you should implement and test the two classes from your finger exercises.
First, build a main class. You will need to create a .java file containing your class definition. The name of the file should match the name of the class. The class should be declared public.In Code Warrior, identify this class as the Java target. Compile and run your code. Does it work as you expected? If not, debug it. Also take notes and include this in your writeup. [TURN-IN]
Next, define your animate object class. Don't forget to make your class, its (no-args) constructor, and the run method public. Each public class must be defined in its own file, and the name of the file must match the name of the class.
When you have finished this code, you can test it by modifying your main class to create an instance of your animate object class. Run your program and see what happens. Also take notes and include this in your writeup. [TURN-IN]
Compile and run your code to make sure that you've built things correctly. If you have problems, now is a good time to work them out.
We have provided you with a graphical user interface (GUI) for the calculator. Your mission is to write the logic controller (the "brains") behind this graphical interface. We've hidden the details of the GUI implementation, but have supplied you with a calculator.Calculator interface (in the java sense) that describes the GUI's functionality in all of the detail that you should need. You can create an instance of the class that implements this interface by executing code that includes the expression
(assuming that you're in package calculator or have imported calculator.*).
The Calculator GUI can do such things as figuring out which button the user presses, and managing redrawing, displaying, and other various things that happen on your computer screen. However, it does not actually know how to interpret these button presses, or what answer to display. That is your object's job.
For this lab, you will need to define an active (i.e., animate) object class that will interact with the Calculator object. Although it will eventually need to be modified, you can start with the animate object you've already written. (Remember: if you renanme the class, you will also need to rename the file and vice versa.) If you actually literally reuse your animate object code to produce this simplest calculator, make sure that you save a copy of the animate object code to turn in with your lab.
You may want to make your new class a part of the package calculator.
Unlike the simple animate object that you built, your calculator controller will need access to a particular Calculator and to a particular CalculatorState. There are several ways that this can be arranged.
[CHECK-IN] Q. Whose job is it to create each of these objects (the Calculator, the CalculatorState, and your controller)? How do they become connected?
[CHECK-IN] Q. What changes do you need to make to your main class in order to test this new code?
[TURN-IN] Q. What happens if your main method starts two separate instances of your calculator class?
Once you are able to start up your calculator, try pressing some buttons. [TURN-IN] What happens?
Now modify your controller class to connect the Calculator with the CalculatorState in a sensible way. Run some experiments. [TURN-IN] What happens now? This code, together with its documentation and the documentation of CalculatorState, are the targets of this assignment.
If you still have time, you can implement some additional features.
Remember: You should always begin your labwork with a simple, independently testable implementation and build on it as each stage works robustly.
Also remember the following, quoted from the Evaluation Policies handout: "... you will in general get a higher score for basic but elegant, well-tested, well-documented, and well-understood code than for adding features to poorly written/documented/tested code. We are more interested in how well you do what you do than in how much you do."
Record your experiences, including tests that various stages of your implementation succeed and fail. Make sure that you understand how your code behaves, and how it will behave under inappropriate as well as appropriate circumstances.
Before you leave lab, you will need to have your code checked off by a course staff member.
Your completed assignment should include:
You should also turn in as well as the overall design writeup.
You should, as always, include information on your collaborators and their roles.
This lab assignment is due on Friday, 22 October, at the beginning of class. It may, of course, be turned in earlier.
This course is a part of Lynn Andrea Stein's
CS101 project at the MIT
AI Lab and the Department of Electrical Engineering and
Computer Science at the Massachusetts Institute of
Questions or comments: