Advertisement
nmnm

Card sorter

Jun 24th, 2015
191
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 11.69 KB | None | 0 0
  1. -----------------------------------------------------------------
  2.  
  3. public class HandSort {
  4.  
  5.   private static final int RANDOM_HAND_SIZE = 13;
  6.  
  7.   public static void main(String[] args) {
  8.     new Hand(RANDOM_HAND_SIZE).sort();
  9.   }
  10. }
  11.  
  12. -----------------------------------------------------------------
  13.  
  14. import java.util.ArrayList;
  15. import java.util.Collections;
  16. import java.util.HashMap;
  17. import java.util.HashSet;
  18. import java.util.Iterator;
  19. import java.util.List;
  20. import java.util.Map;
  21. import java.util.Set;
  22.  
  23. public class Hand implements Iterable<Card> {
  24.  
  25.   private List<ArrayList<Card>> cards;
  26.   private int numSuits;
  27.   private List<Hand> pastMoves = new ArrayList<>();
  28.   private int printFrom;
  29.   private int printLength;
  30.   private int printTo;
  31.  
  32.   public Hand(int numCards) {
  33.     List<Card> deck = new ArrayList<>();
  34.     for (Suit suit : Suit.values()) {
  35.       for (int rank = Card.MAX_RANK; rank >= Card.MIN_RANK; rank--) {
  36.         deck.add(new Card(rank, suit));
  37.       }
  38.     }
  39.     Collections.shuffle(deck);
  40.     buildFromDeck(deck, numCards);
  41.   }
  42.  
  43.   public Hand(List<Card> deck, int numCards) {
  44.     buildFromDeck(deck, numCards);
  45.   }
  46.  
  47.   private Hand(List<ArrayList<Card>> cards) {
  48.     this.cards = cards;
  49.   }
  50.  
  51.   public void buildFromDeck(List<Card> deck, int numCards) {
  52.     cards = new ArrayList<>();
  53.     List<Card> sortCards = new ArrayList<>(numCards);
  54.     Set<Integer> suitsSeen = new HashSet<>();
  55.     for (int i = 0; i < numCards; i++) {
  56.       Card card = deck.get(i);
  57.       ArrayList<Card> cardContainer = new ArrayList<>(4);
  58.       cardContainer.add(card);
  59.       cards.add(cardContainer);
  60.  
  61.       sortCards.add(card);
  62.       suitsSeen.add(card.getSuitRank());
  63.     }
  64.     numSuits = suitsSeen.size();
  65.     Collections.sort(sortCards);
  66.     for (int i = 0; i < numCards - 1; i++) {
  67.       Card currentCard = sortCards.get(i);
  68.       Card nextCard = sortCards.get(i + 1);
  69.       if (nextCard.hasSameSuit(currentCard)) {
  70.         currentCard.setRightAdj(nextCard);
  71.       }
  72.     }
  73.     mergeGroups();
  74.   }
  75.  
  76.   public int getNumContainers() {
  77.     return cards.size();
  78.   }
  79.  
  80.   public int getNumPastMoves() {
  81.     return pastMoves.size();
  82.   }
  83.  
  84.   public int getNumSuits() {
  85.     return numSuits;
  86.   }
  87.  
  88.   public boolean isSorted() {
  89.     int numSuitsSeen = 1;
  90.     Card previousCard = null;
  91.     boolean sameColorTouching = false;
  92.     boolean[] suitsSeen = new boolean[Card.NUM_SUITS];
  93.     suitsSeen[getFirstCardAt(0).getSuitRank()] = true;
  94.     for (Card card : this) {
  95.       int currentSuitRank = card.getSuitRank();
  96.       if (previousCard != null) {
  97.         if (!card.hasSameSuit(previousCard)) {
  98.           numSuitsSeen++;
  99.           if (suitsSeen[currentSuitRank]) {
  100.             return false;
  101.           }
  102.           if (!card.hasDifferentColor(previousCard)) {
  103.             sameColorTouching = true;
  104.           }
  105.           // if there are more than 2 suits, they must alternate colors
  106.           if (sameColorTouching && numSuitsSeen > 2) {
  107.             return false;
  108.           }
  109.           suitsSeen[currentSuitRank] = true;
  110.           previousCard = null;
  111.         } else {
  112.           if (card.getRank() > previousCard.getRank()) {
  113.             return false;
  114.           }
  115.         }
  116.       }
  117.       previousCard = card;
  118.     }
  119.     return true;
  120.   }
  121.  
  122.   public Iterator<Card> iterator() {
  123.     return new HandIterator();
  124.   }
  125.  
  126.   public Hand moveCardContainers(int from, int length, int to) {
  127.     List<ArrayList<Card>> cardCopy = copyCards();
  128.     List<ArrayList<Card>> removed = new ArrayList<>(length);
  129.     for (int i = 0; i < length; i++) {
  130.       removed.add(cardCopy.remove(from));
  131.     }
  132.     cardCopy.addAll(to, removed);
  133.     return new Hand(cardCopy);
  134.   }
  135.  
  136.   public List<Hand> nextMoves(int minContainers) {
  137.     if (cards.size() > minContainers) {
  138.       return new ArrayList<>();
  139.     }
  140.     List<Hand> nextMoves = new ArrayList<>();
  141.     boolean[] sameSuitMoves = new boolean[Card.NUM_SUITS];
  142.     for (int from = 0; from < cards.size() - 1; from++) {
  143.       int currentSuit = getFirstCardAt(from).getSuitRank();
  144.       for (int length = 1; length + from < cards.size(); length++) {
  145.         if (getFirstCardAt(from + length - 1).getSuitRank() != currentSuit) {
  146.           currentSuit = -1;
  147.         }
  148.         boolean unsortingViolation = false;
  149.         for (int to = from + 1; to + length - 1 < cards.size(); to++) {
  150.           Card firstTo = getFirstCardAt(to + length - 1);
  151.           for (int i = from; i < from + length; i++) {
  152.             Card firstFrom = getFirstCardAt(i);
  153.             if (firstFrom.getSuitRank() == firstTo.getSuitRank()
  154.                 && firstFrom.getRank() > firstTo.getRank()) {
  155.               unsortingViolation = true;
  156.               break;
  157.             }
  158.           }
  159.           if (unsortingViolation) {
  160.             break;
  161.           }
  162.           Hand hand = createNextHand(from, length, to);
  163.           if (minContainers > hand.cards.size()) {
  164.             nextMoves = new ArrayList<>();
  165.             sameSuitMoves = new boolean[Card.NUM_SUITS];
  166.             minContainers = hand.cards.size();
  167.           }
  168.           if (currentSuit != -1 && (from == 0 || getFirstCardAt(from - 1).getSuitRank() == currentSuit)
  169.               && (to + length == cards.size() || getFirstCardAt(to + length).getSuitRank() == currentSuit)) {
  170.             // same suit move
  171.             if (sameSuitMoves[currentSuit]) {
  172.               break;
  173.             } else {
  174.               sameSuitMoves[currentSuit] = true;
  175.             }
  176.           }
  177.           if (minContainers == hand.cards.size()) {
  178.             nextMoves.add(hand);
  179.           }
  180.         }
  181.       }
  182.     }
  183.     return nextMoves;
  184.   }
  185.  
  186.   public void pastMovePrint() {
  187.     for (Hand hand : pastMoves) {
  188.       if (hand.printLength == 1) {
  189.         System.out.println("move group " + (hand.printFrom + 1) + " after group "
  190.             + (hand.printLength + hand.printTo));
  191.       } else {
  192.         System.out.println("move groups " + (hand.printFrom + 1) + " to "
  193.             + (hand.printFrom + hand.printLength) + " after group "
  194.             + (hand.printLength + hand.printTo));
  195.       }
  196.       System.out.println(hand);
  197.     };
  198.   }
  199.  
  200.   public void sort() {
  201.     List<Hand> bfsList = new ArrayList<>();
  202.     bfsList.add(this);
  203.     int previousLevel = -1;
  204.     int minContainers = Integer.MAX_VALUE;
  205.     while (!bfsList.isEmpty()) {
  206.       Hand currentHand = bfsList.remove(0);
  207.       if (currentHand.getNumPastMoves() != previousLevel) {
  208.         previousLevel = currentHand.getNumPastMoves();
  209.         System.out.println("level " + previousLevel + ", bfs queue size " + bfsList.size());
  210.         System.out.println(currentHand);
  211.       }
  212.       if (currentHand.isSorted()) {
  213.         System.out.println("\noriginal hand");
  214.         System.out.println(this);
  215.         currentHand.pastMovePrint();
  216.         System.out.println("sorted in " + currentHand.getNumPastMoves() + " moves");
  217.         System.out.println("level " + previousLevel + ", bfs queue size " + bfsList.size());
  218.         break;
  219.       }
  220.  
  221.       if (currentHand.getNumContainers() < minContainers) {
  222.         minContainers = currentHand.getNumContainers();
  223.       }
  224.       bfsList.addAll(currentHand.nextMoves(minContainers));
  225.     }
  226.   }
  227.  
  228.   public String toString() {
  229.     StringBuilder sb = new StringBuilder();
  230.     for (List<Card> cardGroup : cards) {
  231.       for (Card card : cardGroup) {
  232.         sb.append(card.suitToShortString());
  233.       }
  234.       sb.append(' ');
  235.     }
  236.     sb.append('\n');
  237.     for (List<Card> cardGroup : cards) {
  238.       for (Card card : cardGroup) {
  239.         sb.append(card.rankToShortString());
  240.       }
  241.       sb.append(' ');
  242.     }
  243.     return sb.toString();
  244.   }
  245.  
  246.   private Hand createNextHand(int from, int length, int to) {
  247.     Hand hand = moveCardContainers(from, length, to);
  248.     hand.mergeGroups();
  249.     hand.pastMoves.addAll(this.pastMoves);
  250.     hand.pastMoves.add(hand);
  251.     hand.printFrom = from;
  252.     hand.printLength = length;
  253.     hand.printTo = to;
  254.     return hand;
  255.   }
  256.  
  257.   @SuppressWarnings("unchecked")
  258.   private List<ArrayList<Card>> copyCards() {
  259.     List<ArrayList<Card>> copy = new ArrayList<>(cards.size());
  260.     for (ArrayList<Card> cardContainer : cards) {
  261.       copy.add((ArrayList<Card>) cardContainer.clone());
  262.     }
  263.     return copy;
  264.   }
  265.  
  266.   private Card getFirstCard(List<Card> cardContainer) {
  267.     return cardContainer.get(0);
  268.   }
  269.  
  270.   private Card getFirstCardAt(int index) {
  271.     return cards.get(index).get(0);
  272.   }
  273.  
  274.   private Card getLastCard(List<Card> cardContainer) {
  275.     return cardContainer.get(cardContainer.size() - 1);
  276.   }
  277.  
  278.   private void mergeGroups() {
  279.     for (int i = 0; i < cards.size() - 1; i++) {
  280.       List<Card> cardGroup = cards.get(i);
  281.       List<Card> nextCardGroup = cards.get(i + 1);
  282.       if (getLastCard(cardGroup).getRightAdj() == getFirstCard(nextCardGroup)) {
  283.         cardGroup.addAll(nextCardGroup);
  284.         cards.remove(i + 1);
  285.         i--;
  286.       }
  287.     }
  288.   }
  289.  
  290.   private class HandIterator implements Iterator<Card> {
  291.  
  292.     private Iterator<Card> inner;
  293.     private Iterator<ArrayList<Card>> outer = cards.iterator();
  294.  
  295.     private HandIterator() {
  296.       inner = outer.next().iterator();
  297.     }
  298.  
  299.     @Override
  300.     public boolean hasNext() {
  301.       return inner.hasNext();
  302.     }
  303.  
  304.     @Override
  305.     public Card next() {
  306.       Card next = inner.next();
  307.       if (!inner.hasNext() && outer.hasNext()) {
  308.         inner = outer.next().iterator();
  309.       }
  310.       return next;
  311.     }
  312.  
  313.     @Override
  314.     public void remove() {
  315.       throw new UnsupportedOperationException();
  316.     }
  317.   }
  318. }
  319.  
  320. -----------------------------------------------------------------
  321.  
  322. public class Card implements Comparable<Card> {
  323.  
  324.   public static final int MIN_RANK = 2;
  325.   public static final int MAX_RANK = 14;
  326.   public static final int NUM_SUITS = 4;
  327.  
  328.   private int rank; // 2 through 14
  329.   private Card rightAdj;
  330.   private Suit suit;
  331.  
  332.   public Card(int rank, Suit suit) {
  333.     if (rank < MIN_RANK || MAX_RANK > 14) {
  334.       throw new IllegalArgumentException("rank must be in [" + MIN_RANK + ", " + MAX_RANK + "]");
  335.     }
  336.     this.rank = rank;
  337.     this.suit = suit;
  338.   }
  339.  
  340.   public int compareTo(Card other) {
  341.     if (!hasSameSuit(other)) {
  342.       return other.getSuitRank() - getSuitRank();
  343.     }
  344.     return other.rank - rank;
  345.   }
  346.  
  347.   public int getRank() {
  348.     return rank;
  349.   }
  350.  
  351.   public Card getRightAdj() {
  352.     return rightAdj;
  353.   }
  354.  
  355.   public Suit getSuit() {
  356.     return suit;
  357.   }
  358.  
  359.   public int getSuitRank() {
  360.     return suit.getSuitRank();
  361.   }
  362.  
  363.   public boolean hasDifferentColor(Card other) {
  364.     return suit.hasDifferentColor(other.suit);
  365.   }
  366.  
  367.   public boolean hasSameSuit(Card other) {
  368.     return suit == other.suit;
  369.   }
  370.  
  371.   public String rankToShortString() {
  372.     switch (this.rank) {
  373.     case 14:
  374.       return "A";
  375.     case 13:
  376.       return "K";
  377.     case 12:
  378.       return "Q";
  379.     case 11:
  380.       return "J";
  381.     case 10:
  382.       return "T";
  383.     default:
  384.       return String.valueOf(rank);
  385.     }
  386.   }
  387.  
  388.   public void setRightAdj(Card rightAdj) {
  389.     this.rightAdj = rightAdj;
  390.   }
  391.  
  392.   public String suitToShortString() {
  393.     return suit.toShortString();
  394.   }
  395.  
  396.   public String toString() {
  397.     return suitToShortString() + rankToShortString();
  398.   }
  399. }
  400.  
  401. -----------------------------------------------------------------
  402.  
  403. public enum Suit {
  404.  
  405.   SPADES(3),
  406.   HEARTS(2),
  407.   DIAMONDS(1),
  408.   CLUBS(0),
  409.   ;
  410.  
  411.   private int suitRank;
  412.  
  413.   private Suit(int suitRank) {
  414.     this.suitRank = suitRank;
  415.   }
  416.  
  417.   public int getSuitRank() {
  418.     return suitRank;
  419.   }
  420.  
  421.   public boolean hasDifferentColor(Suit other) {
  422.     return this.suitRank + other.suitRank != 3;
  423.   }
  424.  
  425.   public String toShortString() {
  426.     return name().substring(0, 1);
  427.   }
  428. }
  429.  
  430. -----------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement