6: Inheritance & Algorithms
We introduce our first complex algorithms and start to pull back the scaffolding a bit. Students will get their first real experience designing aggregate objects with encapsulated properties.

Learning Targets

    I can secure my class variables with encapsulation.
    I can create a constructor to initialize an object.
    I can override a parent method.
    I can build unit tests for all methods in an aggregate object.

Inheritance

Keep it DRY and OOP-y
DRY stands for Don't Repeat Yourself. So far, that's meant that if you need to repeat a bit of code, you make a loop instead of sloppily copying and pasting the same commands a few times. Now we're seeing that OOP, or Object-Oriented Programming, has was to build classes off of one another. That means we can avoid repeating (aka DRY code) by using inheritance.

Abstract Classes

Polymorphism Practice

Polymorphism is my favorite CS term because it sounds so much fancier than it really is (sort of a theme here). In class we'll build an abstract class called Shape with some encaspulated instance variables like length and width, abstract methods like .area(). Then we'll inherit from those methods when we create types of shapes like Circle, Rectangle, Triangle and so on. Let's look closer at why this is an example of inheritance and polymorphism.

Why this is smart, object-oriented programming

Creating a parent class called Shape that all your shapes will inherit means that the common properties and functions can live in one place. If new features or changes needed to happen across all the elements in your app, you would have a logical place to check.

But why do we declare abstract methods?

Let's take a look at a shortened Shape class:
1
class Shape {
2
3
// a single example encaspulated instance variable
4
private float length;
5
6
// accessor method
7
public float length(){
8
// using this. is not required but helpful when writing
9
return this.length;
10
11
// mutator method
12
public void length(float length){
13
// now using this. is required to tell the local and instance var apart
14
this.length = length;
15
16
// example abstract method. Each shape will need to make or "implement"
17
pubilc abstract float area();
18
19
}
Copied!
All the encapsulation shown between lines 3 - 14 should be familiar by now. Seek additional practice including your teacher's office hours if not. The cool new thing here is line 17. Because the parent is declaring this method, all its children (i.e class Circle extends Shape { )will have to build their own area method. The Circle class will return 3.14 * (length * length); for its area() implementation.

So how exactly is this business "polymorphic?"

Because all of my app's shapes will have a common parent, I can create a collection of Shape like: ArrayList<Shape> myShapes = new ArrayList<>();
That allows me to to loop through the whole collection and report out their areas:
1
for (Shape x : myShapes) {
2
System.out.println("This shape's area is: " + x.area() + " cm2");
3
}
Copied!

Multiple Inheritance?

What if I wanted to build a huge space game with thousands of types of ships. I'd make rules for cargo ships and warships. There may be times when I want multiple inheritances to be applied. Well there are some limits here in Java. You can have multiple vertical levels, like Ship --> Warship --> Battleship but a single ship can't inherit from two places simultaneously. Instead, there are Interfaces.

Elevens

AP_CompSciA_Elevens_Lab_Student_Guide.pdf
538KB
PDF
Elevens Lab Student Guide

Elevens 1

    1.
    Create a new Java project in your IDE (Netbeans, most likely)
    2.
    Add it to GitHub
    3.
    Add the two new classes below
CardTester.java
Card.java
1
/**
2
* This is a class that tests the Card class.
3
*/
4
public class CardTester {
5
6
/**
7
* The main method in this class checks the Card operations for consistency.
8
* @param args is not used.
9
*/
10
public static void main(String[] args) {
11
/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
12
}
13
}
Copied!
1
/**
2
* Card.java
3
*
4
* <code>Card</code> represents a playing card.
5
*/
6
public class Card {
7
8
/**
9
* String value that holds the suit of the card
10
*/
11
private String suit;
12
13
/**
14
* String value that holds the rank of the card
15
*/
16
private String rank;
17
18
/**
19
* int value that holds the point value.
20
*/
21
private int pointValue;
22
23
24
/**
25
* Creates a new <code>Card</code> instance.
26
*
27
* @param cardRank a <code>String</code> value
28
* containing the rank of the card
29
* @param cardSuit a <code>String</code> value
30
* containing the suit of the card
31
* @param cardPointValue an <code>int</code> value
32
* containing the point value of the card
33
*/
34
public Card(String cardRank, String cardSuit, int cardPointValue) {
35
/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
36
}
37
38
39
/**
40
* Accesses this <code>Card's</code> suit.
41
* @return this <code>Card's</code> suit.
42
*/
43
public String suit() {
44
/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
45
}
46
47
/**
48
* Accesses this <code>Card's</code> rank.
49
* @return this <code>Card's</code> rank.
50
*/
51
public String rank() {
52
/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
53
}
54
55
/**
56
* Accesses this <code>Card's</code> point value.
57
* @return this <code>Card's</code> point value.
58
*/
59
public int pointValue() {
60
/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
61
}
62
63
/** Compare this card with the argument.
64
* @param otherCard the other card to compare to this
65
* @return true if the rank, suit, and point value of this card
66
* are equal to those of the argument;
67
* false otherwise.
68
*/
69
public boolean matches(Card otherCard) {
70
/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
71
}
72
73
/**
74
* Converts the rank, suit, and point value into a string in the format
75
* "[Rank] of [Suit] (point value = [PointValue])".
76
* This provides a useful way of printing the contents
77
* of a <code>Deck</code> in an easily readable format or performing
78
* other similar functions.
79
*
80
* @return a <code>String</code> containing the rank, suit,
81
* and point value of the card.
82
*/
83
@Override
84
public String toString() {
85
/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
86
}
87
}
Copied!

Elevens 2

DeckTester.java
Deck.java
1
/**
2
* This is a class that tests the Deck class.
3
*/
4
public class DeckTester {
5
6
/**
7
* The main method in this class checks the Deck operations for consistency.
8
* @param args is not used.
9
*/
10
public static void main(String[] args) {
11
/* *** TO BE IMPLEMENTED IN ACTIVITY 2 *** */
12
}
13
}
Copied!
1
import java.util.List;
2
import java.util.ArrayList;
3
4
/**
5
* The Deck class represents a shuffled deck of cards.
6
* It provides several operations including
7
* initialize, shuffle, deal, and check if empty.
8
*/
9
public class Deck {
10
11
/**
12
* cards contains all the cards in the deck.
13
*/
14
private List<Card> cards;
15
16
/**
17
* size is the number of not-yet-dealt cards.
18
* Cards are dealt from the top (highest index) down.
19
* The next card to be dealt is at size - 1.
20
*/
21
private int size;
22
23
24
/**
25
* Creates a new <code>Deck</code> instance.<BR>
26
* It pairs each element of ranks with each element of suits,
27
* and produces one of the corresponding card.
28
* @param ranks is an array containing all of the card ranks.
29
* @param suits is an array containing all of the card suits.
30
* @param values is an array containing all of the card point values.
31
*/
32
public Deck(String[] ranks, String[] suits, int[] values) {
33
cards = new ArrayList<Card>();
34
for (int j = 0; j < ranks.length; j++) {
35
for (String suitString : suits){
36
cards.add(new Card(ranks[j], suitString, values[j]));
37
}
38
}
39
40
41
/**
42
* Determines if this deck is empty (no undealt cards).
43
* @return true if this deck is empty, false otherwise.
44
*/
45
public boolean isEmpty() {
46
/* *** TO BE IMPLEMENTED IN ACTIVITY 2 *** */
47
}
48
49
/**
50
* Accesses the number of undealt cards in this deck.
51
* @return the number of undealt cards in this deck.
52
*/
53
public int size() {
54
/* *** TO BE IMPLEMENTED IN ACTIVITY 2 *** */
55
}
56
57
/**
58
* Randomly permute the given collection of cards
59
* and reset the size to represent the entire deck.
60
*/
61
public void shuffle() {
62
/* *** TO BE IMPLEMENTED IN ACTIVITY 4 *** */
63
}
64
65
/**
66
* Deals a card from this deck.
67
* @return the card just dealt, or null if all the cards have been
68
* previously dealt.
69
*/
70
public Card deal() {
71
/* *** TO BE IMPLEMENTED IN ACTIVITY 2 *** */
72
// IS EMPTY if so return null
73
size--;
74
Card c = cards.get(size);
75
return c;
76
}
77
78
/**
79
* Generates and returns a string representation of this deck.
80
* @return a string representation of this deck.
81
*/
82
@Override
83
public String toString() {
84
String rtn = "size = " + size + "\nUndealt cards: \n";
85
86
for (int k = size - 1; k >= 0; k--) {
87
rtn = rtn + cards.get(k);
88
if (k != 0) {
89
rtn = rtn + ", ";
90
}
91
if ((size - k) % 2 == 0) {
92
// Insert carriage returns so entire deck is visible on console.
93
rtn = rtn + "\n";
94
}
95
}
96
97
rtn = rtn + "\nDealt cards: \n";
98
for (int k = cards.size() - 1; k >= size; k--) {
99
rtn = rtn + cards.get(k);
100
if (k != size) {
101
rtn = rtn + ", ";
102
}
103
if ((k - cards.size()) % 2 == 0) {
104
// Insert carriage returns so entire deck is visible on console.
105
rtn = rtn + "\n";
106
}
107
}
108
109
rtn = rtn + "\n";
110
return rtn;
111
}
112
}
113
Copied!

Elevens 3: Shuffling Algorithm

This algorithm uses a lot of structures we'll see when we have to start sorting items rather than shuffling. The problem with a perfect shuffle is that after 4 passes, all the cards are back in the original order.
Shuffler.java
1
/**
2
* This class provides a convenient way to test shuffling methods.
3
*/
4
public class Shuffler {
5
6
/**
7
* The number of consecutive shuffle steps to be performed in each call
8
* to each sorting procedure.
9
*/
10
private static final int SHUFFLE_COUNT = 1;
11
12
/**
13
* Tests shuffling methods.
14
* @param args is not used.
15
*/
16
public static void main(String[] args) {
17
System.out.println("Results of " + SHUFFLE_COUNT +
18
" consecutive perfect shuffles:");
19
int[] values1 = {0, 1, 2, 3};
20
for (int j = 1; j <= SHUFFLE_COUNT; j++) {
21
perfectShuffle(values1);
22
System.out.print(" " + j + ":");
23
for (int k = 0; k < values1.length; k++) {
24
System.out.print(" " + values1[k]);
25
}
26
System.out.println();
27
}
28
System.out.println();
29
30
System.out.println("Results of " + SHUFFLE_COUNT +
31
" consecutive efficient selection shuffles:");
32
int[] values2 = {0, 1, 2, 3};
33
for (int j = 1; j <= SHUFFLE_COUNT; j++) {
34
selectionShuffle(values2);
35
System.out.print(" " + j + ":");
36
for (int k = 0; k < values2.length; k++) {
37
System.out.print(" " + values2[k]);
38
}
39
System.out.println();
40
}
41
System.out.println();
42
}
43
44
45
/**
46
* Apply a "perfect shuffle" to the argument.
47
* The perfect shuffle algorithm splits the deck in half, then interleaves
48
* the cards in one half with the cards in the other.
49
* @param values is an array of integers simulating cards to be shuffled.
50
*/
51
public static void perfectShuffle(int[] values) {
52
/* *** TO BE IMPLEMENTED IN ACTIVITY 3 *** */
53
}
54
55
/**
56
* Apply an "efficient selection shuffle" to the argument.
57
* The selection shuffle algorithm conceptually maintains two sequences
58
* of cards: the selected cards (initially empty) and the not-yet-selected
59
* cards (initially the entire deck). It repeatedly does the following until
60
* all cards have been selected: randomly remove a card from those not yet
61
* selected and add it to the selected cards.
62
* An efficient version of this algorithm makes use of arrays to avoid
63
* searching for an as-yet-unselected card.
64
* @param values is an array of integers simulating cards to be shuffled.
65
*/
66
public static void selectionShuffle(int[] values) {
67
/* *** TO BE IMPLEMENTED IN ACTIVITY 3 *** */
68
}
69
}
Copied!
https://youtu.be/tUp0objubs4
youtu.be

Elevens 7

Board.java
ElevensBoard.java
1
import java.util.List;
2
import java.util.ArrayList;
3
4
/**
5
* This class represents a Board that can be used in a collection
6
* of solitaire games similar to Elevens. The variants differ in
7
* card removal and the board size.
8
*/
9
public abstract class Board {
10
11
/**
12
* The cards on this board.
13
*/
14
private Card[] cards;
15
16
/**
17
* The deck of cards being used to play the current game.
18
*/
19
private Deck deck;
20
21
/**
22
* Flag used to control debugging print statements.
23
*/
24
private static final boolean I_AM_DEBUGGING = false;
25
26
/**
27
* Creates a new <code>Board</code> instance.
28
* @param size the number of cards in the board
29
* @param ranks the names of the card ranks needed to create the deck
30
* @param suits the names of the card suits needed to create the deck
31
* @param pointValues the integer values of the cards needed to create
32
* the deck
33
*/
34
public Board(int size, String[] ranks, String[] suits, int[] pointValues) {
35
cards = new Card[size];
36
deck = new Deck(ranks, suits, pointValues);
37
if (I_AM_DEBUGGING) {
38
System.out.println(deck);
39
System.out.println("----------");
40
}
41
dealMyCards();
42
}
43
44
/**
45
* Start a new game by shuffling the deck and
46
* dealing some cards to this board.
47
*/
48
public void newGame() {
49
deck.shuffle();
50
dealMyCards();
51
}
52
53
/**
54
* Accesses the size of the board.
55
* Note that this is not the number of cards it contains,
56
* which will be smaller near the end of a winning game.
57
* @return the size of the board
58
*/
59
public int size() {
60
return cards.length;
61
}
62
63
/**
64
* Determines if the board is empty (has no cards).
65
* @return true if this board is empty; false otherwise.
66
*/
67
public boolean isEmpty() {
68
for (int k = 0; k < cards.length; k++) {
69
if (cards[k] != null) {
70
return false;
71
}
72
}
73
return true;
74
}
75
76
/**
77
* Deal a card to the kth position in this board.
78
* If the deck is empty, the kth card is set to null.
79
* @param k the index of the card to be dealt.
80
*/
81
public void deal(int k) {
82
cards[k] = deck.deal();
83
}
84
85
/**
86
* Accesses the deck's size.
87
* @return the number of undealt cards left in the deck.
88
*/
89
public int deckSize() {
90
return deck.size();
91
}
92
93
/**
94
* Accesses a card on the board.
95
* @return the card at position k on the board.
96
* @param k is the board position of the card to return.
97
*/
98
public Card cardAt(int k) {
99
return cards[k];
100
}
101
102
/**
103
* Replaces selected cards on the board by dealing new cards.
104
* @param selectedCards is a list of the indices of the
105
* cards to be replaced.
106
*/
107
public void replaceSelectedCards(List<Integer> selectedCards) {
108
for (Integer k : selectedCards) {
109
deal(k.intValue());
110
}
111
}
112
113
/**
114
* Gets the indexes of the actual (non-null) cards on the board.
115
*
116
* @return a List that contains the locations (indexes)
117
* of the non-null entries on the board.
118
*/
119
public List<Integer> cardIndexes() {
120
List<Integer> selected = new ArrayList<Integer>();
121
for (int k = 0; k < cards.length; k++) {
122
if (cards[k] != null) {
123
selected.add(new Integer(k));
124
}
125
}
126
return selected;
127
}
128
129
/**
130
* Generates and returns a string representation of this board.
131
* @return the string version of this board.
132
*/
133
public String toString() {
134
String s = "";
135
for (int k = 0; k < cards.length; k++) {
136
s = s + k + ": " + cards[k] + "\n";
137
}
138
return s;
139
}
140
141
/**
142
* Determine whether or not the game has been won,
143
* i.e. neither the board nor the deck has any more cards.
144
* @return true when the current game has been won;
145
* false otherwise.
146
*/
147
public boolean gameIsWon() {
148
if (deck.isEmpty()) {
149
for (Card c : cards) {
150
if (c != null) {
151
return false;
152
}
153
}
154
return true;
155
}
156
return false;
157
}
158
159
/**
160
* Method to be completed by the concrete class that determines
161
* if the selected cards form a valid group for removal.
162
* @param selectedCards the list of the indices of the selected cards.
163
* @return true if the selected cards form a valid group for removal;
164
* false otherwise.
165
*/
166
public abstract boolean isLegal(List<Integer> selectedCards);
167
168
/**
169
* Method to be completed by the concrete class that determines
170
* if there are any legal plays left on the board.
171
* @return true if there is a legal play left on the board;
172
* false otherwise.
173
*/
174
public abstract boolean anotherPlayIsPossible();
175
176
/**
177
* Deal cards to this board to start the game.
178
*/
179
private void dealMyCards() {
180
for (int k = 0; k < cards.length; k++) {
181
cards[k] = deck.deal();
182
}
183
}
184
}
185
Copied!
1
import java.util.List;
2
import java.util.ArrayList;
3
4
/**
5
* The ElevensBoard class represents the board in a game of Elevens.
6
*/
7
public class ElevensBoard {
8
9
/**
10
* The size (number of cards) on the board.
11
*/
12
private static final int BOARD_SIZE = 9;
13
14
/**
15
* The ranks of the cards for this game to be sent to the deck.
16
*/
17
private static final String[] RANKS =
18
{"ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "jack", "queen", "king"};
19
20
/**
21
* The suits of the cards for this game to be sent to the deck.
22
*/
23
private static final String[] SUITS =
24
{"spades", "hearts", "diamonds", "clubs"};
25
26
/**
27
* The values of the cards for this game to be sent to the deck.
28
*/
29
private static final int[] POINT_VALUES =
30
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0};
31
32
33
/**
34
* The cards on this board.
35
*/
36
private Card[] cards;
37
38
/**
39
* The deck of cards being used to play the current game.
40
*/
41
private Deck deck;
42
43
/**
44
* Flag used to control debugging print statements.
45
*/
46
private static final boolean I_AM_DEBUGGING = false;
47
48
49
/**
50
* Creates a new <code>ElevensBoard</code> instance.
51
*/
52
public ElevensBoard() {
53
cards = new Card[BOARD_SIZE];
54
deck = new Deck(RANKS, SUITS, POINT_VALUES);
55
if (I_AM_DEBUGGING) {
56
System.out.println(deck);
57
System.out.println("----------");
58
}
59
dealMyCards();
60
}
61
62
/**
63
* Start a new game by shuffling the deck and
64
* dealing some cards to this board.
65
*/
66
public void newGame() {
67
deck.shuffle();
68
dealMyCards();
69
}
70
71
/**
72
* Accesses the size of the board.
73
* Note that this is not the number of cards it contains,
74
* which will be smaller near the end of a winning game.
75
* @return the size of the board
76
*/
77
public int size() {
78
return cards.length;
79
}
80
81
/**
82
* Determines if the board is empty (has no cards).
83
* @return true if this board is empty; false otherwise.
84
*/
85
public boolean isEmpty() {
86
for (int k = 0; k < cards.length; k++) {
87
if (cards[k] != null) {
88
return false;
89
}
90
}
91
return true;
92
}
93
94
/**
95
* Deal a card to the kth position in this board.
96
* If the deck is empty, the kth card is set to null.
97
* @param k the index of the card to be dealt.
98
*/
99
public void deal(int k) {
100
cards[k] = deck.deal();
101
}
102
103
/**
104
* Accesses the deck's size.
105
* @return the number of undealt cards left in the deck.
106
*/
107
public int deckSize() {
108
return deck.size();
109
}
110
111
/**
112
* Accesses a card on the board.
113
* @return the card at position k on the board.
114
* @param k is the board position of the card to return.
115
*/
116
public Card cardAt(int k) {
117
return cards[k];
118
}
119
120
/**
121
* Replaces selected cards on the board by dealing new cards.
122
* @param selectedCards is a list of the indices of the
123
* cards to be replaced.
124
*/
125
public void replaceSelectedCards(List<Integer> selectedCards) {
126
for (Integer k : selectedCards) {
127
deal(k.intValue());
128
}
129
}
130
131
/**
132
* Gets the indexes of the actual (non-null) cards on the board.
133
*
134
* @return a List that contains the locations (indexes)
135
* of the non-null entries on the board.
136
*/
137
public List<Integer> cardIndexes() {
138
List<Integer> selected = new ArrayList<Integer>();
139
for (int k = 0; k < cards.length; k++) {
140
if (cards[k] != null) {
141
selected.add(new Integer(k));
142
}
143
}
144
return selected;
145
}
146
147
/**
148
* Generates and returns a string representation of this board.
149
* @return the string version of this board.
150
*/
151
public String toString() {
152
String s = "";
153
for (int k = 0; k < cards.length; k++) {
154
s = s + k + ": " + cards[k] + "\n";
155
}
156
return s;
157
}
158
159
/**
160
* Determine whether or not the game has been won,
161
* i.e. neither the board nor the deck has any more cards.
162
* @return true when the current game has been won;
163
* false otherwise.