From 3b53d94305be4eb6324edfce5a006910b8bf4702 Mon Sep 17 00:00:00 2001 From: Joe R Date: Wed, 2 Dec 2020 22:07:52 -0500 Subject: [PATCH] Added Hit or Miss game. --- html-src/rules/hitormiss.html | 15 ++++ pysollib/games/__init__.py | 1 + pysollib/games/hitormiss.py | 162 ++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 html-src/rules/hitormiss.html create mode 100644 pysollib/games/hitormiss.py diff --git a/html-src/rules/hitormiss.html b/html-src/rules/hitormiss.html new file mode 100644 index 00000000..aebef592 --- /dev/null +++ b/html-src/rules/hitormiss.html @@ -0,0 +1,15 @@ +

Hit or Miss

+

+One-Deck game type. 1 deck. Varying number of redeals. + +

Object

+

+Move all cards to the foundation. + +

Rules

+

As you draw cards from the talon, one at a time, you declare a card rank +in sequence (ace to king, then start over from ace). If the card you draw +matches the rank you declared, that is a "Hit", and the card may be moved +to the foundation. Otherwise, it is a "Miss". You can continue to redeal +as many times as you need, until you go through the entire deck twice in a +row without getting a single "Hit". \ No newline at end of file diff --git a/pysollib/games/__init__.py b/pysollib/games/__init__.py index d0429c26..9e54dbf9 100644 --- a/pysollib/games/__init__.py +++ b/pysollib/games/__init__.py @@ -51,6 +51,7 @@ from . import grandfathersclock # noqa: F401 from . import gypsy # noqa: F401 from . import harp # noqa: F401 from . import headsandtails # noqa: F401 +from . import hitormiss # noqa: F401 from . import katzenschwanz # noqa: F401 from . import klondike # noqa: F401 from . import labyrinth # noqa: F401 diff --git a/pysollib/games/hitormiss.py b/pysollib/games/hitormiss.py new file mode 100644 index 00000000..dd61dcdc --- /dev/null +++ b/pysollib/games/hitormiss.py @@ -0,0 +1,162 @@ +#!/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 . +# +# --------------------------------------------------------------------------- + +from pysollib.game import Game +from pysollib.gamedb import GI, GameInfo, registerGame +from pysollib.layout import Layout +from pysollib.mygettext import _ +from pysollib.pysoltk import MfxCanvasText +from pysollib.stack import \ + AbstractFoundationStack, \ + WasteStack, \ + WasteTalonStack +from pysollib.util import ANY_SUIT, RANKS, \ + VARIABLE_REDEALS + + +# ************************************************************************ +# * +# ************************************************************************ + +class HitOrMiss_Foundation(AbstractFoundationStack): + def acceptsCards(self, from_stack, cards): + game = self.game + return game.rank == cards[0].rank # check the rank + + def getHelp(self): + return _('Foundation. Place cards here that match the declared rank.') + + +class HitOrMiss_Talon(WasteTalonStack): + def canDealCards(self): + game = self.game + if (game.deadDeals == 2 and len(self.cards) == 0 and + self.max_rounds == VARIABLE_REDEALS): + return False + return True + + def dealCards(self, sound=False): + game = self.game + old_state = game.enterState(game.S_FILL) + game.saveStateMove(2 | 16) # for undo + if len(self.cards) > 0: + game.rank += 1 + else: + game.deadDeals += 1 + if game.rank > 12: + game.rank = 0 + game.saveStateMove(1 | 16) # for redo + game.leaveState(old_state) + return super(HitOrMiss_Talon, self).dealCards(sound) + + def getHelp(self): + return _('Talon. Unlimited redeals, until running through the deck ' + 'twice with no hits.') + + +class HitOrMiss_Waste(WasteStack): + def moveMove(self, ncards, to_stack, frames=-1, shadow=-1): + game = self.game + if to_stack in game.s.foundations: + old_state = game.enterState(game.S_FILL) + game.saveStateMove(2 | 16) # for undo + game.deadDeals = 0 + game.saveStateMove(1 | 16) # for redo + game.leaveState(old_state) + super(HitOrMiss_Waste, self).moveMove(ncards, to_stack, frames, shadow) + game.s.talon.dealCards() + + +# ************************************************************************ +# * HitOrMiss +# ************************************************************************ + +class HitOrMiss(Game): + + def createGame(self): + layout, s = Layout(self), self.s + self.rank = -1 + self.deadDeals = 1 + self.max_rounds = VARIABLE_REDEALS + self.setSize(layout.XM + 4 * layout.XS, layout.YM + 2 * layout.YS) + x, y = layout.XM + 3 * layout.XS // 2, layout.YM + stack = HitOrMiss_Foundation(x, y, self, ANY_SUIT, + dir=0, mod=13, max_move=0, max_cards=52) + s.foundations.append(stack) + layout.createText(stack, 'ne') + x, y = layout.XM+layout.XS, layout.YM+layout.YS + s.talon = HitOrMiss_Talon(x, y, self, + max_rounds=VARIABLE_REDEALS, num_deal=1) + layout.createText(s.talon, 'nw') + + x += layout.XS + s.waste = HitOrMiss_Waste(x, y, self) + layout.createText(s.waste, 'ne') + x += layout.XS * 1.1 + y = layout.YM + 1.4 * layout.YS + if self.preview <= 1: + self.texts.rank = \ + MfxCanvasText(self.canvas, x, y, anchor="nw", + font=self.app.getFont("canvas_default"), + text=_("")) + + # define stack-groups + layout.defaultStackGroups() + + def startGame(self): + self.rank = -1 + self.deadDeals = 1 + self.justHit = False + self.startDealSample() + self.s.talon.dealCards() + + def updateText(self): + if self.preview > 1: + return + self.texts.rank.config(text=RANKS[self.rank]) + + def _restoreGameHook(self, game): + self.rank = game.loadinfo.dval.get('Rank') + self.deadDeals = game.loadinfo.dval.get('DeadDeals') + + def _loadGameHook(self, p): + self.loadinfo.addattr(dval=p.load()) + + def _saveGameHook(self, p): + dval = {'Rank': self.rank, 'DeadDeals': self.deadDeals} + p.dump(dval) + + def setState(self, state): + # restore saved vars (from undo/redo) + self.rank = state[0] + self.deadDeals = state[1] + + def getState(self): + # save vars (for undo/redo) + return [self.rank, self.deadDeals] + + +# register the game +registerGame(GameInfo(774, HitOrMiss, "Hit or Miss", + GI.GT_1DECK_TYPE, 1, VARIABLE_REDEALS, + GI.SL_LUCK))