Project 2.5.1.
Specification:OneRowNim
OneRowNim
“take away”OneRowNim
OneRowNim
“take away”OneRowNim
so that it can be used in with different kinds of user interfaces:OneRowNim
class. We will design the user interfaces in a subsequent chapter.OneRowNim
Riddle
example, class definitions are broken down into two parts:OneRowNim
object should manage two pieces of information that vary as the game is played. One is the number of sticks remaining and the other is which player has the next turn. We can represent both of these as whole numbers, which correspond to int
in Java: Variable Name | Type | Values |
nSticks | int |
0 through 21 |
player | int |
1 or 2 |
takeOne()
, takeTwo()
, and takeThree()
. Each method will be responsible for reducing the value of nSticks
as well as switching to the other player
.report()
method will report the number of sticks remaining and whose turn it is.OneRowNim
interface. These will be the methods that other objects will use to interact with it.OneRowNim
class.OneRowNim
Class
OneRowNim
class as described in Figure 2.5.1, the next step in building our simulation is to begin writing the Java class definition.OneRowNim
object will interact with other objects, we will designate its access as public
. And because OneRowNim
is not a subclass of any other type of object, we will omit the extends
clause, thereby making it a direct subclass of Object
by default ((Figure 2.5.2).OneRowNim
is a subclass of Object
.OneRowNim
:public class OneRowNim // Class header
{ // Beginning of class body
} // End of class body
public class ClassName
{ // Instance variables
VariableDeclaration1
VariableDeclaration2
...
// Instance methods
MethodDefinition1
MethodDefinition2
...
} // End of class
q
and a
that were defined in the Riddle(String q, String a)
constructor (Figure 2.4.1). As we will see better in the next chapter, Java handles each type of variable differently.private
, to protect them from other objects.private
element cannot be accessed outside the class in which it is declared.public
element is accessible to any other object.protected
element is accessible only within subclasses of its class and by other classes that belong to the same package.public
, protected
, or private
. Or you can leave its access unspecified, in which case Java’s default accessibility rules will apply.Element | Modifier | Rule |
Class | public |
Accessible if its package is accessible. |
by default | Accessible only within its package. | |
Instance variable | public |
Accessible to all other objects. |
or method | protected |
Accessible to its subclasses and to other classes in its package |
private |
Accessible only within the class. | |
by default | Accessible only within the package. |
OneRowNim
class as described in Figure 2.5.1, we get the following declarations for our instance variables: public class OneRowNim
{
private int nSticks = 7;
private int player = 1;
//Method definitions go here
} // OneRowNim
public void methodName() // Method header
{ // Beginning of method body
} // End of method body
MethodModifiers |
ResultType | MethodName | FormalParameterList |
public static
|
void |
main |
(String argv[]) |
public |
void |
paint |
(Graphics g) |
public |
Riddle |
(String q, String a) |
|
public |
String |
getQuestion |
() |
public |
String |
getAnswer |
() |
private
methods are accessible only within the class itself, protected
methods are accessible only to subclasses of the class in which the method is defined and to other classes in the same package, and public
methods are accessible to all other classes.public
. If a method is intended to be used solely for internal operations within the object, it should be declared private
. Private methods are sometimes called utility methods or helper methods.
OneRowNim
class.public class OneRowNim
{
private int nSticks = 7; // Start with 7 sticks.
private int player = 1; // Player 1 plays first.
public void takeOne(){ } // Method bodies still need
public void takeTwo(){ } // to be defined.
public void takeThree(){ }
public void report(){ }
} //OneRowNim class
OneRowNim
instance methods are meant to communicate with other objects, they should all be declared public
. All four methods will receive no data when being called and will not return any values. Thus they should all have void
as a return type and should all have empty parameter lists. Listing 2.5.7> shows the code with these method headers added. takeOne()
method, which represents the act of taking away one stick, should reduce the value stored in nSticks
by one and change the value in player
from 2 to 1 or from 1 to 2. The first of these changes is accomplished by the following assignment:nSticks = nSticks - 1;
nSticks
and assign the new value back to nSticks
.player
is more difficult because we do not know whether its current value is 1 or 2. If its current value is 1, its new value should be 2; if its current value is 2, its new value should be 1. Notice, however, that in both cases the current value plus the desired new value are equal to 3. Therefore, the new value of player
will always be equal to 3 minus its current value. Writing this as an assignment we have:player = 3 - player;
Current player | 3 - player | New player |
-------------- | ---------- | ---------- |
1 | 3-1=2 | 2 |
2 | 3-2=1 | 1 |
takeOne()
method becomes:public void takeOne()
{
nSticks = nSticks - 1; // Take one stick
player = 3 - player; // Change to other player
}
takeTwo()
and takeThree()
methods are completely analogous to the takeOne()
method with the only difference being the amount subtracted from nSticks
.report()
method should print the current values of the instance variables using System.out.println()
, with some additional text to clarufy the meaning of the values. Thus the body of report()
could contain:System.out.println("Number of sticks left: " + nSticks);
System.out.println("Next turn by player " + player);
OneRowNim
class. The completed class definition is shown in Listing 2.5.8.OneRowNim
class definition.public class OneRowNim
{ private int nSticks = 7; // Start with 7 sticks.
private int player = 1; //Player 1 plays first.
public void takeOne()
{ nSticks = nSticks - 1;
player = 3 - player;
} // takeOne()
public void takeTwo()
{ nSticks = nSticks - 2;
player = 3 - player;
} // takeTwo()
public void takeThree()
{ nSticks = nSticks - 3;
player = 3 - player;
} // takeThree()
public void report()
{ System.out.println("Number of sticks left: " + nSticks);
System.out.println("Next turn by player " + player);
} // report()
} // OneRowNim class
OneRowNim
Class
OneRowNim
by defining a main()
method. Following the design we used in the riddle example, we will locate the main()
method in a separate, user-interface class, named OneRowNimTester
.main()
should declare a variable of type OneRowNim
and create a OneRowNim
object. Let’s name the variable game
. To test the OneRowNim
class, we should code a series of moves. For example, three moves taking 3, 3, and 1 sticks respectively would be one way to remove 7 sticks and end the game. Also, executing the report()
method before the first move and after each move should display the current state of the game in the console window so that we can determine whether it is working correctly.main()
method:Declare a variable of type OneRowNim named game. Instantiate a OneRowNim object to which game refers. Tell game to report. Tell game to remove three sticks. Tell game to report. Tell game to remove three sticks. Tell game to report. Tell game to remove one stick. Tell game to report.
main()
method is shown with the complete definition of the OneRowNimTester
class:OneRowNimTester
produces the following output:Number of sticks left: 7 Next turn by player 1 Number of sticks left: 4 Next turn by player 2 Number of sticks left: 1 Next turn by player 1 Number of sticks left: 0 Next turn by player 2
Riddle
class for a private String
instance variable named hint
. Assign the variable an initial value of "This riddle is too easy for a hint"
.Riddle
named getHint()
. Assume that this method requires no parameters and that it simply returns the String
value stored in the hint
instance variable. Should this method be declared public
or private
?public
method for Riddle
named setHint()
which sets the value of the hint
instance variable to whatever String
value it receives as a parameter. What should the result type be for this method?Student
class.String
containing the student’s first name and last name.method1()
and method2()
may be contained in different classes.method1()
method executes sequentially until it calls method2()
. This transfers control to the first statement in method2()
. Execution continues sequentially through the statements in method2()
until the return
statement is executed.return
statement causes a method to return control to the calling statement—that is, to the statement that called the method in the first place.void
method does not contain a return
statement, then control will automatically return to the calling statement after the invoked method executes its last statement.OneRowNim
Program
OneRowNim
, we will perform a trace of its execution. Figure 2.5.11 shows all of the Java code involved in the program. In order to simplify our trace, we have moved the main()
method from OneRowNimTester
to the OneRowNim
class. This does not affect the program’s order of execution in any way. The listing in Listing 2.5.11 adds line numbers to the program to show the order in which its statements are executed.OneRowNim
program.public class OneRowNim
2 { private int nSticks = 7; // Start with 7 sticks.
3 private int player = 1; //Player 1 plays first.
public void takeOne()
20 { nSticks = nSticks - 1;
21 player = 3 - player;
} // takeOne()
public void takeTwo()
{ nSticks = nSticks - 2;
player = 3 - player;
} // takeTwo()
public void takeThree()
8,14 { nSticks = nSticks - 3;
9,15 player = 3 - player;
} // takeThree()
public void report()
5,11,17,23 { System.out.println("Number of sticks left: " + nSticks);
6,12,18,24 System.out.println("Next turn by player " + player);
} // report()
public static void main(String args[])
1 { OneRowNim game = new OneRowNim();
4 game.report();
7 game.takeThree();
10 game.report();
13 game.takeThree();
16 game.report();
19 game.takeOne();
22 game.report();
23 } //main()
} //OneRowNim class
OneRowNim
program begins with the first statement in the main()
method, labeled with line number 1. This statement declares a variable of type OneRowNim
named game
and calls a constructor OneRowNim()
to create and initialize it. The constructor causes control to shift to the declaration of the instance variables nSticks
and player
in statements 2 and 3, and assigns them initial values of 7 and 1 respectively. Control then shifts back to the second statement in main()
, which has the label 4.game
.game
refers to an instance of the OneRowNim
class with an initial state shown in Figure 2.5.12. Executing statement 4 causes control to shift to the report()
method where statements 5 and 6 use System.out.println()
to write the following statements to the console.Number of sticks left: 7 Next turn by player 1
main()
method, which calls the takeThree()
method, sending control to the first statement of that method.nSticks
, leaving the value of player
, leading to the state shown in Figure 2.5.13.main()
method calls game.report()
four different times so that the two statements in the report()
method are both executed on four different occasions. Note also that there is no call of game.takeTwo()
in main()
. As a result, the two statements in that method are never executed.game
after line 9 is executed.OneRowNim
class with a brief review of some of the object-oriented design principles that were employed in this example.OneRowNim
class was designed to simulate playing the One Row Nim game. As such it encapsulate a certain state and a certain set of actions. In addition, its methods were designed to encapsulate the actions that make up their particular tasks.OneRowNim
’s instance variables, nSticks
and player
are declared private
and can only be changed through the class’s public methods.OneRowNim
’s interface is defined in terms of its public methods, which constrain the way users can interact with OneRowNim
objects. This ensures that OneRowNim
instances remain in a valid state.OneRowNim
class has some obvious shortcomings that are a result of our decision to limit methods to those without parameters or return values. These shortcomings include:OneRowNim
has no way communicate how many sticks remain or whose turn it is, other than by writing a report to the console.takeOne()
, takeTwo()
and takeThree()
methods all have similar definitions. It would be a better design a single method that could take away a specified number of sticks.OneRowNim
game, a user interface class would need to be developed that would allow the user to receive information about the state of the game and to input moves to make.OneRowNim
class to address these shortcomings.