Card Lab 1:War

This lab is good for distinguishing Object methods, and how to test their method's behaviour. The student needs to use and improve the Card class to make their own version of the card game "War." I hope the Card class is a little more interesting to students than the Bank class in the text. It is a good example for discussion of encapsulation and comparison methods with objects, which work differently than with simple data types like int or double.

The game of War has two players, in this case the computer and the user. Each player has a card, and the biggest card wins both cards. In case of a tie, neither player wins the round.

For 8 points, 10 turns are played by simply getting random cards from the Card class. The winner of the game is the one who had won the most turns. You need to change the War class so that it knows how to score the turns.

For 9 points, the Card class needs to be adapted to compare not only the number of pips on the card, but also the suit. The method of the Card class that has to be implemented is the isLessThan() method. The order of the suits from highest to lowest is Spades, Hearts, Diamonds and Clubs. In this version, an ace of spades beats an ace of clubs, whereas in the 8 point version, they tie.

For 10 points, each player starts with a score of 26, and the games ends when one player has a score of zero. In this version, the winner of the turn gets their score increased by one, and the loser gets their score decreased by one. In case of a tie, both their scores remain the same. Here you need to change the War class and change the scoring as well as the while loop in order to see when the game is over.


So far, we have still not simulated the deck of cards, but are just randomly creating cards. It is possible for two players to have exactly the same card on a turn! In another Lab, a Deck Class will be used and each player's hand will be an ArrayList of Cards.

Card.java

Here is a starter file that defines the Card class. If you compile this in your IDE you will get the API that can also be found here
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);
		}
		
    }
}

War.java

import java.util.Scanner;
/**
 *  War is a card game, where the higher cards wins.
 * 
 * @author Chris Thiel, OFMCap
 * @version 21 September 2008
 */
public class War
{
	
	public static void main(String[] args)
	{
		Scanner in=new Scanner(System.in);
		int compScore=0;
		int userScore=0;
		int turn=1;
		while (turn<=10)
		{
		   Card c=new Card();
		   Card u=new Card();
		   System.out.println("War turn #"+turn);
		   System.out.println("You have a "+u);
		   System.out.println("Computer has a "+c);
		    
		   // Figure out how to score this turn here
		   
		   System.out.println("Score:\n Computer: "+compScore);
		   System.out.println(" You:"+userScore);
		   System.out.println("\nPress enter to continue\n");
		   String s=in.nextLine();
		   turn++;
		}
		if (compScore>userScore) 
		    System.out.println("\nYOU LOSE!");
		if (compScore<userScore) 
		    System.out.println("\nYOU WIN!");
		if (compScore==userScore) 
		    System.out.println("\nTIE!");
	}
}