#!/usr/bin/env python
"""
The Towers of Hanoi for wxPython
by S. Foster, Jan. 2004
based on wxHanoi.cpp
by Martin Bernreuther
"""
from wxPython.wx import *
import cPickle
import zlib
COLOURS = [ 'RED', 'CORAL', 'YELLOW', 'GREEN', 'BLUE', 'MAGENTA', 'PURPLE' ]
ICON = """\
\x78\x9c\x9d\x91\xbd\x0a\xc2\x30\x00\x84\xf7\x3c\x45\xc0\x21\x42\
\x21\xe4\xa7\xad\xba\x3a\x74\xb4\x43\x97\xac\xa1\x88\x83\xc5\xf4\
\xfd\x27\xef\x4c\x83\x20\x18\xc1\xa3\x3d\x9a\x8f\xef\xb2\x74\xbf\
\xac\x56\x4c\xca\x3b\x89\xa7\x97\x56\x89\xd5\x89\x38\x29\x2d\x67\
\x79\x5e\xe2\x7c\x07\xf0\x04\x0d\xc0\x6e\x18\x0c\x02\xd4\x12\x8d\
\x44\xc6\x10\x02\x75\x44\x21\x5b\x1b\xea\x89\x52\xb6\xe8\x01\x1d\
\x88\x24\xd0\x25\x3d\xae\x38\x1f\xf3\xb9\x1e\x78\x27\x11\x6f\x7f\
\xbe\xdb\xfd\xfa\x7d\x9f\xfe\xf8\xc2\xfd\xd6\x40\x66\x65\x3b\x84\
\x50\xb5\x2d\xed\x52\xaf\x49\x62\x6a\x13\x47\xbb\x14\x27\x63\x4e\
\x65\xe2\x69\x97\xc2\xa4\x29\xf9\x3e\x69\x69\x97\xc2\x6f\xfc\x11\
\x4e\x3a\xda\xa5\xf4\x13\x8d\x92\x69\x2c"""
def getIconData():
return cPickle.loads( zlib.decompress( ICON ))
class wxHanoiDisc:
def __init__( self, n, width, height ):
self.width = ( n + 1 ) * width
self.height = height
self.n = n
self.brush = wxBrush( wxNamedColour( COLOURS[ n % len( COLOURS )] ))
class wxHanoiFrame( wxFrame ):
def __init__( self, title, pos, size ):
wxFrame.__init__( self, None, -1,
title, pos = pos, size = size )
icon = wxIconFromXPMData( getIconData() )
self.SetIcon( icon )
self.CreateMenu()
self.CreateStatusBar();
self.sleepTime = 3
self.numDiscs = 4
self.pen = wxPen( wxNamedColour( 'BLACK' ), 1, wxSOLID )
self.Initialize()
EVT_CLOSE( self, self.OnCloseWindow )
EVT_PAINT( self, self.OnPaint )
def CreateMenu( self ):
def MenuCallback( menu, item, callback ):
id = wxNewId()
menu.Append( id, item )
EVT_MENU( self, id, callback )
menuBar = wxMenuBar()
menuFile = wxMenu()
MenuCallback( menuFile, 'E&xit...\tCtrl-X', self.OnQuit )
menuBar.Append( menuFile, '&File' )
menuPlay = wxMenu()
MenuCallback( menuPlay, '&Number of Discs...', self.OnInpNumDiscs )
MenuCallback( menuPlay, '&Time between Moves...', self.OnInpSleepTime )
menuPlay.AppendSeparator()
MenuCallback( menuPlay, '&Play', self.OnPlay )
MenuCallback( menuPlay, '&Reset', self.OnReset )
menuBar.Append( menuPlay, '&Play' )
menuHelp = wxMenu()
MenuCallback( menuHelp, '&About...', self.OnAbout )
menuBar.Append( menuHelp, '&Help' )
self.SetMenuBar( menuBar )
def Initialize( self ):
self.width, self.height = self.GetClientSize()
maxwidth = self.width / 3
w = self.width / 6
self.xpos = [ i * w for i in [ 1, 3, 5 ]]
height = self.height / self.numDiscs
width = maxwidth / self.numDiscs
if height > width:
height = width
self.discheight = height
self.discwidthfac = width
discs = range( self.numDiscs )
discs.reverse()
self.pegs = [[ wxHanoiDisc( i, width, height ) for i in discs ], [], []]
self.moves = 0
width, height = self.GetClientSize()
self.Draw( wxClientDC( self ), width, height )
def OnQuit( self, _event ):
self.Close( true );
def OnCloseWindow( self, event ):
self.Destroy()
def OnAbout( self, event ):
wxMessageBox( __doc__, 'About wxHanoi', wxOK|wxICON_INFORMATION, self )
def OnInpNumDiscs( self, _event ):
self.numDiscs = wxGetNumberFromUser( '', 'Discs:', 'Number of Discs',
self.numDiscs, 1, 25, self )
if self.numDiscs == -1:
self.SetStatusText( "Invalid number entered or dialog cancelled." )
else:
self.Initialize()
def OnInpSleepTime( self, _event ):
self.sleepTime = wxGetNumberFromUser( '', 'Wait [sec/10]:', 'Time between Moves',
self.sleepTime, 0, 10, self )
if self.sleepTime == -1:
self.SetStatusText( "Invalid number entered or dialog cancelled." )
else:
self.Initialize()
def OnPlay( self, _event ):
self.Initialize()
self.SetStatusText( 'Playing' )
self.Move( 0, 2, 1, self.numDiscs )
self.SetStatusText( 'Finished: %s Moves' % self.moves )
def OnReset( self, event ):
self.Initialize()
def DrawDisc( self, dc, disc, x, y ):
assert x <= 2
dc.SetPen( self.pen )
dc.SetBrush( disc.brush )
dc.DrawRectangle(
self.xpos[x] - ( disc.width / 2 ),
self.height - ( y * self.discheight ),
disc.width,
disc.height )
def Draw( self, dc, width, height ):
mdc = wxMemoryDC()
mdc.SelectObject( wxEmptyBitmap( width, height ))
mdc.BeginDrawing()
for x, peg in enumerate( self.pegs ):
for y, disc in enumerate( peg ):
self.DrawDisc( mdc, disc, x, y+1 )
mdc.EndDrawing()
dc.Blit( 0, 0, width, height, mdc, 0, 0 )
def OnPaint( self, event ):
width, height = self.GetClientSize()
self.Draw( wxPaintDC( self ), width, height )
def MoveDisc( self, src, dst ):
disc = self.pegs[src].pop()
self.pegs[dst].append( disc )
self.moves += 1
self.SetStatusText( 'Move %s' % self.moves )
width, height = self.GetClientSize()
self.Draw( wxClientDC( self ), width, height )
wxUsleep( 100 * self.sleepTime )
def Move( self, src, dst, temp, n ):
if n == 1:
self.MoveDisc( src, dst )
else:
self.Move( src, temp, dst, n-1 )
self.MoveDisc( src, dst )
self.Move( temp, dst, src, n-1 )
class wxHanoiApp( wxApp ):
def OnInit( self ):
self.frame = wxHanoiFrame(
'Towers of Hanoi for wxPython',
wxPoint( 50, 50 ),
wxSize( 450, 350 ))
self.frame.Show( True )
self.SetTopWindow( self.frame )
return True
app = wxHanoiApp(0)
app.MainLoop()