Skip to content

Commit

Permalink
Added Cribbage Patience game.
Browse files Browse the repository at this point in the history
  • Loading branch information
joeraz committed Mar 13, 2024
1 parent 77fd05e commit b31ea75
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 6 deletions.
39 changes: 39 additions & 0 deletions html-src/rules/cribbagepatience.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<h1>Cribbage Patience</h1>
<p>
Cribbage type. 1 deck. No redeal.

<h3>Object</h3>
<p>
Deal five cribbage hands to get a total score of 61 points or more.

<h3>Rules</h3>
<p>
Six cards are dealt face-up, and two cards are dealt face-down to the crib.
Move two cards from the six face-up cards to the crib, then flip the
face-down cards. Then, one card is dealt face-up to be the starter.
<p>
Points are awarded for the 2 Cribbage hands: the remaining four cards, plus
the four cards in the crib.
<p>
After each hand, repeat the process four more times to deal a total of five
hands. You win if after all five hands, your score reaches 61 points.
<h3>Cribbage Scoring</h3>
<p>
Cribbage hands are scored as follows - each hand is worth the total value
of all of the following:
<ul>
<li>15 - 2 points are added to each hand for every combination of cards that
adds up to 15.
<li>Pair - 2 points are added for each set of two cards of the same rank.
<li>Pair Royal - For sets of the same rank of more than two cards, they
are scored by the number of individual pairs they contain.
<li>Run - Each combination of three or more cards of consecutive ranks
scores 1 point per card. Only the largest possible run is considered.
<li>Flush - Four cards of the same suit are worth 4 points. The starter
is not considered when scoring flushes, but if it does match the suit of a
flush, that is an extra point.
<li>His Nobs - A jack of the same suit as the starter adds 1 point to
the hand.
<li>His Heels - If the starter is a Jack, 2 points are added to the
entire game.
</ul>
2 changes: 1 addition & 1 deletion html-src/rules/cribbageshuffle.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ <h3>Cribbage Scoring</h3>
<li>Run - Each combination of three or more cards of consecutive ranks
scores 1 point per card. Only the largest possible run is considered.
<li>Flush - Four cards of the same suit are worth 4 points. The starter
is not consiered when scoring flushes, but if it does match the suit of a
is not considered when scoring flushes, but if it does match the suit of a
flush, that is an extra point.
<li>His Nobs - A jack of the same suit as the starter adds 1 point to
the hand.
Expand Down
2 changes: 1 addition & 1 deletion html-src/rules/cribbagesquare.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ <h3>Cribbage Scoring</h3>
<li>Run - Each combination of three or more cards of consecutive ranks
scores 1 point per card. Only the largest possible run is considered.
<li>Flush - Four cards of the same suit are worth 4 points. The starter
is not consiered when scoring flushes, but if it does match the suit of a
is not considered when scoring flushes, but if it does match the suit of a
flush, that is an extra point.
<li>His Nobs - A jack of the same suit as the starter adds 1 point to
the hand.
Expand Down
2 changes: 1 addition & 1 deletion pysollib/gamedb.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,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, 955)) + tuple(range(11017, 11020)) +
('dev', tuple(range(906, 956)) + tuple(range(11017, 11020)) +
tuple(range(5600, 5624)) + tuple(range(18000, 18005)) +
tuple(range(19000, 19012)) + tuple(range(22303, 22311)) +
tuple(range(22353, 22361))),
Expand Down
205 changes: 202 additions & 3 deletions pysollib/games/special/cribbage.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
InitialDealTalonStack, \
InvisibleStack, \
OpenTalonStack, \
RedealTalonStack, \
ReserveStack, \
Stack, \
StackWrapper

# ************************************************************************
Expand Down Expand Up @@ -199,8 +201,8 @@ def getHandScore(self, hand):
upcard = None
upcard_talon = None
if self.isBoardFull():
upcard = self.s.talon.cards[0]
upcard_talon = self.s.talon
upcard_talon = self.getUpcardStack()
upcard = upcard_talon.cards[0]

# First get flushes and his nobs, as these can only be
# scored once per hand.
Expand Down Expand Up @@ -267,8 +269,11 @@ def getHandScore(self, hand):

return hand_score

def getUpcardStack(self):
return self.s.talon

def checkHisHeels(self, score):
if self.isBoardFull() and self.s.talon.cards[0].rank == 10:
if self.isBoardFull() and self.getUpcardStack().cards[0].rank == 10:
return score + 2
return score

Expand Down Expand Up @@ -330,6 +335,197 @@ class CribbageSquare2Reserves(CribbageSquare):
NUM_RESERVE = 2


# ************************************************************************
# * Cribbage Patience
# ************************************************************************

class CribbagePatience_Talon(RedealTalonStack):

def canDealCards(self):
return self.game.isFinalizedHand and len(self.cards) >= 9

def dealCards(self, sound=False):
old_state = self.game.enterState(self.game.S_FILL)
self.game.dealHand()
self.game.leaveState(old_state)


class CribbagePatience_HandStack(ReserveStack):
getBottomImage = Stack._getNoneBottomImage

def clickHandler(self, event):
for s in self.game.s.rows[0:4]:
if len(s.cards) == 0:
return self.playMoveMove(1, s)
return 0

rightclickHandler = clickHandler

def acceptsCards(self, from_stack, cards):
return False

def moveMove(self, ncards, to_stack, frames=-1, shadow=-1):
ReserveStack.moveMove(self, ncards, to_stack, frames=frames,
shadow=shadow)
if self.game.isBoardFull():
self.game.finalizeHand()


class CribbagePatience_CribStack(ReserveStack):
def acceptsCards(self, from_stack, cards):
if from_stack not in self.game.s.rows[4:10]:
return False
return ReserveStack.acceptsCards(self, from_stack, cards)


class CribbagePatience(CribbageShuffle):
WIN_SCORE = 61

def createGame(self):
self.score = 0
self.isFinalizedHand = False
l, s = Layout(self), self.s
self.setSize((2 * l.XM) + 8 * l.XS,
l.YM + l.YS + 12 * l.YOFFSET)
x, y = self.getInvisibleCoords()
s.waste = ReserveStack(x, y, self)
x, y = l.XM, l.YM
s.talon = CribbagePatience_Talon(x, y, self)
l.createText(s.talon, "se")
x += 2 * l.XS
for i in range(4):
s.rows.append(CribbagePatience_CribStack(x, y, self, max_move=1))
x += l.XS
x, y = l.XM, l.YM + l.YS
s.reserves.append(ReserveStack(x, y, self))
x += 2 * l.XS
for i in range(6):
s.rows.append(CribbagePatience_HandStack(x, y, self, max_move=1))
x += l.XS

# define hands for scoring
r = s.rows
self.cribbage_hands = [
r[0:4], r[4:8]
]
self.cribbage_hands = list(map(tuple, self.cribbage_hands))

if self.preview <= 1:
for i in (0, 4):
tx, ty, ta, tf = l.getTextAttr(s.rows[i], anchor="w")
t = MfxCanvasText(self.canvas, tx - 8, ty,
anchor=ta,
font=self.app.getFont("canvas_default"))
self.texts.list.append(t)
self.texts.score = MfxCanvasText(
self.canvas, l.XM + 6 * l.XS, 1 * l.YS, anchor="sw",
font=self.app.getFont("canvas_large"))

l.defaultStackGroups()

def fillStack(self, stack):
if not stack.cards:
old_state = self.enterState(self.S_FILL)
hand = self.s.rows[4:10]
if stack in hand:
i = list(hand).index(stack)
if i < len(hand)-1:
from_stack = hand[i+1]
pile = from_stack.getPile()
if pile:
from_stack.moveMove(len(pile), stack)
self.leaveState(old_state)

def startGame(self):
self.moveMove(7, self.s.talon, self.s.waste, frames=0)
self.score = 0
self.isFinalizedHand = False
self.dealHand()

def dealHand(self):
self.startDealSample()
if self.isFinalizedHand:
for r in reversed(self.s.rows[:8]):
r.moveMove(1, self.s.waste)
self.s.reserves[0].moveMove(1, self.s.waste)
self.saveStateMove(2 | 16)
self.isFinalizedHand = False
self.saveStateMove(1 | 16)

self.s.talon.dealRow(rows=self.s.rows[:2], flip=0)
self.s.talon.dealRow(rows=self.s.rows[4:10])
self.stopSamples()

def isBoardFull(self):
for i in range(8):
if len(self.s.rows[i].cards) == 0:
return False
return True

def finalizeHand(self):
if self.isFinalizedHand:
return
self.saveStateMove(2 | 16)
self.isFinalizedHand = True
old_state = self.enterState(self.S_FILL)
for c in self.s.rows[0:2]:
if not c.cards[0].face_up:
c.flipMove()
self.s.talon.flipMove()
self.s.talon.moveMove(1, self.s.reserves[0])
self.leaveState(old_state)
for i in range(2):
value = self.getHandScore(self.cribbage_hands[i])
self.texts.list[i].config(text=str(value))
self.score += value
self.score = self.checkHisHeels(self.score)
self.saveStateMove(1 | 16)

def updateText(self):
if self.preview > 1:
return
if self.isBoardFull():
for i in range(2):
value = self.getHandScore(self.cribbage_hands[i])

self.texts.list[i].config(text=str(value))
else:
for i in range(2):
self.texts.list[i].config(text="")
#
t = ""
if self.score >= self.WIN_SCORE and len(self.s.talon.cards) == 0:
t = _("WON\n\n")
t += _("Total: %d") % self.score
self.texts.score.config(text=t)

def getUpcardStack(self):
return self.s.reserves[0]

def getGameScore(self):
return self.score

def _restoreGameHook(self, game):
self.score = game.loadinfo.dval.get('Score')
self.isFinalizedHand = game.loadinfo.dval.get('Finalized')

def _loadGameHook(self, p):
self.loadinfo.addattr(dval=p.load())

def _saveGameHook(self, p):
dval = {'Score': self.score, 'Finalized': self.isFinalizedHand}
p.dump(dval)

def setState(self, state):
# restore saved vars (from undo/redo)
self.score = state[0]
self.isFinalizedHand = state[1]

def getState(self):
# save vars (for undo/redo)
return [self.score, self.isFinalizedHand]


# register the game
registerGame(GameInfo(805, CribbageSquare, "Cribbage Square",
GI.GT_CRIBBAGE_TYPE | GI.GT_SCORE, 1, 0,
Expand All @@ -352,3 +548,6 @@ class CribbageSquare2Reserves(CribbageSquare):
GI.GT_CRIBBAGE_TYPE | GI.GT_SCORE | GI.GT_OPEN, 1, 0,
GI.SL_MOSTLY_SKILL,
si={"ncards": 17}))
registerGame(GameInfo(955, CribbagePatience, "Cribbage Patience",
GI.GT_CRIBBAGE_TYPE | GI.GT_SCORE, 1, 0,
GI.SL_MOSTLY_SKILL))

0 comments on commit b31ea75

Please sign in to comment.