## 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 pysoltk import MfxCanvasText, getFont


# /***********************************************************************
# //
# ************************************************************************/

class Calculation_Hint(DefaultHint):
    # FIXME: demo logic is a complete nonsense
    def _getMoveWasteScore(self, score, color, r, t, pile, rpile):
        assert r is self.game.s.waste and len(pile) == 1
        score = 30000
        if len(t.cards) == 0:
            score = score - (KING - r.cards[0].rank) * 1000
        elif t.cards[-1].rank < r.cards[0].rank:
            score = 10000 + t.cards[-1].rank - len(t.cards)
        elif t.cards[-1].rank == r.cards[0].rank:
            score = 20000
        else:
            score = score - (t.cards[-1].rank - r.cards[0].rank) * 1000
        return score, color


# /***********************************************************************
# //
# ************************************************************************/

class BetsyRoss_Foundation(RK_FoundationStack):
    def updateText(self):
        if self.game.preview > 1:
            return
        if self.texts.misc:
            if len(self.cards) == 0:
                rank = self.cap.base_rank
                self.texts.misc.config(text=RANKS[rank])
            elif len(self.cards) == self.cap.max_cards:
                self.texts.misc.config(text="")
            else:
                rank = (self.cards[-1].rank + self.cap.dir) % self.cap.mod
                self.texts.misc.config(text=RANKS[rank])


class Calculation_Foundation(BetsyRoss_Foundation):
    def getBottomImage(self):
        return self.game.app.images.getLetter(self.cap.base_rank)


class Calculation_RowStack(BasicRowStack):
    def acceptsCards(self, from_stack, cards):
        if not BasicRowStack.acceptsCards(self, from_stack, cards):
            return 0
        # this stack accepts any one card from the Waste pile
        return from_stack is self.game.s.waste and len(cards) == 1

    def getBottomImage(self):
        return self.game.app.images.getReserveBottom()


# /***********************************************************************
# // Calculation
# ************************************************************************/

class Calculation(Game):
    Hint_Class = Calculation_Hint

    #
    # game layout
    #

    def createGame(self):
        # create layout
        l, s = Layout(self), self.s

        # set window
        # (piles up to 20 cards are playable in default window size)
        h = max(2*l.YS, 20*l.YOFFSET)
        self.setSize(5.5*l.XS+l.XM, l.YM + l.YS + 30 + h)

        # create stacks
        x0 = l.XM + l.XS * 3 / 2
        x, y = x0, l.YM
        for i in range(4):
            stack = Calculation_Foundation(x, y, self, base_rank=i, mod=13, dir=i+1)
            s.foundations.append(stack)
            stack.texts.misc = MfxCanvasText(self.canvas, x + l.CW / 2, y + l.YS,
                                             anchor="n", font=getFont("canvas_card", cardw=l.CW))
            x = x + l.XS
        help = (
            "1: A 2 3 4 5 6 7 8 9 T J Q K\n" +
            "2: 2 4 6 8 T Q A 3 5 7 9 J K\n" +
            "3: 3 6 9 Q 2 5 8 J A 4 7 T K\n" +
            "4: 4 8 Q 3 7 J 2 6 T A 5 9 K")
        self.texts.help = MfxCanvasText(self.canvas, x + l.XM, y + l.CH / 2, text=help,
                                        anchor="w", font=getFont("canvas_fixed"))
        x = x0
        y = l.YM + l.YS + 30
        for i in range(4):
            s.rows.append(Calculation_RowStack(x, y, self, max_move=1, max_accept=1))
            x = x + l.XS
        self.setRegion(s.rows, (-999, y, 999999, 999999))
        x = l.XM
        s.talon = WasteTalonStack(x, y, self, max_rounds=1)
        l.createText(s.talon, "nn")
        y = y + l.YS
        s.waste = WasteStack(x, y, self, max_cards=1)

        # define stack-groups
        l.defaultStackGroups()

    #
    # game overrides
    #

    def _shuffleHook(self, cards):
        # prepare first cards
        topcards = [ None ] * 4
        for c in cards[:]:
            if c.rank <= 3 and topcards[c.rank] is None:
                topcards[c.rank] = c
                cards.remove(c)
        topcards.reverse()
        return cards + topcards

    def startGame(self):
        self.startDealSample()
        self.s.talon.dealRow(rows=self.s.foundations)
        self.s.talon.dealCards()          # deal first card to WasteStack

    def getHighlightPilesStacks(self):
        return ()


# /***********************************************************************
# // Hopscotch
# ************************************************************************/

class Hopscotch(Calculation):
    def _shuffleHook(self, cards):
        # prepare first cards
        topcards = [ None ] * 4
        for c in cards[:]:
            if c.suit == 0 and c.rank <= 3 and topcards[c.rank] is None:
                topcards[c.rank] = c
                cards.remove(c)
        topcards.reverse()
        return cards + topcards


# /***********************************************************************
# // Betsy Ross
# ************************************************************************/

class BetsyRoss(Calculation):

    #
    # game layout
    #

    def createGame(self):
        # create layout
        l, s = Layout(self), self.s

        # set window
        self.setSize(5.5*l.XS+l.XM, l.YM + l.YS + 30 + 3*l.YS)

        # create stacks
        x0 = l.XM + l.XS * 3 / 2
        x, y = x0, l.YM
        for i in range(4):
            stack = BetsyRoss_Foundation(x, y, self, base_rank=i,
                                         max_cards=1, max_move=0, max_accept=0)
            s.foundations.append(stack)
            x = x + l.XS
        x = x0
        y = l.YM + l.YS + 30
        for i in range(4):
            stack = BetsyRoss_Foundation(x, y, self, base_rank=2*i+1, mod=13, dir=i+1,
                                        max_cards=12, max_move=0)
            stack.texts.misc = MfxCanvasText(self.canvas, x + l.CW / 2, y - l.YM,
                                             anchor="s", font=getFont("canvas_card", cardw=l.CW))
            s.foundations.append(stack)
            x = x + l.XS
        help = (
            "1: 2 3 4 5 6 7 8 9 T J Q K\n" +
            "2: 4 6 8 T Q A 3 5 7 9 J K\n" +
            "3: 6 9 Q 2 5 8 J A 4 7 T K\n" +
            "4: 8 Q 3 7 J 2 6 T A 5 9 K")
        self.texts.help = MfxCanvasText(self.canvas, x + l.XM, y + l.CH / 2, text=help,
                                        anchor="w", font=getFont("canvas_fixed"))
        x = l.XM
        s.talon = WasteTalonStack(x, y, self, max_rounds=3)
        l.createText(s.talon, "nn")
        y = y + l.YS
        s.waste = WasteStack(x, y, self)
        l.createText(s.waste, "ss")

        # define stack-groups
        l.defaultStackGroups()


    #
    # game overrides
    #

    def _shuffleHook(self, cards):
        # prepare first cards
        topcards = [ None ] * 8
        for c in cards[:]:
            if c.rank <= 3 and topcards[c.rank] is None:
                topcards[c.rank] = c
                cards.remove(c)
            elif c.rank in (1, 3, 5, 7):
                i = 4 + (c.rank - 1) / 2
                if topcards[i] is None:
                    topcards[i] = c
                    cards.remove(c)
        topcards.reverse()
        return cards + topcards


# register the game
registerGame(GameInfo(256, Calculation, "Calculation",
                      GI.GT_1DECK_TYPE, 1, 0))
registerGame(GameInfo(94, Hopscotch, "Hopscotch",
                      GI.GT_1DECK_TYPE, 1, 0))
registerGame(GameInfo(134, BetsyRoss, "Betsy Ross",
                      GI.GT_1DECK_TYPE, 1, 2))

