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))