diff --git a/html-src/rules/crispy.html b/html-src/rules/crispy.html
new file mode 100644
index 00000000..f786d17e
--- /dev/null
+++ b/html-src/rules/crispy.html
@@ -0,0 +1,26 @@
+<h1>Crispy</h1>
+<p>
+One-Deck game type. 1 deck. No redeal.
+
+<h3>Object</h3>
+<p>
+Move all cards except the picture cards to the single foundation.
+The picture cards are to be arranged in the tableau with the jacks
+in the corners, kings on the top and bottom, and queens on the
+sides.
+
+<h3>Rules</h3>
+<p>
+Cards are dealt in a four by four grid.  Pairs of cards of the same
+rank, except picture cards, can be removed.  Picture cards can be
+moved to the edges of the tableau - jacks to the corners, kings
+to the top and bottom, and queens to the sides.
+<p>
+When there are no moves left, you can deal one card from the talon
+to each empty tableau space.  THe game is won if all cards are
+removed, except the picture cards, which are in their respective
+spaces.
+
+<h3>Notes</h3>
+<p>
+<i>Autodrop</i> is disabled for this game.
diff --git a/pysollib/gamedb.py b/pysollib/gamedb.py
index b24b33cb..300c59ae 100644
--- a/pysollib/gamedb.py
+++ b/pysollib/gamedb.py
@@ -575,7 +575,7 @@ class GI:
         ('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, 923)) + tuple(range(11017, 11020)) +
+        ('dev', tuple(range(906, 924)) + tuple(range(11017, 11020)) +
          tuple(range(22303, 22311)) + tuple(range(22353, 22361))),
     )
 
diff --git a/pysollib/games/montecarlo.py b/pysollib/games/montecarlo.py
index de115cfe..b8f1de59 100644
--- a/pysollib/games/montecarlo.py
+++ b/pysollib/games/montecarlo.py
@@ -38,7 +38,8 @@ from pysollib.stack import \
         SS_FoundationStack, \
         StackWrapper, \
         TalonStack
-from pysollib.util import ANY_RANK, ANY_SUIT, KING, NO_RANK, UNLIMITED_REDEALS
+from pysollib.util import ANY_RANK, ANY_SUIT, JACK, KING, NO_RANK, \
+    QUEEN, UNLIMITED_REDEALS
 
 # ************************************************************************
 # *
@@ -369,6 +370,72 @@ class SimpleTens(BlockTen):
         return len(self.s.foundations[0].cards) == 36
 
 
+# ************************************************************************
+# * Crispy
+# ************************************************************************
+
+class Crispy_Talon(MonteCarlo_Talon):
+
+    def canDealCards(self):
+        if len(self.cards) == 0:
+            return False
+        return MonteCarlo_Talon.canDealCards(self)
+
+
+class Crispy_RowStack(MonteCarlo_RowStack):
+
+    getBottomImage = BasicRowStack._getReserveBottomImage
+
+    def acceptsCards(self, from_stack, cards):
+        cr = cards[0].rank
+        if len(self.cards) == 0:
+            if cr == KING:
+                return self.id in (1, 2, 13, 14)
+            elif cr == QUEEN:
+                return self.id in (4, 7, 8, 11)
+            elif cr == JACK:
+                return self.id in (0, 3, 12, 15)
+        if cr in (JACK, QUEEN, KING):
+            return False
+        return MonteCarlo_RowStack.acceptsCards(self, from_stack, cards)
+
+
+class Crispy(SimpleCarlo):
+    Talon_Class = Crispy_Talon
+    RowStack_Class = Crispy_RowStack
+    FILL_STACKS_AFTER_DROP = False
+    FILL_STACKS_BEFORE_SHIFT = True
+
+    def createGame(self):
+        MonteCarlo.createGame(self, rows=4, cols=4)
+
+    def isGameWon(self):
+        for i in (1, 2, 13, 14):
+            if len(self.s.rows[i].cards) != 0 and \
+                    self.s.rows[i].cards[0].rank != KING:
+                return False
+        for i in (4, 7, 8, 11):
+            if len(self.s.rows[i].cards) != 0 and \
+                    self.s.rows[i].cards[0].rank != QUEEN:
+                return False
+        for i in (0, 3, 12, 15):
+            if len(self.s.rows[i].cards) != 0 and \
+                    self.s.rows[i].cards[0].rank != JACK:
+                return False
+        for i in (5, 6, 9, 10):
+            if len(self.s.rows[i].cards) != 0:
+                return False
+        return len(self.s.talon.cards) == 0
+
+    def shiftCards(self):
+        free = 0
+        for r in self.s.rows:
+            assert len(r.cards) <= 1
+            if not r.cards:
+                free += 1
+        return free
+
+
 # ************************************************************************
 # * Neighbour
 # ************************************************************************
@@ -1096,3 +1163,5 @@ registerGame(GameInfo(875, PatientPairsOpen, "Patient Pairs (Open)",
                       GI.SL_MOSTLY_SKILL, rules_filename="patientpairs.html"))
 registerGame(GameInfo(898, AcesSquare, "Aces Square",
                       GI.GT_1DECK_TYPE, 1, 0, GI.SL_BALANCED))
+registerGame(GameInfo(923, Crispy, "Crispy",
+                      GI.GT_1DECK_TYPE, 1, 0, GI.SL_BALANCED))