## vim:ts=4:et:nowrap
##
##---------------------------------------------------------------------------##
##
## PySol -- a Python Solitaire game
##
## Copyright (C) 2000 by T. Kirk
## 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
##
## T. Kirk
## <grania@mailcity.com>
## http://www.inetarena.com/~grania
##
##---------------------------------------------------------------------------##


# 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


# /***********************************************************************
# // Hex A Deck Foundation Stacks
# ************************************************************************/

class HexADeck_FoundationStack(SS_FoundationStack):
    def __init__(self, x, y, game, suit, **cap):
        kwdefault(cap, max_move=0, max_cards=12)
        apply(SS_FoundationStack.__init__, (self, x, y, game, suit), cap)


class HexATrump_Foundation(HexADeck_FoundationStack):
    def acceptsCards(self, from_stack, cards):
        if not self.basicAcceptsCards(from_stack, cards):
            return 0
        for s in self.game.s.foundations[:3]:
            if len(s.cards) != 16:
                return 0
        return 1


# /***********************************************************************
# // Hex A Deck Row Stacks
# ************************************************************************/

class HexADeck_OpenStack(OpenStack):
    def __init__(self, x, y, game, yoffset, **cap):
        kwdefault(cap, max_move=999999)
        apply(OpenStack.__init__, (self, x, y, game), cap)
        self.CARD_YOFFSET = yoffset


class Bits_RowStack(ReserveStack):
    def acceptsCards(self, from_stack, cards):
        if not self.basicAcceptsCards(from_stack, cards):
            return 0
        stackcards = self.cards
        if stackcards or cards[0].suit == 4:
            return 0
        i = self.id / 4
        for r in self.game.s.rows[i * 4:self.id]:
            if not r.cards:
                return 0
        return ((self.game.s.foundations[i].cards[-1].rank + 1
                    >> (self.id % 4)) % 2 == (cards[0].rank + 1) % 2)


class Bytes_RowStack(ReserveStack):
    def acceptsCards(self, from_stack, cards):
        if not self.basicAcceptsCards(from_stack, cards):
            return 0
        stackcards = self.cards
        if stackcards or cards[0].suit == 4:
            return 0
        id = self.id - 16
        i = id / 2
        for r in self.game.s.rows[16 + i * 2:self.id]:
            if not r.cards:
                return 0
        return self.game.s.foundations[i].cards[-1].rank == cards[0].rank


class HexAKlon_RowStack(AC_RowStack):
    def acceptsCards(self, from_stack, cards):
        if AC_RowStack.acceptsCards(self, from_stack, cards):
            return 1
        stackcards = self.cards
        return (not stackcards
                or stackcards[-1].suit == 4
                or cards[0].suit == 4)


# /***********************************************************************
# // Bits n Bytes
# ************************************************************************/

class BitsNBytes(Game):
    GAME_VERSION = 2

    #
    # Game layout
    #

    def createGame(self):
        l, s = Layout(self), self.s
        font = getFont("canvas_card", cardw=l.CW)

        # Set window size
        self.setSize(l.XM * 4 + l.XS * 8, l.YM + l.YS * 4)

        # Create bit stacks
        y = l.YM
        for j in range(4):
            x = l.XM * 4 + l.XS * 7
            for i in range(4):
                s.rows.append(Bits_RowStack(x, y, self, max_cards = 1,
                                    max_accept = 1, base_suit = j, max_move = 0))
                x = x - l.XS
            y = y + l.YS

        # Create byte stacks
        y = l.YM
        for j in range(4):
            x = l.XM * 3 + l.XS * 3
            for i in range(2):
                s.rows.append(Bytes_RowStack(x, y, self, max_cards = 1,
                                    max_accept = 1, base_suit = ANY_SUIT, max_move = 0))
                x = x - l.XS
            y = y + l.YS

        # Create foundations
        x = l.XM * 2 + l.XS
        y = l.YM
        for i in range(4):
            s.foundations.append(SS_FoundationStack(x, y, self, i, mod = 1,
                                             max_move = 0, max_cards = 1))
            y = y + l.YS
        self.setRegion(s.rows, (0, 0, 999999, 999999))

        # Create talon
        x = l.XM
        y = l.YM
        s.talon = WasteTalonStack(x, y, self, num_deal=2, max_rounds=2)
        l.createText(s.talon, "ss")
        y = y + l.YS + l.YM * 2
        s.waste = WasteStack(x, y, self)
        l.createText(s.waste, "ss")

        # Define stack groups
        l.defaultStackGroups()

    #
    # Game over rides
    #

    def _shuffleHook(self, cards):
        topcards, ranks = [None] * 4, [None] * 4
        for c in cards[:]:
            if not c.suit == 4:
                if not topcards[c.suit]:
                    haverank = 0
                    for i in range(4):
                        if c.rank == ranks[i]:
                            haverank = 1
                    if not haverank:
                        topcards[c.suit] = c
                        ranks[c.suit] = c.rank
                        cards.remove(c)
        cards = topcards + cards
        cards.reverse()
        return cards

    def startGame(self):
        assert len(self.s.talon.cards) == 68
        self.startDealSample()
        self.s.talon.dealRow(rows=self.s.foundations)
        self.s.talon.dealCards()

    def isGameWon(self):
        for s in self.s.rows:
            if not s.cards:
                return 0
        return 1

    def shallHighlightMatch(self, stack1, card1, stack2, card2):
        return 0


# /***********************************************************************
# // Hex A Klon
# ************************************************************************/

class HexAKlon(Game):
    Hint_Class = CautiousDefaultHint

    #
    # Game layout
    #

    def createGame(self):
        l, s = Layout(self), self.s
        font = getFont("canvas_card", cardw=l.CW)

        # Set window size
        self.setSize(l.XM + l.XS * 8, l.YM + l.YS * 5)

        # Create talon
        x = l.XM
        y = l.YM
        s.talon = WasteTalonStack(x, y, self, num_deal=1, max_rounds=-1)
        l.createText(s.talon, "ss")
        x = x + l.XS
        s.waste = WasteStack(x, y, self)
        l.createText(s.waste, "ss")

        # Create foundations
        x = l.XM + l.XS * 3
        for i in range(4):
            s.foundations.append(SS_FoundationStack(x, y, self, i, mod = 16,
                                             max_move = 16, max_cards = 16))
            x = x + l.XS
        s.foundations.append(HexATrump_Foundation(x, y, self, 4, mod = 4,
                                             max_move = 0, max_cards = 4))

        # Create rows
        x = l.XM
        y = l.YM * 3 + l.YS
        for i in range(8):
            s.rows.append(HexAKlon_RowStack(x, y, self, max_cards = 99,
                                    max_accept = 99, base_suit = ANY_SUIT,
                                    base_rank = 15, max_move = 99))
            x = x + l.XS
        self.setRegion(s.rows, (0, y - l.YM/2, 999999, 999999))

        # Define stack groups
        l.defaultStackGroups()

    #
    # Game over rides
    #

    def startGame(self):
        assert len(self.s.talon.cards) == 68
        for i in range(len(self.s.rows)):
            self.s.talon.dealRow(rows=self.s.rows[i+1:], flip=0, frames=0)
        self.startDealSample()
        self.s.talon.dealRow()
        self.s.talon.dealCards()

    def shallHighlightMatch(self, stack1, card1, stack2, card2):
        return 0



registerGame(GameInfo(165, BitsNBytes, "Bits n Bytes",
                      GI.GT_HEXADECK, 1, 1,
                      suits=range(4), ranks=range(16), trumps=range(4)))
registerGame(GameInfo(166, HexAKlon, "Hex A Klon",
                      GI.GT_HEXADECK, 1, -1,
                      suits=range(4), ranks=range(16), trumps=range(4)))

