|
In lesson 3, a simple class called "Card" was constructed. In this lesson, the "Card" class is extended to form the "Cards" class. In addition, a simple class named "RunInfo" is built for scoring runs in the game of Color Belot. The code for these classes is located in "Cards.java" and "RunInfo.java" respectively. Cards class Locate the first line of the file. This is the class declaration line. In this example, the name of the class is "Cards" and it will use the "BelotConstants" interface. The final two lines of the file preceding the closing right brace are the data fields of the "Cards" class. There is a field called "deck" that is an array representing the deck of cards and an integer variable named "currentPosition" that indicates the position in "deck" that is currently being referenced. Locate the "Cards" constructor following the opening left brace of the class. The data field "currentPosition" is set to zero. Then the "new" method is invoked to create an array containing 28 (the number of cards needed to play Color Belot) cards. Initially, each slot in the array contains a null pointer. Later on in the constructor, these null pointers will be made to point to individual "Card"s. The next two lines introduce two local variables, whose scope only endures between their encapsulating braces. The purpose of "cardNumber" is to keep track of where in "deck" the next card goes. The purpose of "cardIndex" is to give each generated card a number that can be used for sorting and comparison purposes by other methods. The remainder of the constructor is encapsulated in two nested "for" loops, a Java programming language construct that has heretofore not been encountered. The purpose of these two loops is to go through all possible combinations of suits and ranks needed for Color Belot and to construct one card representing each combination. Let's dissect the outer "for" loop. The "int s = CLUBS" declares a local loop variable named s and gives it the initial value of the constant CLUBS. Semicolons serve as separators. The "s <= SPADES" is the exit condition. The body of the loop is executed, providing that this test evaluates to true. If it evaluates to false, the loop is terminated. Finally, "s++" shows how the loop variable is updated after the completion of the body of the loop. In this case, it is incremented by one. The inner loop works in a similar fashion. Would you like to learn more about iterative constructs? The body of the loop takes care of constructing new cards and keeping track of the bookkeeping variables. POTENTIAL PITFALL: Notice that the "new" method is used with the "Card" class twice in this method. When the array of "Card" objects is first created, the effect is to create an array of pointers that point to nothing (null) but can potentially point to "Card" objects. Inside the nested loops, a "new Card" object must be explicitly created so that the "Card" pointer can point to this object instead of nothing. In Java, the programmer must explicitly "new" every object. In this case there are two objects: the array object and the "Card" object. Thus, two "new"s are needed. Locate the "assignValues" method. The purpose of this procedure is to determine the scoring value of a card after trump has been called. (Recall that the values of nines and jacks change depending on whether they are in the trump suit.) The most interesting aspect of this method is to notice that a "Card" object can be referenced through "deck[i]". Once a "Card" object is produced, one of its methods (such as "updateValue") can be called using the standard period syntax. Locate the "getNextCard" method. This function returns the "Card" that is at the top of the deck and updates the deck of cards so that a new "Card" is now at the top. The method "showNextCard" is even simpler. It merely returns the "Card" at the top of the deck while keeping that "Card" in the top position. Locate the "shuffle" method. The purpose of this procedure is to simulate shuffling the deck of Belot Cards. The procedure accomplishes the shuffle by going through each position in the deck of cards. For each position, a second position is randomly chosen and the "Card" objects in the two positions are swapped. There are two interesting Java features to notice in this routine. First, notice "deck.length" in the loop exit condition of the for loop. All array objects have a built in "length" method that returns the number of slots that the array contains. This is a very useful method for building general code. Second, notice the line that includes "(int) (Math.random() * deck.length)". "Math" is the name of a Java library that includes many useful built in methods. The "random" method returns a floating point number in the range starting with 0.0 and going up to, but not including 1.0. When this number is multiplied by the length of the deck and converted to an integer via "(int)", a number between 0 and 27 is produced and then can be used for swapping two "Card" objects. Locate the "print" method. The reader is encouraged to figure out this routine on his or her own. RunInfo Class Now it is time to turn our attention to "RunInfo.java". The purpose of the "RunInfo" class is to figure out which player has a better run (three in a row, four in a row, etc.) and how much that run is worth. The class definition is the first line of the file and once again uses the constants from the "BelotConstants" interface. Preceding the closing right brace of the class are the two data fields needed by the "RunInfo" class. The "howMany" integer indicates how many cards are in the player's longest run. The "topCard" is the highest card (using regular card ordering, not Belot card ordering) in that run. Following the opening left brace of the class are two constructors named "RunInfo". This is an example of overloading. The "RunInfo" constructor can either be called with no arguments or with an "integer" and a "Card". Locate the "calculateValue" method. This function returns the value of the run using a nested if construct. Locate the "betterThan" method. This function returns "true" if the current run that called the method is better than the one passed in and "false" otherwise. The logic of this method is a little tricky. Since a run must contain three or more cards to count, if the run has two or less cards in it, a "false" can safely be returned. Otherwise the lengths of the two runs are compared. If the run that called the method has more cards in it than the run passed in, "true" is returned. If the runs have equal lengths, but the top card of the run that called the method is higher than the top card of the other run, a "true" is returned. If the two top cards are the same, but the run that called the method is in trump and the other run is not, a "true" is returned. Otherwise, a "false" is returned. Locate the "print" method. This method should be readily understood. That concludes today's lesson. Before moving on, take another look at both the classes that were introduced and make sure that you understand the big picture. |