mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-05 00:02:29 -04:00
333 lines
11 KiB
Python
333 lines
11 KiB
Python
#!/usr/bin/env python
|
|
# -*- mode: python; coding: utf-8; -*-
|
|
# ---------------------------------------------------------------------------##
|
|
#
|
|
# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
|
|
# Copyright (C) 2003 Mt. Hood Playing Card Co.
|
|
# Copyright (C) 2005-2009 Skomoroh
|
|
#
|
|
# 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 3 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. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# ---------------------------------------------------------------------------##
|
|
|
|
__all__ = []
|
|
|
|
# imports
|
|
|
|
# PySol imports
|
|
from pysollib.gamedb import registerGame, GameInfo, GI
|
|
from pysollib.util import *
|
|
from pysollib.stack import *
|
|
from pysollib.game import Game
|
|
from pysollib.layout import Layout
|
|
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
|
|
|
# ************************************************************************
|
|
# *
|
|
# ************************************************************************
|
|
|
|
class PushPin_Hint(AbstractHint):
|
|
|
|
def computeHints(self):
|
|
game = self.game
|
|
rows = game.s.rows
|
|
for i in range(len(rows)-3):
|
|
r = rows[i+1]
|
|
if not rows[i+2].cards:
|
|
break
|
|
if r._checkPair(i, i+2):
|
|
self.addHint(5000, 1, r, game.s.foundations[0])
|
|
if not rows[i+3].cards:
|
|
break
|
|
if r._checkPair(i, i+3):
|
|
self.addHint(5000, 1, r, rows[i+2])
|
|
|
|
|
|
class PushPin_Foundation(AbstractFoundationStack):
|
|
def acceptsCards(self, from_stack, cards):
|
|
return True
|
|
|
|
class PushPin_Talon(DealRowTalonStack):
|
|
def dealCards(self, sound=False):
|
|
for r in self.game.s.rows:
|
|
if not r.cards:
|
|
return self.dealRowAvail(rows=[r], sound=sound)
|
|
return self.dealRowAvail(rows=[self.game.s.rows[0]], sound=sound)
|
|
getBottomImage = Stack._getNoneBottomImage
|
|
|
|
class PushPin_RowStack(ReserveStack):
|
|
|
|
def _checkPair(self, ps, ns):
|
|
if ps < 0 or ns > 51:
|
|
return False
|
|
rows = self.game.allstacks
|
|
pc, nc = rows[ps].cards, rows[ns].cards
|
|
if pc and nc:
|
|
if pc[0].suit == nc[0].suit or pc[0].rank == nc[0].rank:
|
|
return True
|
|
return False
|
|
|
|
def clickHandler(self, event):
|
|
ps, ns = self.id - 1, self.id + 1
|
|
if self._checkPair(ps, ns):
|
|
if not self.game.demo:
|
|
self.game.playSample("autodrop", priority=20)
|
|
self.playMoveMove(1, self.game.s.foundations[0], sound=False)
|
|
return True
|
|
return False
|
|
|
|
def acceptsCards(self, from_stack, cards):
|
|
if not self.cards:
|
|
return False
|
|
if abs(self.id - from_stack.id) != 1:
|
|
return False
|
|
ps = min(self.id, from_stack.id)-1
|
|
ns = ps + 3
|
|
return self._checkPair(ps, ns)
|
|
|
|
def fillStack(self):
|
|
self.game.fillEmptyStacks()
|
|
|
|
def moveMove(self, ncards, to_stack, frames=-1, shadow=-1):
|
|
if not to_stack is self.game.s.foundations[0]:
|
|
self._dropPairMove(ncards, to_stack, frames=-1, shadow=shadow)
|
|
else:
|
|
ReserveStack.moveMove(self, ncards, to_stack, frames=frames, shadow=shadow)
|
|
|
|
def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1):
|
|
game = self.game
|
|
old_state = game.enterState(game.S_FILL)
|
|
f = game.s.foundations[0]
|
|
game.updateStackMove(game.s.talon, 2|16) # for undo
|
|
if not game.demo:
|
|
game.playSample("droppair", priority=200)
|
|
game.moveMove(n, self, f, frames=frames, shadow=shadow)
|
|
game.moveMove(n, other_stack, f, frames=frames, shadow=shadow)
|
|
self.fillStack()
|
|
game.updateStackMove(game.s.talon, 1|16) # for redo
|
|
game.leaveState(old_state)
|
|
|
|
getBottomImage = Stack._getBlankBottomImage
|
|
|
|
|
|
class PushPin(Game):
|
|
|
|
Hint_Class = PushPin_Hint
|
|
RowStack_Class = PushPin_RowStack
|
|
|
|
#
|
|
# game layout
|
|
#
|
|
|
|
def createGame(self):
|
|
# create layout
|
|
l, s = Layout(self), self.s
|
|
|
|
# set window
|
|
xx, yy = 9, 6
|
|
w, h = l.XM+xx*l.XS, l.YM+yy*l.YS
|
|
self.setSize(w, h)
|
|
|
|
# create stacks
|
|
for i in range(yy):
|
|
for j in range(xx):
|
|
n = j+xx*i
|
|
if n < 1:
|
|
continue
|
|
if n > 52:
|
|
break
|
|
k = j
|
|
if i%2:
|
|
k = xx-j-1
|
|
x, y = l.XM + k*l.XS, l.YM + i*l.YS
|
|
s.rows.append(self.RowStack_Class(x, y, self))
|
|
s.talon = PushPin_Talon(l.XM, l.YM, self)
|
|
s.foundations.append(PushPin_Foundation(l.XM, h-l.YS, self,
|
|
suit=ANY_SUIT, dir=0, base_rank=ANY_RANK,
|
|
max_accept=0, max_move=0, max_cards=52))
|
|
|
|
# define stack-groups
|
|
l.defaultStackGroups()
|
|
return l
|
|
|
|
def startGame(self):
|
|
self.startDealSample()
|
|
self.s.talon.dealRow(rows=self.s.rows[:3])
|
|
|
|
def isGameWon(self):
|
|
return len(self.s.foundations[0].cards) == 50
|
|
|
|
def _fillOne(self):
|
|
rows = self.s.rows
|
|
i = 0
|
|
for r in rows:
|
|
if not r.cards:
|
|
break
|
|
i += 1
|
|
j = i
|
|
for r in rows[i:]:
|
|
if r.cards:
|
|
break
|
|
j += 1
|
|
else:
|
|
return 0
|
|
self.moveMove(1, rows[j], rows[i], frames=2, shadow=0)
|
|
return 1
|
|
|
|
def fillEmptyStacks(self):
|
|
if not self.demo:
|
|
self.startDealSample()
|
|
old_state = self.enterState(self.S_FILL)
|
|
while True:
|
|
if not self._fillOne():
|
|
break
|
|
self.leaveState(old_state)
|
|
if not self.demo:
|
|
self.stopSamples()
|
|
|
|
def getAutoStacks(self, event=None):
|
|
return ((), (), ())
|
|
|
|
|
|
class RoyalMarriage(PushPin):
|
|
def _shuffleHook(self, cards):
|
|
qi, ki = -1, -1
|
|
for i in range(len(cards)):
|
|
c = cards[i]
|
|
if c.suit == 2 and c.rank == 11:
|
|
qi = i
|
|
if c.suit == 2 and c.rank == 12:
|
|
ki = i
|
|
if qi >= 0 and ki >= 0:
|
|
break
|
|
q, k = cards[qi], cards[ki]
|
|
del cards[max(qi, ki)]
|
|
del cards[min(qi, ki)]
|
|
cards.insert(0, k)
|
|
cards.append(q)
|
|
return cards
|
|
|
|
|
|
class Queens(PushPin):
|
|
def startGame(self):
|
|
self.startDealSample()
|
|
self.s.talon.dealRow()
|
|
|
|
|
|
# ************************************************************************
|
|
# * Bayan (ex. Accordion)
|
|
# ************************************************************************
|
|
|
|
class Accordion_Hint(AbstractHint):
|
|
|
|
def computeHints(self):
|
|
game = self.game
|
|
rows = game.s.rows
|
|
for i in range(len(rows)-3):
|
|
r1, r2 = rows[i], rows[i+1]
|
|
if r1.cards and r2.cards:
|
|
c1, c2 = r1.cards[0], r2.cards[0]
|
|
if c1.rank == c2.rank or c1.suit == c2.suit:
|
|
if r2.acceptsCards(r1, [c1]):
|
|
self.addHint(5000, 1, r1, r2)
|
|
if r1.acceptsCards(r2, [c2]):
|
|
self.addHint(5000, 1, r2, r1)
|
|
r1, r2 = rows[i], rows[i+3]
|
|
if r1.cards and r2.cards:
|
|
c1, c2 = r1.cards[0], r2.cards[0]
|
|
if c1.rank == c2.rank or c1.suit == c2.suit:
|
|
if r2.acceptsCards(r1, [c1]):
|
|
self.addHint(6000, 1, r1, r2)
|
|
if r1.acceptsCards(r2, [c2]):
|
|
self.addHint(6000, 1, r2, r1)
|
|
|
|
|
|
class Accordion_RowStack(PushPin_RowStack):
|
|
|
|
def acceptsCards(self, from_stack, cards):
|
|
if not self.cards:
|
|
return False
|
|
if abs(self.id - from_stack.id) not in (1,3):
|
|
return False
|
|
c1, c2 = self.cards[-1], cards[0]
|
|
if c1.rank == c2.rank:
|
|
return True
|
|
return c1.suit == c2.suit
|
|
|
|
clickHandler = ReserveStack.clickHandler
|
|
|
|
|
|
class Accordion(PushPin):
|
|
Hint_Class = Accordion_Hint
|
|
RowStack_Class = Accordion_RowStack
|
|
|
|
def startGame(self):
|
|
self.startDealSample()
|
|
self.s.talon.dealRow(rows=self.s.rows[:2])
|
|
|
|
def isGameWon(self):
|
|
return len(self.s.foundations[0].cards) == 52
|
|
|
|
# ************************************************************************
|
|
# * Accordion (fixed)
|
|
# ************************************************************************
|
|
|
|
class Accordion2_RowStack(Accordion_RowStack):
|
|
def acceptsCards(self, from_stack, cards):
|
|
if not Accordion_RowStack.acceptsCards(self, from_stack, cards):
|
|
return False
|
|
# accepts only from right stack
|
|
return self.id < from_stack.id
|
|
def moveMove(self, ncards, to_stack, frames=-1, shadow=-1):
|
|
game = self.game
|
|
old_state = game.enterState(game.S_FILL)
|
|
f = game.s.foundations[0]
|
|
game.updateStackMove(game.s.talon, 2|16) # for undo
|
|
|
|
game.moveMove(ncards, to_stack, f, frames=frames, shadow=shadow)
|
|
game.moveMove(ncards, self, to_stack, frames=frames, shadow=shadow)
|
|
self.fillStack()
|
|
|
|
game.updateStackMove(game.s.talon, 1|16) # for redo
|
|
game.leaveState(old_state)
|
|
|
|
class Accordion2(Accordion):
|
|
RowStack_Class = Accordion2_RowStack
|
|
def isGameWon(self):
|
|
return len(self.s.foundations[0].cards) == 51
|
|
|
|
# ************************************************************************
|
|
# * Relaxed Accordion
|
|
# ************************************************************************
|
|
|
|
class RelaxedAccordion_RowStack(Accordion2_RowStack):
|
|
acceptsCards = Accordion_RowStack.acceptsCards
|
|
|
|
class RelaxedAccordion(Accordion2):
|
|
RowStack_Class = RelaxedAccordion_RowStack
|
|
|
|
|
|
registerGame(GameInfo(287, PushPin, "Push Pin",
|
|
GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK))
|
|
registerGame(GameInfo(288, RoyalMarriage, "Royal Marriage",
|
|
GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK))
|
|
## registerGame(GameInfo(303, Queens, "Queens",
|
|
## GI.GT_1DECK_TYPE | GI.GT_OPEN, 1, 0))
|
|
registerGame(GameInfo(656, Accordion, "Bayan",
|
|
GI.GT_1DECK_TYPE, 1, 0, GI.SL_BALANCED))
|
|
registerGame(GameInfo(772, Accordion2, "Accordion",
|
|
GI.GT_1DECK_TYPE, 1, 0, GI.SL_BALANCED,
|
|
altnames=('Idle Year', 'Methuselah', 'Tower of Babel') ))
|
|
registerGame(GameInfo(773, RelaxedAccordion, "Relaxed Accordion",
|
|
GI.GT_1DECK_TYPE, 1, 0, GI.SL_BALANCED))
|