Chapter 7
<< Chapter 6 | HomeworkTrailIndex | Chapter 8 >>
Arrays
Demos
In class we will make Arrays and ArrayLists (with and without autoboxing) of Simple datatypes and Objects, like Cards (see the War Card gameProject).
Finally, try to make Deck of Cards which we can draw from to simulate a Texas-Hold-Em poker game.
See the Card Class video Part 1
See Card Class Video 2 (Test Unit)
Card.java
package poker; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Rectangle; /** * class Card here represents a playing card * * @author Chris Thiel * @version 28 Sept 2008 */ public class Card { //some handy constants public static final int SPADES=3; public static final int HEARTS=2; public static final int DIAMONDS=1; public static final int CLUBS=0; /** * suitName is an array contains the name of the Suit * so that the index matches the suit number */ public static final String[] suitName={"Clubs","Diamonds","Hearts","Spades" }; /** * suitSymbol Have the unicode values to print the correct symbol, * arranges so thet the index matches the suit number */ public static final String[] suitSymbol={"\u2663", "\u2666","\u2665","\u2660"}; /** * pipName is an array that contains the name of the card's pips * so that the index matches the number of the card. * For example pipName[1] has a "Ace" */ public static final String[] pipName={"-","Ace","2","3","4","5","6","7","8","9","10", "Jack","Queen","King"}; // instance variables - or Card Attributes /** * suit contains the suit (0 to 3) */ private int suit; /** * pips contains the number of pips of the card (1-13) * Ace is 1 and 13 is King */ private int pips; /** * faceUp is true is the card is exposed * and false otherwise. */ private boolean faceUp; /** * Default Constructor for objects of class Card * is a random card of a random suit */ public Card() { // The default card is randomly chosen suit = (int)(Math.random()*4); pips = 1+(int)(Math.random()*13); faceUp=false; } /** * A Card can be constructed with a determined * number of pips (and integer 1-13) * and suit (an integer from 0-3) */ public Card(int p, int s) { if (s>=0 && s<4) suit = s; if (p>0 && p<14) pips = p; faceUp=false; } /** * A Card can be constructed with a determined * number of pips (a String "Ace" to "King") * and suit (a String "Clubs" to "Spades") */ public Card(String p, String s) { suit = indexOf(suitName, s); pips = indexOf(pipName, p); faceUp=false; } /** * indexOf returns the index of the String s * in the String Array a * (it returns -1 if not found). This method * ignores case. */ public int indexOf(String[] a, String s) { int idx=-1; for (int i=0; i< a.length; i++) if (a[i].toLowerCase().equals(s.toLowerCase())) idx=i; return idx; } /** * @return getSuit returns the Card's suit, * an int from 0 to 3 */ public int getSuit() { return suit; } /** * setSuit changes the Card's suit, * @param the suit 0 to 3. You can use the * predefined integer constants * SPADES, HEARTS, DIAMONDS and CLUBS * from the Card class. */ public void setSuit(int s) { if (s>=0 && s<4) suit=s; } /** * @return getPips returns the Card's pips, * an int from 1 to 13 where an Ace is a 1 * and a King is a 13. */ public int getPips() { // put your code here return pips; } /** * setPips changes the Card's pips, * @param the pips are an integer from 1 to 13, * where 1 is an Ace and 13 is a King. */ public void setPips(int p) { // put your code here if (p>0 && p<14) pips=p; } /** * @return getSuit returns the Card's suit, * an int from 0 to 3 */ public int getValue() { if (pips>9) return 10; return pips; } /** * Two cards are equal if they have * the same number of pips. The suit is ignored * with this comparison * * @return true if they match the number of pips */ public boolean equals(Card c) { if (c.getPips()==pips) return true; return false; } /** * toString will return the contents of the card * in a string format * @return The pips and suit of a card */ public String toString() { return pipName[pips]+" of "+suitName[suit]; } /** * info will return the contents of the card * in a short two character string * @return The pips and suit of a card */ public String info() { if (pips==10) return pipName[pips].substring(0,2)+suitSymbol[suit]; return pipName[pips].substring(0,1)+suitSymbol[suit]; } /** * comparePips will return the difference between * two cards' number of pips. The suit is ignored * with this comparison. Here the ace is low. * If the two cards happen to have the same * number of pips, it returns the integer 0. * * If, for example, * card1 is a 2 of clubs and card2 is a 6 of spades, * then card1.comparePips(card2) returns -4, since * card1 has four less pips than card2. * * @return the difference between number of pips */ public int comparePips( Card c ) { return pips-c.getPips(); } /** * comparePipsAceHigh will return the difference between * two cards' number of pips, Ace High. The suit is ignored * with this comparison, but the Ace is above a King. * If the two cards happen to have the same * number of pips, it returns the integer 0. * * If, for example, * card1 is an ace of clubs and card2 is a queen of spades, * then card1.comparePips(card2) returns 2, since * card1 is two larger than card2. * * @return the difference between number of pips */ public int comparePipsAceHigh( Card c ) { // This needs to be be implemented int myPips=pips; int theirPips=c.getPips(); if (myPips==1) myPips=14; if (theirPips==1) theirPips=14; return myPips-theirPips; } /** * isLessThan will compare two cards by pips, and in case of * a match, will compare the suit. If the number * of pips match, then the higher suit is considered. * * The the order of the suits * (from high to low) is SPADES, HEARTS, DIAMONDS, CLUBS * * The Ace is low, and is considered to be below a 2. * * If the two cards happen to have the same * number of pips, it then compares the suit returns the integer 0. * * If, for example, * card1 is an ace of clubs and card2 is a 2 of spades, * then card1.comparePips(card2) returns true, since * card1 is less than card2. * * If card1 is a 6 of hearts and card2 is a 6 of clubs, * than card1.isLessThan(card2) returns false, * since hearts is greater than clubs * * @return the difference between number of pips */ public boolean isLessThan( Card c ) { if (pips>c.getPips()) return false; if (pips<c.getPips()) return true; //if we got this far, its the same number of pips if (suit <c.getSuit()) return true; // if we got this far, it must have same suit or more return false; } public boolean isLessThanAceHigh( Card c ) { int myPips=pips; int theirPips=c.getPips(); if (myPips==1) myPips=14; if (theirPips==1) theirPips=14; if (myPips>theirPips) return false; if (myPips<theirPips) return true; //if we got this far, its the same number of pips if (suit <c.getSuit()) return true; // if we got this far, it must have same suit or more return false; } public void turnUp(){ faceUp=true; } public void turnDown(){ faceUp=false; } public void turnOver(){ faceUp=!faceUp; } public boolean isFaceUp(){ return faceUp; } public void draw(Graphics g, int x, int y){ g.setColor(Color.WHITE); Rectangle loc=new Rectangle(x,y,60,80); if (faceUp){ g.setFont(new Font("Helvetica", Font.BOLD, 20)); g.setColor(Color.WHITE); g.fillRect(loc.x,loc.y,loc.width,loc.height); g.setColor(Color.BLACK); g.drawRect(loc.x,loc.y,loc.width,loc.height); if (suit>0 && suit<3) g.setColor(Color.RED); g.drawString(this.info(), loc.x+8,loc.y+23); } else { g.setColor(Color.BLUE); g.fillRect(loc.x,loc.y,loc.width,loc.height); g.setColor(Color.BLACK); g.drawRect(loc.x,loc.y,loc.width,loc.height); g.setColor(Color.WHITE); for (int i=2; i<25; i+=5) g.drawRoundRect(loc.x+i, loc.y+i, loc.width-i*2, loc.height-i*2, i, i); } } }
TexasApplet.java
package poker; import java.applet.Applet; import java.awt.Color; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; public class TexasApplet extends Applet implements MouseListener { Card c; public void init() { c= new Card("Ace", "Hearts"); addMouseListener(this); } public void paint(Graphics g) { g.setColor(Color.white); g.fillRect(0, 0, 600, 400); g.setColor(Color.black); g.drawString("Texas Hold-Em", 20, 20); g.setColor(Color.blue); g.drawString("created by BlueJ", 20, 40); c.draw(g, 120, 100); } public void mouseClicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { int x=e.getX(); int y=e.getY(); c.turnOver(); repaint(); } }
Review Exercises
- R7.2. Write a program that contains a bounds error. Run the program. What happens on your computer? How does the error message help you locate the error?
- R7.3. Write Java code for a loop that simultaneously computes the maximum and minimum values of an array list. Use an array list of accounts as an example.
- R7.4. Write a loop that reads 10 strings and inserts them into an array list. Write a second loop that prints out the strings in the opposite order from which they were entered.
- R7.6. Consider another variation of the algorithm for determining the maximum value. Here, we compute the maximum value of an array of numbers.
double max = 0; // Contains an error! for (x : values) { if (x > max) max = x; }
However, this approach contains a subtle error. What is the error, and how can you fix it?
- R7.7. For each of the following sets of values, write code that fills an array a with the values.
To help you get started, here is some "starter code" that will make an array a
, fill it with 0
's and print the contents of a
public class ArrayExperimenting { public static void main(String[] args) { int [] a = new int[10]; for (int i=0; i<10; i++) { a[i]=0; } System.out.println("Contents of a:"); for (int element:a) System.out.print(element); System.out.println(); } }
(a) 1 2 3 4 5 6 7 8 9 10 (b) 0 2 4 6 8 10 12 14 16 18 20 (c) 1 4 9 16 25 36 49 64 81 100 (d) 0 0 0 0 0 0 0 0 0 0 (e) 1 4 9 16 9 7 4 9 11
Use a loop when appropriate.
- R7.9. What is wrong with the following loop?
double[] data = new double[10]; for (int i = 1; i <= 10; i++ ) data[i] = i * i;
Explain two ways of fixing the error.
- R7.16. How do you perform the following tasks with arrays in Java?
(a) Test that two arrays contain the same elements in the same order (b) Copy one array to another (c) Fill an array with zeroes, overwriting all elements in it (d) Remove all elements from an array list
- R7.18. True or false?
(a) A method cannot return a two-dimensional array. (b) A method can change the length of an array parameter. (c) A method can change the length of an array list that is passed as a parameter. (d) An array list can hold values of any type.
- R7.19. Define the terms regression testing and test suite.
- R7.20. What is the debugging phenomenon known as cycling? What can you do to avoid it?
Programming Exercises
For 8 points do three, for 9 do four and for 10 do all. It makes sense to do them in order, as each one builds upon the Purse
class done in the previous problem.
- P7.2. Implement a class
Purse
. Apurse
contains a collection of coins. For simplicity, we will only store the coin names in anArrayList<String>
. (We will discuss a better representation in Chapter 8.) Supply a method
void addCoin(String coinName)
Add a method toString
to the Purse
class that prints the coins in the purse in the format
Purse[Quarter,Dime,Nickel,Dime]
Use the following class in your solution:
import java.util.ArrayList; /** A purse holds a collection of coins. */ public class Purse { /** Constructs an empty purse. */ public Purse() { coins = new ArrayList<String>(); } /** Adds a coin to the purse. @param coinName the coin to add */ public void addCoin(String coinName) { . . . } /** Returns a string describing the object. @return a string in the format "Purse[coinName1,coinName2,...]" */ public String toString() { . . . } private ArrayList<String> coins; }
Use the following class as your tester class:
/** This class tests the Purse class. */ public class PurseTester { public static void main(String[] args) { Purse p = new Purse(); p.addCoin("Quarter"); p.addCoin("Dime"); p.addCoin("Nickel"); p.addCoin("Dime"); System.out.println(p.toString()); System.out.println("Expected: Purse[Quarter,Dime,Nickel,Dime]"); } }
- P7.3. Write a method
reverse
that reverses the sequence of coins in a purse. Use thetoString
method of the preceding assignment to test your code. For example, ifreverse
is called with a purse
Purse[Quarter,Dime,Nickel,Dime]
then the purse is changed to
Purse[Dime,Nickel,Dime,Quarter]
Use the following class in your solution:
import java.util.ArrayList; /** A purse holds a collection of coins. */ public class Purse { /** Constructs an empty purse. */ public Purse() { coins = new ArrayList<String>(); } /** Adds a coin to the purse. @param coinName the coin to add */ public void addCoin(String coinName) { . . . } /** Returns a string describing the object. @return a string in the format "Purse[coinName1,coinName2,...]" */ public String toString() { . . . } /** Reverses the elements in the purse. */ public void reverse() { . . . } private ArrayList<String> coins; }
Use the following class as your tester class:
/** This class tests the Purse class. */ public class PurseTester { public static void main(String[] args) { Purse p = new Purse(); p.addCoin("Quarter"); p.addCoin("Dime"); p.addCoin("Nickel"); p.addCoin("Dime"); System.out.println("Original purse: " + p.toString()); System.out.println("Expected: Purse[Quarter,Dime,Nickel,Dime]"); p.reverse(); System.out.println("Reversed purse: " + p.toString()); System.out.println("Expected: Purse[Dime,Nickel,Dime,Quarter]"); } }
- P7.4. Add a method
public void transfer(Purse other)
that transfers the contents of one purse to another. For example, if a
is
Purse[Quarter,Dime,Nickel,Dime]
and b
is
Purse[Dime,Nickel]
then after the call a.transfer(b), a is Purse[Quarter,Dime,Nickel,Dime,Dime,Nickel] and b is empty.
Use the following class in your solution:
import java.util.ArrayList; /** A purse holds a collection of coins. */ public class Purse { /** Constructs an empty purse. */ public Purse() { coins = new ArrayList<String>(); } /** Adds a coin to the purse. @param coinName the coin to add */ public void addCoin(String coinName) { . . . } /** Returns a string describing the object. @return a string in the format "Purse[coinName1,coinName2,...]" */ public String toString() { . . . } /** Transfers the coins from one purse to another. @param other the other purse */ public void transfer(Purse other) { . . . } private ArrayList<String> coins; }
Use the following class as your tester class:
/** This class tests the Purse class. */ public class PurseTester { public static void main(String[] args) { Purse a = new Purse(); a.addCoin("Quarter"); a.addCoin("Dime"); a.addCoin("Nickel"); a.addCoin("Dime"); Purse b = new Purse(); b.addCoin("Dime"); b.addCoin("Nickel"); a.transfer(b); System.out.println(a.toString()); System.out.println("Expected: Purse[ Quarter,Dime,Nickel,Dime,Dime,Nickel]"); System.out.println(b.toString()); System.out.println("Expected: Purse[]"); } }
- P7.5. Write a method for the Purse class
public boolean sameContents(Purse other) that checks whether the other purse has the same coins in the same order. Use the following class in your solution:
import java.util.ArrayList; /** A purse holds a collection of coins. */ public class Purse { /** Constructs an empty purse. */ public Purse() { coins = new ArrayList<String>(); } /** Adds a coin to the purse. @param coinName the coin to add */ public void addCoin(String coinName) { . . . } /** Returns a string describing the object. @return a string in the format "Purse[coinName1,coinName2,...]" */ public String toString() { . . . } /** Determines if a purse has the same coins in the same order as another purse. @param other the other purse @return true if the two purses have the same coins in the same order, false otherwise */ public boolean sameContents(Object other) { . . . } private ArrayList<String> coins; }
Use the following class as your tester class:
/** This class tests the Purse class. */ public class PurseTester { public static void main(String[] args) { Purse a = new Purse(); a.addCoin("Quarter"); a.addCoin("Dime"); Purse b = new Purse(); b.addCoin("Quarter"); b.addCoin("Dime"); System.out.println(a.sameContents(b)); System.out.println("Expected: true"); Purse c = new Purse(); c.addCoin("Nickel"); c.addCoin("Dime"); c.addCoin("Nickel"); Purse d = new Purse(); d.addCoin("Nickel"); d.addCoin("Dime"); d.addCoin("Quarter"); System.out.println(c.sameContents(d)); System.out.println("Expected: false"); Purse e = new Purse(); e.addCoin("Nickel"); e.addCoin("Dime"); e.addCoin("Nickel"); Purse f = new Purse(); f.addCoin("Nickel"); f.addCoin("Dime"); System.out.println(e.sameContents(f)); System.out.println("Expected: false"); } }
- P7.10. Add a method
getWinner
to theTicTacToe
class of Section 7.6. It should return “x” or “o” to indicate a winner, or “ ” if there is no winner yet. Recall that a winning position has three matching marks in a row, column, or diagonal.
Use the following class in your solution:
/** A 3 x 3 Tic-Tac-Toe board. */ public class TicTacToe { /** Constructs an empty board. */ public TicTacToe() { board = new String[ROWS][COLUMNS]; // fill with spaces for (int i = 0; i < ROWS; i++) for (int j = 0; j < COLUMNS; j++) board[i][j] = " "; } /** Sets a field in the board. The field must be unoccupied. @param i the row index @param j the column index @param player the player ("x" or "o") */ public void set(int i, int j, String player) { if (board[i][j].equals(" ")) board[i][j] = player; } /** * checks if a loacation is valid and unoccupied * @param i the row index * @param j the column index * @return true if valid */ public boolean validPlace(int i, int j) { return (i>=0 && i<3 && j>=0 && j<3 && board[i][j].equals(" ")); } /** Creates a string representation of the board such as |x o| | x | | o| @return the string representation */ public String toString() { String r = ""; for (int i = 0; i < ROWS; i++) { r = r + "|"; for (int j = 0; j < COLUMNS; j++) r = r + board[i][j]+" "; r = r.substring(0,r.length()-1) + "|\n"; } return r; } /** Gets the winner. @return the winner */ public String getWinner() { . . . } private String[][] board; private static final int ROWS = 3; private static final int COLUMNS = 3; }
Use the following class as your tester class:
/** This program tests the getWinner method of the TicTacToe class. */ public class TicTacToeTester { public static void main(String[] args) { TicTacToe game = new TicTacToe(); game.set(0, 0, "x"); game.set(2, 0, "o"); game.set(1, 1, "x"); game.set(2, 1, "o"); System.out.println(game+"Winner: " + game.getWinner()); System.out.println("Expected: "); game.set(2, 2, "x"); System.out.println(game+"Winner: " + game.getWinner()); System.out.println("Expected: x"); game = new TicTacToe(); game.set(0, 0, "x"); game.set(2, 0, "o"); game.set(1, 1, "x"); game.set(2, 1, "o"); game.set(2, 2, "o"); System.out.println(game+"Winner: " + game.getWinner()); System.out.println("Expected: o"); } }
For 11 Points- do all the above and P7.11
- P7.11. Write an application that plays tic-tac-toe. Your program should draw the game board, change players after every successful move, and pronounce the winner.
Here is a sample program run:
| | | | | | Row for x (Q to exit): 0 Column for x: 0 |x | | | | | Row for o (Q to exit): 2 Column for o: 0 |x | | | |o | Row for x (Q to exit): 1 Column for x: 1 |x | | x | |o | Row for o (Q to exit): 2 Column for o: 1 | x | | x | |o o | Row for x (Q to exit): 2 Column for x: 2 |x | | x | |o o x| The winner is x!
Your main class should be called TicTacToePlayer
.
import java.util.Scanner; /** This program uses the TicTacToe class to play a game from user input The user types the row (0..2) and column (0..2) to select the location. */ public class TicTacToePlayer { public static void main(String[] args) { TicTacToe game = new TicTacToe(); Scanner kb = new Scanner(System.in); String input; String player="x"; System.out.print(game+"Row for "+player+"(Q to exit): "); input=kb.nextLine(); input = input.toLowerCase(); while (!input.equals("q") ) { . . . } System.out.println(game+"Winner: " + game.getWinner()); } }