1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-03-12 04:07:01 -04:00

Compare commits

...

5 commits

Author SHA1 Message Date
Joe R
9773eee2d6 Add Wizard's Storeroom game 2025-03-03 21:28:35 -05:00
Joe R
015e860557 Fix endgame hints for Crossword 2025-03-03 19:37:54 -05:00
Joe R
04b7eacfcb Fix highlight match logic for Nines/Tens/Elevens 2025-03-01 22:24:17 -05:00
Joe R
52e2ffc58f Add two mahjongg layouts 2025-03-01 16:17:53 -05:00
Joe R
81150b4681 Add Relaxed Cruel game 2025-02-26 19:55:01 -05:00
10 changed files with 215 additions and 7 deletions

View file

@ -0,0 +1,13 @@
<h1>Big Storeroom</h1>
<p>
Hex A Deck type. 2 decks. 1 redeal.
<h3>Object</h3>
<p>
Move all cards to the foundations.
<h3>Rules</h3>
<p>
Like <a href="wizardsstoreroom.html">Wizard's Storeroom</a>
but with two decks and nine piles.

View file

@ -0,0 +1,12 @@
<h1>Relaxed Cruel</h1>
<p>
Baker's Dozen type. 1 deck. Unlimited redeals.
<h3>Object</h3>
<p>
Move all cards to the foundations.
<h3>Quick Description</h3>
<p>
Just like <a href="cruel.html">Cruel</a>,
but the number of cards you can move as a sequence is not restricted.

View file

@ -0,0 +1,23 @@
<h1>Wizard's Storeroom</h1>
<p>
Hex A Deck type. 1 deck. 1 redeal.
<h3>Object</h3>
<p>
Move all cards to the foundations.
<h3>Rules</h3>
<p>
The tableau consists of one reserve stack and five row stacks.
Fourteen cards are dealt to the reserve stack and one card each to the
row stacks. When a row stack is emptied it must be filled from the reserve
stack first. When the reserve stack is empty any card can be played on an
empty row stack. Wizards are wild - any card can be played on them, and they
can be played on any card. The Wizards have ranks like the suit cards
corresponding to Ace through Four. If a Wizard is played in it's proper rank
position the row can still be moved, otherwise, the full sequence can't be moved.
The row stacks build down in rank by alternate colors.
<p>
The foundations build up in rank by suit. The Wizards will not move off of the
tableau until all the other cards have been moved to the foundations.
The game is won when all cards are moved to the foundations.

View file

@ -594,7 +594,8 @@ class GI:
tuple(range(19000, 19012)) + tuple(range(22303, 22311)) +
tuple(range(22353, 22361))),
('fc-3.1', tuple(range(961, 971))),
('dev', tuple(range(971, 977)) + tuple(range(18005, 18007)) +
('dev', tuple(range(971, 978)) + tuple(range(5419, 5421)) +
tuple(range(16683, 16685)) + tuple(range(18005, 18007)) +
(44, 526,)),
)

View file

@ -225,6 +225,7 @@ class Vineyard(CastlesInSpain):
# ************************************************************************
# * Cruel
# * Relaxed Cruel
# * Unusual
# ************************************************************************
@ -310,6 +311,10 @@ class Cruel(CastlesInSpain):
shallHighlightMatch = Game._shallHighlightMatch_SS
class RelaxedCruel(Cruel):
RowStack_Class = StackWrapper(SS_RowStack, base_rank=NO_RANK)
class Unusual(Cruel):
def createGame(self):
@ -453,3 +458,6 @@ registerGame(GameInfo(876, Vineyard, "Vineyard",
GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(907, Martha, "Stewart",
GI.GT_BAKERS_DOZEN, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(977, RelaxedCruel, "Relaxed Cruel",
GI.GT_BAKERS_DOZEN | GI.GT_OPEN | GI.GT_RELAXED, 1, -1,
GI.SL_BALANCED))

View file

@ -46,6 +46,11 @@ class Crossword_Hint(AbstractHint):
r = rows[i]
if r.cards:
continue
if len(game.s.talon.cards) == 0:
for s in game.s.reserves:
if game.isValidPlay(r.id, s.getCard().rank + 1):
self.addHint(5000, 1, s, r)
continue
if game.isValidPlay(r.id, game.s.talon.getCard().rank + 1):
# TODO: Check a few moves ahead to get better hints.
self.addHint(5000, 1, game.s.talon, r)

View file

@ -407,7 +407,7 @@ class AbstractMahjonggGame(Game):
# width of self.texts.info
# ti_width = Font(self.canvas, font).measure(_('Remaining'))
ti_width = 80
ti_width = max(80, l.CW)
# set window size
dxx, dyy = abs(dx) * (max_tl+1), abs(dy) * (max_tl+1)

View file

@ -356,6 +356,50 @@ r(5418, "Zigzag", layout="0aabaajaaracahcb" +
"ynvyniyoaypaAehA" +
"faAgaAmhAnaAoaCa" +
"aCfaCnaCs")
r(5419, "Lizard", layout="0aadaafaahaajhbe" +
"hbghbibccaceacga" +
"ciackidjbebaejae" +
"laeqheraesifkbga" +
"agehgfaggagkagmb" +
"grihlaiabifailai" +
"nbirijmojqakaakg" +
"hkhakiokihkjakko" +
"kkvklakmvknakook" +
"ohkpakqhllolmhln" +
"amaamkammamohnlo" +
"nmhnnaokaomaoohp" +
"lopmhpnaqjaqlaqn" +
"hrkorlhrmasjasla" +
"snhtkotlhtmaujau" +
"launhvkovlhvmawi" +
"awkawmhxjpxkhxla" +
"yiaykaymazehzfaz" +
"gozghzhozihzjvzj" +
"ozkhzlvzlozmhzna" +
"zoozohzpazqaAiaA" +
"kaAmbBdiBkbBraCj" +
"aClaDchDdaDehDka" +
"DqhDraDsaEjaElaF" +
"daFraGk")
r(5420, "Candy", layout="0daadaccaebagbai" +
"aakdcbccdbcfbcha" +
"cjcecbeebegaeibg" +
"dbgfaghbieaigakd" +
"akfakhhlfambamda" +
"mfamhamjhnchneon" +
"fhnghniaobaodaof" +
"aohaojhpcipeipgh" +
"piaqbaqdaqfvqfaq" +
"haqjhrcireirghri" +
"asbasdasfashasjh" +
"tchteotfhtghtiau" +
"baudaufauhaujhvf" +
"awdawfawhayebyga" +
"AdbAfbAhaCcbCebC" +
"gcCiaEbbEdbEfcEh" +
"dEjaGabGcbGecGgd" +
"GidGk")
# ----------------------------------------------------------------------

View file

@ -583,8 +583,8 @@ class Elevens(Pyramid):
self.leaveState(old_state)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
# FIXME
return False
return (card1.rank + card2.rank == 9 or
(9 < card1.rank != card2.rank > 9))
class ElevensToo(Elevens):
@ -633,6 +633,11 @@ class SuitElevens(Elevens):
def createGame(self):
Elevens.createGame(self, rows=3, cols=5)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (Elevens.shallHighlightMatch(self, stack1, card1,
stack2, card2)
and card1.suit == card2.suit)
# ************************************************************************
# * Tens
@ -665,6 +670,10 @@ class Tens(ElevensToo):
def createGame(self):
Elevens.createGame(self, rows=2, cols=7, maxpiles=13, reserves=4)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (card1.rank + card2.rank == 8 or
(8 < card1.rank == card2.rank > 8))
class Nines_RowStack(Elevens_RowStack):
ACCEPTED_SUM = 7
@ -709,6 +718,10 @@ class Nines(Tens):
def createGame(self):
Elevens.createGame(self, rows=3, cols=3, reserves=4)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (card1.rank + card2.rank == 7 or
(8 < card1.rank != card2.rank > 8))
# ************************************************************************
# * The Lucky Number

View file

@ -62,7 +62,8 @@ 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]:
for s in self.game.s.foundations[:((self.game.gameinfo.decks
* 4) - 1)]:
if len(s.cards) != 16:
return 0
return 1
@ -93,11 +94,12 @@ class Merlins_Foundation(AbstractFoundationStack):
class HexADeck_OpenStack(OpenStack):
def __init__(self, x, y, game, yoffset, **cap):
def __init__(self, x, y, game, yoffset=None, **cap):
kwdefault(cap, max_move=UNLIMITED_MOVES, max_accept=UNLIMITED_ACCEPTS,
dir=-1)
OpenStack.__init__(self, x, y, game, **cap)
self.CARD_YOFFSET = yoffset
if yoffset is not None:
self.CARD_YOFFSET = yoffset
def isRankSequence(self, cards, dir=None):
if not dir:
@ -1600,6 +1602,89 @@ class MagicMontana(Montana):
return True
# ************************************************************************
# * Wizard's Storeroom
# ************************************************************************
class WizardsStoreroom(AbstractHexADeckGame):
MAX_ROUNDS = 2
#
# Game layout
#
def createGame(self):
l, s = Layout(self), self.s
# Set window size
decks = self.gameinfo.decks
self.setSize(2*l.XM + (2 + 5*decks)*l.XS, 3*l.YM + 5*l.YS)
yoffset = min(l.YOFFSET, max(10, l.YOFFSET // 2))
# Create talon
x = l.XM
y = l.YM
s.talon = WasteTalonStack(
x, y, self, num_deal=1, max_rounds=self.MAX_ROUNDS)
l.createText(s.talon, "s")
x = x + l.XS
s.waste = WasteStack(x, y, self)
l.createText(s.waste, "s")
# Create foundations
x = x + l.XM + l.XS
for j in range(4):
for i in range(decks):
s.foundations.append(
SS_FoundationStack(x, y, self, j, max_cards=16))
x = x + l.XS
for i in range(decks):
s.foundations.append(
HexATrump_Foundation(x, y, self, 4, max_cards=4))
x = x + l.XS
# Create reserve
x = l.XM
y = l.YM + l.YS + l.TEXT_HEIGHT
s.reserves.append(OpenStack(x, y, self))
s.reserves[0].CARD_YOFFSET = (l.YOFFSET, yoffset)[decks == 2]
# Create rows
x = x + l.XM + l.XS
for i in range(4*decks+1):
s.rows.append(HexAKlon_RowStack(x, y, self))
x = x + l.XS
self.setRegion(s.rows, (-999, y - l.YS, 999999, 999999))
# Define stack groups
l.defaultStackGroups()
#
# Game over rides
#
def startGame(self):
decks = self.gameinfo.decks
self.startDealSample()
for i in range(14 * decks):
self.s.talon.dealRow(rows=self.s.reserves, flip=0, frames=4)
self.s.reserves[0].flipMove()
self.s.talon.dealRow(rows=self.s.rows)
self.s.talon.dealCards() # deal first card to WasteStack
def fillStack(self, stack):
r = self.s.reserves[0]
if not stack.cards and stack in self.s.rows:
if r.cards and stack.acceptsCards(r, r.cards[-1:]):
r.moveMove(1, stack)
if r.canFlipCard():
r.flipMove()
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return ((card1.rank + 1 == card2.rank or
card1.rank - 1 == card2.rank) and
card1.color != card2.color)
# ************************************************************************
# *
# ************************************************************************
@ -1646,4 +1731,8 @@ r(16680, Snakestone, 'Snakestone', GI.GT_HEXADECK | GI.GT_OPEN, 2, 0,
r(16681, HexYukon, 'Hex Yukon', GI.GT_HEXADECK, 1, 0, GI.SL_BALANCED)
r(16682, MagicMontana, 'Magic Montana', GI.GT_HEXADECK | GI.GT_OPEN, 1, 2,
GI.SL_MOSTLY_SKILL)
r(16683, WizardsStoreroom, "Wizard's Storeroom", GI.GT_HEXADECK, 1, 1,
GI.SL_MOSTLY_SKILL)
r(16684, WizardsStoreroom, "Big Storeroom", GI.GT_HEXADECK, 2, 1,
GI.SL_MOSTLY_SKILL)
del r