Listing C. Domain layer for SET game—OO design (triple dispatch).

Java Primer
The Game of SET & Software Design
Vince Huston
Listing C. Domain layer for SET game—OO design (triple dispatch).


// Domain layer for SET game - OO design (triple dispatch)

import java.util.Random;

abstract class Facet {
  public abstract boolean isValid1( Facet second, Facet third );

  public abstract boolean isValid2( Facet third, Zer first );
  public abstract boolean isValid2( Facet third, One first );
  public abstract boolean isValid2( Facet third, Two first );

  public boolean isValid3( Zer first, Zer second ) { return false; }
  public boolean isValid3( Zer first, One second ) { return false; }
  public boolean isValid3( Zer first, Two second ) { return false; }
  public boolean isValid3( One first, Zer second ) { return false; }
  public boolean isValid3( One first, One second ) { return false; }
  public boolean isValid3( One first, Two second ) { return false; }
  public boolean isValid3( Two first, Zer second ) { return false; }
  public boolean isValid3( Two first, One second ) { return false; }
  public boolean isValid3( Two first, Two second ) { return false; }
}

class Zer extends Facet {
  public String toString() { return "0"; }

  public boolean isValid1( Facet second, Facet third ) {
                           return second.isValid2( third, this ); }

  public boolean isValid2( Facet third, Zer first ) {
                           return third.isValid3( first, this ); }
  public boolean isValid2( Facet third, One first ) {
                           return third.isValid3( first, this ); }
  public boolean isValid2( Facet third, Two first ) {
                           return third.isValid3( first, this ); }

  public boolean isValid3( Zer first, Zer second ) { return true; }
  public boolean isValid3( One first, Two second ) { return true; }
  public boolean isValid3( Two first, One second ) { return true; }
}

class One extends Facet {
  public String toString() { return "1"; }

  public boolean isValid1( Facet second, Facet third ) {
                           return second.isValid2( third, this ); }

  public boolean isValid2( Facet third, Zer first ) {
                           return third.isValid3( first, this ); }
  public boolean isValid2( Facet third, One first ) {
                           return third.isValid3( first, this ); }
  public boolean isValid2( Facet third, Two first ) {
                           return third.isValid3( first, this ); }

  public boolean isValid3( Zer first, Two second ) { return true; }
  public boolean isValid3( One first, One second ) { return true; }
  public boolean isValid3( Two first, Zer second ) { return true; }
}

class Two extends Facet {
  public String toString() { return "2"; }

  public boolean isValid1( Facet second, Facet third ) {
                           return second.isValid2( third, this ); }

  public boolean isValid2( Facet third, Zer first ) {
                           return third.isValid3( first, this ); }
  public boolean isValid2( Facet third, One first ) {
                           return third.isValid3( first, this ); }
  public boolean isValid2( Facet third, Two first ) {
                           return third.isValid3( first, this ); }

  public boolean isValid3( Zer first, One second ) { return true; }
  public boolean isValid3( One first, Zer second ) { return true; }
  public boolean isValid3( Two first, Two second ) { return true; }
}

class Card {
  private static Facet[] objects = { new Zer(), new One(), new Two() };
  private static boolean[] used = new boolean[27];
  private static Random rn = new Random();

  private int     number; ///// 0..26
  private Facet[] facets = new Facet[3];

  public Card() {
    number = rn.nextInt(27);
    while ( used[number] )
      number = rn.nextInt(27);
    used[number] = true;
    facets[0] = objects[ number % 3 ];
    facets[1] = objects[ number % 9 / 3 ];
    facets[2] = objects[ number / 9 ];
  }
  public Facet getFacet( int i ) { return facets[i]; }
  public int   getNumber()       { return number;   }
  public String toString() {
    return "" + (number+1) + '-' + facets[0] + facets[1] + facets[2];
} }

class Set {
  private Card[] cards = new Card[3];
  public Set( Card one, Card two, Card thr ) {
    cards[0] = one;  cards[1] = two;  cards[2] = thr;
  }
  public boolean isValid() {
    for (int i=0; i < 3; i++)
      if ( ! cards[0].getFacet(i).isValid1(
                         cards[1].getFacet(i), cards[2].getFacet(i) ))
        return false;
    return true;
} }