Skip to content

Commit

Permalink
Added Clear the Dungeon game.
Browse files Browse the repository at this point in the history
  • Loading branch information
joeraz committed Aug 20, 2023
1 parent 1e9151e commit 54178a1
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 1 deletion.
44 changes: 44 additions & 0 deletions html-src/rules/clearthedungeon.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<h1>Clear the Dungeon</h1>
<p>
One-Deck game type. 1 joker deck. No redeal.

<h3>Object</h3>
<p>
Clear the dungeon by removing all the "monster cards" (face cards)
from the tableau.

<h3>Rules</h3>
<p>
The face cards are dealt in four rows of three cards each, with only the top
card of each pile face-up. These represent the dungeon monsters. The remaining
cards are set aside in the talon, called the "power deck".
<p>
Cards are dealt from the talon three at a time. These cards can be moved to
the monsters on the tableau, or moved to a single reserve pile. The top card
of this reserve pile can also be moved to the tableau. Once all three cards
have been moved to either the tableau or the reserve, three additional cards
are dealt.
<p>
To slay a monster and remove it from the tableau, three additional cards must
be placed on it.
<ul>
<li>The first two cards must have a total rank that's greater than or equal
to the rank of the face card (Jacks are 11, Queens are 12, Kings are 13). This
represents the monster's power.
<li>Finally, a card of the same suit as the face card must be played to it to
finish the attack.
</ul>
<p>
Jokers are wild. They are treated as having a value of 10, and can be of any
suit.
<p>
Once all three cards have been played correctly, the monster is slain, and all
four cards are immediately removed (to the foundation). Cards in the tableau
cannot be moved or removed otherwise.
<p>
The game is won if you're able to discard all the monster cards in the tableau.

<h3>Notes</h3>
<p>
Clear the Dungeon was invented by Mark S. Ball. More details can be found
on <a href="https://www.riffleshuffleandroll.com/clear-the-dungeon">his website</a>.
3 changes: 2 additions & 1 deletion pysollib/gamedb.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ def _callback(gi, gt=game_type):
GAMES_BY_INVENTORS = (
("Paul Alfille", (8,)),
("C.L. Baker", (45,)),
("Mark S. Ball", (909,)),
("David Bernazzani", (314, 830,)),
("Gordon Bower", (763, 783, 852,)),
("Art Cabral", (9,)),
Expand Down Expand Up @@ -565,7 +566,7 @@ def _callback(gi, gt=game_type):
('fc-2.20', tuple(range(855, 897))),
('fc-2.21', tuple(range(897, 900)) + tuple(range(11014, 11017)) +
tuple(range(13160, 13163)) + (16682,)),
('dev', tuple(range(906, 909)) + tuple(range(11017, 11020))),
('dev', tuple(range(906, 910)) + tuple(range(11017, 11020))),
)

# deprecated - the correct way is to or a GI.GT_XXX flag
Expand Down
1 change: 1 addition & 0 deletions pysollib/games/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from . import camelot # noqa: F401
from . import canfield # noqa: F401
from . import capricieuse # noqa: F401
from . import clearthedungeon # noqa: F401
from . import crossword # noqa: F401
from . import curdsandwhey # noqa: F401
from . import daddylonglegs # noqa: F401
Expand Down
164 changes: 164 additions & 0 deletions pysollib/games/clearthedungeon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#!/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/>.
#
# ---------------------------------------------------------------------------##

from pysollib.game import Game
from pysollib.gamedb import GI, GameInfo, registerGame
from pysollib.layout import Layout
from pysollib.stack import \
AbstractFoundationStack, \
BasicRowStack, \
OpenStack, \
ReserveStack, \
TalonStack
from pysollib.util import ANY_SUIT, JACK, KING, NO_RANK, QUEEN

# ************************************************************************
# * Clear the Dungeon
# ************************************************************************


class ClearTheDungeon_RowStack(BasicRowStack):
def acceptsCards(self, from_stack, cards):
cardnum = 0
goal_rank = 0
goal_suit = 0
total = 0
for card in self.cards:
if card.face_up:
if cardnum == 0:
goal_rank = card.rank + 1
goal_suit = card.suit
elif cardnum == 1:
if card.suit == 4:
total += 10
else:
total += (card.rank + 1)
cardnum += 1
if cards[0].suit == 4:
new_val = 10
else:
new_val = cards[0].rank + 1
if cardnum == 1:
if new_val + 10 < goal_rank:
return False
if cardnum == 2:
if total + new_val < goal_rank:
return False
elif cardnum == 3:
if cards[0].suit not in (goal_suit, 4):
return False

return BasicRowStack.acceptsCards(self, from_stack, cards)


class ClearTheDungeon(Game):
#
# game layout
#

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

# set window
self.setSize(l.XM + 5 * l.XS,
l.YM + 2 * l.YS + 12 * l.YOFFSET)

# create stacks
x, y = l.XM, l.YM
for i in range(4):
s.rows.append(ClearTheDungeon_RowStack(x, y, self,
max_move=0, max_accept=1,
dir=0, base_rank=NO_RANK))
x += l.XS
s.foundations.append(AbstractFoundationStack(x, y, self, suit=ANY_SUIT,
max_move=0, max_accept=0,
max_cards=52))
x, y = l.XM, self.height - l.YS
for i in range(3):
s.reserves.append(OpenStack(x, y, self, max_cards=1, max_accept=0))
x += l.XS

x += l.XS
s.talon = TalonStack(x, y, self)
l.createText(s.talon, "sw")

y -= l.YS
s.reserves.append(ReserveStack(x, y, self, max_accept=1, max_move=1,
max_cards=52))

# define stack-groups
l.defaultStackGroups()

def _shuffleHook(self, cards):
topcards = []
for c in cards[:]:
if c.rank in (JACK, QUEEN, KING):
topcards.append(c)
cards.remove(c)
topcards.reverse()
return cards + topcards

def startGame(self):
for r in self.s.rows:
for j in range(2):
self.s.talon.dealRow(rows=[r], flip=0, frames=0)
self.startDealSample()
self.s.talon.dealRow(rows=self.s.rows)
self.s.talon.dealRow(rows=self.s.reserves[:3])

def fillStack(self, stack):
old_state = self.enterState(self.S_FILL)

for s in self.s.rows:
num_cards = 0
for c in s.cards:
if c.face_up:
num_cards += 1
if num_cards == 4:
s.moveMove(4, self.s.foundations[0])
if len(s.cards) > 0:
s.flipMove()

if stack in self.s.reserves[:3]:
for stack in self.s.reserves[:3]:
if stack.cards:
self.leaveState(old_state)
return
self.s.talon.dealRow(rows=self.s.reserves[:3], sound=1)
self.leaveState(old_state)

def isGameWon(self):
for s in self.s.rows:
if len(s.cards) > 0:
return False
return True

def getAutoStacks(self, event=None):
return ((), (), self.sg.dropstacks)


# register the game
registerGame(GameInfo(909, ClearTheDungeon, "Clear the Dungeon",
GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_SKILL,
subcategory=GI.GS_JOKER_DECK, trumps=list(range(2))))

0 comments on commit 54178a1

Please sign in to comment.