diff --git a/pysollib/games/golf.py b/pysollib/games/golf.py
index ef4669b6..015881c7 100644
--- a/pysollib/games/golf.py
+++ b/pysollib/games/golf.py
@@ -106,6 +106,9 @@ class Golf_Waste(WasteStack):
                 return 0
         return (r1 + 1) % self.cap.mod == r2 or (r2 + 1) % self.cap.mod == r1
 
+    def getHelp(self):
+        return _('Waste. Build up or down regardless of suit.')
+
 
 class Golf_RowStack(BasicRowStack):
     def clickHandler(self, event):
@@ -678,6 +681,7 @@ class Waterfall(Game):
 
 # /***********************************************************************
 # // Vague
+# // Thirty Two Cards
 # ************************************************************************/
 
 class Vague_RowStack(BasicRowStack):
@@ -685,25 +689,29 @@ class Vague_RowStack(BasicRowStack):
 
 
 class Vague(Game):
+    Foundation_Classes = [StackWrapper(SS_FoundationStack,
+                                       base_rank=ANY_RANK, mod=13)]
 
-    def createGame(self):
+    def createGame(self, rows=3, columns=6):
         l, s = Layout(self), self.s
-        self.setSize(l.XM+6*l.XS, l.YM+4*l.YS)
+        decks = self.gameinfo.decks
+        maxrows = max(columns, 2+decks*4)
+        self.setSize(l.XM+maxrows*l.XS, l.YM+(rows+1)*l.YS)
 
         x, y = l.XM, l.YM
         s.talon = TalonStack(x, y, self)
         l.createText(s.talon, 'ne')
 
         x, y = l.XM+2*l.XS, l.YM
-        for i in range(4):
-            s.foundations.append(SS_FoundationStack(x, y, self, suit=i,
-                                 base_rank=ANY_RANK, mod=13))
-            x += l.XS
+        for found in self.Foundation_Classes:
+            for i in range(4):
+                s.foundations.append(found(x, y, self, suit=i))
+                x += l.XS
 
         y = l.YM+l.YS
-        for i in range(3):
-            x = l.XM
-            for j in range(6):
+        for i in range(rows):
+            x = l.XM + (maxrows-columns)*l.XS/2
+            for j in range(columns):
                 s.rows.append(Vague_RowStack(x, y, self))
                 x += l.XS
             y += l.YS
@@ -734,6 +742,19 @@ class Vague(Game):
             return ((), self.sg.dropstacks, self.sg.dropstacks)
 
 
+class ThirtyTwoCards(Vague):
+    Foundation_Classes = [
+        SS_FoundationStack,
+        StackWrapper(SS_FoundationStack, base_rank=KING, dir=-1)]
+
+    def createGame(self):
+        Vague.createGame(self, rows=4, columns=8)
+
+    def startGame(self):
+        self.startDealSample()
+        self.s.talon.dealRow()
+
+
 # /***********************************************************************
 # // Devil's Solitaire
 # ************************************************************************/
@@ -840,6 +861,79 @@ class DevilsSolitaire(Game):
         f.texts.misc.config(text=t)
 
 
+# /***********************************************************************
+# // Three Fir-trees
+# ************************************************************************/
+
+class ThreeFirTrees_RowStack(Golf_RowStack):
+    def __init__(self, x, y, game):
+        Golf_RowStack.__init__(self, x, y, game, max_accept=0, max_cards=1)
+        self.CARD_YOFFSET = 0
+        self.blockmap = []
+
+    def basicIsBlocked(self):
+        for r in self.blockmap:
+            if r.cards:
+                return True
+        return False
+
+
+class ThreeFirTrees(Golf):
+    Hint_Class = CautiousDefaultHint
+
+    def _createFirTree(self, l, x0, y0):
+        rows = []
+        # create stacks
+        for i in range(11):
+            x = x0 + ((i+1)%2) * l.XS / 2
+            y = y0 + i * l.YS / 4
+            for j in range((i%2) + 1):
+                rows.append(ThreeFirTrees_RowStack(x, y, self))
+                x += l.XS
+        # compute blocking
+        n = 0
+        for i in range(10):
+            if i%2:
+                rows[n].blockmap = [rows[n+2]]
+                rows[n+1].blockmap = [rows[n+2]]
+                n += 2
+            else:
+                rows[n].blockmap = [rows[n+1],rows[n+2]]
+                n += 1
+        return rows
+
+    def createGame(self):
+
+        l, s = Layout(self), self.s
+
+        self.setSize(l.XM+max(7*l.XS, 2*l.XS+26*l.XOFFSET), l.YM+5*l.YS)
+
+        x0, y0 = (self.width-7*l.XS)/2, l.YM
+        for i in range(3):
+            s.rows += self._createFirTree(l, x0, y0)
+            x0 += 2.5*l.XS
+
+        x, y = l.XM, self.height - l.YS
+        s.talon = Golf_Talon(x, y, self, max_rounds=1)
+        l.createText(s.talon, 'n')
+        x += l.XS
+        s.waste = Golf_Waste(x, y, self)
+        s.waste.CARD_XOFFSET = l.XOFFSET/4
+        l.createText(s.waste, 'n')
+        # the Waste is also our only Foundation in this game
+        s.foundations.append(s.waste)
+
+        # define stack-groups (non default)
+        self.sg.openstacks = [s.waste]
+        self.sg.talonstacks = [s.talon]
+        self.sg.dropstacks = s.rows
+
+    def startGame(self):
+        self.startDealSample()
+        self.s.talon.dealRow(frames=4)
+        self.s.talon.dealCards()
+
+
 
 # register the game
 registerGame(GameInfo(36, Golf, "Golf",
@@ -873,4 +967,8 @@ registerGame(GameInfo(720, Vague, "Vague",
                       GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK))
 registerGame(GameInfo(723, DevilsSolitaire, "Devil's Solitaire",
                       GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED))
+registerGame(GameInfo(728, ThirtyTwoCards, "Thirty Two Cards",
+                      GI.GT_2DECK_TYPE, 2, 0, GI.SL_LUCK))
+registerGame(GameInfo(731, ThreeFirTrees, "Three Fir-trees",
+                      GI.GT_GOLF, 2, 0, GI.SL_BALANCED))
 
diff --git a/pysollib/games/klondike.py b/pysollib/games/klondike.py
index f1790b9e..3cfe5426 100644
--- a/pysollib/games/klondike.py
+++ b/pysollib/games/klondike.py
@@ -1351,6 +1351,28 @@ class Scarp(Klondike):
         Klondike.startGame(self, flip=1)
 
 
+# /***********************************************************************
+# // Eight Sages
+# ************************************************************************/
+
+class EightSages_Row(AC_RowStack):
+    def acceptsCards(self, from_stack, cards):
+        if not AC_RowStack.acceptsCards(self, from_stack, cards):
+            return False
+        return from_stack is self.game.s.waste
+
+class EightSages(Klondike):
+    RowStack_Class = EightSages_Row
+
+    def createGame(self):
+        Klondike.createGame(self, max_rounds=2, rows=8, playcards=12)
+
+    def startGame(self):
+        self.startDealSample()
+        self.s.talon.dealRow()
+        self.s.talon.dealCards()
+
+
 
 # register the game
 registerGame(GameInfo(2, Klondike, "Klondike",
@@ -1493,5 +1515,6 @@ registerGame(GameInfo(667, Kingsley, "Kingsley",
                       GI.GT_KLONDIKE, 1, 0, GI.SL_MOSTLY_LUCK))
 registerGame(GameInfo(669, Scarp, "Scarp",
                       GI.GT_GYPSY | GI.GT_ORIGINAL, 3, 0, GI.SL_MOSTLY_SKILL))
-
+registerGame(GameInfo(726, EightSages, "Eight Sages",
+                      GI.GT_KLONDIKE, 2, 1, GI.SL_MOSTLY_LUCK))
 
diff --git a/pysollib/games/montecarlo.py b/pysollib/games/montecarlo.py
index c5246ab9..2399c32f 100644
--- a/pysollib/games/montecarlo.py
+++ b/pysollib/games/montecarlo.py
@@ -840,6 +840,54 @@ class DoubletsII(Game):
                     self.leaveState(old_state)
 
 
+# /***********************************************************************
+# // Right and Left
+# ************************************************************************/
+
+class RightAndLeft_Talon(DealRowRedealTalonStack):
+    def _redeal(self, rows=None, reverse=False, frames=0):
+        return DealRowRedealTalonStack._redeal(self, rows=rows,
+                                               reverse=reverse, frames=3)
+
+
+class RightAndLeft(Game):
+
+    FILL_STACKS_AFTER_DROP = 0
+
+    def createGame(self):
+        # create layout
+        l, s = Layout(self), self.s
+
+        # set window
+        self.setSize(l.XM+5*l.XS, l.YM+3*l.YS)
+
+        # create stacks
+        x, y = l.XM+l.XS, l.YM+2*l.YS
+        s.talon = RightAndLeft_Talon(x, y, self, max_rounds=UNLIMITED_REDEALS)
+
+        x, y = l.XM+0.5*l.XS, l.YM
+        for i in range(2):
+            stack = Nestor_RowStack(x, y, self, max_move=1, max_accept=1,
+                                    dir=0, base_rank=NO_RANK)
+            stack.CARD_YOFFSET = 0
+            s.rows.append(stack)
+            x += l.XS
+
+        x += 1.5*l.XS
+        s.foundations.append(AbstractFoundationStack(x, y, self, suit=ANY_SUIT,
+                             max_move=0, max_cards=104,
+                             max_accept=0, base_rank=ANY_RANK))
+        l.createText(s.foundations[0], 'nw')
+
+        # define stack-groups
+        l.defaultStackGroups()
+
+    def startGame(self):
+        self.startDealSample()
+        self.s.talon.dealRow()
+
+
+
 # register the game
 registerGame(GameInfo(89, MonteCarlo, "Monte Carlo",
                       GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK,
@@ -874,4 +922,6 @@ registerGame(GameInfo(649, DoubletsII, "Doublets II",
                       GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK))
 registerGame(GameInfo(663, TheLastMonarchII, "The Last Monarch II",
                       GI.GT_2DECK_TYPE | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL))
+registerGame(GameInfo(727, RightAndLeft, "Right and Left",
+                      GI.GT_PAIRING_TYPE, 2, -1, GI.SL_LUCK))
 
diff --git a/pysollib/games/sultan.py b/pysollib/games/sultan.py
index 03209c7a..b1932e1e 100644
--- a/pysollib/games/sultan.py
+++ b/pysollib/games/sultan.py
@@ -564,6 +564,7 @@ class Patriarchs(PicturePatience):
 
 # /***********************************************************************
 # // Sixes and Sevens
+# // Two Rings
 # ************************************************************************/
 
 class SixesAndSevens(Game):
@@ -617,6 +618,64 @@ class SixesAndSevens(Game):
         self.s.talon.dealCards()
 
 
+class TwoRings(Game):
+
+    def createGame(self, max_rounds=2):
+
+        l, s = Layout(self), self.s
+        self.setSize(l.XM+10*l.XS, l.YM+5*l.YS)
+
+        lay = (
+            (1.5, 0  ),
+            (2.5, 0.3),
+            (3,   1.3),
+            (2.5, 2.3),
+            (1.5, 2.6),
+            (0.5, 2.3),
+            (0,   1.3),
+            (0.5, 0.3),
+            )
+
+        suit = 0
+        x0, y0 = l.XM+l.XS, l.YM
+        for xx, yy in lay:
+            x, y = x0+xx*l.XS, y0+yy*l.YS
+            s.foundations.append(SS_FoundationStack(x, y, self, suit=suit/2,
+                                 base_rank=6, max_cards=7))
+            suit += 1
+        suit = 0
+        x0, y0 = l.XM+5*l.XS, l.YM
+        for xx, yy in lay:
+            x, y = x0+xx*l.XS, y0+yy*l.YS
+            s.foundations.append(SS_FoundationStack(x, y, self, suit=suit/2,
+                                 base_rank=5, dir=-1, max_cards=6))
+            suit += 1
+
+        x, y = l.XM, l.YM+4*l.YS
+        for i in range(8):
+            stack = BasicRowStack(x, y, self)
+            stack.CARD_YOFFSET = 0
+            s.rows.append(stack)
+            x += l.XS
+
+        x += l.XS
+        s.talon = DealRowRedealTalonStack(x, y, self, max_rounds=2)
+        l.createText(s.talon, 'sw')
+
+        l.defaultStackGroups()
+
+
+    def _shuffleHook(self, cards):
+        return self._shuffleHookMoveToTop(cards,
+            lambda c: (c.rank in (5, 6), (-c.rank, c.suit)))
+
+
+    def startGame(self):
+        self.s.talon.dealRow(rows=self.s.foundations, frames=0)
+        self.startDealSample()
+        self.s.talon.dealRow()
+
+
 # /***********************************************************************
 # // Corner Suite
 # ************************************************************************/
@@ -1008,6 +1067,50 @@ class Khedive(Game):
             self.leaveState(old_state)
 
 
+# /***********************************************************************
+# // Phalanx
+# ************************************************************************/
+
+class Phalanx(Game):
+
+    def createGame(self):
+
+        l, s = Layout(self), self.s
+        self.setSize(l.XM+8*l.XS, l.YM+5*l.YS)
+
+        y = l.YM
+        for i in range(5):
+            x = l.XM+(8-i)*l.XS/2
+            for j in range(i+1):
+                s.rows.append(ReserveStack(x, y, self))
+                x += l.XS
+            y += l.YS
+
+        suit = 0
+        for xx, yy in ((1.5, 1.5),
+                       (1,   2.5),
+                       (6.5, 1.5),
+                       (7,   2.5)):
+            x, y = l.XM+xx*l.XS, l.YM+yy*l.YS
+            s.foundations.append(SS_FoundationStack(x, y, self, suit))
+            suit += 1
+
+        x, y = l.XM, l.YM
+        s.talon = WasteTalonStack(x, y, self, max_rounds=1)
+        l.createText(s.talon, 's')
+        x += l.XS
+        s.waste = WasteStack(x, y, self)
+        l.createText(s.waste, 's')
+
+        l.defaultStackGroups()
+
+
+    def startGame(self):
+        self.startDealSample()
+        self.s.talon.dealRow(frames=4)
+        self.s.talon.dealCards()
+
+
 
 # register the game
 registerGame(GameInfo(330, Sultan, "Sultan",
@@ -1050,3 +1153,7 @@ registerGame(GameInfo(660, Toni, "Toni",
                       GI.GT_2DECK_TYPE, 2, 2, GI.SL_MOSTLY_LUCK))
 registerGame(GameInfo(691, Khedive, "Khedive",
                       GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_LUCK))
+registerGame(GameInfo(729, TwoRings, "Two Rings",
+                      GI.GT_2DECK_TYPE, 2, 1, GI.SL_MOSTLY_LUCK))
+registerGame(GameInfo(730, Phalanx, "Phalanx",
+                      GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK))