## vim:ts=4:et:nowrap
##
##---------------------------------------------------------------------------##
##
## PySol -- a Python Solitaire game
##
## Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
##
## This program 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 2 of the License, or
## (at your option) any later version.
##
## This program 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 this program; see the file COPYING.
## If not, write to the Free Software Foundation, Inc.,
## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
##
## Markus F.X.J. Oberhumer
## <markus@oberhumer.com>
## http://www.oberhumer.com/pysol
##
##---------------------------------------------------------------------------##


# imports
import sys

# PySol imports
if sys.modules.has_key("pysoltk"):
    from gamedb import registerGame, GameInfo, GI
    from util import *
    from stack import *
    from game import Game
    from layout import Layout
    from hint import AbstractHint, DefaultHint, CautiousDefaultHint
    from hint import FreeCellType_Hint, FreeCellSolverWrapper
    from layout import Layout


# /***********************************************************************
# // FreeCell
# ************************************************************************/

# To simplify playing we also consider the number of free rows.
# Note that this only is legal if the game.s.rows have a
# cap.base_rank == ANY_RANK.
# See also the "SuperMove" section in the FreeCell FAQ.
class FreeCell_RowStack(AC_RowStack):
    def _getMaxMove(self, to_stack_ncards):
        max_move = getNumberOfFreeStacks(self.game.s.reserves) + 1
        n = getNumberOfFreeStacks(self.game.s.rows)
        if to_stack_ncards == 0:
            n = n - 1
        while n > 0 and max_move < 1000:
            max_move = max_move * 2
            n = n - 1
        return max_move

    def canMoveCards(self, cards):
        max_move = self._getMaxMove(1)
        return len(cards) <= max_move and AC_RowStack.canMoveCards(self, cards)

    def acceptsCards(self, from_stack, cards):
        max_move = self._getMaxMove(len(self.cards))
        return len(cards) <= max_move and AC_RowStack.acceptsCards(self, from_stack, cards)


class FreeCell(Game):
    Layout_Method = Layout.freeCellLayout
    Talon_Class = InitialDealTalonStack
    Foundation_Class = SS_FoundationStack
    RowStack_Class = FreeCell_RowStack
    Hint_Class = FreeCellSolverWrapper(FreeCellType_Hint, 0, 0)


    #
    # game layout
    #

    def createGame(self, **layout):
        # create layout
        l, s = Layout(self), self.s
        kwdefault(layout, rows=8, reserves=4, texts=0)
        apply(self.Layout_Method, (l,), layout)
        self.setSize(l.size[0], l.size[1])
        # create stacks
        s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self)
        for r in l.s.foundations:
            s.foundations.append(self.Foundation_Class(r.x, r.y, self, suit=r.suit))
        for r in l.s.rows:
            s.rows.append(self.RowStack_Class(r.x, r.y, self))
        for r in l.s.reserves:
            s.reserves.append(ReserveStack(r.x, r.y, self))
        # default
        l.defaultAll()

    #
    # game overrides
    #

    def startGame(self):
        for i in range(5):
            self.s.talon.dealRow(frames=0)
        self.startDealSample()
        self.s.talon.dealRow()
        r = self.s.rows
        ##self.s.talon.dealRow(rows=(r[0], r[2], r[4], r[6]))
        self.s.talon.dealRow(rows=r[:4])
        assert len(self.s.talon.cards) == 0

    def shallHighlightMatch(self, stack1, card1, stack2, card2):
        return (card1.color != card2.color and
                (card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))


# /***********************************************************************
# // Relaxed FreeCell
# ************************************************************************/

class RelaxedFreeCell(FreeCell):
    RowStack_Class = AC_RowStack
    Hint_Class = FreeCellSolverWrapper(FreeCellType_Hint, 0, 0, 1)


# /***********************************************************************
# // ForeCell
# ************************************************************************/

class ForeCell(FreeCell):
    RowStack_Class = StackWrapper(FreeCell_AC_RowStack, base_rank=KING)

    def startGame(self):
        for i in range(5):
            self.s.talon.dealRow(frames=0)
        self.startDealSample()
        self.s.talon.dealRow()
        self.s.talon.dealRow(rows=self.s.reserves)
        assert len(self.s.talon.cards) == 0


# /***********************************************************************
# // Stalactites
# ************************************************************************/

class Stalactites(FreeCell):
    Foundation_Class = StackWrapper(RK_FoundationStack, suit=ANY_SUIT, mod=13, min_cards=1)
    RowStack_Class = StackWrapper(BasicRowStack, max_move=1, max_accept=0)
    Hint_Class = FreeCellType_Hint

    def createGame(self):
        FreeCell.createGame(self, reserves=2)

    def startGame(self):
        for i in range(5):
            self.s.talon.dealRow(frames=0)
        self.startDealSample()
        self.s.talon.dealRow()
        self.s.talon.dealRow(rows=self.s.foundations)
        assert len(self.s.talon.cards) == 0
        self._restoreGameHook(None)

    def _restoreGameHook(self, game):
        for s in self.s.foundations:
            s.cap.base_rank = s.cards[0].rank


# register the game
registerGame(GameInfo(5, RelaxedFreeCell, "Relaxed FreeCell",
                      GI.GT_FREECELL | GI.GT_RELAXED, 1, 0))
registerGame(GameInfo(8, FreeCell, "FreeCell",
                      GI.GT_FREECELL, 1, 0))
registerGame(GameInfo(46, ForeCell, "ForeCell",
                      GI.GT_FREECELL, 1, 0))
registerGame(GameInfo(77, Stalactites, "Stalactites",
                      GI.GT_FREECELL, 1, 0))

