diff --git a/Canvas.py b/Canvas.py
new file mode 100644
index 00000000..7edce44a
--- /dev/null
+++ b/Canvas.py
@@ -0,0 +1,190 @@
+# This module exports classes for the various canvas item types
+
+# NOTE: This module was an experiment and is now obsolete.
+# It's best to use the Tkinter.Canvas class directly.
+
+from six.moves.tkinter import Canvas, _cnfmerge, _flatten
+
+
+class CanvasItem:
+    def __init__(self, canvas, itemType, *args, **kw):
+        self.canvas = canvas
+        self.id = canvas._create(itemType, args, kw)
+        if not hasattr(canvas, 'items'):
+            canvas.items = {}
+        canvas.items[self.id] = self
+    def __str__(self):
+        return str(self.id)
+    def __repr__(self):
+        return '<%s, id=%d>' % (self.__class__.__name__, self.id)
+    def delete(self):
+        del self.canvas.items[self.id]
+        self.canvas.delete(self.id)
+    def __getitem__(self, key):
+        v = self.canvas.tk.split(self.canvas.tk.call(
+                self.canvas._w, 'itemconfigure',
+                self.id, '-' + key))
+        return v[4]
+    cget = __getitem__
+    def __setitem__(self, key, value):
+        self.canvas.itemconfig(self.id, {key: value})
+    def keys(self):
+        if not hasattr(self, '_keys'):
+            self._keys = map(lambda x, tk=self.canvas.tk:
+                             tk.splitlist(x)[0][1:],
+                             self.canvas.tk.splitlist(
+                                     self.canvas._do(
+                                             'itemconfigure',
+                                             (self.id,))))
+        return self._keys
+    def has_key(self, key):
+        return key in self.keys()
+    def __contains__(self, key):
+        return key in self.keys()
+    def addtag(self, tag, option='withtag'):
+        self.canvas.addtag(tag, option, self.id)
+    def bbox(self):
+        x1, y1, x2, y2 = self.canvas.bbox(self.id)
+        return (x1, y1), (x2, y2)
+    def bind(self, sequence=None, command=None, add=None):
+        return self.canvas.tag_bind(self.id, sequence, command, add)
+    def unbind(self, sequence, funcid=None):
+        self.canvas.tag_unbind(self.id, sequence, funcid)
+    def config(self, cnf={}, **kw):
+        return self.canvas.itemconfig(self.id, _cnfmerge((cnf, kw)))
+    def coords(self, pts = ()):
+        flat = ()
+        for x, y in pts: flat = flat + (x, y)
+        return self.canvas.coords(self.id, *flat)
+    def dchars(self, first, last=None):
+        self.canvas.dchars(self.id, first, last)
+    def dtag(self, ttd):
+        self.canvas.dtag(self.id, ttd)
+    def focus(self):
+        self.canvas.focus(self.id)
+    def gettags(self):
+        return self.canvas.gettags(self.id)
+    def icursor(self, index):
+        self.canvas.icursor(self.id, index)
+    def index(self, index):
+        return self.canvas.index(self.id, index)
+    def insert(self, beforethis, string):
+        self.canvas.insert(self.id, beforethis, string)
+    def lower(self, belowthis=None):
+        self.canvas.tag_lower(self.id, belowthis)
+    def move(self, xamount, yamount):
+        self.canvas.move(self.id, xamount, yamount)
+    def tkraise(self, abovethis=None):
+        self.canvas.tag_raise(self.id, abovethis)
+    raise_ = tkraise # BW compat
+    def scale(self, xorigin, yorigin, xscale, yscale):
+        self.canvas.scale(self.id, xorigin, yorigin, xscale, yscale)
+    def type(self):
+        return self.canvas.type(self.id)
+
+class Arc(CanvasItem):
+    def __init__(self, canvas, *args, **kw):
+        CanvasItem.__init__(self, canvas, 'arc', *args, **kw)
+
+class Bitmap(CanvasItem):
+    def __init__(self, canvas, *args, **kw):
+        CanvasItem.__init__(self, canvas, 'bitmap', *args, **kw)
+
+class ImageItem(CanvasItem):
+    def __init__(self, canvas, *args, **kw):
+        CanvasItem.__init__(self, canvas, 'image', *args, **kw)
+
+class Line(CanvasItem):
+    def __init__(self, canvas, *args, **kw):
+        CanvasItem.__init__(self, canvas, 'line', *args, **kw)
+
+class Oval(CanvasItem):
+    def __init__(self, canvas, *args, **kw):
+        CanvasItem.__init__(self, canvas, 'oval', *args, **kw)
+
+class Polygon(CanvasItem):
+    def __init__(self, canvas, *args, **kw):
+        CanvasItem.__init__(self, canvas, 'polygon', *args, **kw)
+
+class Rectangle(CanvasItem):
+    def __init__(self, canvas, *args, **kw):
+        CanvasItem.__init__(self, canvas, 'rectangle', *args, **kw)
+
+# XXX "Text" is taken by the Text widget...
+class CanvasText(CanvasItem):
+    def __init__(self, canvas, *args, **kw):
+        CanvasItem.__init__(self, canvas, 'text', *args, **kw)
+
+class Window(CanvasItem):
+    def __init__(self, canvas, *args, **kw):
+        CanvasItem.__init__(self, canvas, 'window', *args, **kw)
+
+class Group:
+    def __init__(self, canvas, tag=None):
+        if not tag:
+            tag = 'Group%d' % id(self)
+        self.tag = self.id = tag
+        self.canvas = canvas
+        self.canvas.dtag(self.tag)
+    def str(self):
+        return self.tag
+    __str__ = str
+    def _do(self, cmd, *args):
+        return self.canvas._do(cmd, (self.tag,) + _flatten(args))
+    def addtag_above(self, tagOrId):
+        self._do('addtag', 'above', tagOrId)
+    def addtag_all(self):
+        self._do('addtag', 'all')
+    def addtag_below(self, tagOrId):
+        self._do('addtag', 'below', tagOrId)
+    def addtag_closest(self, x, y, halo=None, start=None):
+        self._do('addtag', 'closest', x, y, halo, start)
+    def addtag_enclosed(self, x1, y1, x2, y2):
+        self._do('addtag', 'enclosed', x1, y1, x2, y2)
+    def addtag_overlapping(self, x1, y1, x2, y2):
+        self._do('addtag', 'overlapping', x1, y1, x2, y2)
+    def addtag_withtag(self, tagOrId):
+        self._do('addtag', 'withtag', tagOrId)
+    def bbox(self):
+        return self.canvas._getints(self._do('bbox'))
+    def bind(self, sequence=None, command=None, add=None):
+        return self.canvas.tag_bind(self.id, sequence, command, add)
+    def unbind(self, sequence, funcid=None):
+        self.canvas.tag_unbind(self.id, sequence, funcid)
+    def coords(self, *pts):
+        return self._do('coords', pts)
+    def dchars(self, first, last=None):
+        self._do('dchars', first, last)
+    def delete(self):
+        self._do('delete')
+    def dtag(self, tagToDelete=None):
+        self._do('dtag', tagToDelete)
+    def focus(self):
+        self._do('focus')
+    def gettags(self):
+        return self.canvas.tk.splitlist(self._do('gettags', self.tag))
+    def icursor(self, index):
+        return self._do('icursor', index)
+    def index(self, index):
+        return self.canvas.tk.getint(self._do('index', index))
+    def insert(self, beforeThis, string):
+        self._do('insert', beforeThis, string)
+    def config(self, cnf={}, **kw):
+        return self.canvas.itemconfigure(self.tag, _cnfmerge((cnf,kw)))
+    def lower(self, belowThis=None):
+        self._do('lower', belowThis)
+    def move(self, xAmount, yAmount):
+        self._do('move', xAmount, yAmount)
+    def tkraise(self, aboveThis=None):
+        self._do('raise', aboveThis)
+    lift = tkraise
+    def scale(self, xOrigin, yOrigin, xScale, yScale):
+        self._do('scale', xOrigin, yOrigin, xScale, yScale)
+    def select_adjust(self, index):
+        self.canvas._do('select', ('adjust', self.tag, index))
+    def select_from(self, index):
+        self.canvas._do('select', ('from', self.tag, index))
+    def select_to(self, index):
+        self.canvas._do('select', ('to', self.tag, index))
+    def type(self):
+        return self._do('type')
diff --git a/pysollib/app.py b/pysollib/app.py
index 184afa11..ccd0ae32 100644
--- a/pysollib/app.py
+++ b/pysollib/app.py
@@ -521,13 +521,14 @@ class Application:
             # this is the mainloop
             while 1:
                 assert self.cardset is not None
-                id, random = self.nextgame.id, self.nextgame.random
+                id_, random = self.nextgame.id, self.nextgame.random
                 self.nextgame.id, self.nextgame.random = 0, None
                 try:
-                    self.runGame(id, random)
+                    print("fopako id_", id_)
+                    self.runGame(id_, random)
                 except Exception:
                     # try Klondike if current game fails
-                    if id == 2:
+                    if id_ == 2:
                         raise           # internal error?
                     if DEBUG:
                         raise
@@ -569,7 +570,7 @@ class Application:
             destroy_find_card_dialog()
             destroy_solver_dialog()
             # update options
-            self.opt.last_gameid = id
+            self.opt.last_gameid = id_
             # save options
             try:
                 self.saveOptions()
@@ -595,22 +596,22 @@ class Application:
                 traceback.print_exc()
                 pass
 
-    def runGame(self, id, random=None):
+    def runGame(self, id_, random=None):
         self.top.connectApp(self)
         # create game instance
-        g = self.getGameClass(id)
+        g = self.getGameClass(id_)
         if g is None:
-            id = 2          # start Klondike as default game
+            id_ = 2          # start Klondike as default game
             random = None
-            g = self.getGameClass(id)
+            g = self.getGameClass(id_)
             if g is None:
                 # start first available game
-                id = self.gdb.getGamesIdSortedByName()[0]
-                g = self.getGameClass(id)
-        gi = self.getGameInfo(id)
-        assert gi is not None and gi.id == id
-        self.game = self.constructGame(id)
-        self.gdb.setSelected(id)
+                id_ = self.gdb.getGamesIdSortedByName()[0]
+                g = self.getGameClass(id_)
+        gi = self.getGameInfo(id_)
+        assert gi is not None and gi.id == id_
+        self.game = self.constructGame(id_)
+        self.gdb.setSelected(id_)
         self.game.busy = 1
         # create stacks and layout
         self.game.create(self)
@@ -620,9 +621,9 @@ class Application:
             self.toolbar.connectGame(self.game)
         self.game.updateStatus(player=self.opt.player)
         # update "Recent games" menubar entry
-        if id in self.opt.recent_gameid:
-            self.opt.recent_gameid.remove(id)
-        self.opt.recent_gameid.insert(0, id)
+        if id_ in self.opt.recent_gameid:
+            self.opt.recent_gameid.remove(id_)
+        self.opt.recent_gameid.insert(0, id_)
         del self.opt.recent_gameid[self.opt.num_recent_games:]
         self.menubar.updateRecentGamesMenu(self.opt.recent_gameid)
         self.menubar.updateFavoriteGamesMenu()
diff --git a/pysollib/configobj/configobj.py b/pysollib/configobj/configobj.py
index d04857cd..dbef477d 100644
--- a/pysollib/configobj/configobj.py
+++ b/pysollib/configobj/configobj.py
@@ -21,7 +21,7 @@ import sys
 import os
 import re
 
-from types import StringTypes
+from six import string_types
 from warnings import warn
 INTP_VER = sys.version_info[:2]
 if INTP_VER < (2, 2):
@@ -544,7 +544,7 @@ class Section(dict):
     def __getitem__(self, key):
         """Fetch the item and do string interpolation."""
         val = dict.__getitem__(self, key)
-        if self.main.interpolation and isinstance(val, StringTypes):
+        if self.main.interpolation and isinstance(val, string_types):
             return self._interpolate(key, val)
         return val
 
@@ -562,7 +562,7 @@ class Section(dict):
         `unrepr`` must be set when setting a value to a dictionary, without
         creating a new sub-section.
         """
-        if not isinstance(key, StringTypes):
+        if not isinstance(key, string_types):
             raise ValueError('The key "%s" is not a string.' % key)
         # add the comment
         if key not in self.comments:
@@ -595,11 +595,11 @@ class Section(dict):
             if key not in self:
                 self.scalars.append(key)
             if not self.main.stringify:
-                if isinstance(value, StringTypes):
+                if isinstance(value, string_types):
                     pass
                 elif isinstance(value, (list, tuple)):
                     for entry in value:
-                        if not isinstance(entry, StringTypes):
+                        if not isinstance(entry, string_types):
                             raise TypeError(
                                 'Value is not a string "%s".' % entry)
                 else:
@@ -641,7 +641,7 @@ class Section(dict):
             del self.comments[key]
             del self.inline_comments[key]
             self.sections.remove(key)
-        if self.main.interpolation and isinstance(val, StringTypes):
+        if self.main.interpolation and isinstance(val, string_types):
             return self._interpolate(key, val)
         return val
 
@@ -990,7 +990,7 @@ class Section(dict):
             return False
         else:
             try:
-                if not isinstance(val, StringTypes):
+                if not isinstance(val, string_types):
                     raise KeyError
                 else:
                     return self.main._bools[val.lower()]
@@ -1149,6 +1149,7 @@ class ConfigObj(Section):
 
         ``ConfigObj(infile=None, options=None, **kwargs)``
         """
+        print('pink infile = ',infile)
         if infile is None:
             infile = []
         if options is None:
@@ -1191,10 +1192,13 @@ class ConfigObj(Section):
         #
         self._terminated = False
         #
-        if isinstance(infile, StringTypes):
+        if isinstance(infile, string_types):
             self.filename = infile
             if os.path.isfile(infile):
-                infile = open(infile).read() or []
+                if sys.version_info > (3,):
+                    infile = unicode(open(infile).read()) or []
+                else:
+                    infile = open(infile).read() or []
             elif self.file_error:
                 # raise an error if the file doesn't exist
                 raise IOError('Config file not found: "%s".' % self.filename)
@@ -1233,6 +1237,7 @@ class ConfigObj(Section):
                             ' file like object, or list of lines.')
         #
         if infile:
+            print('infile flyt = ',infile)
             # don't do it for the empty ConfigObj
             infile = self._handle_bom(infile)
             # infile is now *always* a list
@@ -1256,6 +1261,7 @@ class ConfigObj(Section):
         if self._errors:
             info = "at line %s." % self._errors[0].line_number
             if len(self._errors) > 1:
+                raise self._errors[0]
                 msg = ("Parsing failed with several errors.\nFirst error %s" %
                        info)
                 error = ConfigObjError(msg)
@@ -1302,6 +1308,10 @@ class ConfigObj(Section):
         ``infile`` must always be returned as a list of lines, but may be
         passed in as a single string.
         """
+        if sys.version_info > (3,):
+            if isinstance(infile, list):
+                return infile
+            return infile.splitlines(True)
         if ((self.encoding is not None) and
                 (self.encoding.lower() not in BOM_LIST)):
             # No need to check for a BOM
@@ -1367,7 +1377,7 @@ class ConfigObj(Section):
                     else:
                         infile = newline
                     # UTF8 - don't decode
-                    if isinstance(infile, StringTypes):
+                    if isinstance(infile, string_types):
                         return infile.splitlines(True)
                     else:
                         return infile
@@ -1375,7 +1385,7 @@ class ConfigObj(Section):
                 return self._decode(infile, encoding)
         #
         # No BOM discovered and no encoding specified, just return
-        if isinstance(infile, StringTypes):
+        if isinstance(infile, string_types):
             # infile read from a file will be a single string
             return infile.splitlines(True)
         else:
@@ -1383,6 +1393,8 @@ class ConfigObj(Section):
 
     def _a_to_u(self, aString):
         """Decode ASCII strings to unicode if a self.encoding is specified."""
+        if sys.version_info > (3,):
+            return str(aString)
         if self.encoding:
             return aString.decode('ascii')
         else:
@@ -1394,7 +1406,7 @@ class ConfigObj(Section):
 
         if is a string, it also needs converting to a list.
         """
-        if isinstance(infile, StringTypes):
+        if isinstance(infile, string_types):
             # can't be unicode
             # NOTE: Could raise a ``UnicodeDecodeError``
             return infile.decode(encoding).splitlines(True)
@@ -1420,13 +1432,14 @@ class ConfigObj(Section):
         Used by ``stringify`` within validate, to turn non-string values
         into strings.
         """
-        if not isinstance(value, StringTypes):
+        if not isinstance(value, string_types):
             return str(value)
         else:
             return value
 
     def _parse(self, infile):
         """Actually parse the config file."""
+        print('aolk', infile)
         temp_list_values = self.list_values
         if self.unrepr:
             self.list_values = False
@@ -1671,7 +1684,7 @@ class ConfigObj(Section):
                 return self._quote(value[0], multiline=False) + ','
             return ', '.join([self._quote(val, multiline=False)
                              for val in value])
-        if not isinstance(value, StringTypes):
+        if not isinstance(value, string_types):
             if self.stringify:
                 value = str(value)
             else:
diff --git a/pysollib/game.py b/pysollib/game.py
index 9ce3118b..fdd82cd1 100644
--- a/pysollib/game.py
+++ b/pysollib/game.py
@@ -80,7 +80,7 @@ PLAY_TIME_TIMEOUT = 200
 # ************************************************************************
 
 
-class Game:
+class Game(object):
     # for self.gstats.updated
     U_PLAY = 0
     U_WON = -2
diff --git a/pysollib/games/freecell.py b/pysollib/games/freecell.py
index a6543a34..3ca2b007 100644
--- a/pysollib/games/freecell.py
+++ b/pysollib/games/freecell.py
@@ -77,7 +77,8 @@ class FreeCell(Game):
         # create layout
         l, s = Layout(self), self.s
         kwdefault(layout, rows=8, reserves=4, texts=0)
-        self.Layout_Method(l, **layout)
+        # self.Layout_Method(l, **layout)
+        self.__class__.__dict__['Layout_Method'](l, **layout)
         self.setSize(l.size[0], l.size[1])
         # create stacks
         s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self)
diff --git a/pysollib/games/klondike.py b/pysollib/games/klondike.py
index 5077bfa4..3e707407 100644
--- a/pysollib/games/klondike.py
+++ b/pysollib/games/klondike.py
@@ -79,7 +79,9 @@ class Klondike(Game):
         # create layout
         l, s = Layout(self), self.s
         kwdefault(layout, rows=7, waste=1, texts=1, playcards=16)
-        self.Layout_Method(l, **layout)
+        print(l, layout)
+        self.__class__.__dict__['Layout_Method'](l, **layout)
+        # self.Layout_Method.__get__(l, l.__class__)(**layout)
         self.setSize(l.size[0], l.size[1])
         # create stacks
         s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self,
diff --git a/pysollib/games/mahjongg/mahjongg.py b/pysollib/games/mahjongg/mahjongg.py
index 9c5b4f36..740c5800 100644
--- a/pysollib/games/mahjongg/mahjongg.py
+++ b/pysollib/games/mahjongg/mahjongg.py
@@ -47,8 +47,6 @@ from pysollib.stack import \
         InitialDealTalonStack, \
         OpenStack
 
-from new import classobj
-
 if sys.version_info > (3,):
     xrange = range
 
@@ -987,11 +985,11 @@ def comp_cardset(ncards):
     assert ncards % 4 == 0
     assert 0 < ncards <= 288  # ???
     decks = 1
-    cards = ncards/4
+    cards = ncards//4
     if ncards > 144:
         assert ncards % 8 == 0
         decks = 2
-        cards = cards/2
+        cards = cards//2
     ranks, trumps = divmod(cards, 3)
     if ranks > 10:
         trumps += (ranks-10)*3
@@ -1012,7 +1010,7 @@ def r(id, short_name, name=None, ncards=144, layout=None):
         name = "Mahjongg " + short_name
     classname = re.sub('\W', '', name)
     # create class
-    gameclass = classobj(classname, (AbstractMahjonggGame,), {})
+    gameclass = type(classname, (AbstractMahjonggGame,), {})
     gameclass.L = layout
     gameclass.NCARDS = ncards
     decks, ranks, trumps = comp_cardset(ncards)
diff --git a/pysollib/hint.py b/pysollib/hint.py
index 2e776ef3..4724dfb9 100644
--- a/pysollib/hint.py
+++ b/pysollib/hint.py
@@ -884,7 +884,7 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
             kw['close_fds'] = True
         p = subprocess.Popen(command, **kw)
         pin, pout, perr = p.stdin, p.stdout, p.stderr
-        pin.write(board)
+        pin.write(bytes(board, 'utf-8'))
         pin.close()
         #
         stack_types = {
@@ -896,39 +896,41 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
             start_time = time.time()
         if progress:
             # iteration output
-            iter = 0
+            iter_ = 0
             depth = 0
             states = 0
 
-            for s in pout:
+            for sbytes in pout:
+                s = str(sbytes, encoding='utf-8')
                 if DEBUG >= 5:
                     print(s)
 
                 if self.colonPrefixMatch('Iteration', s):
-                    iter = self._v
+                    iter_ = self._v
                 elif self.colonPrefixMatch('Depth', s):
                     depth = self._v
                 elif self.colonPrefixMatch('Stored-States', s):
                     states = self._v
-                    if iter % 100 == 0:
-                        self.dialog.setText(iter=iter, depth=depth,
+                    if iter_ % 100 == 0:
+                        self.dialog.setText(iter=iter_, depth=depth,
                                             states=states)
                 elif re.search('^(?:-=-=)', s):
                     break
                 elif self._determineIfSolverState(s):
                     break
-            self.dialog.setText(iter=iter, depth=depth, states=states)
+            self.dialog.setText(iter=iter_, depth=depth, states=states)
 
         hints = []
-        for s in pout:
+        for sbytes in pout:
+            s = str(sbytes, encoding='utf-8')
             if DEBUG:
                 print(s)
             if self._determineIfSolverState(s):
                 next
             m = re.match('Total number of states checked is (\d+)\.', s)
             if m:
-                iter = int(m.group(1))
-                self.dialog.setText(iter=iter)
+                iter_ = int(m.group(1))
+                self.dialog.setText(iter=iter_)
 
             m = re.match('This scan generated (\d+) states\.', s)
 
@@ -1061,7 +1063,7 @@ class BlackHoleSolver_Hint(Base_Solver_Hint):
 
         result = ''
         # iteration output
-        iter = 0
+        iter_ = 0
         depth = 0
         states = 0
 
@@ -1073,7 +1075,7 @@ class BlackHoleSolver_Hint(Base_Solver_Hint):
             if m:
                 result = m.group(1)
                 break
-        self.dialog.setText(iter=iter, depth=depth, states=states)
+        self.dialog.setText(iter=iter_, depth=depth, states=states)
 
         if (result == 'Intractable!'):
             self.solver_state = 'intractable'
@@ -1090,8 +1092,8 @@ class BlackHoleSolver_Hint(Base_Solver_Hint):
                 print(s)
             m = re.match('Total number of states checked is (\d+)\.', s)
             if m:
-                iter = int(m.group(1))
-                self.dialog.setText(iter=iter)
+                iter_ = int(m.group(1))
+                self.dialog.setText(iter=iter_)
                 continue
 
             m = re.match('This scan generated (\d+) states\.', s)
diff --git a/pysollib/layout.py b/pysollib/layout.py
index f1cc2e40..f32fdeb8 100644
--- a/pysollib/layout.py
+++ b/pysollib/layout.py
@@ -115,9 +115,9 @@ class Layout:
         self.__dict__.update(kw)
         if self.game.preview > 1:
             if "XOFFSET" in kw:
-                self.XOFFSET /= self.game.preview
+                self.XOFFSET //= self.game.preview
             if "YOFFSET" in kw:
-                self.YOFFSET /= self.game.preview
+                self.YOFFSET //= self.game.preview
             self.TEXT_HEIGHT = 10
 
     def __createStack(self, x, y, suit=None):
@@ -158,7 +158,7 @@ class Layout:
             s.waste = waste_class(self.s.waste.x, self.s.waste.y, game)
         if foundation_class:
             if isinstance(foundation_class, (list, tuple)):
-                n = len(self.s.foundations)/len(foundation_class)
+                n = len(self.s.foundations)//len(foundation_class)
                 i = 0
                 for j in range(n):
                     for cls in foundation_class:
@@ -197,16 +197,16 @@ class Layout:
         delta_x, delta_y = 4, 4
         delta_yy = 10
         d = {
-            "n": (x+self.CW/2,       y-delta_y,          "s",  "%d"),
-            "nn": (x+self.CW/2,       y-delta_yy,         "s",  "%d"),
-            "s": (x+self.CW/2,       y+self.CH+delta_y,  "n",  "%d"),
-            "ss": (x+self.CW/2,       y+self.CH+delta_yy, "n",  "%d"),
+            "n": (x+self.CW//2,       y-delta_y,          "s",  "%d"),
+            "nn": (x+self.CW//2,       y-delta_yy,         "s",  "%d"),
+            "s": (x+self.CW//2,       y+self.CH+delta_y,  "n",  "%d"),
+            "ss": (x+self.CW//2,       y+self.CH+delta_yy, "n",  "%d"),
             "nw": (x-delta_x,         y,                  "ne", "%d"),
             "sw": (x-delta_x,         y+self.CH,          "se", "%d"),
             "ne": (x+self.CW+delta_x, y,                  "nw", "%d"),
             "se": (x+self.CW+delta_x, y+self.CH,          "sw", "%d"),
-            "w": (x-delta_x,         y+self.CH/2,        "e",  "%d"),
-            "e": (x+self.CW+delta_x, y+self.CH/2,        "w",  "%d"),
+            "w": (x-delta_x,         y+self.CH//2,        "e",  "%d"),
+            "e": (x+self.CW+delta_x, y+self.CH//2,        "w",  "%d"),
             }
         return d[anchor]
 
@@ -305,11 +305,11 @@ class Layout:
 
         decks = self.game.gameinfo.decks
         suits = len(self.game.gameinfo.suits) + bool(self.game.gameinfo.trumps)
-        halfrows = (rows + 1) / 2
+        halfrows = (rows + 1) // 2
 
         # set size so that at least 9 cards are fully playable
         h = YS + min(2*YS, (playcards-1)*self.YOFFSET)
-        h = max(h, 5*YS/2, 3*YS/2+CH)
+        h = max(h, 5*YS//2, 3*YS//2+CH)
         h = min(h, 3*YS)
 
         # create rows
@@ -321,7 +321,7 @@ class Layout:
 
         # create foundations
         x, y = XM + halfrows * XS, YM
-        self.setRegion(self.s.rows, (-999, -999, x - CW / 2, 999999))
+        self.setRegion(self.s.rows, (-999, -999, x - CW // 2, 999999))
         for suit in range(suits):
             for i in range(decks):
                 self.s.foundations.append(S(x+i*XS, y, suit=suit))
@@ -343,7 +343,7 @@ class Layout:
     #  - left bottom: talon, waste
     #
 
-    def freeCellLayout(self, rows, reserves, waste=0,
+    def freeCellLayout(self, rows=0, reserves=0, waste=0,
                        texts=0, reserve_texts=False, playcards=18):
         S = self.__createStack
         CH = self.CH
@@ -359,14 +359,14 @@ class Layout:
 
         w = XM + maxrows*XS
 
-        # set size so that at least 2/3 of a card is visible with 18 cards
-        h = CH*2/3 + (playcards-1)*self.YOFFSET
+        # set size so that at least 2//3 of a card is visible with 18 cards
+        h = CH*2//3 + (playcards-1)*self.YOFFSET
         h = YM + YS + max(h, 3*YS)
         if reserves and reserve_texts:
             h += self.TEXT_HEIGHT
 
         # create reserves & foundations
-        x, y = (w - (toprows*XS - XM))/2, YM
+        x, y = (w - (toprows*XS - XM))//2, YM
         if reserves:
             for i in range(reserves):
                 s = S(x, y)
@@ -381,13 +381,13 @@ class Layout:
                 x += XS
 
         # create rows
-        x, y = (w - (rows*XS - XM))/2, YM + YS
+        x, y = (w - (rows*XS - XM))//2, YM + YS
         if reserves and reserve_texts:
             y += self.TEXT_HEIGHT
         for i in range(rows):
             self.s.rows.append(S(x, y))
             x += XS
-        self.setRegion(self.s.rows, (-999, y - CH / 2, 999999, 999999))
+        self.setRegion(self.s.rows, (-999, y - CH // 2, 999999, 999999))
 
         # create talon
         x, y = XM, h - YS
@@ -431,8 +431,8 @@ class Layout:
         if reserves:
             h = YS+(playcards-1)*self.YOFFSET+YS
         else:
-            # set size so that at least 2/3 of a card is visible with 25 cards
-            h = CH*2/3 + (playcards-1)*self.YOFFSET
+            # set size so that at least 2//3 of a card is visible with 25 cards
+            h = CH*2//3 + (playcards-1)*self.YOFFSET
         h = YM + max(h, (suits+1)*YS)
         if reserves and reserve_texts:
             h += self.TEXT_HEIGHT
@@ -443,10 +443,10 @@ class Layout:
             self.s.rows.append(S(x, y))
             x += XS
         if reserves:
-            yy = h - YS - CH/2
+            yy = h - YS - CH//2
         else:
             yy = 999999
-        self.setRegion(self.s.rows, (-999, -999, x - CW / 2, yy))
+        self.setRegion(self.s.rows, (-999, -999, x - CW // 2, yy))
 
         # create foundations
         x = w - decks*XS
@@ -458,7 +458,7 @@ class Layout:
         # create talon and waste
         x, y = x + (decks-1)*XS, h - YS
         if texts:
-            x -= XS/2
+            x -= XS//2
         self.s.talon = s = S(x, y)
         anchor = 's'
         if round_text:
@@ -519,7 +519,7 @@ class Layout:
         if reserves:
             if reserve_texts:
                 y += self.TEXT_HEIGHT
-            x = (w - (reserves*XS - XM))/2
+            x = (w - (reserves*XS - XM))//2
             for i in range(reserves):
                 s = S(x, y)
                 self.s.reserves.append(s)
@@ -527,7 +527,7 @@ class Layout:
                 if reserve_texts:
                     self._setText(s, anchor="n")
             y += YS
-        x = (w - (rows*XS - XM))/2
+        x = (w - (rows*XS - XM))//2
         for i in range(rows):
             self.s.rows.append(S(x, y))
             x += XS
@@ -539,12 +539,12 @@ class Layout:
                 self.s.foundations.append(S(x, y, suit=suit))
                 x += XS
         if reserves:
-            yy = YM + YS - CH/2
+            yy = YM + YS - CH//2
             if reserve_texts:
                 yy += self.TEXT_HEIGHT
         else:
             yy = -999
-        self.setRegion(self.s.rows, (-999, yy, 999999, y - YS / 2))
+        self.setRegion(self.s.rows, (-999, yy, 999999, y - YS // 2))
         if waste:
             x = w - 2*XS
             self.s.waste = s = S(x, y)
@@ -567,7 +567,7 @@ class Layout:
     #  - bottom: reserves
     #
 
-    def klondikeLayout(self, rows, waste, reserves=0,
+    def klondikeLayout(self, rows=0, waste=0, reserves=0,
                        texts=1, reserve_texts=False, round_text=False,
                        playcards=16, center=1, text_height=0):
         S = self.__createStack
@@ -578,15 +578,15 @@ class Layout:
         decks = self.game.gameinfo.decks
         suits = len(self.game.gameinfo.suits) + bool(self.game.gameinfo.trumps)
         foundrows = 1 + (suits > 5)
-        frows = decks * suits / foundrows
+        frows = decks * suits // foundrows
         toprows = 1 + waste + frows
         if round_text:
             toprows += 1
         maxrows = max(rows, toprows, reserves)
 
         w = XM + maxrows * XS
-        # set size so that at least 2/3 of a card is visible with 16 cards
-        h = CH * 2 / 3 + (playcards - 1) * self.YOFFSET
+        # set size so that at least 2//3 of a card is visible with 16 cards
+        h = CH * 2 // 3 + (playcards - 1) * self.YOFFSET
         h = max(h, 2 * YS)
         h += YM + YS * foundrows
         if reserves and reserve_texts:
@@ -616,32 +616,32 @@ class Layout:
             x = w - frows * XS
             if center and frows + 2 * (1 + waste + 1) <= maxrows:
                 # center the foundations
-                x = XM + (maxrows - frows) * XS / 2
-            for suit in range(suits / foundrows):
+                x = XM + (maxrows - frows) * XS // 2
+            for suit in range(suits // foundrows):
                 for i in range(decks):
                     self.s.foundations.append(
-                        S(x, y, suit=suit + (row * (suits / 2))))
+                        S(x, y, suit=suit + (row * (suits // 2))))
                     x += XS
             y += YS
 
         # below
         x = XM
         if rows < maxrows:
-            x += (maxrows-rows) * XS/2
+            x += (maxrows-rows) * XS//2
         # y += YM * (3 - foundrows)
         y += text_height
         for i in range(rows):
             self.s.rows.append(S(x, y))
             x += XS
         if reserves:
-            yy = h - CH/2
+            yy = h - CH//2
         else:
             yy = 999999
-        self.setRegion(self.s.rows, (-999, y-CH/2, 999999, yy))
+        self.setRegion(self.s.rows, (-999, y-CH//2, 999999, yy))
 
         # bottom
         if reserves:
-            x = (maxrows-reserves)*XS/2
+            x = (maxrows-reserves)*XS//2
             y = h
             h += YS
             for i in range(reserves):
@@ -670,8 +670,8 @@ class Layout:
         decks = self.game.gameinfo.decks
         suits = len(self.game.gameinfo.suits) + bool(self.game.gameinfo.trumps)
 
-        # set size so that at least 2/3 of a card is visible with 20 cards
-        h = CH*2/3 + (playcards-1)*self.YOFFSET
+        # set size so that at least 2//3 of a card is visible with 20 cards
+        h = CH*2//3 + (playcards-1)*self.YOFFSET
         h = YM + max(h, suits*YS)
 
         # create rows
@@ -679,7 +679,7 @@ class Layout:
         for i in range(rows):
             self.s.rows.append(S(x, y))
             x += XS
-        self.setRegion(self.s.rows, (-999, -999, x - CW / 2, 999999))
+        self.setRegion(self.s.rows, (-999, -999, x - CW // 2, 999999))
 
         # create foundations
         for suit in range(suits):
@@ -711,13 +711,13 @@ class Layout:
 
         decks = self.game.gameinfo.decks
         ranks = len(self.game.gameinfo.ranks)
-        frows = 4 * decks / (1 + (decks >= 3))
+        frows = 4 * decks // (1 + (decks >= 3))
         toprows = 1 + waste + frows
         maxrows = max(rows, toprows)
         yextra = 0
 
-        # set size so that at least 2/3 of a card is visible with 10 cards
-        h = CH * 2 / 3 + (playcards - 1) * self.YOFFSET
+        # set size so that at least 2//3 of a card is visible with 10 cards
+        h = CH * 2 // 3 + (playcards - 1) * self.YOFFSET
         h = max(h, 2 * YS)
 
         # top
@@ -740,7 +740,7 @@ class Layout:
         x = XM + (maxrows - frows) * XS
         if center and frows + 2 * (1 + waste + 1) <= maxrows:
             # center the foundations
-            x = XM + (maxrows - frows) * XS / 2
+            x = XM + (maxrows - frows) * XS // 2
 
         x0, y0 = x, y
         for i in range(decks):
@@ -753,7 +753,7 @@ class Layout:
 
         # bottom
         x, y = XM, y + YS + yextra * (decks <= 2)
-        self.setRegion(self.s.rows, (-999, y - YM / 2, 999999, 999999))
+        self.setRegion(self.s.rows, (-999, y - YM // 2, 999999, 999999))
         for i in range(rows):
             self.s.rows.append(S(x, y))
             x += XS
@@ -778,12 +778,12 @@ class Layout:
         toprows = 2 * decks + rows
         yextra = 0
 
-        # set size so that at least 2/3 of a card is visible with 20 cards
-        h = CH * 2 / 3 + (playcards - 1) * self.YOFFSET
+        # set size so that at least 2//3 of a card is visible with 20 cards
+        h = CH * 2 // 3 + (playcards - 1) * self.YOFFSET
         h = max(h, 2 * YS)
 
         # bottom center
-        x = (XM + (toprows * XS) / 2) - XS
+        x = (XM + (toprows * XS) // 2) - XS
         y = h
         self.s.talon = s = S(x, y)
         if texts:
@@ -815,7 +815,7 @@ class Layout:
 
         # top center
         x, y = XM + XS * decks, YM
-        self.setRegion(self.s.rows, (x - XM / 2, 0, x + XS * rows, 999999))
+        self.setRegion(self.s.rows, (x - XM // 2, 0, x + XS * rows, 999999))
         for i in range(rows):
             self.s.rows.append(S(x, y))
             x += XS
@@ -842,8 +842,8 @@ class Layout:
         maxrows = max(rows, toprows)
         w = XM + maxrows * XS
 
-        # set size so that at least 2/3 of a card is visible with 12 cards
-        h = CH * 2 / 3 + (playcards - 1) * self.YOFFSET
+        # set size so that at least 2//3 of a card is visible with 12 cards
+        h = CH * 2 // 3 + (playcards - 1) * self.YOFFSET
         h = max(h, 2 * YS)
 
         # create foundations
@@ -855,21 +855,21 @@ class Layout:
             x, y = XM, y + YS
 
         # create rows
-        x, y = XM + XS * ((toprows - rows) / 2), YM + YS * decks
+        x, y = XM + XS * ((toprows - rows) // 2), YM + YS * decks
         for i in range(rows):
             self.s.rows.append(S(x, y))
             x += XS
         self.setRegion(
             self.s.rows,
-            (XS + XM / 2, YS * decks + YM / 2, XS * 11 - XM / 2, 999999))
+            (XS + XM // 2, YS * decks + YM // 2, XS * 11 - XM // 2, 999999))
 
         # create reserves
         x, y = XM, YM + YS * decks
-        for i in range(reserves / 2):
+        for i in range(reserves // 2):
             self.s.reserves.append(S(x, y))
             y += YS
         x, y = w - XS, YM + YS * decks
-        for i in range(reserves / 2):
+        for i in range(reserves // 2):
             self.s.reserves.append(S(x, y))
             y += YS
 
@@ -900,12 +900,12 @@ class Layout:
         ranks = len(self.game.gameinfo.ranks)
         assert rows % 2 == 0
         assert reserves % decks == 0
-        toprows = decks + rows / 2
+        toprows = decks + rows // 2
         w = XM * 2 + toprows * XS
 
-        # set size so that at least 2/3 of a card is visible with 12 cards
-        h1 = CH * 2 / 3 + (playcards - 1) * self.YOFFSET
-        h2 = (3 + reserves / decks) * YS
+        # set size so that at least 2//3 of a card is visible with 12 cards
+        h1 = CH * 2 // 3 + (playcards - 1) * self.YOFFSET
+        h2 = (3 + reserves // decks) * YS
         h = max(h1, h2)
 
         # create foundations
@@ -918,19 +918,19 @@ class Layout:
 
         # create rows
         x, y = XM, YM
-        for i in range(rows / 2):
+        for i in range(rows // 2):
             self.s.rows.append(S(x, y))
             x += XS
-        x, y = XM, (YS + h) / 2
-        for i in range(rows / 2):
+        x, y = XM, (YS + h) // 2
+        for i in range(rows // 2):
             self.s.rows.append(S(x, y))
             x += XS
-        self.setRegion(self.s.rows, (0, 0, XS * rows / 2 + XM / 2, 999999))
+        self.setRegion(self.s.rows, (0, 0, XS * rows // 2 + XM // 2, 999999))
 
         # create reserves
         x, y = w - XS * decks, YM + YS * 4
         for i in range(decks):
-            for i in range(reserves / decks):
+            for i in range(reserves // decks):
                 self.s.reserves.append(S(x, y))
                 y += YS
             x, y = x + XS, YM + YS * 4
@@ -960,11 +960,11 @@ class Layout:
 
         decks = self.game.gameinfo.decks
         assert rows % 2 == 0
-        toprows = decks + rows / 2
+        toprows = decks + rows // 2
         w = XM * 2 + toprows * (XS + XM)
 
-        # set size so that at least 2/3 of a card is visible with 12 cards
-        h = CH * 2 / 3 + (playcards - 1) * self.YOFFSET
+        # set size so that at least 2//3 of a card is visible with 12 cards
+        h = CH * 2 // 3 + (playcards - 1) * self.YOFFSET
         h = max(h, 2 * YS)
 
         # create talon
@@ -976,11 +976,11 @@ class Layout:
 
         # create rows
         x, y = XS + XM * 3, YM
-        for i in range(rows / 2):
+        for i in range(rows // 2):
             self.s.rows.append(S(x, y))
             x += XS + XM
-        x, y = XS + XM * 3, (YS + h) / 2
-        for i in range(rows / 2):
+        x, y = XS + XM * 3, (YS + h) // 2
+        for i in range(rows // 2):
             self.s.rows.append(S(x, y))
             x += XS + XM
         self.setRegion(self.s.rows, (XS + XM, -999, 999999, 999999))
@@ -988,7 +988,7 @@ class Layout:
         # create reserves
         x, y = XM, YM + YS + self.TEXT_HEIGHT
         for i in range(decks):
-            for i in range(reserves / decks):
+            for i in range(reserves // decks):
                 self.s.reserves.append(S(x, y))
                 y += YS
             x, y = x + XS, YM + YS * 4
@@ -1013,28 +1013,28 @@ class Layout:
         assert reserves % 2 == 0
 
         # set size
-        w, h = XM * 3 + XS * ((rows / 2) + 2), YM + YS * ((suits / 2) + 2)
+        w, h = XM * 3 + XS * ((rows // 2) + 2), YM + YS * ((suits // 2) + 2)
 
         # create foundations
         x, y = XM, YM
         for i in range(suits):
             self.s.foundations.append(S(x, y, suit=i))
             y += YS
-            if i == suits / 2 - 1:
+            if i == suits // 2 - 1:
                 x, y = w - XS, YM
 
         # create rows
         x = XM * 2 + XS
-        for i in range(rows / 2):
+        for i in range(rows // 2):
             self.s.rows.append(S(x + i * XS, YM))
-        for i in range(rows / 2):
-            self.s.rows.append(S(x + i * XS, h / 2))
+        for i in range(rows // 2):
+            self.s.rows.append(S(x + i * XS, h // 2))
         self.setRegion(self.s.rows, (XM + XS, -999, w - XM - XS, 999999))
 
         # create reserves
-        for i in range(reserves / 2):
+        for i in range(reserves // 2):
             self.s.reserves.append(S(XM, h - YS * (i + 1)))
-        for i in range(reserves / 2):
+        for i in range(reserves // 2):
             self.s.reserves.append(S(w - XS, h - YS * (i + 1)))
 
         # create talon
@@ -1058,8 +1058,8 @@ class Layout:
 
         decks = self.game.gameinfo.decks
         suits = len(self.game.gameinfo.suits) + bool(self.game.gameinfo.trumps)
-        frows = suits * decks / 2
-        fspace = XS * (rows - 1) / 2
+        frows = suits * decks // 2
+        fspace = XS * (rows - 1) // 2
 
         # Set window size
         w, h = XM + XS * rows, YM * 2 + YS * height
@@ -1073,16 +1073,16 @@ class Layout:
         self._setText(s, 'se')
 
         # Create foundations
-        x = w - fspace - XS * frows / 2
-        for suit in range(suits / 2):
+        x = w - fspace - XS * frows // 2
+        for suit in range(suits // 2):
             for i in range(decks):
                 self.s.foundations.append(S(x, y, suit=suit))
                 x += XS
-        x = w - fspace - XS * frows / 2
+        x = w - fspace - XS * frows // 2
         y += YS
-        for suit in range(suits / 2):
+        for suit in range(suits // 2):
             for i in range(decks):
-                self.s.foundations.append(S(x, y, suit=(suit + suits / 20)))
+                self.s.foundations.append(S(x, y, suit=(suit + suits // 20)))
                 x += XS
 
         # bottom
diff --git a/pysollib/mfxutil.py b/pysollib/mfxutil.py
index 35ab1229..d57bad5c 100644
--- a/pysollib/mfxutil.py
+++ b/pysollib/mfxutil.py
@@ -37,7 +37,6 @@ __all__ = [
 import sys
 import os
 import time
-import types
 import locale
 import webbrowser
 from six import print_
@@ -87,6 +86,8 @@ class SubclassResponsibility(Exception):
 
 
 def latin1_to_ascii(n):
+    if sys.version_info > (3,):
+        return n
     # return n
     n = n.encode('iso8859-1', 'replace')
     # FIXME: rewrite this for better speed
@@ -183,7 +184,6 @@ def win32_getprefdir(package):
 def destruct(obj):
     # assist in breaking circular references
     if obj is not None:
-        assert isinstance(obj, types.InstanceType)
         for k in obj.__dict__.keys():
             obj.__dict__[k] = None
             # del obj.__dict__[k]
diff --git a/pysollib/options.py b/pysollib/options.py
index 30fe01e9..2b78b950 100644
--- a/pysollib/options.py
+++ b/pysollib/options.py
@@ -487,7 +487,8 @@ class Options:
         for key, t in self.GENERAL_OPTIONS:
             val = getattr(self, key)
             if isinstance(val, str):
-                val = unicode(val, 'utf-8')
+                if sys.version_info < (3,):
+                    val = unicode(val, 'utf-8')
             config['general'][key] = val
 
         config['general']['recent_gameid'] = self.recent_gameid
@@ -563,10 +564,12 @@ class Options:
 
         # create ConfigObj instance
         try:
+            print(filename)
             config = configobj.ConfigObj(filename,
                                          configspec=configspec,
                                          encoding=self._config_encoding)
         except configobj.ParseError:
+            raise BaseException('foo')
             traceback.print_exc()
             config = configobj.ConfigObj(configspec=configspec,
                                          encoding=self._config_encoding)
diff --git a/pysollib/pysolrandom.py b/pysollib/pysolrandom.py
index 75303c7b..16b14cf3 100644
--- a/pysollib/pysolrandom.py
+++ b/pysollib/pysolrandom.py
@@ -116,19 +116,19 @@ class MTRandom(BasicRandom, random.Random):
 # * uses the standard python module `random'
 # ************************************************************************
 
-class WHRandom(BasicRandom, random.WichmannHill):
-
-    def __init__(self, seed=None):
-        if seed is None:
-            seed = self._getRandomSeed()
-        BasicRandom.__init__(self)
-        random.WichmannHill.__init__(self, seed)
-        self.initial_seed = seed
-        self.initial_state = self.getstate()
-        self.origin = self.ORIGIN_UNKNOWN
-
-    def reset(self):
-        self.setstate(self.initial_state)
+# class WHRandom(BasicRandom, random.WichmannHill):
+#
+#     def __init__(self, seed=None):
+#         if seed is None:
+#             seed = self._getRandomSeed()
+#         BasicRandom.__init__(self)
+#         random.WichmannHill.__init__(self, seed)
+#         self.initial_seed = seed
+#         self.initial_state = self.getstate()
+#         self.origin = self.ORIGIN_UNKNOWN
+#
+#     def reset(self):
+#         self.setstate(self.initial_state)
 
 # ************************************************************************
 # * Abstract class for LC Random number generators.
diff --git a/pysollib/settings.py b/pysollib/settings.py
index 43ee9bdd..31749e0c 100644
--- a/pysollib/settings.py
+++ b/pysollib/settings.py
@@ -79,5 +79,5 @@ SELECT_GAME_MENU = True
 TRANSLATE_GAME_NAMES = True
 
 # debug
-DEBUG = 0                               # must be integer
+DEBUG = 121                               # must be integer
 CHECK_GAMES = False                     # check duplicated names and classes
diff --git a/pysollib/ui/tktile/tkhtml.py b/pysollib/ui/tktile/tkhtml.py
index b1bcb7c1..9a0e5188 100644
--- a/pysollib/ui/tktile/tkhtml.py
+++ b/pysollib/ui/tktile/tkhtml.py
@@ -22,7 +22,7 @@
 # ---------------------------------------------------------------------------
 
 import os
-import htmllib
+# import htmllib
 import formatter
 from six.moves import tkinter
 
@@ -182,7 +182,8 @@ class tkHTMLWriter(formatter.NullWriter):
 # *
 # ************************************************************************
 
-class tkHTMLParser(htmllib.HTMLParser):
+# class tkHTMLParser(htmllib.HTMLParser):
+class tkHTMLParser:
     def anchor_bgn(self, href, name, type):
         self.formatter.flush_softspace()
         htmllib.HTMLParser.anchor_bgn(self, href, name, type)