Skip to content

Commit

Permalink
Version 7 of the cardset format with subtype and joker support.
Browse files Browse the repository at this point in the history
  • Loading branch information
joeraz committed Jul 27, 2023
1 parent 9237c30 commit bef82cb
Show file tree
Hide file tree
Showing 20 changed files with 187 additions and 79 deletions.
7 changes: 5 additions & 2 deletions contrib/customize_cardset.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ config.txt template
-------------------

....
PySolFC solitaire cardset;$A;$FMT;$B;$C;$D,$E;$F
PySolFC solitaire cardset;$A;$FMT;$B;$C;$D,$E;$F;$G;$H
<internal_name>;<cardset_name>
X Y D
XOFF YOFF SXOFF SYOFF
Expand All @@ -21,7 +21,7 @@ Line 1

*$A:* The cardset version number that belongs to the number of fields divided through ";" on the first line (e.g. `.gif;1;78;8,1016` -> `$A=4`)

( *WARNING:* For Mahjongg, $A must always be 6 and the $F field must be included in the line; however, you can put `0` in `$F` if you wish, in that case. )
( *WARNING:* For Mahjongg, $A must always be 6 or 7 and the $F field must be included in the line; however, you can put `0` in `$F` if you wish, in that case. )

( *NOTE:* $D and $E are comma separated and count for one field )

Expand Down Expand Up @@ -112,6 +112,9 @@ Cardsets Origins:
*$F:* The Year the cardset was created (in the range 1000 to 2299)

*$G:* The subtype of the cardset. Usually 0 - for French type cardsets, a value of 1 is used if there are jokers.

*$H:* Whether the cardset is a 3D Mahjongg cardset - 1 if it is, 0 if it isn't. For cardsets with a version less than 7, version 6 cardsets treat this value as 1, and older version cardsets treat it as 0.

Line 2
------
Expand Down
Binary file added data/images/cards/finder/french/01z.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/cards/finder/french/01z.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/cards/finder/french/02z.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/cards/finder/french/02z.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 7 additions & 2 deletions html-src/cardset_customization.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<h1>Cardset Customization Tutorial</h1>
<h2>config.txt template</h2>
<pre>PySolFC solitaire cardset;$A;$FMT;$B;$C;$D,$E;$F
<pre>PySolFC solitaire cardset;$A;$FMT;$B;$C;$D,$E;$F;$G;$H
&lt;internal_name&gt;;&lt;cardset_name&gt;
X Y D
XOFF YOFF SXOFF SYOFF
Expand All @@ -9,7 +9,7 @@ <h2>config.txt template</h2>
<h2>Line 1</h2>
<p><b>$A:</b> The cardset version number that belongs to the number
of fields divided through ";" on the first line (e.g. <code>.gif;1;78;8,1016</code> &#8594; <code>$A=4</code>)</p>
<p>(<b>WARNING:</b> For Mahjongg, $A must always be 6 and the $F
<p>(<b>WARNING:</b> For Mahjongg, $A must always be 6 or 7 and the $F
field must be included in the line; however, you can put <code>0</code> in <code>$F</code> if you wish, in that case.)</p>
<p>(<b>NOTE:</b> $D and $E are comma separated and count for one
field)</p>
Expand Down Expand Up @@ -220,6 +220,11 @@ <h3>Cardsets Origins:</h3>
</ul>
<p><b>$F:</b> The Year the cardset was created (in the range 1000
to 2299)</p>
<p><b>$G:</b> The subtype of the cardset. Usually 0 - for French type
cardsets, a value of 1 is used if there are jokers.</p>
<p><b>$H:</b> Whether the cardset is a 3D Mahjongg cardset - 1 if it is, 0
if it isn't. For cardsets with a version less than 7, version 6 cardsets
treat this value as 1, and older version cardsets treat it as 0.</p>
<h2>Line 2</h2>
<p><code>&lt;internal_name&gt;</code>: A name for PySolFC to identify your
cardset (without spaces)</p>
Expand Down
3 changes: 1 addition & 2 deletions html-src/glossary.html
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,7 @@ <h1>Glossary</h1>

<dd>
<p>A deck of cards consisting of a STANDARD DECK and two jokers
making a total of 54 cards. Currently, joker decks are not
used in PySol.</p>
making a total of 54 cards.</p>
</dd>

<dt><b>OPEN</b></dt>
Expand Down
14 changes: 14 additions & 0 deletions html-src/rules/thieves.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<h1>Thieves</h1>
<p>
Golf type. 1 joker deck. No redeal.

<h3>Object</h3>
<p>
Move all cards to the waste stack.

<h3>Quick Description</h3>
<p>
Like <a href="golf.html">Golf</a>,
but with two jokers. Jokers are wild, any card
can be played on a joker, and a joker can be played
on any card.
55 changes: 36 additions & 19 deletions pysollib/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -652,22 +652,25 @@ def updateCardset(self, id=0, update=7):
self.images.setNegative(self.opt.negative_bottom)
self.subsampled_images.setNegative(self.opt.negative_bottom)
if update & 1:
self.opt.cardset[0] = (cs.name, cs.backname)
self.opt.cardset[0][0] = (cs.name, cs.backname)
if update & 2:
self.opt.cardset[cs.si.type] = (cs.name, cs.backname)
self.opt.cardset[cs.si.type][cs.si.subtype] = (cs.name,
cs.backname)
gi = self.getGameInfo(id)
if gi:
if update & 256:
try:
del self.opt.cardset[(1, gi.id)]
del self.opt.cardset[(1, gi.id)][gi.subcategory]
except KeyError:
pass
t = self.checkCompatibleCardsetType(gi, cs)
if not t[1]:
if update & 4:
self.opt.cardset[gi.category] = (cs.name, cs.backname)
self.opt.cardset[gi.category][gi.subcategory] = \
(cs.name, cs.backname)
if update & 8:
self.opt.cardset[(1, gi.id)] = (cs.name, cs.backname)
self.opt.cardset[(1, gi.id)][gi.subcategory] = \
(cs.name, cs.backname)
# from pprint import pprint; pprint(self.opt.cardset)

def loadCardset(self, cs, id=0, update=7, progress=None,
Expand All @@ -685,14 +688,16 @@ def loadCardset(self, cs, id=0, update=7, progress=None,
# key: Cardset.type
# value: (Cardset.ident, Images, SubsampledImages)
c = self.cardsets_cache.get(cs.type)
if c and c[0] == cs.ident:
# print 'load from cache', c
self.images, self.subsampled_images = c[1], c[2]
if not tocache:
self.updateCardset(id, update=update)
if self.menubar is not None:
self.menubar.updateBackgroundImagesMenu()
return 1
if c:
c2 = c.get(cs.subtype)
if c2 and c2[0] == cs.ident:
# print 'load from cache', c
self.images, self.subsampled_images = c2[1], c2[2]
if not tocache:
self.updateCardset(id, update=update)
if self.menubar is not None:
self.menubar.updateBackgroundImagesMenu()
return 1
#
if progress is None and not noprogress:
self.wm_save_state()
Expand All @@ -718,9 +723,13 @@ def loadCardset(self, cs, id=0, update=7, progress=None,
# if self.opt.save_cardsets:
c = self.cardsets_cache.get(cs.type)
if c:
# c[1].destruct()
destruct(c[1])
self.cardsets_cache[cs.type] = (cs.ident, images, simages)
c2 = c.get(cs.subtype)
if c2:
# c2[1].destruct()
destruct(c2[1])
self.cardsets_cache[cs.type] = {}
self.cardsets_cache[cs.type][cs.subtype] = (cs.ident, images,
simages)
if not tocache:
# elif self.images is not None:
# # self.images.destruct()
Expand Down Expand Up @@ -757,14 +766,19 @@ def checkCompatibleCardsetType(self, gi, cs):
assert gi is not None
assert cs is not None
gc = gi.category
gs = gi.subcategory
cs_type = cs.si.type
cs_subtype = cs.si.subtype
t0, t1 = None, None
if gc == GI.GC_FRENCH:
t0 = "French"
if cs_type not in (CSI.TYPE_FRENCH,
# CSI.TYPE_TAROCK,
):
t1 = t0
if (cs_subtype == CSI.SUBTYPE_NONE
and gs == CSI.SUBTYPE_JOKER_DECK):
t1 = t0
elif gc == GI.GC_HANAFUDA:
t0 = "Hanafuda"
if cs_type not in (CSI.TYPE_HANAFUDA,):
Expand Down Expand Up @@ -823,14 +837,17 @@ def getCompatibleCardset(self, gi, cs, trychange=True):
# try by gameid / category
for key, flag in (((1, gi.id), 8), (gi.category, 4)):
c = self.opt.cardset.get(key)
if not c or len(c) != 2:
c2 = None
if c:
c2 = c.get(gi.subcategory)
if not c2 or len(c2) != 2:
continue
cs = self.cardset_manager.getByName(c[0])
cs = self.cardset_manager.getByName(c2[0])
if not cs:
continue
t = self.checkCompatibleCardsetType(gi, cs)
if not t[1]:
cs.updateCardback(backname=c[1])
cs.updateCardback(backname=c2[1])
return cs, flag, t
# ask
return None, 0, t
Expand Down
14 changes: 14 additions & 0 deletions pysollib/cardsetparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ def parse_cardset_config(lines_list):
except ValueError:
_perr(1, 6, 'not integer')
return None
if cs.version >= 7:
if len(fields) < 9:
_perr(1, msg='not enough fields')
return None
try:
cs.subtype = int(fields[7])
except ValueError:
_perr(1, 7, 'not integer')
return None
try:
cs.mahjongg3d = bool(fields[8])
except ValueError:
_perr(1, 8, 'not boolean')
return None
if len(cs.ext) < 2 or cs.ext[0] != ".":
_perr(1, msg='specifies an invalid file extension')
return None
Expand Down
16 changes: 11 additions & 5 deletions pysollib/gamedb.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ class GI:

NUM_CATEGORIES = CSI.TYPE_MATCHING

# game subcategory
GS_NONE = CSI.SUBTYPE_NONE
GS_JOKER_DECK = CSI.SUBTYPE_JOKER_DECK

# game type
GT_1DECK_TYPE = 0
GT_2DECK_TYPE = 1
Expand Down Expand Up @@ -341,15 +345,15 @@ def _callback(gi, gt=game_type):
# Gnome AisleRiot 2.2.0 (we have 65 out of 70 games)
# Gnome AisleRiot 3.22.7
# still missing:
# Hamilton, Labyrinth, Thieves, Treize, Valentine, Wall
# Hamilton, Labyrinth, Treize, Valentine, Wall
("Gnome AisleRiot", (
1, 2, 8, 9, 11, 12, 13, 19, 24, 27, 29, 31, 33, 34, 35, 36,
38, 40, 41, 42, 43, 45, 48, 58, 65, 67, 89, 91, 92, 93, 94,
95, 96, 97, 100, 104, 105, 111, 112, 113, 130, 135, 139, 144,
146, 147, 148, 200, 201, 206, 224, 225, 229, 230, 233, 257,
258, 277, 280, 281, 282, 283, 284, 334, 384, 479, 495, 551,
552, 553, 572, 593, 674, 700, 715, 716, 737, 772, 810, 819,
824, 829, 859, 874, 22231,
824, 829, 859, 874, 906, 22231,
)),

# Hoyle Card Games
Expand Down Expand Up @@ -560,7 +564,8 @@ def _callback(gi, gt=game_type):
('fc-2.15', tuple(range(827, 855)) + tuple(range(22400, 22407))),
('fc-2.20', tuple(range(855, 897))),
('fc-2.21', tuple(range(897, 900)) + tuple(range(11014, 11017)) +
tuple(range(13160, 13163)) + (16682,))
tuple(range(13160, 13163)) + (16682,)),
('dev', tuple(range(906, 907))),
)

# deprecated - the correct way is to or a GI.GT_XXX flag
Expand Down Expand Up @@ -608,7 +613,7 @@ def __init__(self, id, gameclass, name,
game_type, decks, redeals,
skill_level=None,
# keyword arguments:
si={}, category=0,
si={}, category=0, subcategory=GI.GS_NONE,
short_name=None, altnames=(),
suits=list(range(4)), ranks=list(range(13)), trumps=(),
rules_filename=None,
Expand Down Expand Up @@ -692,7 +697,8 @@ def to_unicode(s):
name=name, short_name=short_name,
altnames=tuple(altnames), en_name=en_name,
decks=decks, redeals=redeals, ncards=ncards,
category=category, skill_level=skill_level,
category=category, subcategory=subcategory,
skill_level=skill_level,
suits=tuple(suits), ranks=tuple(ranks),
trumps=tuple(trumps),
si=gi_si, rules_filename=rules_filename)
Expand Down
14 changes: 14 additions & 0 deletions pysollib/games/golf.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ def acceptsCards(self, from_stack, cards):
return True
if not WasteStack.acceptsCards(self, from_stack, cards):
return False
# if there are jokers, they're wild
if self.cards[-1].suit == 4 or cards[0].suit == 4:
return True
# check cards
r1, r2 = self.cards[-1].rank, cards[0].rank
if self.game.getStrictness() == 1:
Expand Down Expand Up @@ -217,6 +220,14 @@ def startGame(self):
Golf.startGame(self, 7)


# ************************************************************************
# * Thieves
# ************************************************************************

class Thieves(Golf):
pass


# ************************************************************************
# *
# ************************************************************************
Expand Down Expand Up @@ -1491,3 +1502,6 @@ def fillStack(self, stack):
GI.GT_GOLF | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(892, DoublePutt, "Double Putt",
GI.GT_GOLF, 2, 0, GI.SL_BALANCED))
registerGame(GameInfo(906, Thieves, "Thieves",
GI.GT_GOLF, 1, 0, GI.SL_BALANCED,
subcategory=GI.GS_JOKER_DECK, trumps=list(range(2))))
2 changes: 1 addition & 1 deletion pysollib/games/mahjongg/mahjongg.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ def createGame(self):
# dx, dy = 2, -2
# dx, dy = 3, -3
cs = self.app.images.cs
if cs.version >= 6:
if cs.version == 6 or cs.mahjongg3d:
dx = l.XOFFSET
dy = -l.YOFFSET
d_x = cs.SHADOW_XOFFSET
Expand Down
4 changes: 2 additions & 2 deletions pysollib/games/mahjongg/shisensho.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ def drawArrow(self, other_stack, sleep):
x0, y0 = (game.XMARGIN + game.center_offset[0],
game.YMARGIN + game.center_offset[1])
cardw, cardh = images.CARDW, images.CARDH
if cs.version >= 6:
if cs.version == 6 or cs.mahjongg3d:
cardw -= cs.SHADOW_XOFFSET
cardh -= cs.SHADOW_YOFFSET
coords = []
Expand Down Expand Up @@ -314,7 +314,7 @@ def createGame(self):
# dx, dy = 3, -3

cs = self.app.images.cs
if cs.version >= 6:
if cs.version == 6 or cs.mahjongg3d:
dx = l.XOFFSET
dy = -l.YOFFSET
d_x = cs.SHADOW_XOFFSET
Expand Down
2 changes: 1 addition & 1 deletion pysollib/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ def progressCallback(*args):
# init cardsets
app.initCardsets()
cardset = None
c = app.opt.cardset.get(0)
c = app.opt.cardset.get(0).get(0)
if c:
cardset = app.cardset_manager.getByName(c[0])
if cardset and c[1]:
Expand Down
Loading

0 comments on commit bef82cb

Please sign in to comment.