15b: Equality

ICS211, Spring 2013
Dr. Zach

(switch view)

Status

Common Methods

PlayingCard (from last time)

public class PlayingCard {

  private int value;
  private Suit suit;

  public PlayingCard(int value, Suit suit) {
    if (value < 1 || value > 13) {
      throw new IllegalArgumentException("Value " + value +
          " out of valid 1 - 13 range.");
    }
    this.value = value;
    this.suit = suit;
  }

  public int getValue() {
    return this.value;
  }
  public Suit getSuit()  {
    return this.suit;
  }

  @Override
  public String toString() {
    String v = "" + this.value;
    switch (this.value) {
      case 1:  v = "A"; break;
      case 11: v = "J"; break;
      case 12: v = "Q"; break;
      case 13: v = "K"; break;
    }
    return v + this.suit;
  }

  // nested class for Suit
  public static enum Suit {
    C, D, H, S;
  }
}

At this point

  PlayingCard fourC = new PlayingCard(4, PlayingCard.Suit.C);
  PlayingCard fourC2 = new PlayingCard(4, PlayingCard.Suit.C);
  PlayingCard jackH = new PlayingCard(11, PlayingCard.Suit.H);

  // overridden toString() (vs orginal in Object)
  System.out.println(fourC);  // 4C  (was: PlayingCard@4d29dcc0)
  System.out.println(fourC2); // 4C  (was: PlayingCard@4c53ccba)
  System.out.println(jackH);  // JH  (was: PlayingCard@11a5ee7c)

  // equals
  System.out.println(fourC.equals(fourC));  // true
  System.out.println(fourC.equals(jackH));  // false
  System.out.println(fourC.equals(fourC2)); // false
  
  // as Set
  List<PlayingCard> hand = Arrays.asList(fourC, fourC2, jackH);
  Set<PlayingCard> set = new HashSet<PlayingCard>(hand);
  System.out.println(set);  // [4C, JH, 4C]

Equals method

PlayingCard equals

  @Override
  public boolean equals(Object obj) {
    if (obj instanceof PlayingCard) {
      PlayingCard pc = (PlayingCard) obj;
      return this.getValue() == pc.getValue() && this.getSuit() == pc.getSuit();
    }
    return false;
  }

Effect of new equals

  PlayingCard fourC = new PlayingCard(4, PlayingCard.Suit.C);
  PlayingCard fourC2 = new PlayingCard(4, PlayingCard.Suit.C);
  PlayingCard jackH = new PlayingCard(11, PlayingCard.Suit.H);

  // equals
  System.out.println(fourC.equals(fourC));  // true
  System.out.println(fourC.equals(jackH));  // false
  System.out.println(fourC.equals(fourC2)); // true
  
  // as set
  List<PlayingCard> hand = Arrays.asList(fourC, fourC2, jackH);
  Set<PlayingCard> set = new HashSet<PlayingCard>(hand);
  System.out.println(set);  // [4C, JH, 4C]  still the same?
  System.out.println(set.contains(new PlayingCard(4, PlayingCard.Suit.C)); //false !?!

Will return to the Set problem in a minute...

More complex equals example

Second attempt

  //In Point...
  @Override
  public boolean equals(Object obj) {
    if (obj instanceof Point) {
      Point p = (Point) obj;
      return this.x == p.x && this.y == p.y;
    }
    return false;
  }
  //In Pixel...
  @Override
  public boolean equals(Object obj) {
    if (obj instanceof Point) {
      if (obj instanceof Pixel) {
        Pixel p = (Pixel) obj;
        return this.x == p.x && this.y == p.y && this.color == p.color;
      }else {
        //just a Point, so ignore color
        return super.equals(obj);
      }
    }
    return false;
  }

Point and Pixel Conclusion

Returning to PlayingCard

  // hashCode
  System.out.printf("%x\n", fourC.hashCode());  // 4d29dcc0
  System.out.printf("%x\n", fourC2.hashCode()); // 4c53ccba
  System.out.printf("%x\n", jackH.hashCode());  // 11a5ee7c

hashCode

Writing hashCode

PlayingCard's hashCode

@Override
public int hashCode() {
  int total = 17;
  total = total * 31 + this.value;
  total = total * 31 + this.suit.hashCode();   //or .ordinal() for enums
  return total;
}

Effect of new hashCode()

  // hashCode
  System.out.printf("%x\n", fourC.hashCode());  // 3312f22a (404d with .ordinal())
  System.out.printf("%x\n", fourC2.hashCode()); // 3312f22a (404d with .ordinal())
  System.out.printf("%x\n", jackH.hashCode());  // 24cc5917 (4128 with .ordinal())
  
  // as set
  List<PlayingCard> hand = Arrays.asList(fourC, fourC2, jackH);
  Set<PlayingCard> set = new HashSet<PlayingCard>(hand);
  System.out.println(set);  // [4C, JH] 
  System.out.println(set.contains(new PlayingCard(4, PlayingCard.Suit.C)); // true

Comparable

Making PlayingCard Comparable

public class PlayingCard implements Comparable<PlayingCard> {

  //...

  /**
   * Natural ordering is by value only (smaller to larger).
   * This is inconsistent with equals.
   */
  @Override
  public int compareTo(PlayingCard pc) {
    return this.value - pc.value;
  }

Potential bugs

  // as a Set
  PlayingCard fourD = new PlayingCard(4, PlayingCard.Suit.D);
  List<PlayingCard> hand = Arrays.asList(fourC, fourD, jackH);
  Set<PlayingCard> set = new HashSet<PlayingCard>(hand);
  System.out.println(set);   // [4C, JH, 4D]
  System.out.println(set.contains(new PlayingCard(4, PlayingCard.Suit.S)));  // false
  // as a Set
  PlayingCard fourD = new PlayingCard(4, PlayingCard.Suit.D);
  List<PlayingCard> hand = Arrays.asList(fourC, fourD, jackH);
  Set<PlayingCard> set = new TreeSet<PlayingCard>(hand);
  System.out.println(set);   // [4C, JH] (but no 4D)
  System.out.println(set.contains(new PlayingCard(4, PlayingCard.Suit.S)));  // true

Job Interview Question #3

We're going to play a game.
* First person gets to announce a number between 1 and 10.
* Then, starting with second person, each player take turns adding a value 
   b/w 1 and 10 to the running total.  Announces the new total.
* First person to say "fifty" wins the game.
* Is there a strategy that always lets you win this game? If so, what is it?
* What if we change the target from 50 to a different value?  Is your strategy general?
* Does it matter to your strategy whether you are the first player?
* "Stepping stone" values: 39, 28, 17, 6 
* Determined by taking goal value and repeatedly subtracting 11
* Yes, whoever knows this strategy and gets on a "stepping stone" first controls the game.  

Job Interview Question #4

Assume you have a dictionary of valid English words.
Given a word as input, (efficiently) give all the valid anagrams of that word.
Example: nails, snail, slain are anagrams of each other.

This will be your A11...

Job Interview Question #5

You own 25 horses but no watch, clock, or way of measuring time.
You want to know which of your horses is the fastest.
You have a track wide enough to run only 5 horses at a time in a race.
What is the fewest number of races you'd need to run to find the fastest horse?
What if you want to find the top two fastest horses? (min # of races?)
What if you want to find the top three fastest horses? (min # of races?)

This one is fairly artificial. Who would be rich enough to own and feed 25 horses, smart enough to figure this problem out, and yet not be able to find some way to measure time? And it assumes that horses don't get tired or slower after running in multiple races in a row. And, apparently, assumes there are no ties.

Also, I only heard of this one while preparing; I didn't get it in an interview myself. Took me quite a while to figure out, though.

Hint: The last two answers are the same.

For Next Time