Android Open Source - FourRowSolitaire Solitaire Board






From Project

Back to project page FourRowSolitaire.

License

The source code is released under:

GNU General Public License

If you think the Android project FourRowSolitaire listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 This file is a part of Four Row Solitaire
/*  www  . ja v a2  s.  c o m*/
 Copyright (C) 2010-2014 by Matt Stephen, Todor Balabanov, Konstantin Tsanov, Ventsislav Medarov, Vanya Gyaurova, Plamena Popova, Hristiana Kalcheva, Yana Genova

 Four Row Solitaire is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Four Row Solitaire is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with FourRowSolitaire.  If not, see <http://www.gnu.org/licenses/>.
 */

package eu.veldsoft.four.row.solitaire;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

/**
 * Class: SolitaireBoard
 * 
 * Description: The SolitaireBoard class manages the entire playing field.
 * 
 * @author Matt Stephen
 */
class SolitaireBoard {

  /**
   * 
   */
  private static final int INITIAL_CARDS_NUMBER_IN_COLUMN = 5;

  /**
   * Can be 1 or 3. Should be only here!
   */
  static int drawCount = 1;

  /**
   * To store new option selection for next new game, otherwise the count
   * would be changed at next click of the deck (in the middle of the game).
   */
  private int newDrawCount = drawCount;

  /**
   * 1 = easy, 2 = medium, 3 = hard Should be only here!
   */
  private GameDifficulty difficulty = GameDifficulty.EASY;

  /**
   * Game difficulty.
   */
  private GameDifficulty newDifficulty = difficulty;

  /**
   * Card numbers.
   */
  // TODO Should be private.
  LinkedList<Integer> numCards = new LinkedList<Integer>();

  /**
   * The cards from the discard pile.
   */
  LinkedList<Integer> numCardsInDiscardView = new LinkedList<Integer>();

  /**
   * The four columns for the main playing field.
   */
  // TODO Should be private.
  Column[] columns = { null, null, null, null };

  /**
   * The discard pile.
   */
  // TODO Should be private.
  DiscardPile discardPile = new DiscardPile();

  /**
   * The deal pile.
   */
  // TODO Should be private.
  DealDeck dealDeck = new DealDeck(discardPile);

  /**
   * The four ace piles (to stack Ace - King of a single suit).
   */
  // TODO Should be private.
  AcePile[] acePiles = { null, null, null, null };

  /**
   * The four top individual cells.
   */
  // TODO Should be private.
  SingleCell[] cells = { null, null, null, null };

  /**
   * Source.
   */
  // TODO Should be private.
  LinkedList<CardStack> sourceList = new LinkedList<CardStack>();

  /**
   * Destination.
   */
  // TODO Should be private.
  LinkedList<CardStack> destinationList = new LinkedList<CardStack>();

  /**
   * Sets the board's window name, size, location, close button option, makes
   * it unresizable and puts the logo on it.
   * 
   * @author Todor Balabanov
   */
  public SolitaireBoard() {
  }

  /**
   * Check for highlighted cards in the board.
   * 
   * @return True if there is a card or bunch of cards highlighted and false
   *         otherwise.
   * 
   * @author Todor Balabanov
   */
  public int highlightedCards() {
    int counter = 0;

    for (int i = 0; i < columns.length; i++) {
      for (int j = 0; j < columns[i].length(); j++) {
        if (columns[i].getCardAtLocation(j).isHighlighted() == true) {
          counter++;
        }
      }
    }

    for (int i = 0; i < cells.length; i++) {
      if (cells[i].isEmpty() == false
          && cells[i].peek().isHighlighted() == true) {
        counter++;
      }
    }

    for (int i = 0; i < acePiles.length; i++) {
      if (acePiles[i].isEmpty() == false
          && acePiles[i].peek().isHighlighted() == true) {
        counter++;
      }
    }

    if (discardPile.isEmpty() == false
        && discardPile.peek().isHighlighted() == true) {
      counter++;
    }

    return (counter);
  }

  /**
   * Mark all cards on the board as non highlighted.
   * 
   * @author Todor Balabanov
   */
  public void clearHighlighting() {
    for (int n = 1; n <= 52; n++) {
      Card.valueBy(n).unhighlight();
    }
  }

  /**
   * Creates the solitaire board.
   * 
   * @param cards
   *            List of cards.
   * 
   * @param numViewableCards
   *            Number of viewable cards.
   * 
   * @author Todor Balabanov
   */
  public void createBoard(LinkedList<Integer> cards, int numViewableCards) {
    for (int i = 0; i < columns.length; i++) {
      columns[i] = new Column();
    }

    for (int i = 0; i < cells.length; i++) {
      cells[i] = new SingleCell();
    }

    for (int i = 0; i < acePiles.length; i++) {
      switch (i) {
      case 0:
        acePiles[i] = new AcePile(CardSuit.SPADES);
        break;
      case 1:
        acePiles[i] = new AcePile(CardSuit.CLUBS);
        break;
      case 2:
        acePiles[i] = new AcePile(CardSuit.DIAMONDS);
        break;
      case 3:
        acePiles[i] = new AcePile(CardSuit.HEARTS);
        break;
      default:
        break;
      }
    }
  }

  /**
   * Deals the cards.
   * 
   * @author Todor Balabanov
   */
  void dealOutBoard() {
    LinkedList<Card> cards = (LinkedList<Card>) Deck.getFullShuffledDeck();

    /*
     * Fill five cards by column.
     */
    for (int i = 0; i < INITIAL_CARDS_NUMBER_IN_COLUMN; i++) {
      for (int j = 0; j < columns.length; j++) {
        columns[j].addCard(cards.getLast());
        cards.removeLast();
      }
    }

    /*
     * Fill cards in buffer area.
     */
    for (int j = 0; j < cells.length; j++) {
      cells[j].addCard(cards.getLast());
      cards.removeLast();
    }

    dealDeck.setDeck(cards);
    dealDeck.setDrawCount(newDrawCount);
    dealDeck.setDifficulty(newDifficulty);

    if (newDrawCount != drawCount) {
      drawCount = newDrawCount;
    }

    if (newDifficulty != difficulty) {
      difficulty = newDifficulty;
    }

    clearHighlighting();
  }

  /**
   * Used to deal the cards on the board after opening a saved game.
   * 
   * @param numbers
   *            List of integers.
   * 
   * @param numViewableCards
   *            Number of viewable cards.
   * 
   * @author Todor Balabanov
   */
  void dealOutCustomBoard(LinkedList<Integer> numbers, int numViewableCards) {
    List<Card> cards = Deck.getDeckSubsetByCardNumbers(numbers);

    int pileNumber = 0;
    int cardNumber = -1;

    dealDeck.setDrawCount(drawCount);
    dealDeck.setDifficulty(difficulty);

    for (int i = 0; i < numbers.size(); i++) {
      if (numbers.get(i) > 0) {
        cardNumber++;
      } else {
        pileNumber++;
        continue;
      }

      if (0 <= pileNumber && pileNumber <= 3) {
        cells[pileNumber % 4].addCard(cards.get(cardNumber));
      } else if (4 <= pileNumber && pileNumber <= 7) {
        columns[pileNumber % 4].addCard(cards.get(cardNumber));
      } else if (8 <= pileNumber && pileNumber <= 11) {
        acePiles[pileNumber % 4].addCard(cards.get(cardNumber));
      } else if (pileNumber == 12) {
        CardComponent card = CardComponent.cardsMapping.get(cards
            .get(cardNumber));
        card.setFaceDown();
        dealDeck.addCard(card.getCard());
      } else if (pileNumber == 13) {
        discardPile.push(cards.get(cardNumber));
      }
    }

    discardPile.setView(numViewableCards);
  }

  /**
   * Clears the board.
   * 
   * @author Todor Balabanov
   */
  void clearBoard() {
    for (int i = 0; i < columns.length; i++) {
      while (columns[i].isEmpty() == false) {
        columns[i].pop();
      }
    }

    for (int i = 0; i < cells.length; i++) {
      while (cells[i].isEmpty() == false) {
        cells[i].pop();
      }
    }

    for (int i = 0; i < acePiles.length; i++) {
      while (acePiles[i].isEmpty() == false) {
        acePiles[i].pop();
      }
    }

    while (dealDeck.isEmpty() == false) {
      dealDeck.pop();
    }

    while (discardPile.isEmpty() == false) {
      discardPile.pop();
    }
  }

  /**
   * For starting a new game.
   * 
   * @param winOrLoss
   *            Game state.
   * 
   * @author Todor Balabanov
   */
  public void newGame(GameState winOrLoss) {
    /*
     * Remove cards from ace piles. Set numTimesThroughDeck back to 1.
     */
    clearBoard();
    dealDeck.reset();

    sourceList.clear();
    destinationList.clear();
    numCards.clear();
    numCardsInDiscardView.clear();
  }

  /**
   * Manages the game states.
   * 
   * @param winOrLoss
   *            Game state.
   * 
   * @param timerCount
   *            Timer.
   * 
   * @param backgroundNumber
   *            Background number.
   * 
   * @param deckNumber
   *            Card back number.
   * 
   * @param timerToRunNextGame
   *            Timer to next game.
   * 
   * @param timerToRun
   *            Timer to run.
   * 
   * @author Todor Balabanov
   */
  void recordGame(GameState winOrLoss, int deckNumber, int backgroundNumber,
      int timerCount, int timerToRunNextGame, boolean timerToRun) {
    int count = 0, temp = 0;
    int gamesPlayed1e = 0, gamesWon1e = 0, winStreak1e = 0, lossStreak1e = 0, currentStreak1e = 0;
    int gamesPlayed1m = 0, gamesWon1m = 0, winStreak1m = 0, lossStreak1m = 0, currentStreak1m = 0;
    int gamesPlayed1h = 0, gamesWon1h = 0, winStreak1h = 0, lossStreak1h = 0, currentStreak1h = 0;
    int gamesPlayed3e = 0, gamesWon3e = 0, winStreak3e = 0, lossStreak3e = 0, currentStreak3e = 0;
    int gamesPlayed3m = 0, gamesWon3m = 0, winStreak3m = 0, lossStreak3m = 0, currentStreak3m = 0;
    int gamesPlayed3h = 0, gamesWon3h = 0, winStreak3h = 0, lossStreak3h = 0, currentStreak3h = 0;

    String fileLocation = System.getProperty("user.home")
        + System.getProperty("file.separator");
    File file = new File(fileLocation + "frs-statistics.dat");

    try {
      file.createNewFile();
    } catch (Exception ex) {
      System.out.println(ex);
    }

    try {
      DataInputStream input = new DataInputStream(new FileInputStream(
          file));

      if (input.available() > 0) {
        temp = input.readInt();
        count++;
      }

      if (temp != -1) {
        gamesPlayed1m = temp;

        while ((input.available() > 0) && count < 5) {
          temp = input.readInt();
          switch (count) {
          /*
           * Case 0 is the format checker.
           */
          case 1:
            gamesWon1m = temp;
            break;
          case 2:
            winStreak1m = temp;
            break;
          case 3:
            lossStreak1m = temp;
            break;
          case 4:
            currentStreak1m = temp;
            break;

          default:
            break;
          }

          count++;
        }
      } else {
        while ((input.available() > 0) && count < 31) {
          temp = input.readInt();
          switch (count) {
          /*
           * Case 0 is the format checker.
           */
          case 1:
            gamesPlayed1e = temp;
            break;
          case 2:
            gamesWon1e = temp;
            break;
          case 3:
            winStreak1e = temp;
            break;
          case 4:
            lossStreak1e = temp;
            break;
          case 5:
            currentStreak1e = temp;
            break;

          case 6:
            gamesPlayed1m = temp;
            break;
          case 7:
            gamesWon1m = temp;
            break;
          case 8:
            winStreak1m = temp;
            break;
          case 9:
            lossStreak1m = temp;
            break;
          case 10:
            currentStreak1m = temp;
            break;

          case 11:
            gamesPlayed1h = temp;
            break;
          case 12:
            gamesWon1h = temp;
            break;
          case 13:
            winStreak1h = temp;
            break;
          case 14:
            lossStreak1h = temp;
            break;
          case 15:
            currentStreak1h = temp;
            break;

          case 16:
            gamesPlayed3e = temp;
            break;
          case 17:
            gamesWon3e = temp;
            break;
          case 18:
            winStreak3e = temp;
            break;
          case 19:
            lossStreak3e = temp;
            break;
          case 20:
            currentStreak3e = temp;
            break;

          case 21:
            gamesPlayed3m = temp;
            break;
          case 22:
            gamesWon3m = temp;
            break;
          case 23:
            winStreak3m = temp;
            break;
          case 24:
            lossStreak3m = temp;
            break;
          case 25:
            currentStreak3m = temp;
            break;

          case 26:
            gamesPlayed3h = temp;
            break;
          case 27:
            gamesWon3h = temp;
            break;
          case 28:
            winStreak3h = temp;
            break;
          case 29:
            lossStreak3h = temp;
            break;
          case 30:
            currentStreak3h = temp;
            break;

          default:
            break;
          }

          count++;
        }
      }

      input.close();
    } catch (Exception ex) {
      System.out.println(ex);
    }

    try {
      DataOutputStream output = new DataOutputStream(
          new FileOutputStream(file));

      if (winOrLoss == GameState.GAME_WON) {
        if (drawCount == 3) {
          if (difficulty == GameDifficulty.EASY) {
            gamesPlayed3e++;
            gamesWon3e++;

            if (currentStreak3e >= 0) {
              currentStreak3e++;
            } else {
              currentStreak3e = 1;
            }

            if (winStreak3e < currentStreak3e) {
              winStreak3e = currentStreak3e;
            }
          } else if (difficulty == GameDifficulty.MEDIUM) {
            gamesPlayed3m++;
            gamesWon3m++;

            if (currentStreak3m >= 0) {
              currentStreak3m++;
            } else {
              currentStreak3m = 1;
            }

            if (winStreak3m < currentStreak3m) {
              winStreak3m = currentStreak3m;
            }
          } else {
            gamesPlayed3h++;
            gamesWon3h++;

            if (currentStreak3h >= 0) {
              currentStreak3h++;
            } else {
              currentStreak3h = 1;
            }

            if (winStreak3h < currentStreak3h) {
              winStreak3h = currentStreak3h;
            }
          }
        } else if (drawCount == 1) {
          if (difficulty == GameDifficulty.EASY) {
            gamesPlayed1e++;
            gamesWon1e++;

            if (currentStreak1e >= 0) {
              currentStreak1e++;
            } else {
              currentStreak1e = 1;
            }

            if (winStreak1e < currentStreak1e) {
              winStreak1e = currentStreak1e;
            }
          } else if (difficulty == GameDifficulty.MEDIUM) {
            gamesPlayed1m++;
            gamesWon1m++;

            if (currentStreak1m >= 0) {
              currentStreak1m++;
            } else {
              currentStreak1m = 1;
            }

            if (winStreak1m < currentStreak1m) {
              winStreak1m = currentStreak1m;
            }
          } else {
            gamesPlayed1h++;
            gamesWon1h++;

            if (currentStreak1h >= 0) {
              currentStreak1h++;
            } else {
              currentStreak1h = 1;
            }

            if (winStreak1h < currentStreak1h) {
              winStreak1h = currentStreak1h;
            }
          }
        }
      } else if (winOrLoss == GameState.RESET_STATS) {
        gamesWon1e = 0;
        gamesPlayed1e = 0;
        currentStreak1e = 0;
        winStreak1e = 0;
        lossStreak1e = 0;

        gamesWon1m = 0;
        gamesPlayed1m = 0;
        currentStreak1m = 0;
        winStreak1m = 0;
        lossStreak1m = 0;

        gamesWon1h = 0;
        gamesPlayed1h = 0;
        currentStreak1h = 0;
        winStreak1h = 0;
        lossStreak1h = 0;

        gamesWon3e = 0;
        gamesPlayed3e = 0;
        currentStreak3e = 0;
        winStreak3e = 0;
        lossStreak3e = 0;

        gamesWon3m = 0;
        gamesPlayed3m = 0;
        currentStreak3m = 0;
        winStreak3m = 0;
        lossStreak3m = 0;

        gamesWon3h = 0;
        gamesPlayed3h = 0;
        currentStreak3h = 0;
        winStreak3h = 0;
        lossStreak3h = 0;
      } else if (winOrLoss == GameState.DO_NOTHING
          || winOrLoss == GameState.GAME_SAVED) {
        /*
         * Just updating options.
         */
      } else {
        if (drawCount == 3) {
          if (difficulty == GameDifficulty.EASY) {
            gamesPlayed3e++;

            if (currentStreak3e <= 0) {
              currentStreak3e--;
            } else {
              currentStreak3e = -1;
            }

            if (lossStreak3e > currentStreak3e) {
              lossStreak3e = currentStreak3e;
            }
          } else if (difficulty == GameDifficulty.MEDIUM) {
            gamesPlayed3m++;

            if (currentStreak3m <= 0) {
              currentStreak3m--;
            } else {
              currentStreak3m = -1;
            }

            if (lossStreak3m > currentStreak3m) {
              lossStreak3m = currentStreak3m;
            }
          } else {
            gamesPlayed3h++;

            if (currentStreak3h <= 0) {
              currentStreak3h--;
            } else {
              currentStreak3h = -1;
            }

            if (lossStreak3h > currentStreak3h) {
              lossStreak3h = currentStreak3h;
            }
          }
        } else if (drawCount == 1) {
          if (difficulty == GameDifficulty.EASY) {
            gamesPlayed1e++;

            if (currentStreak1e <= 0) {
              currentStreak1e--;
            } else {
              currentStreak1e = -1;
            }

            if (lossStreak1e > currentStreak1e) {
              lossStreak1e = currentStreak1e;
            }
          } else if (difficulty == GameDifficulty.MEDIUM) {
            gamesPlayed1m++;

            if (currentStreak1m <= 0) {
              currentStreak1m--;
            } else {
              currentStreak1m = -1;
            }

            if (lossStreak1m > currentStreak1m) {
              lossStreak1m = currentStreak1m;
            }
          } else {
            gamesPlayed1h++;

            if (currentStreak1h <= 0) {
              currentStreak1h--;
            } else {
              currentStreak1h = -1;
            }

            if (lossStreak1h > currentStreak1h) {
              lossStreak1h = currentStreak1h;
            }
          }
        }
      }

      /*
       * New format indicator.
       */
      output.writeInt(-1);

      output.writeInt(gamesPlayed1e);
      output.writeInt(gamesWon1e);
      output.writeInt(winStreak1e);
      output.writeInt(lossStreak1e);
      output.writeInt(currentStreak1e);

      output.writeInt(gamesPlayed1m);
      output.writeInt(gamesWon1m);
      output.writeInt(winStreak1m);
      output.writeInt(lossStreak1m);
      output.writeInt(currentStreak1m);

      output.writeInt(gamesPlayed1h);
      output.writeInt(gamesWon1h);
      output.writeInt(winStreak1h);
      output.writeInt(lossStreak1h);
      output.writeInt(currentStreak1h);

      output.writeInt(gamesPlayed3e);
      output.writeInt(gamesWon3e);
      output.writeInt(winStreak3e);
      output.writeInt(lossStreak3e);
      output.writeInt(currentStreak3e);

      output.writeInt(gamesPlayed3m);
      output.writeInt(gamesWon3m);
      output.writeInt(winStreak3m);
      output.writeInt(lossStreak3m);
      output.writeInt(currentStreak3m);

      output.writeInt(gamesPlayed3h);
      output.writeInt(gamesWon3h);
      output.writeInt(winStreak3h);
      output.writeInt(lossStreak3h);
      output.writeInt(currentStreak3h);

      output.writeInt(drawCount);
      output.writeInt(newDrawCount);
      output.writeInt(deckNumber);
      output.writeInt(backgroundNumber);
      output.writeInt(timerToRunNextGame);

      /*
       * Finish saving options.
       */
      output.writeInt(WinScreen.animation);
      output.writeInt(WinScreen.sounds);
      output.writeInt(dealDeck.getDeckThroughs());
      output.writeInt(difficulty.getValue());
      output.writeInt(newDifficulty.getValue());
      output.writeInt(discardPile.getNumViewableCards());

      File savedFile = new File(fileLocation + "frs-savedgame.dat");
      DataOutputStream saved = new DataOutputStream(new FileOutputStream(
          savedFile));

      if (winOrLoss == GameState.GAME_SAVED) {
        /*
         * Saved.
         */
        output.writeInt(1);

        for (int i = 0; i < cells.length; i++) {
          if (!cells[i].isEmpty()) {
            saved.writeInt(cells[i].peek().getFullNumber());
            saved.writeInt(-1);
          } else {
            saved.writeInt(-1);
          }
        }

        for (int i = 0; i < columns.length; i++) {
          if (!columns[i].isEmpty()) {
            for (int j = 0; j < columns[i].length(); j++) {
              saved.writeInt(columns[i].getCardAtLocation(j)
                  .getFullNumber());
            }

            saved.writeInt(-1);
          } else {
            saved.writeInt(-1);
          }
        }

        for (int i = 0; i < acePiles.length; i++) {
          if (!acePiles[i].isEmpty()) {
            for (int j = 0; j < acePiles[i].length(); j++) {
              saved.writeInt(acePiles[i].getCardAtLocation(j)
                  .getFullNumber());
            }

            saved.writeInt(-1);
          } else {
            saved.writeInt(-1);
          }
        }

        if (!dealDeck.isEmpty()) {
          for (int j = 0; j < dealDeck.length(); j++) {
            saved.writeInt(dealDeck.getCardAtLocation(j)
                .getFullNumber());
          }

          saved.writeInt(-1);
        } else {
          saved.writeInt(-1);
        }

        if (!discardPile.isEmpty()) {
          for (int j = 0; j < discardPile.length(); j++) {
            saved.writeInt(discardPile.getCardAtLocation(j)
                .getFullNumber());
          }

          saved.writeInt(-1);
        } else {
          saved.writeInt(-1);
        }

        if (timerToRun == true)
          saved.writeInt(timerCount);
        else
          saved.writeInt(-1);
      } else {
        /*
         * Not saved.
         */
        output.writeInt(0);
        savedFile.delete();
      }

      output.close();
      saved.close();
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  /**
   * Returns the draw count.
   * 
   * @return drawCount Current draw count.
   * 
   * @author Todor Balabanov
   */
  public int getDrawCount() {
    return drawCount;
  }

  /**
   * Sets draw count.
   * 
   * @param draw
   *            Sets the new draw count.
   * 
   * @author Todor Balabanov
   */
  public void setDrawCount(int draw) {
    drawCount = draw;

    if (drawCount != 3 && drawCount != 1) {
      drawCount = 1;
    }
  }

  /**
   * Returns the new draw count.
   * 
   * @return newDrawCount New draw count.
   * 
   * @author Todor Balabanov
   */
  public int getNewDrawCount() {
    return newDrawCount;
  }

  /**
   * Sets the new draw count.
   * 
   * @param draw
   *            New draw count to be set.
   * 
   * @author Todor Balabanov
   */
  public void setNewDrawCount(int draw) {
    newDrawCount = draw;

    if (newDrawCount != 3 && newDrawCount != 1) {
      newDrawCount = 1;
    }
  }

  /**
   * Returns game difficulty.
   * 
   * @return difficulty Current game difficulty.
   * 
   * @author Todor Balabanov
   */
  public GameDifficulty getDifficulty() {
    return difficulty;
  }

  /**
   * Sets game difficulty.
   * 
   * @param difficulty
   *            The new game difficulty.
   * 
   * @author Todor Balabanov
   */
  public void setDifficulty(GameDifficulty difficulty) {
    this.difficulty = difficulty;
  }

  /**
   * Returns the new difficulty.
   * 
   * @return newDifficulty New difficulty.
   * 
   * @author Todor Balabanov
   */
  public GameDifficulty getNewDifficulty() {
    return newDifficulty;
  }

  /**
   * Sets the new difficulty.
   * 
   * @param newDifficulty
   *            New difficulty to be set.
   * 
   * @author Todor Balabanov
   */
  public void setNewDifficulty(GameDifficulty newDifficulty) {
    this.newDifficulty = newDifficulty;
  }

  /**
   * Sets the number of times through deck.
   * 
   * @param deckThroughs
   *            Deck throughs to be set.
   * 
   * @author Todor Balabanov
   */
  public void setDeckThroughs(int deckThroughs) {
    dealDeck.setDeckThroughs(deckThroughs);
  }

  /**
   * Used to undo a move.
   * 
   * @author Todor Balabanov
   */
  public synchronized void undoMove() {
    if (sourceList.isEmpty()) {
      return;
    }

    /*
     * If player is holding on to a card.
     */
    if (sourceList.size() > destinationList.size()) {
      CardStack tempSource = sourceList.getLast();
      sourceList.removeLast();

      int num = numCards.getLast();
      numCards.removeLast();

      int numDiscard = numCardsInDiscardView.getLast();
      numCardsInDiscardView.removeLast();

      if (num == 1) {
        discardPile.setView(numDiscard);
        tempSource.peek().unhighlight();
      } else {
        for (int i = 0; i < num; i++) {
          tempSource.getCardAtLocation(tempSource.length() - i - 1)
              .unhighlight();
        }
      }
    } else if (!(sourceList.getLast() instanceof DealDeck)) {
      CardStack tempSource = sourceList.getLast();
      CardStack tempDest = destinationList.getLast();
      int num = numCards.getLast();
      int numDiscard = numCardsInDiscardView.getLast();

      sourceList.removeLast();
      destinationList.removeLast();
      numCards.removeLast();
      numCardsInDiscardView.removeLast();

      if (num == 1) {
        tempSource.addCard(tempDest.pop());
      } else {
        Vector<Card> temp = tempDest.undoStack(num);
        tempSource.addStack(temp);
      }

      discardPile.setView(numDiscard);
    }
    /*
     * The last draw from the deck didn't reset the discard pile to make it
     * an empty pile.
     */
    else if (sourceList.getLast() instanceof DealDeck
        && !destinationList.getLast().isEmpty()) {
      int num = numCards.getLast();
      int numDiscard = numCardsInDiscardView.getLast();

      sourceList.removeLast();
      destinationList.removeLast();
      numCards.removeLast();
      numCardsInDiscardView.removeLast();

      for (int i = 0; i < num; i++) {
        Card card = discardPile.undoPop();
        card.setFaceDown();
        dealDeck.addCard(card);
      }

      discardPile.setView(numDiscard);
    }
    /*
     * Last move was a reset on the discard pile.
     */
    else if (sourceList.getLast() instanceof DealDeck) {
      dealDeck.undoPop();

      int numDiscard = numCardsInDiscardView.getLast();
      discardPile.setView(numDiscard);

      sourceList.removeLast();
      destinationList.removeLast();
      numCards.removeLast();
      numCardsInDiscardView.removeLast();
    }
  }

  /**
   * Manages the hints.
   * 
   * @return Hint structure.
   * 
   * @author Todor Balabanov
   */
  @SuppressWarnings("fallthrough")
  public String[] getHint() {
    CardStack source = null;
    CardStack destination = null;
    CardStack temp = null;

    LinkedList<String> hints = new LinkedList<String>();
    String sourceString = "";

    for (int i = 0; i < 9; i++) {
      switch (i) {
      case 0:
      case 1:
      case 2:
      case 3: {
        source = columns[i];
        sourceString = "Column " + (i + 1);
      }
        break;
      case 4:
      case 5:
      case 6:
      case 7: {
        source = cells[i - 4];
        sourceString = "Cell " + (i - 3);
      }
        break;
      case 8: {
        source = discardPile;
        sourceString = "the Discard Pile";
      }
        break;

      default:
        break;
      }

      if (source != null && !source.isEmpty()) {
        temp = source.getAvailableCards();
        String destinationString = "";

        for (int j = 0; j < 8; j++) {
          switch (j) {
          case 0:
          case 1:
          case 2:
          case 3: {
            destination = columns[j];
            destinationString = "Column " + (j + 1);
          }
            break;
          case 4:
          case 5:
          case 6:
          case 7: {
            destination = acePiles[j - 4];
            destinationString = "its Ace Pile";
          }
            break;

          default:
            break;
          }

          if (destination != null && !destination.isEmpty()
              && destination != source
              && !(destination instanceof SingleCell)) {
            for (int k = temp.length() - 1; k >= 0; k--) {
              CardComponent card = CardComponent.cardsMapping
                  .get(temp.getCardAtLocation(k));

              if (((destination instanceof AcePile)
                  && card.getCard()
                      .getSuit()
                      .equals(((AcePile) destination)
                          .getSuit())
                  && card.getCard()
                      .getRank()
                      .isLessByOneThan(
                          ((AcePile) (destination))
                              .peek().getRank()) && k == 0)
                  || (!(destination instanceof AcePile)
                      && card.getCard().getColor() != ((AcePile) destination)
                          .peek().getColor() && card
                      .getCard()
                      .getRank()
                      .isGreaterByOneThan(
                          (((AcePile) destination)
                              .peek()).getRank()))) {
                String hintString = "Move the ";

                if (card.getCard().getRank()
                    .equals(CardRank.JACK)) {
                  hintString += "Jack";
                } else if (card.getCard().getRank()
                    .equals(CardRank.QUEEN)) {
                  hintString += "Queen";
                } else if (card.getCard().getRank()
                    .equals(CardRank.KING)) {
                  hintString += "King";
                } else if (card.getCard().getRank()
                    .equals(CardRank.ACE)) {
                  hintString += "Ace";
                } else {
                  hintString += card.getCard().getRank();
                }

                hintString += " of " + card.getCard().getSuit()
                    + " in " + sourceString + " to the ";

                if (((AcePile) (destination)).peek().getRank()
                    .equals(CardRank.JACK)) {
                  hintString += "Jack";
                } else if (((AcePile) (destination)).peek()
                    .getRank().equals(CardRank.QUEEN)) {
                  hintString += "Queen";
                } else if (((AcePile) (destination)).peek()
                    .getRank().equals(CardRank.KING)) {
                  hintString += "King";
                } else if (((AcePile) (destination)).peek()
                    .getRank().equals(CardRank.ACE)) {
                  hintString += "Ace";
                } else {
                  hintString += ((AcePile) (destination))
                      .peek().getRank();
                }

                hintString += " of "
                    + ((AcePile) (destination)).peek()
                        .getSuit() + " in "
                    + destinationString;

                hints.add(hintString);
                /*
                 * Once a move is found from a source to
                 * destination, stop looking for more.
                 */
                break;
              }
            }
          } else if (destination != null
              && destination != source
              && (destination instanceof Column)
              && ((Column) destination).isEmpty()
              && (source.getBottom().getRank()
                  .equals(CardRank.KING) == false || source instanceof SingleCell)) {
            for (int k = 0; k < temp.length(); k++) {
              CardComponent card = CardComponent.cardsMapping
                  .get(temp.getCardAtLocation(k));

              if (card.getCard().getRank().equals(CardRank.KING)) {
                String hintString = "Move the King of "
                    + card.getCard().getSuit() + " in "
                    + sourceString + " to the empty "
                    + destinationString;

                hints.add(hintString);
                /*
                 * Once a move is found from a source to
                 * destination, stop looking for more.
                 */
                break;
              }
            }
          } else if (destination != null && destination != source
              && (destination instanceof AcePile)
              && ((AcePile) destination).isEmpty()) {
            CardComponent card = CardComponent.cardsMapping
                .get(temp.peek());

            if (card.getCard().getRank().equals(CardRank.ACE)
                && card.getCard()
                    .getSuit()
                    .equals(((AcePile) destination)
                        .getSuit())) {
              String hintString = "Move the Ace of "
                  + card.getCard().getSuit() + " in "
                  + sourceString + " to " + destinationString;

              hints.add(hintString);
              /*
               * Once a move is found from a source to
               * destination, stop looking for more.
               */
              break;
            }
          }
        }
      }
    }

    for (int i = 0; i < cells.length; i++) {
      if (cells[i].isEmpty() == true) {
        String hintString = "Move any available card to Cell "
            + (i + 1);
        hints.add(hintString);
      }
    }

    String hint[] = { "", "" };
    if (hints.isEmpty() == false) {
      for (int i = 0; i < hints.size(); i++) {
        hint[0] += hints.get(i) + "\n";
      }
      hint[1] = "Hints Galore";
    } else {
      hint[0] = "There are no moves on the field.\n"
          + "Either deal more cards or start a new game";
      hint[1] = "Hints";
    }

    return (hint);
  }

  /**
   * Try to move selected card to its ace pile.
   * 
   * @param index
   *            Index of the ace pile to be used.
   * @param numberOfSelectedCards
   *            Number of cards to be moved.
   * 
   * @author Todor Balabanov
   */
  public void moveToAces(int index, int numberOfSelectedCards) {
    if (numberOfSelectedCards > 1) {
      return;
    }

    CardStack stack = null;
    for (int i = 0; i < cells.length; i++) {
      if (cells[i].isEmpty() == true) {
        continue;
      }

      if (cells[i].peek().isHighlighted() == true) {
        stack = cells[i];
      }
    }
    for (int i = 0; i < columns.length; i++) {
      if (columns[i].isEmpty() == true) {
        continue;
      }
      if (columns[i].peek().isHighlighted() == true) {
        stack = columns[i];
      }
    }
    if (discardPile.isEmpty() == false
        && discardPile.peek().isHighlighted() == true) {
      stack = discardPile;
    }

    if (stack == null) {
      return;
    }
    if (stack == acePiles[index]) {
      return;
    }

    /*
     * The card is Ace and should be collected in Ace Pile.
     */
    if (stack.peek().getRank().equals(CardRank.ACE) == true
        && stack.peek().getSuit().equals(acePiles[index].getSuit()) == true) {
      Card card = stack.pop();
      acePiles[index].push(card);

      return;
    }

    /*
     * The card is not Ace and should be collected in Ace Pile only if suite
     * and rank are matching with Ace Pile state.
     */
    if (acePiles[index].isEmpty() == true) {
      return;
    }
    if (stack.peek().getSuit().equals(acePiles[index].getSuit()) == false) {
      return;
    }
    if (stack.peek().getRank()
        .isLessByOneThan((acePiles[index].peek().getRank())) == false) {
      return;
    }

    Card card = stack.pop();
    acePiles[index].push(card);
  }

  /**
   * Try to move selected card to one of the single cells.
   * 
   * @param index
   *            Index of the single cell to be used.
   * @param numberOfSelectedCards
   *            Number of cards to be moved.
   * 
   * @author Todor Balabanov
   */
  public void moveToCells(int index, int numberOfSelectedCards) {
    if (numberOfSelectedCards > 1) {
      return;
    }

    /*
     * Single cells can hold only single card.
     */
    if (cells[index].isEmpty() == false) {
      return;
    }

    CardStack stack = null;
    for (int i = 0; i < acePiles.length; i++) {
      if (acePiles[i].isEmpty() == true) {
        continue;
      }

      if (acePiles[i].peek().isHighlighted() == true) {
        stack = acePiles[i];
      }
    }
    for (int i = 0; i < cells.length; i++) {
      if (cells[i].isEmpty() == true) {
        continue;
      }

      if (cells[i].peek().isHighlighted() == true) {
        stack = cells[i];
      }
    }
    for (int i = 0; i < columns.length; i++) {
      if (columns[i].isEmpty() == true) {
        continue;
      }
      if (columns[i].peek().isHighlighted() == true) {
        stack = columns[i];
      }
    }
    if (discardPile.isEmpty() == false
        && discardPile.peek().isHighlighted() == true) {
      stack = discardPile;
    }

    if (stack == null) {
      return;
    }
    if (stack == cells[index]) {
      return;
    }

    Card card = stack.pop();
    cells[index].push(card);
  }

  /**
   * Try to move selected card to one of the columns.
   * 
   * @param index
   *            Index of the column to be used.
   * @param numberOfSelectedCards
   *            Number of cards to be moved.
   * 
   * @author Todor Balabanov
   */
  public void moveToColumns(int index, int numberOfSelectedCards) {
    CardStack stack = null;
    for (int i = 0; i < acePiles.length; i++) {
      if (acePiles[i].isEmpty() == true) {
        continue;
      }

      if (acePiles[i].peek().isHighlighted() == true) {
        stack = acePiles[i];
      }
    }
    for (int i = 0; i < cells.length; i++) {
      if (cells[i].isEmpty() == true) {
        continue;
      }

      if (cells[i].peek().isHighlighted() == true) {
        stack = cells[i];
      }
    }
    for (int i = 0; i < columns.length; i++) {
      if (columns[i].isEmpty() == true) {
        continue;
      }
      if (columns[i].peek().isHighlighted() == true) {
        stack = columns[i];
      }
    }
    if (discardPile.isEmpty() == false
        && discardPile.peek().isHighlighted() == true) {
      stack = discardPile;
    }

    if (stack == null) {
      return;
    }
    if (stack == columns[index]) {
      return;
    }

    if (stack instanceof AcePile || stack instanceof SingleCell
        || stack instanceof DiscardPile
        || (stack instanceof Column && numberOfSelectedCards == 1)) {
      Card card = stack.peek();

      if (columns[index].isValidMove(card) == true) {
        card = stack.pop();
        columns[index].push(card);
      }
    } else if (stack instanceof Column && numberOfSelectedCards > 1) {
      boolean valid = false;
      Column a = (Column) stack;
      Column b = columns[index];
      for (int i = 0; i < a.length(); i++) {
        if (a.getCardAtLocation(i).isHighlighted() == true) {
          if (b.isValidMove(a.getCardAtLocation(i)) == true) {
            valid = true;
          }
          break;
        }
      }
      if (valid == true) {
        for (int i = 0; i < a.length(); i++) {
          if (a.getCardAtLocation(i).isHighlighted() == true) {
            b.push(a.getCardAtLocation(i));
          }
        }
        for (int i = a.length() - 1; i >= 0; i--) {
          if (a.getCardAtLocation(i).isHighlighted() == true) {
            a.pop();
          }
        }
      }
    }
  }

  /**
   * Check is the solitaire solved.
   * 
   * @return True if the solitaire is solved, false otherwise.
   * 
   * @author Todor Balabanov
   */
  public boolean isSolved() {
    // TODO Check much better for final solution.
    for (int i = 0; i < acePiles.length; i++) {
      if (acePiles[i].isFull() == false) {
        return false;
      }
    }

    return true;
  }
}




Java Source Code List

eu.veldsoft.four.row.solitaire.AboutGameActivity.java
eu.veldsoft.four.row.solitaire.AcePileLayeredPane.java
eu.veldsoft.four.row.solitaire.AcePile.java
eu.veldsoft.four.row.solitaire.AnimationSettings.java
eu.veldsoft.four.row.solitaire.BestTimesActivity.java
eu.veldsoft.four.row.solitaire.CardColor.java
eu.veldsoft.four.row.solitaire.CardComponent.java
eu.veldsoft.four.row.solitaire.CardRank.java
eu.veldsoft.four.row.solitaire.CardStackLayeredPane.java
eu.veldsoft.four.row.solitaire.CardStack.java
eu.veldsoft.four.row.solitaire.CardSuit.java
eu.veldsoft.four.row.solitaire.Card.java
eu.veldsoft.four.row.solitaire.ChangeAppearance.java
eu.veldsoft.four.row.solitaire.ChangeOptions.java
eu.veldsoft.four.row.solitaire.ColumnLayeredPane.java
eu.veldsoft.four.row.solitaire.Column.java
eu.veldsoft.four.row.solitaire.Common.java
eu.veldsoft.four.row.solitaire.DealDeckLayeredPane.java
eu.veldsoft.four.row.solitaire.DealDeck.java
eu.veldsoft.four.row.solitaire.Deck.java
eu.veldsoft.four.row.solitaire.DiscardPileLayeredPane.java
eu.veldsoft.four.row.solitaire.DiscardPile.java
eu.veldsoft.four.row.solitaire.FireworksDisplay.java
eu.veldsoft.four.row.solitaire.FourRowSolitaire.java
eu.veldsoft.four.row.solitaire.GameActivity.java
eu.veldsoft.four.row.solitaire.GameDifficulty.java
eu.veldsoft.four.row.solitaire.GameState.java
eu.veldsoft.four.row.solitaire.HelpActivity.java
eu.veldsoft.four.row.solitaire.MenuActivity.java
eu.veldsoft.four.row.solitaire.SettingsActivity.java
eu.veldsoft.four.row.solitaire.SingleCellLayeredPane.java
eu.veldsoft.four.row.solitaire.SingleCell.java
eu.veldsoft.four.row.solitaire.SolitaireBoardFrame.java
eu.veldsoft.four.row.solitaire.SolitaireBoard.java
eu.veldsoft.four.row.solitaire.SolitaireLayout.java
eu.veldsoft.four.row.solitaire.SolitairePanel.java
eu.veldsoft.four.row.solitaire.SoundsSettings.java
eu.veldsoft.four.row.solitaire.StatisticsActivity.java
eu.veldsoft.four.row.solitaire.StatisticsTab0Activity.java
eu.veldsoft.four.row.solitaire.StatisticsTab1Activity.java
eu.veldsoft.four.row.solitaire.StatisticsTab2Activity.java
eu.veldsoft.four.row.solitaire.StatisticsTab3Activity.java
eu.veldsoft.four.row.solitaire.StatisticsTab4Activity.java
eu.veldsoft.four.row.solitaire.StatisticsTab5Activity.java
eu.veldsoft.four.row.solitaire.ThroughLimit.java
eu.veldsoft.four.row.solitaire.TopTimes.java
eu.veldsoft.four.row.solitaire.WinActivity.java
eu.veldsoft.four.row.solitaire.WinScreen.java