/**
 * Tests a PokerHand for basic correctness.  Also checks that a PlayingCard
 * implements the Comparable interface (won't compile otherwise).
 *
 * @author Zach Tomaszewski
 * @version 30 Mar 2010
 */
public class PokerHandTester {

  public static void main(String[] args) {

    //cards to use in tests below
    // (using literals for face card values as not everyone defined constants)
    PlayingCard aceS = new PlayingCard(1, PlayingCard.SPADES);
    PlayingCard aceH = new PlayingCard(1, PlayingCard.HEARTS);
    PlayingCard twoS = new PlayingCard(2, PlayingCard.SPADES);
    PlayingCard twoH = new PlayingCard(2, PlayingCard.HEARTS);
    PlayingCard threeS = new PlayingCard(3, PlayingCard.SPADES);
    PlayingCard fourS = new PlayingCard(4, PlayingCard.SPADES);
    PlayingCard fiveS = new PlayingCard(5, PlayingCard.SPADES);
    PlayingCard sixS = new PlayingCard(6, PlayingCard.SPADES);
    PlayingCard sixH = new PlayingCard(6, PlayingCard.HEARTS);
    PlayingCard sixD = new PlayingCard(6, PlayingCard.DIAMONDS);
    PlayingCard sixC = new PlayingCard(6, PlayingCard.CLUBS);
    PlayingCard tenS = new PlayingCard(10, PlayingCard.SPADES);
    PlayingCard tenH = new PlayingCard(10, PlayingCard.HEARTS);
    PlayingCard jackS = new PlayingCard(11, PlayingCard.SPADES);
    PlayingCard queenS = new PlayingCard(12, PlayingCard.SPADES);
    PlayingCard kingS = new PlayingCard(13, PlayingCard.SPADES);

    //is PlayingCard a Comparable object?
    Comparable card = tenS;
    //test compareTo method
    System.out.println("Testing PlayingCard's compareTo method: ");
    System.out.print(twoS + " < " + sixS + ": ");
    System.out.println((twoS.compareTo(sixS) < 0) ? "PASS" : "FAIL");
    System.out.print(sixS + " > " + twoS + ": ");
    System.out.println((sixS.compareTo(twoS) > 0) ? "PASS" : "FAIL");
    System.out.print(twoS + " == " + twoS + ": ");
    System.out.println((twoS.compareTo(twoS) == 0) ? "PASS" : "FAIL");
    //tests Aces, which are special cases
    System.out.print(sixS + " < " + aceS + ": ");
    System.out.println((sixS.compareTo(aceS) < 0) ? "PASS" : "FAIL");
    System.out.print(aceS + " > " + sixS + ": ");
    System.out.println((aceS.compareTo(sixS) > 0) ? "PASS" : "FAIL");
    System.out.print(aceS + " == " + aceS + ": ");
    System.out.println((aceS.compareTo(aceS) == 0) ? "PASS" : "FAIL");
    System.out.println();


    //sample hands to tests
    PlayingCard[][] hands = {{twoS, aceH, kingS, threeS, sixD},  //high card
                             {twoS, aceS, twoH, threeS, fourS},  //pair
                             {twoS, aceS, twoH, threeS, threeS}, //2 pair
                             {twoS, queenS, twoH, sixH, sixS},   //2 pair
                             {sixC, queenS, sixH, sixS, threeS}, //3 kind

                             {twoH, threeS, fourS, fiveS, sixH}, //straight
                             {twoH, threeS, fourS, fiveS, aceS}, // ", Ace-low
                             {tenH, jackS, queenS, kingS, aceS}, // ", Ace-hi
                             {twoS, kingS, fourS, fiveS, sixS},  //flush

                             {twoH, twoS, sixC, sixH, sixS},     //full house
                             {tenH, tenS, sixC, sixH, sixS},     //full house
                             {twoH, sixD, sixC, sixH, sixS},     //4 kind
                             {tenH, sixD, sixC, sixH, sixS},     //4 kind
                             {twoS, threeS, fourS, fiveS, sixS}, //str-flush
                             {tenS, jackS, queenS, kingS, aceS}, //royal flush
                            };

    //expected results corresponding to each hand defined in hands above
    int[][] expected = {{0, 0, 0, 0, 0, 0, 0, 0, 0},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0},
                        {-1, 1, 0, 0, 0, 0, 0, 0, 0},
                        {-1, 1, 0, 0, 0, 0, 0, 0, 0},
                        {-1, 0, 1, 0, 0, 0, 0, 0, 0},

                        {0, 0, 0, 1, 0, 0, 0, 0, 0},
                        {0, 0, 0, 1, 0, 0, 0, 0, 0},
                        {0, 0, 0, 1, 0, 0, 0, 0, 0},
                        {0, 0, 0, 0, 1, 0, 0, 0, 0},

                        {-1, -1, -1, 0, 0, 1, 0, 0, 0},
                        {-1, -1, -1, 0, 0, 1, 0, 0, 0},
                        {-1, -1, -1, 0, 0, 0, 1, 0, 0},
                        {-1, -1, -1, 0, 0, 0, 1, 0, 0},
                        {0, 0, 0, -1, -1, 0, 0, 1, 0},
                        {0, 0, 0, -1, -1, 0, 0, -1, 1},
                       };

    //print rules of test
    System.out.println("is??? methods tested below in the following order:");
    System.out.println("isPair, isTwoPair, isThreeOfAKind, isStraight, isFlush");
    System.out.println("isFullHouse, isFourOfAKind, isStraightFlush, isRoyalFlush.");
    System.out.println("Expected values for each hand include:");
    System.out.println(" 1 = must be true");
    System.out.println(" 0 = must be false");
    //-1 is probably true in most implementations, but not required to be
    System.out.println("-1 = may be true or false depending on implementation");
    System.out.println();

    //run tests
    for (int i = 0; i < hands.length; i++) {

      //construct given hand and call methods, storing results
      PokerHand hand = new PokerHand(hands[i][0], hands[i][1], hands[i][2],
                                     hands[i][3], hands[i][4]);
      System.out.println("Hand: " + hand);
      int[] results = new int[expected[i].length];
      for (int test = 0; test < expected.length; test++) {
        results[0] = (hand.isPair()) ? 1 : 0;
        results[1] = (hand.isTwoPair()) ? 1 : 0;
        results[2] = (hand.isThreeOfAKind()) ? 1 : 0;
        results[3] = (hand.isStraight()) ? 1 : 0;
        results[4] = (hand.isFlush()) ? 1 : 0;
        results[5] = (hand.isFullHouse()) ? 1 : 0;
        results[6] = (hand.isFourOfAKind()) ? 1 : 0;
        results[7] = (hand.isStraightFlush()) ? 1 : 0;
        results[8] = (hand.isRoyalFlush()) ? 1 : 0;
      }

      //print expected and actual results for this hand
      System.out.println("Expected: " + java.util.Arrays.toString(expected[i]));
      System.out.print("Results:  " + java.util.Arrays.toString(results));

      //compare results with loop, so we can ignore any -1 tests
      boolean passed = true;
      for (int r = 0; r < results.length; r++) {
        if (results[r] != expected[i][r] && expected[i][r] != -1) {
          passed = false;
          break;
        }
      }

      //print if all tests for this hand passed
      System.out.println((passed) ? "\t[PASS]" : "\t[FAIL]");
      System.out.println();
    }
    System.out.println("DONE.");

  }
}