slide1 n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Solitaire Case Study (Budd's UOOPJ, Ch. 9) PowerPoint Presentation
Download Presentation
Solitaire Case Study (Budd's UOOPJ, Ch. 9)

Loading in 2 Seconds...

play fullscreen
1 / 44

Solitaire Case Study (Budd's UOOPJ, Ch. 9) - PowerPoint PPT Presentation


  • 122 Views
  • Uploaded on

Engr 691 Special Topics in Engineering Science Software Architecture Spring Semester 2004 Lecture Notes. Solitaire Case Study (Budd's UOOPJ, Ch. 9). This is a set of slides to accompany chapter 9 of Timothy Budd's textbook Understanding Object-Oriented Programming with Java,

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Solitaire Case Study (Budd's UOOPJ, Ch. 9)' - annona


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
slide1
Engr 691Special Topics in Engineering ScienceSoftware ArchitectureSpring Semester 2004Lecture Notes
solitaire case study budd s uoopj ch 9

Solitaire Case Study (Budd's UOOPJ, Ch. 9)

This is a set of slides to accompany chapter 9 of

Timothy Budd's textbook

Understanding Object-Oriented Programming with Java,

Updated Edition

(Addison-Wesley, 2000)

the solitaire game
The Solitaire Game
  • Good example of inheritance in action
  • Constructed from classes for cards, card piles, and the game application
class card
Class Card

import java.awt.*;

public class Card

{

// public constants for card dimensions

public final static int width = 50;

public final static int height = 70;

// public constants for card suits

public final static int heart = 0;

public final static int spade = 1;

public final static int diamond = 2;

public final static int club = 3;

class card continued
Class Card (continued)

// constructors

public Card (int sv, int rv)

{

s = sv;

r = rv;

faceup = false;

}

// mutators

public final void flip()

{

faceup = ! faceup;

}

class card continued1
Class Card (continued)

// accessors

public final int rank ()

{

return r;

}

public final int suit()

{

return s;

}

public final boolean faceUp()

{

return faceup;

}

class card continued2
Class Card (continued)

public final Color color()

{

if (faceUp())

if (suit() == heart || suit() == diamond)

return Color.red;

else

return Color.black;

return Color.yellow;

}

public void draw (Graphics g, int x, int y) { /* ... */ }

// internal data fields

private boolean faceup; // card face exposed?

private int r; // card rank

private int s; // card suit

}

notes on class card
Notes on Class Card
  • Class implements playing card abstraction
  • Textbook code rearranged into our standard format
  • import makes package java.awt available to program—part of Java API
  • Variables and classes can be used before defined (except local variables in methods)
notes on class card continued
Notes on Class Card (continued)

Java has no global variables, constants, or enumerated data types

  • static data fields (i.e., class variables) used for global
  • final data fields used for constants – assigned once, then not redefined
  • Three internal data fields
    • rank and suit are read-only – accessors but no mutators
    • faceup can be modified – flip() mutator
  • draw is complex method – accessor with side effects
  • final methods – accessors rank(),suit(),faceup(), and color(), and mutator flip()
    • cannot be overridden in subclasses
    • can be optimized – expanded inline like a macro – efficient but inhibits reuse!
  • draw is not final – implementation may be somewhat platform dependent
card images
Card Images

See Figure 9.3 on page 145 of Budd's

UOOPJ.

method draw
Method draw

import java.awt.*;

public class Card

{

// ...

public void draw (Graphics g, int x, int y)

{

String names[] = {"A", "2", "3", "4", "5", "6", "7", "8", "9",

"10", "J", "Q", "K"};

// clear rectangle, draw border

g.clearRect(x, y, width, height);

g.setColor(Color.blue);

g.drawRect(x, y, width, height);

// draw body of card

g.setColor(color());

method draw continued
Method draw (continued)

if (faceUp())

{

g.drawString(names[rank()], x+3, y+15);

if (suit() == heart)

{ g.drawLine(x+25, y+30, x+35, y+20); g.drawLine(x+35, y+20, x+45, y+30);

g.drawLine(x+45, y+30, x+25, y+60); g.drawLine(x+25, y+60, x+5, y+30);

g.drawLine(x+5, y+30, x+15, y+20); g.drawLine(x+15, y+20, x+25, y+30);

} else if (suit() == spade) {

g.drawLine(x+25, y+20, x+40, y+50); g.drawLine(x+40, y+50, x+10, y+50);

g.drawLine(x+10, y+50, x+25, y+20); g.drawLine(x+23, y+45, x+20, y+60);

g.drawLine(x+20, y+60, x+30, y+60); g.drawLine(x+30, y+60, x+27, y+45);

} else if (suit() == diamond) {

g.drawLine(x+25, y+20, x+40, y+40); g.drawLine(x+40, y+40, x+25, y+60);

g.drawLine(x+25, y+60, x+10, y+40); g.drawLine(x+10, y+40, x+25, y+20);

} else if (suit() == club) {

g.drawOval(x+20, y+25, 10, 10); g.drawOval(x+25, y+35, 10, 10);

g.drawOval(x+15, y+35, 10, 10); g.drawLine(x+23, y+45, x+20, y+55);

g.drawLine(x+20, y+55, x+30, y+55); g.drawLine(x+30, y+55, x+27, y+45);

}

}

method draw continued1
Method draw (continued)

else {

// face down

g.drawLine(x+15, y+5, x+15, y+65);

g.drawLine(x+35, y+5, x+35, y+65);

g.drawLine(x+5, y+20, x+45, y+20);

g.drawLine(x+5, y+35, x+45, y+35);

g.drawLine(x+5, y+50, x+45, y+50);

}

}

}

notes on method draw
Notes on Method draw
  • Displays the card on screen
  • Parameter is current graphics context
    • argument is object of class java.awt.Graphics
    • class Graphics in Java API provides many drawing primitives
    • methods for printing bit-maps available for more sophisticated visuals
  • Constants such as Color.red and Color.black defined in class java.awt.Color
  • draw is instance method – every card responsible for drawing itself
the game
The Game
  • See Figure 9.4 on page 145 of Budd's UOOPJ.
class cardpile
Class CardPile

import java.awt.*;

import java.util.Stack;

import java.util.EmptyStackException;

public class CardPile

{

// constructors

public CardPile (int xl, int yl)

{

x = xl;

y = yl;

thePile = new Stack();

}

class cardpile continued
Class CardPile (continued)

//mutators

public final Card pop()

{

try {

return (Card) thePile.pop();

} catch (EmptyStackException e) {

return null;

}

}

public void addCard (Card aCard) // sometimes overridden

{

thePile.push(aCard);

}

public void select (int tx, int ty) // sometimes overridden

{ /* do nothing */ }

class cardpile continued1
Class CardPile (continued)

// accessors

public final Card top()

{ return (Card) thePile.peek(); }

public final boolean isEmpty()

{ return thePile.empty(); }

public boolean includes (int tx, int ty) // sometimes overridden

{

return x <= tx && tx <= x + Card.width

&& y <= ty && ty <= y + Card.height;

}

public boolean canTake (Card aCard) // sometimes overridden

{ return false; }

public void display (Graphics g) // sometimes overridden

{

g.setColor(Color.blue);

if (isEmpty())

g.drawRect(x, y, Card.width, Card.height);

else

top().draw(g, x, y);

}

class cardpile continued2
Class CardPile (continued)

// protected data fields

// coordinates of the card pile

protected int x;

// (x,y) is upper left corner

protected int y;

// cards in the pile

protected Stack thePile;

}

notes on class cardpile
Notes on Class CardPile
  • Implementation of card deck abstraction

– base class extended for specific behaviors

  • Uses generic container Stack from Java API for pile of cards
    • empty initially
    • Stack operations implement Card operations – adapter pattern
    • Cast objects back to Card when taken from stack
  • Uses global symbolic constants Card.width and Card.height

– access to static fields using class name, not instance name (actually, either works)

  • pop, top, and isEmpty implementation for subclasses -- final methods
  • addCard, select, includes, canTake, and display part of abstraction, but implementation varies among subclasses
  • protected data fields accessible by subclasses
  • Instructor's comment:
    • protected data fields usually bad practice – trusts subclasses (perhaps in different package) to manipulate internal fields correctly – safer to provide appropriate protected mutators and accessors instead (perhaps final)
informal specification of cardpile s non final methods
Informal Specification of CardPile's Non-final Methods

Methods may need to be overridden to give the card deck the appropriate behaviors.

  • addCard(c)
    • adds card c to the card pile
  • select(x,y)
    • performs an action in response to mouse click at (x,y)
  • includes(x,y)
    • determines whether (x,y) within boundary of the pile
  • canTake(c)
    • determines whether the pile can take card c (according to the rules governing the pile)
  • display(g)
    • displays the pile using graphics context g
class suitpile
Class SuitPile

class SuitPile extends CardPile

{ // constructors

public SuitPile (int x, int y)

{ super(x, y); }

// accessors

public boolean canTake (Card aCard)

// overrides parent

{ if (isEmpty())

return aCard.rank() == 0;

Card topCard = top();

return (aCard.suit() == topCard.suit())

&& (aCard.rank() == 1 + topCard.rank());

}

}

notes on class suitpile
Notes on Class SuitPile
  • Represents one of the (4) piles of cards at top of playing surface – built up in suit from Ace (1) to King (13)
  • Keyword extends indicates inheritance from CardPile
  • super indicates parent – in constructor used to call parent's constructor for initialization – first statement only
  • Method canTake overridden by replacement – canTake if pile empty or card is next higher of same suit
class deckpile
Class DeckPile

import java.util.Random ;

class DeckPile extends CardPile

{ // constructors

public DeckPile (int x, int y)

{ // first initialize parent

super(x, y);

// then create the new deck, first put them into a local pile

for (int i = 0; i < 4; i++)

for (int j = 0; j <= 12; j++)

addCard(new Card(i, j));

// then shuffle the cards

Random generator = new Random();

for (int i = 0; i < 52; i++) {

int j = Math.abs(generator.nextInt() % 52);

// swap the two card values

Object temp = thePile.elementAt(i);

thePile.setElementAt(thePile.elementAt(j), i);

thePile.setElementAt(temp, j);

}

}

// mutators

public void select(int tx, int ty) {

if (isEmpty()) return;

Solitaire.discardPile.addCard(pop());

}

}

notes on class deckpile
Notes on Class DeckPile
  • Represents the original deck of cards
  • Uses super in constructor for basic initialization, new code for specific initialization
  • Accesses static (class) methods – absolute value function Math.abs()
  • Overrides method select by replacement – if pile nonempty, add top card to discard pile
  • Java API Stack extends Vector – select uses the "ranked sequence" methods of Vector
  • Instructor's comment:
    • Stack extending Vector is poor design in the Java API! Similarly, the choice of Stack is a questionable design. Better to just use Vector directly
notes on class deckpile continued
Notes on Class DeckPile (continued)
  • Accesses utility class java.util.Random to generate pseudo-random numbers
  • Accesses static (class) variables to share single copies
    • Solitaire.discardPile
    • Author has only one discard pile, so made this class access that instance directly
  • Instructor's comment:
    • Hard-coding of reference to static discard pile inhibits reusability of the deck
    • Probably better to pass discard deck to constructor of DeckPile, store reference, manipulate it
notes on class deckpile continued1
Notes on Class DeckPile(continued)
  • Manipulates protected field thePile from parent class CardPile

Possible alternatives to use of protected data fields:

    • Add (protected?) "ranked sequence" get and set operations to CardPile abstraction?
    • Add constructor or (protected?) set operation to CardPile that takes a sequence (vector, array, etc.) of cards to (re)initialize pile? get method?
    • Add shuffle operation to CardPile abstraction?
class discardpile
Class DiscardPile

import java.util.Random;

class DiscardPile extends CardPile

{

// constructors

public DiscardPile (int x, int y)

{

super (x, y);

}

// mutators

public void addCard (Card aCard)

{

if (! aCard.faceUp())

aCard.flip();

super.addCard(aCard);

}

class discardpile continued
Class DiscardPile (continued)

//mutators

public void select (int tx, int ty)

{

if (isEmpty())

return;

Card topCard = pop();

for (int i = 0; i < 4; i++)

if (Solitaire.suitPile[i].canTake(topCard)) {

Solitaire.suitPile[i].addCard(topCard);

return;

}

for (int i = 0; i < 7; i++)

if (Solitaire.tableau[i].canTake(topCard)) {

Solitaire.tableau[i].addCard(topCard);

return;

}

// nobody can use it, put it back on our list

addCard(topCard);

}

}

notes on class discardpile
Notes on Class DiscardPile
  • Represents the discard pile in a Solitaire game
  • Constructor refines parent's constructor – uses super call in initialization
  • select method overrides and replaces one in parent
    • checks whether topmost card can be played any suit pile or tableau pile
  • addCard method overrides and refines one in parent
    • executes parent method (super.addCard), but also adds new behavior
    • flips card faceup when put on discard pile
  • Hard-coded access to static variables for the (4) suit piles and (7) tableau piles
    • probably better to pass these to constructor, store references, and manipulate via local references
class tablepile
Class TablePile

import java.util.Enumeration ;

class TablePile extends CardPile

{

// constructors

public TablePile (int x, int y, int c)

{ // initialize the parent class

super(x, y);

// then initialize our pile of cards

for (int i = 0; i < c; i++) {

addCard(Solitaire.deckPile.pop());

}

// flip topmost card face up

top().flip();

}

class tablepile continued
Class TablePile (continued)

// mutators

public void select (int tx, int ty) {

if (isEmpty()) return;

// if face down, then flip

Card topCard = top();

if (! topCard.faceUp()) {

topCard.flip();

return;

} // else see if any suit pile can take card

topCard = pop();

for (int i = 0; i < 4; i++)

if (Solitaire.suitPile[i].canTake(topCard)) {

Solitaire.suitPile[i].addCard(topCard);

return;

} // else see if any other table pile can take card

for (int i = 0; i < 7; i++)

if (Solitaire.tableau[i].canTake(topCard)) {

Solitaire.tableau[i].addCard(topCard);

return;

} // else put it back on our pile

addCard(topCard);

}

class tablepile continued1
Class TablePile (continued)

// accessors

public boolean canTake (Card aCard) {

if (isEmpty())

return aCard.rank() == 12;

Card topCard = top();

return (aCard.color() != topCard.color()) &&

(aCard.rank() == topCard.rank() - 1);

}

public boolean includes (int tx, int ty) {

// don't test bottom of card

return x <= tx && tx <= x + Card.width && y <= ty;

}

public void display (Graphics g) {

int localy = y;

for (Enumeration e = thePile.elements(); e.hasMoreElements();) {

Card aCard = (Card) e.nextElement();

aCard.draw (g, x, localy);

localy += 35;

}

}

}

notes on class tablepile
Notes on Class TablePile
  • Represents one of the (7) tableau piles on the lower part of the playing surface
    • Initialized with cards from deck – constructor argument gives number needed
    • Top card is face up
    • Add card to empty pile only if King
    • Add card to nonempty pile only if opposite color to top and one rank lower
    • Selection action moves any cards from this table pile to suit pile or another table pile
  • Uses super in constructor for basic initialization, new code for specific initialization
  • Methods select, canTake, includes, and display override and replace ones in parent
  • Method display
    • Uses java.util.Enumeration object returned by the Stack to iterate through the tableau pile
    • Displays each card slightly offset from the one below it
    • Accesses protected field thePile from parent class CardPile

Perhaps define (protected?) elements() method in CardPile to return a pile-Enumeration object – to avoid protected fields

Another alternative: method to return cards in pile as sequence (e.g., array or vector)

the game class solitaire
The Game Class: Solitaire

import java.awt.*;

import java.awt.event.*;

public class Solitaire

{ // public class variables for the various card piles of game

static public DeckPile deckPile;

static public DiscardPile discardPile;

static public TablePile tableau [ ];

static public SuitPile suitPile [ ];

// single array to alias all above piles -- aids polymorphism

static public CardPile allPiles [ ];

the game class solitaire continued
The Game Class: Solitaire (continued)

// application entry point

static public void main (String[] args)

{

Solitaire world = new Solitaire();

}

// constructors

public Solitaire ()

{

window = new SolitaireFrame();

init();

window.show();

}

the game class solitaire continued1
The Game Class: Solitaire (continued)

//mutators

public void init ()

{ // first allocate the arrays

allPiles = new CardPile[13];

suitPile = new SuitPile[4];

tableau = new TablePile[7];

// then fill them in

allPiles[0] = deckPile = new DeckPile(335, 30);

allPiles[1] = discardPile = new DiscardPile(268, 30);

for (int i = 0; i < 4; i++)

allPiles[2+i] = suitPile[i] = new SuitPile(15 + (Card.width+10) * i, 30);

for (int i = 0; i < 7; i++)

allPiles[6+i] = tableau[i]

= new TablePile(15 + (Card.width+5) * i, Card.height + 35, i+1);

}

the game class solitaire continued2
The Game Class: Solitaire (continued)

// inner classes

private class SolitaireFrame extends Frame

{ /* expanded later */ }

// internal data fields

private Frame window;// the application window

}

notes on class solitaire
Notes on Class Solitaire
  • Class declares and allocates class (static) variables for piles of cards on playing surface
  • Class sets up allpiles array to "alias" all other piles, regardless of subclass
  • Control goes initially to class method main
  • main creates an instance of Solitaire application (its only action)
  • Solitaire constructor creates window for application, initializes the playing surface, and displays window
  • SolitaireFrame is an inner class

inner class (from the glossary to Budd's UOOPJ textbook):

    • a class definition that appears inside another class. Inner classes are allowed access to both the private data fields and the methods of the surrounding class. Inner classes are frequently used in building listener objects for handling events.
  • SolitaireFrame manages the application window
inner class solitaireframe
Inner Class SolitaireFrame

// part of Class Solitaire

private class SolitaireFrame extends Frame

{

private class RestartButtonListener implements ActionListener

{

public void actionPerformed (ActionEvent e)

{

init();

window.repaint();

}

}

inner class solitaireframe continued
Inner Class SolitaireFrame(continued)

private class MouseKeeper extends MouseAdapter

{

public void mousePressed (MouseEvent e)

{

int x = e.getX();

int y = e.getY();

for (int i = 0; i < 13; i++)

if (allPiles[i].includes(x, y))

{

allPiles[i].select(x, y);

repaint();

}

}

}

inner class solitaireframe continued1
Inner Class SolitaireFrame(continued)

public SolitaireFrame()

{

setSize(600, 500);

setTitle("Solitaire Game");

addMouseListener (new MouseKeeper());

Button restartButton = new Button("New Game");

restartButton.addActionListener(

new RestartButtonListener());

add("South", restartButton);

}

public void paint(Graphics g)

{

for (int i = 0; i < 13; i++)

allPiles[i].display(g);

}

}

notes on class solitaireframe
Notes on Class SolitaireFrame
  • GUI window for the Solitaire game application
  • Extends java.awt.Frame class
  • Event-driven program – system GUI manager in control, user code "called back" in response to GUI events
  • SolitaireFrame constructor
    • sets window size, title
    • adds mouse listener "callback" code to respond to mouse events
    • adds restart button at bottom of window ("South") and "callback" code to respond to button events
notes on class solitaireframe continued
Notes on Class SolitaireFrame (continued)
  • Inner class MouseKeeper's method mousePressed called on mouse click event
    • determines which pile selected
    • performs select operation for that pile
      • note use of polymorphism
      • action depends on pile type (i.e., on which subclass)
    • repaints window
  • Inner class RestartButtonListener method actionPerformed called on button event
    • reinitializes game
    • repaints window
  • Method paint of SolitaireFrame called by GUI when frame needs to be displayed
    • note use of polymorphism