Welcome, guest | Sign In | My Account | Store | Cart

It's a simple solver of the problem of Hanoi Tower with a minimal GUI written in wxPython. It can handle just 10 plates, due to windows size..however it's very simple to modify this and the 'pure' solver is not affected by this limitation

Python, 121 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#author: A. Polino
import wx
import sys


## make sure the windows is focused than press any button, and the program will move a plate. keep  ## pressing until the problem is solved
## by default it will display 5 plates. To change this, you have to call the script with a second   ## argument, wich is the number of plates (max 10)

def gen_hanoi(stack, start=1, temp=2, goal=3):
    if stack == 2:
        yield start, temp
        yield start, goal
        yield temp, goal
    else:
        for x in gen_hanoi(stack - 1, start, goal, temp):
            yield x
        yield start, goal
        for x in gen_hanoi(stack - 1, temp, start, goal):
            yield x


class Plate(object):
    def __init__(self, x_len, x_start):
        self.x_len = x_len
        self.x_start = x_start


def create_plates(num):
    assert num <= 10
    x_start = 10
    x_len = 100
    plates = []
    for x in xrange(num):
        plates.append(Plate(x_len, x_start))
        x_len -= 10
        x_start += 5
    return plates


class HanoiWindow(wx.Window):
    def __init__(self, parent, num):
        wx.Window.__init__(self, parent, id=-1, pos = wx.Point(0, 0),
                           size=wx.DefaultSize, style=wx.SUNKEN_BORDER|
                           wx.WANTS_CHARS|wx.FULL_REPAINT_ON_RESIZE)
        self.SetBackgroundColour(wx.NamedColour('white'))
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
        self.towers = [create_plates(num), [], []]
        self.solver = gen_hanoi(num)

    def OnPaint(self, evt):
        def draw_rect(x_len, x_start, y_start):
            dc = wx.PaintDC(self)
            font = dc.GetFont()
            font.SetPointSize(15)
            dc.SetFont(font)
            size, colour = 2, wx.NamedColour('black')
            dc.SetPen(wx.Pen(colour, size, wx.SOLID))
            point = wx.Point(x_start, y_start)
            dc.DrawLines([point, point + wx.Point(x_len, 0)])
            dc.DrawLines([point - wx.Point(0, 5), point + wx.Point(x_len, 0) - wx.Point(0, 5)])
            dc.DrawLines([point, point - wx.Point(0, 5)])
            dc.DrawLines([point + wx.Point(x_len, 0), point - wx.Point(0, 5) + wx.Point(x_len, 0)])

        w, h = self.GetClientSizeTuple()
        buffer = wx.EmptyBitmap(w, h)
        dc = wx.PaintDC(self)
        font = dc.GetFont()
        font.SetPointSize(15)
        dc.SetFont(font)
        msg = 'Hanoi Towers'
        w, h = dc.GetTextExtent(msg)
        dc.DrawText(msg, 200, 20)
        size, colour = 8, wx.NamedColour('black')
        dc.SetPen(wx.Pen(colour, size, wx.SOLID))
        for num in xrange(len(self.towers)):
            y_start = 300
            tower = self.towers[num]
            num = num * 200 + 10
            point = wx.Point(num, y_start)
            dc.DrawLines([point, point + wx.Point(120, 0)]) #base
            ## plates
            for plate in tower:
                y_start -= 10
                draw_rect(plate.x_len, num + plate.x_start, y_start)

    def OnKeyUp(self, evt):
        try:
            from_, to = self.solver.next()
            self.towers[to-1].append(self.towers[from_-1].pop())
            self.Refresh()
        except StopIteration:
            wx.MessageBox('Problem Solved!', 'Problem solved', wx.OK)
                

class HanoiFrame(wx.Frame):
    def __init__(self, title, num):
        wx.Frame.__init__(self, parent=None, id=-1,
                          title=title, size=(600, 500), pos=(200, 200))
        self.Window = HanoiWindow(self, num)
        self.Bind(wx.EVT_CLOSE, self.close_frame)

    def close_frame(self, evt):
        sys.exit(0)


class HanoiApp(wx.App):
    def OnInit(self):
        if len(sys.argv) < 2:
            num = 5
        else:
            num = int(sys.argv[1])
        hano = HanoiFrame('Hanoi Towers', num)
        hano.Show(True)
        self.SetTopWindow(hano)
        return True


if __name__ == '__main__':
    fh = HanoiApp(0)
    fh.MainLoop()
Created by A. Polino on Tue, 21 Dec 2010 (MIT)
Python recipes (4591)
A. Polino's recipes (2)

Required Modules

Other Information and Tasks