Package uk.co.iscoding.freecell.game

Source Code of uk.co.iscoding.freecell.game.FreeCellLayout

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package uk.co.iscoding.freecell.game;

import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import uk.co.iscoding.freecell.cards.DeckOfCards;
import uk.co.iscoding.freecell.cards.PlayingCard;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static uk.co.iscoding.freecell.game.CardCollection.StartingSuit;

/**
*
* @author   Stuart David James McHattie
* @version  1.0 2011-06-30
* @since    2011-06-30
*/
public class FreeCellLayout {
    private enum Area {
        FREECELLS,
        FOUNDATIONS,
        COLUMNS,
    }

    private final ArrayList<String> moveSequence;
    private final ArrayList<FreeCell> cells;
    private final ArrayList<Foundation> founds;
    private final ArrayList<FreeCellColumn> cols;

    public FreeCellLayout(DeckOfCards deck) {
        this.moveSequence = Lists.newArrayList()// No prior moves

        // Create FreeCells
        this.cells = Lists.newArrayList();
        for (int i = 1; i <= 4; i++) {
            FreeCell freeCell = new FreeCell();
            freeCell.setName("FreeCell #" + i);
            cells.add(freeCell);
        }

        // Create Foundations
        this.founds = Lists.newArrayList();
        for (int i = 1; i <= 4; i++) {
            Foundation newFound = new Foundation(StartingSuit.values()[i]);
            newFound.setName("Foundation #" + i);
            founds.add(newFound);
        }

        // Create some columns and name them
        this.cols = Lists.newArrayList();
        for (int i = 0; i < 8; i++) {
            FreeCellColumn newCol = new FreeCellColumn();
            newCol.setName("Column #" + (i + 1));
            cols.add(newCol);
        }

        // Add cards to the columns
        for (int i = 0; i < 52; i++) {
            cols.get(i % 8).addCard(deck.nextCard(), true);
        }
    }

    private FreeCellLayout(ArrayList<String> moveSequence, ArrayList<FreeCell> cells,
                           ArrayList<Foundation> founds, ArrayList<FreeCellColumn> cols) {
        this.moveSequence = moveSequence;
        this.cells = cells;
        this.founds = founds;
        this.cols = cols;
    }

    private FreeCellLayout deepClone() {
        // Strings are immutable so can just clone the move sequence
        ArrayList<String> cloneMoveSequence = Lists.newArrayList(moveSequence);

        ArrayList<FreeCell> cloneCells = Lists.newArrayList();
        for (FreeCell cell : cells) {
            cloneCells.add(cell.deepClone());
        }

        ArrayList<Foundation> cloneFounds = Lists.newArrayList();
        for (Foundation found : founds) {
            cloneFounds.add(found.deepClone());
        }

        ArrayList<FreeCellColumn> cloneCols = Lists.newArrayList();
        for (FreeCellColumn col : cols) {
            cloneCols.add(col.deepClone());
        }

        return new FreeCellLayout(cloneMoveSequence, cloneCells, cloneFounds, cloneCols);
    }

    public boolean isFinished() {
        boolean finished = true;
        for (Foundation found : founds) {
            if (found.getNumberOfCards() != 13) finished = false;
        }
        return finished;
    }

    public void printMoves() {
        for (int i = 0; i < moveSequence.size(); i++) {
            System.out.println(String.format("%03d: %s", (i+1), moveSequence.get(i)));
        }
    }

    public Set<FreeCellLayout> getPossibleMoves() {
        Set<FreeCellLayout> possibleMoves = Sets.newHashSet();

        int maxMove = 5;
        for (FreeCell cell : cells) {
            if (cell.isOccupied()) {
                maxMove--;
            }
        }
        int emptyColumns = 0;
        for (FreeCellColumn col : cols) {
            if (col.getNumberOfCards() == 0) emptyColumns++;
        }
        if (emptyColumns > 0) maxMove *= 2 * emptyColumns;


        /**
         * Move cards to foundations
         */
        for (int foundIndex = 0; foundIndex < founds.size(); foundIndex++) {
            Foundation found = founds.get(foundIndex);

            for (int colIndex = 0; colIndex < cols.size(); colIndex++) {
                FreeCellColumn col = cols.get(colIndex);

                if (col.getNumberOfCards() > 0 && found.canAddCard(col.getTopCard())) {
                    possibleMoves.add(cloneAndMove(Area.COLUMNS, colIndex, Area.FOUNDATIONS, foundIndex, 1));
                }
            }

            for (int cellIndex = 0; cellIndex < cells.size(); cellIndex++) {
                FreeCell cell = cells.get(cellIndex);

                if (cell.isOccupied() && found.canAddCard(cell.getTopCard())) {
                    possibleMoves.add(cloneAndMove(Area.FREECELLS, cellIndex, Area.FOUNDATIONS, foundIndex, 1));
                }
            }
        }


        /**
         * Move holding cards to non-empty columns
         */
        for (int cellIndex = 0; cellIndex < cells.size(); cellIndex++) {
            FreeCell cell = cells.get(cellIndex);

            for (int colIndex = 0; colIndex < cols.size(); colIndex++) {
                FreeCellColumn col = cols.get(colIndex);

                if (cell.isOccupied() && col.getNumberOfCards() > 0 && col.canAddCard(cell.getTopCard())) {
                    possibleMoves.add(cloneAndMove(Area.FREECELLS, cellIndex, Area.COLUMNS, colIndex, 1));
                }
            }
        }


        /**
         * Move whole sequences to other columns
         */
        for (int fromIndex = 0; fromIndex < cols.size(); fromIndex++) {
            FreeCellColumn fromCol = cols.get(fromIndex);

            CardCollection candidatesToMove = fromCol.getLongestSequenceNoLongerThan(maxMove);

            if (candidatesToMove == null) {
                continue;
            }

            for (int toIndex = 0; toIndex < cols.size(); toIndex++) {
                FreeCellColumn toCol = cols.get(toIndex);

                if (toCol.canAddCard(candidatesToMove.getBottomCard())) {
                    possibleMoves.add(cloneAndMove(Area.COLUMNS, fromIndex, Area.COLUMNS, toIndex,
                            candidatesToMove.getNumberOfCards()));
                }
            }
        }


        /**
         * Move whole sequences to empty columns, unless:
         *    The sequence being moved is the whole column
         */
        int emptyColIndex = -1;
        for (int colIndex = 0; colIndex < cols.size(); colIndex++) {
            FreeCellColumn col = cols.get(colIndex);
            if (col.getNumberOfCards() == 0) {
                emptyColIndex = colIndex;
                break;
            }
        }

        if (emptyColIndex >= 0) {
            int reducedMaxMove = maxMove /= 2 * emptyColumns;
            if (emptyColumns > 1) reducedMaxMove *= 2 * (emptyColumns - 1);

            for (int fromIndex = 0; fromIndex < cols.size(); fromIndex++) {
                FreeCellColumn fromCol = cols.get(fromIndex);

                CardCollection candidatesToMove = fromCol.getLongestSequenceNoLongerThan(reducedMaxMove);

                if (candidatesToMove == null || candidatesToMove.getNumberOfCards() == fromCol.getNumberOfCards()) {
                    continue;
                }

                possibleMoves.add(cloneAndMove(Area.COLUMNS, fromIndex, Area.COLUMNS, emptyColIndex,
                        candidatesToMove.getNumberOfCards()));
            }
        }


        /**
         * Move whole sequences to free cells, unless:
         *    The sequence being moved could move to a non-empty column
         */
        List<Integer> emptyFreeCellIndices = Lists.newArrayList();
        for (int cellIndex = 0; cellIndex < cells.size(); cellIndex++) {
            if (!cells.get(cellIndex).isOccupied()) {
                emptyFreeCellIndices.add(cellIndex);
            }
        }

        for (int fromIndex = 0; fromIndex < cols.size(); fromIndex++) {
            FreeCellColumn fromCol = cols.get(fromIndex);

            CardCollection candidatesToMove = fromCol.getLongestSequenceNoLongerThan(emptyFreeCellIndices.size());

            if (candidatesToMove == null) {
                continue;
            }

            boolean cannotAddToNonEmptyColumn = true;
            for (FreeCellColumn col : cols) {
                if (col.getNumberOfCards() > 0 && col.canAddCard(candidatesToMove.getBottomCard())) {
                    cannotAddToNonEmptyColumn = false;
                }
            }

            if (cannotAddToNonEmptyColumn) {
                FreeCellLayout clone = deepClone();
                FreeCellColumn cloneFromCol = clone.cols.get(fromIndex);
                cloneFromCol.removeTopCards(candidatesToMove.getNumberOfCards());

                for (int i = 0; i < candidatesToMove.getNumberOfCards(); i++) {
                    clone.cells.get(emptyFreeCellIndices.get(i)).addCard(candidatesToMove.getCard(i));
                }

                if (candidatesToMove.getNumberOfCards() == 2) {
                    clone.moveSequence.add(String.format("Move %s and 1 other card from %s to freecells",
                            candidatesToMove.getBottomCard(), fromCol));
                } else {
                    clone.moveSequence.add(String.format("Move %s and %d other cards from %s to freecells",
                            candidatesToMove.getBottomCard(), candidatesToMove.getNumberOfCards() - 1, fromCol));
                }

                possibleMoves.add(clone);
            }
        }


        /**
         * Move whole column into free cells, unless:
         *    Doing so would reduce maxMove
         */


        /**
         * Move holding cards to an empty column, unless:
         *    Another holding card could be its parent
         */

        return possibleMoves;
    }

    private FreeCellLayout cloneAndMove(Area fromArea, int fromIndex, Area toArea, int toIndex, int numCards) {
        FreeCellLayout clone = deepClone();
        CardCollection from = null;
        CardCollection to = null;

        switch(fromArea) {
            case FREECELLS:
                from = clone.cells.get(fromIndex);
                break;
            case FOUNDATIONS:
                from = clone.founds.get(fromIndex);
                break;
            case COLUMNS:
                from = clone.cols.get(fromIndex);
                break;
        }

        switch(toArea) {
            case FREECELLS:
                to = clone.cells.get(toIndex);
                break;
            case FOUNDATIONS:
                to = clone.founds.get(toIndex);
                break;
            case COLUMNS:
                to = clone.cols.get(toIndex);
                break;
        }

        if (numCards == 1) {
            clone.moveSequence.add(String.format("Move %s from %s to %s", from.getTopCard(), from, to));
        } else {
            PlayingCard topOfMovedPile = from.getTopCards(numCards).getBottomCard();
            if (numCards == 2) {
                clone.moveSequence.add(String.format("Move %s and 1 other card from %s to %s", topOfMovedPile, from, to));
            } else {
                clone.moveSequence.add(String.format("Move %s and %d other cards from %s to %s", topOfMovedPile, numCards - 1, from, to));
            }
        }

        CardCollection.moveCards(from, to, numCards);

        return clone;
    }

    @Override
    public boolean equals(Object other) {
        if (!(other instanceof FreeCellLayout)) return false;

        FreeCellLayout otherLayout = (FreeCellLayout)other;

        // Check each set for equality
        if (!Sets.newHashSet(cells).equals(Sets.newHashSet(otherLayout.cells))) return false;
        if (!Sets.newHashSet(founds).equals(Sets.newHashSet(otherLayout.founds))) return false;
        if (!Sets.newHashSet(cols).equals(Sets.newHashSet(otherLayout.cols))) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(Sets.newHashSet(cells), Sets.newHashSet(cols), Sets.newHashSet(founds));
    }
}
TOP

Related Classes of uk.co.iscoding.freecell.game.FreeCellLayout

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.