Computer Science 15-100 (Sections S-V), Fall 2008
Homework 12
Due: Thu 4-Dec-2008 at 9:59pm (email copy) and at Friday's
class/recitation (identical physical copy)
(no late submissions accepted).
Note: As this assignment is due the night before midterm #2, the deadline was moved forward to 9:59pm, to encourage you to get a reasonable amount of sleep before the test. You are encouraged to finish sooner, if possible. No late submissions will be accepted.
Read these instructions first!
The Game of Set
Here is a test method that confirms that your methods work according to the spec:
public static void testSetCardClass() { System.out.print("Testing SetCard class... "); SetCard setCard1 = new SetCard(1,2,3,2); assert(setCard1.getCount() == 1); assert(setCard1.getShape() == 2); assert(setCard1.getColor() == 3); assert(setCard1.getFill() == 2); int expectedCardIndex = ((1-1)*27 + (2-1)*9 + (3-1)*3 + (2-1)); assert(setCard1.getCardIndex() == expectedCardIndex); // This card equals the first card SetCard setCard2 = new SetCard(1,2,3,2); assert(setCard2.getCount() == 1); assert(setCard2.getShape() == 2); assert(setCard2.getColor() == 3); assert(setCard2.getFill() == 2); expectedCardIndex = ((1-1)*27 + (2-1)*9 + (3-1)*3 + (2-1)); assert(setCard2.getCardIndex() == expectedCardIndex); // And this one does not equal the previous two SetCard setCard3 = new SetCard(1,2,1,3); assert(setCard3.getCount() == 1); assert(setCard3.getShape() == 2); assert(setCard3.getColor() == 1); assert(setCard3.getFill() == 3); expectedCardIndex = ((1-1)*27 + (2-1)*9 + (1-1)*3 + (3-1)); assert(setCard3.getCardIndex() == expectedCardIndex); // Check equals method assert(setCard1.equals(setCard2) == true); assert(setCard1.equals(setCard3) == false); assert(setCard2.equals(setCard1) == true); assert(setCard2.equals(setCard3) == false); assert(setCard3.equals(setCard1) == false); assert(setCard3.equals(setCard2) == false); // Check hashCode method assert(setCard1.hashCode() == setCard2.hashCode()); assert(setCard1.hashCode() != setCard3.hashCode()); System.out.println("Passed all tests!"); }
public static void testSetDeckClass() { System.out.print("Testing SetDeck class... "); // first test an unshuffled deck SetDeck setDeck = new SetDeck(false); // unshuffled! for (int i=0; i<81; i++) { assert(setDeck.getCardsLeft() == 81-i); assert((setDeck.hasNextCard() == true) && (setDeck.nextCard().getCardIndex() == i)); } assert(setDeck.hasNextCard() == false); assert(setDeck.getCardsLeft() == 0); // now test that SetDeck is iterable setDeck = new SetDeck(false); // another unshuffled deck int seen = 0; for (SetCard setCard : setDeck) seen++; assert(seen == 81); // now test a shuffled deck HashSet<Integer> seenCards = new HashSet<Integer>(); setDeck = new SetDeck(); // default is shuffled! for (SetCard setCard : setDeck) { int cardIndex = setCard.getCardIndex(); assert((cardIndex >= 0) && (cardIndex < 81)); assert(seenCards.contains(cardIndex) == false); seenCards.add(cardIndex); } // now test that the shuffle itself works. We'll use a very // simplistic approach and just get two shuffled decks and require // that they not have more than 3 of the same cards occur // at the same indexes: int matches = 0; SetDeck setDeck1 = new SetDeck(); SetDeck setDeck2 = new SetDeck(); for (SetCard setCard1 : setDeck1) { SetCard setCard2 = setDeck2.nextCard(); if (setCard1.equals(setCard2)) matches++; } if (matches > 3) { System.out.println("There may be a problem with your shuffling, because"); System.out.println("two different SetDecks had the same cards in "); System.out.println(matches + " locations, where more than 3 is very unlikely."); System.out.println("Try running the test again. If this message comes up"); System.out.println("more than once-in-a-blue-moon, then you probably have a bug."); assert(matches <= 3); } System.out.println("Passed all tests!"); }
// THESE ARE PROVIDED FOR YOU (but, if you really want, you // can delete these and use other instance variables of your choosing) private SetDeck setDeck; // The deck for this game private SetCard[] cardsInPlay; // The 12 (or fewer) visible cards at this time private int[] selectedCardIndexes; // The indexes (from among the 12 visible cards) // of the 3 (or fewer) cards that are selected // (and so are highlighted in gray) right now private int selectedCardCount; // The # of selected (gray highighted) cards right now
Important note: the "cards-in-play" are the 12 (or fewer)
visible cards at any given time.
Here are the methods you need to write, along with explanations (read the
comments carefully!):
// Construct a new SetGame
that uses the given SetDeck.
// The constructor must place the first 12 cards in the deck
// into play (perhaps by storing them in a suitably-named array).
// Right after the constructor is called (at the start of the game),
// no cards should be selected.
public SetGame(SetDeck setDeck)
// Return the number of cards that are currently selected.
public int getSelectedCardCount()
// Return true if the card-in-play with the given index
// is selected, and false otherwise. The index will be between
// 0 and 11 inclusive.
// Hint: be sure to use the selectedCardIndexes array here!
public boolean isSelected(int index)
// Given an index (between 0 and 11 inclusive) into the cards-in-play,
// and a boolean whether to set that card to be selected or unselected,
// this method tries to set the given card's selection as given.
// If the request would result in more than 3 cards being
// selected (which is never allowed), then the method does nothing
// and returns false. Otherwise, it makes the change (if necessary)
// and returns true.
// Note that selecting an already-selected card, or unselecting an
// already-unselected card, is not an error, and the method should
// return true in either case.
public boolean setSelected(int index, boolean selected)
// This method replaces the currently-selected cards-in-play,
// replacing as many of them as possible with cards dealt from the deck.
// However, if there are not enough cards remaining in the deck for this,
// then the behavior depends on whether or not the selected cards form
// a set. If they do not form a set, then once the cards in the deck
// are exhausted, the remaining cards should remain in play. On the other
// hand, if they do form a set, then once the cards in the deck are
exhausted,
// the remaining cards in the set should be entirely removed from play (so
// they are set to null rather than being replaced), so that afterwards there
// are fewer than 12 cards in
play. If there is no selection, this method
// does nothing. In any case, after this method is called, there should be
// no selected cards.
public void replaceSelectedCards()
// Returns true if the selected cards are a set -- that is, if they
// are either all the same or all different in each of the 4 properties.
// When writing this method, you may want to make use of the static
// version of the method which follows (see below).
public boolean isSet()
// A static method that returns true if the given cards are a set -- that
is, if they
// are either all the same or all different in each of the 4 properties.
public static boolean isSet(SetCard[] cards)
// Given an index (between 0 and 11 inclusive) into the cards-in-play,
// returns the corresponding SetCard.
public SetCard getCardInPlay(int index)
// Returns the number of cards left to be dealt from the deck.
public int getCardsLeft()
And here is a test method that confirms that your methods work according
to the spec:
public static void testSetGameClass() { System.out.print("Testing SetGame class... "); // first test static isSet method SetCard[] cards = new SetCard[3]; cards[0] = new SetCard(1,2,1,2); cards[1] = new SetCard(1,2,2,3); cards[2] = new SetCard(1,2,3,1); assert(SetGame.isSet(cards) == true); cards[2] = new SetCard(1,2,2,1); assert(SetGame.isSet(cards) == false); // now test the game on an unshuffled deck (because // it's hard to test on a shuffled deck)! SetDeck setDeck = new SetDeck(false); // unshuffled! SetGame setGame = new SetGame(setDeck); for (int i=0; i<12; i++) assert(setGame.getCardInPlay(i).getCardIndex() == i); assert(setGame.getCardsLeft() == 69); // 69 == 81 - 12 assert(setGame.isSet() == false); assert(setGame.getSelectedCardCount() == 0); // now select card 0 assert(setGame.isSelected(0) == false); assert(setGame.setSelected(0,true) == true); assert(setGame.isSelected(0) == true); assert(setGame.getSelectedCardCount() == 1); // reselect card 0 (should have no effect) assert(setGame.setSelected(0,true) == true); assert(setGame.isSelected(0) == true); // deselect card 0 assert(setGame.setSelected(0,false) == true); assert(setGame.getSelectedCardCount() == 0); assert(setGame.isSelected(0) == false); // select cards 0, 1, and 2 to form a set assert(setGame.setSelected(0,true) == true); assert(setGame.isSet() == false); assert(setGame.setSelected(1,true) == true); assert(setGame.isSet() == false); assert(setGame.setSelected(2,true) == true); assert(setGame.isSet() == true);
// you can deselect when 3 cards are already selected assert(setGame.setSelected(2,false) == true); // deselect 2 assert(setGame.isSet() == false); assert(setGame.setSelected(2,true) == true); // reselect 2 assert(setGame.isSet() == true); // but you cannot select another card when 3 are selected assert(setGame.setSelected(3,true) == false); // cannot make a 4th selection // replace the selected cards (which form a set) by dealing off // the top of the deck of remaining cards setGame.replaceSelectedCards(); assert(setGame.getSelectedCardCount() == 0); assert(setGame.isSet() == false); assert(setGame.getCardsLeft() == 66); // at this point, cards 2, 3, and 4 do NOT form a set assert(setGame.setSelected(2,true) == true); assert(setGame.setSelected(3,true) == true); assert(setGame.setSelected(4,true) == true); assert(setGame.isSet() == false); System.out.println("Passed all tests!"); }
Carpe diem!