]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/tests/hangman.py
   1 """Hangman.py, a simple wxPython game, inspired by the  
   2 old bsd game by Ken Arnold. 
   3 From the original man page: 
   5  In hangman, the computer picks a word from the on-line  
   6  word list and you must try to guess it.  The computer  
   7  keeps track of which letters have been guessed and how  
   8  many wrong guesses you have made on the screen in a 
  11 That says it all, doesn't it? 
  15 Harm van der Heijden (H.v.d.Heijden@phys.tue.nl)""" 
  17 import random
,re
,string
 
  18 from wxPython
.wx 
import * 
  21     def __init__(self
, filename
, min_length 
= 5): 
  22         self
.min_length 
= min_length
 
  23         print "Trying to open file %s" % (filename
,) 
  25             f 
= open(filename
, "r") 
  27             print "Couldn't open dictionary file %s, using build-ins" % (filename
,) 
  28             self
.words 
= self
.builtin_words
 
  32         self
.filename 
= filename
 
  33         print "Got %d bytes." % (len(self
.words
),) 
  34     def SetMinLength(min_length
): 
  35         self
.min_length 
= min_length
 
  37         reg 
= re
.compile('\s+([a-zA-Z]+)\s+') 
  38         n 
= 50 # safety valve; maximum number of tries to find a suitable word 
  40             index 
= int(random
.random()*len(self
.words
)) 
  41             m 
= reg
.search(self
.words
[index
:]) 
  42             if m 
and len(m
.groups()[0]) >= self
.min_length
: break 
  44         if n
: return string
.lower(m
.groups()[0]) 
  46     builtin_words 
= ' albatros  banana  electrometer  eggshell' 
  51 class URLWordFetcher(WordFetcher
): 
  52     def __init__(self
, url
): 
  54         WordFetcher
.__init
__(self
, "hangman_dict.txt") 
  57     def RetrieveAsFile(self
, host
, path
=''): 
  58         from httplib 
import HTTP
 
  62             self
.logprint("Failed to create HTTP connection to %s... is the network available?" % (host
)) 
  64         h
.putrequest('GET',path
) 
  65         h
.putheader('Accept','text/html') 
  66         h
.putheader('Accept','text/plain') 
  68         errcode
, errmsg
, headers 
= h
.getreply() 
  70             self
.logprint("HTTP error code %d: %s" % (errcode
, errmsg
)) 
  74     def OpenURL(self
,url
): 
  75         from htmllib 
import HTMLParser
 
  78         m 
= re
.match('http://([^/]+)(/\S*)\s*', url
) 
  83             m 
= re
.match('http://(\S+)\s*', url
) 
  86                 self
.logprint("Invalid or unsupported URL: %s" % (url
)) 
  90         f 
= self
.RetrieveAsFile(host
,path
) 
  92             self
.logprint("Could not open %s" % (url
)) 
  94         self
.logprint("Receiving data...") 
  96         tmp 
= open('hangman_dict.txt','w') 
  97         fmt 
= formatter
.AbstractFormatter(formatter
.DumbWriter(tmp
)) 
  99         self
.logprint("Parsing data...") 
 104 class HangmanWnd(wxWindow
): 
 105     def __init__(self
, parent
, id, pos
=wxDefaultPosition
, size
=wxDefaultSize
): 
 106         wxWindow
.__init
__(self
, parent
, id, pos
, size
) 
 107         self
.SetBackgroundColour(wxNamedColour('white')) 
 108         if wxPlatform 
== '__WXGTK__': 
 109             self
.font 
= wxFont(12, wxMODERN
, wxNORMAL
, wxNORMAL
) 
 111             self
.font 
= wxFont(10, wxMODERN
, wxNORMAL
, wxNORMAL
) 
 113     def StartGame(self
, word
): 
 121         self
.guess 
= map(chr, range(ord('a'),ord('z')+1)) 
 123     def HandleKey(self
, key
): 
 125         if self
.guess
.count(key
): 
 126             self
.message 
= 'Already guessed %s' % (key
,) 
 128         self
.guess
.append(key
) 
 130         self
.tries 
= self
.tries
+1 
 131         if not key 
in self
.word
: 
 132             self
.misses 
= self
.misses
+1 
 137         for letter 
in self
.word
: 
 138             if not self
.guess
.count(letter
): 
 146     def Draw(self
, dc 
= None): 
 148             dc 
= wxClientDC(self
) 
 149         dc
.SetFont(self
.font
) 
 151         (x
,y
) = self
.GetSizeTuple() 
 153         for letter 
in self
.word
: 
 154             if self
.guess
.count(letter
): 
 155                 dc
.DrawText(letter
, x1
, y1
) 
 157                 dc
.DrawText('.', x1
, y1
) 
 160         dc
.DrawText("tries %d misses %d" % (self
.tries
,self
.misses
),x1
,50) 
 162         for letter 
in self
.guess
:  
 163             guesses 
= guesses 
+ letter
 
 164         dc
.DrawText("guessed:", x1
, 70) 
 165         dc
.DrawText(guesses
[:13], x1
+80, 70) 
 166         dc
.DrawText(guesses
[13:], x1
+80, 90) 
 167         dc
.SetUserScale(x
/1000., y
/1000.) 
 169     def DrawVictim(self
, dc
): 
 170         dc
.SetPen(wxPen(wxNamedColour('black'), 20)) 
 171         dc
.DrawLines([(10, 980), (10,900), (700,900), (700,940), (720,940), 
 172                       (720,980), (900,980)]) 
 173         dc
.DrawLines([(100,900), (100, 100), (300,100)]) 
 174         dc
.DrawLine(100,200,200,100) 
 175         if ( self
.misses 
== 0 ): return 
 176         dc
.SetPen(wxPen(wxNamedColour('blue'), 10)) 
 177         dc
.DrawLine(300,100,300,200) 
 178         if ( self
.misses 
== 1 ): return 
 179         dc
.DrawEllipse(250,200,100,100) 
 180         if ( self
.misses 
== 2 ): return 
 181         dc
.DrawLine(300,300,300,600) 
 182         if ( self
.misses 
== 3) : return 
 183         dc
.DrawLine(300,300,250,550) 
 184         if ( self
.misses 
== 4) : return 
 185         dc
.DrawLine(300,300,350,550) 
 186         if ( self
.misses 
== 5) : return 
 187         dc
.DrawLine(300,600,350,850) 
 188         if ( self
.misses 
== 6) : return 
 189         dc
.DrawLine(300,600,250,850) 
 190     def OnPaint(self
, event
): 
 194 class HangmanDemo(HangmanWnd
): 
 195     def __init__(self
, wf
, parent
, id, pos
, size
): 
 196         HangmanWnd
.__init
__(self
, parent
, id, pos
, size
) 
 197         self
.StartGame("dummy") 
 201         self
.timer 
= self
.PlayTimer(self
.MakeMove
) 
 205             self
.StartGame(self
.wf
.Get()) 
 207             self
.left 
= list('aaaabcdeeeeefghiiiiijklmnnnoooopqrssssttttuuuuvwxyz') 
 209             key 
= self
.left
[int(random
.random()*len(self
.left
))] 
 210             while self
.left
.count(key
): self
.left
.remove(key
) 
 211             self
.start_new 
= self
.HandleKey(key
) 
 212         self
.timer
.Start(self
.delay
) 
 215     class PlayTimer(wxTimer
): 
 216         def __init__(self
,func
): 
 217             wxTimer
.__init
__(self
) 
 223 class HangmanDemoFrame(wxFrame
): 
 224     def __init__(self
, wf
, parent
, id, pos
, size
): 
 225         wxFrame
.__init
__(self
, parent
, id, "Hangman demo", pos
, size
) 
 226         self
.demo 
= HangmanDemo(wf
, self
, -1, wxDefaultPosition
, wxDefaultSize
) 
 227     def OnCloseWindow(self
, event
): 
 228         self
.demo
.timer
.Stop() 
 231 class AboutBox(wxDialog
): 
 232     def __init__(self
, parent
,wf
): 
 233         wxDialog
.__init
__(self
, parent
, -1, "About Hangman", wxDefaultPosition
, wxSize(350,450)) 
 234         self
.wnd 
= HangmanDemo(wf
, self
, -1, wxPoint(1,1), wxSize(350,150)) 
 235         self
.static 
= wxStaticText(self
, -1, __doc__
, wxPoint(1,160), wxSize(350, 250)) 
 236         self
.button 
= wxButton(self
, 2001, "OK", wxPoint(150,420), wxSize(50,-1)) 
 237         EVT_BUTTON(self
, 2001, self
.OnOK
) 
 238     def OnOK(self
, event
): 
 240         self
.EndModal(wxID_OK
) 
 242 class MyFrame(wxFrame
): 
 243     def __init__(self
, wf
): 
 245         wxFrame
.__init
__(self
, NULL
, -1, "hangman", wxDefaultPosition
, wxSize(400,300)) 
 246         self
.wnd 
= HangmanWnd(self
, -1) 
 248         menu
.Append(1001, "New") 
 249         menu
.Append(1002, "End") 
 250         menu
.AppendSeparator() 
 251         menu
.Append(1003, "Reset") 
 252         menu
.Append(1004, "Demo...") 
 253         menu
.AppendSeparator() 
 254         menu
.Append(1005, "Exit") 
 255         menubar 
= wxMenuBar() 
 256         menubar
.Append(menu
, "Game") 
 258         #menu.Append(1010, "Internal", "Use internal dictionary", TRUE) 
 259         menu
.Append(1011, "ASCII File...") 
 260         urls 
= [ 'wxPython home', 'http://208.240.253.245/wxPython/main.html', 
 261                  'slashdot.org', 'http://slashdot.org/', 
 262                  'cnn.com', 'http://cnn.com', 
 263                  'The New York Times', 'http://www.nytimes.com', 
 264                  'De Volkskrant', 'http://www.volkskrant.nl/frameless/25000006.html', 
 265                  'Gnu GPL', 'http://www.fsf.org/copyleft/gpl.html', 
 266                  'Bijbel: Genesis', 'http://www.coas.com/bijbel/gn1.htm'] 
 268         for item 
in range(0,len(urls
),2): 
 269             urlmenu
.Append(1020+item
/2, urls
[item
], urls
[item
+1]) 
 270         urlmenu
.Append(1080, 'Other...', 'Enter an URL') 
 271         menu
.AppendMenu(1012, 'URL', urlmenu
, 'Use a webpage') 
 272         menu
.Append(1013, 'Dump', 'Write contents to stdout') 
 273         menubar
.Append(menu
, "Dictionary") 
 275         self
.urloffset 
= 1020 
 277         menu
.Append(1090, "About...") 
 278         menubar
.Append(menu
, "Help") 
 279         self
.SetMenuBar(menubar
) 
 280         self
.CreateStatusBar(2) 
 281         EVT_MENU(self
, 1001, self
.OnGameNew
) 
 282         EVT_MENU(self
, 1002, self
.OnGameEnd
) 
 283         EVT_MENU(self
, 1003, self
.OnGameReset
) 
 284         EVT_MENU(self
, 1004, self
.OnGameDemo
) 
 285         EVT_MENU(self
, 1005, self
.OnWindowClose
) 
 286         EVT_MENU(self
, 1011, self
.OnDictFile
) 
 287         EVT_MENU_RANGE(self
, 1020, 1020+len(urls
)/2, self
.OnDictURL
) 
 288         EVT_MENU(self
, 1080, self
.OnDictURLSel
) 
 289         EVT_MENU(self
, 1013, self
.OnDictDump
) 
 290         EVT_MENU(self
, 1090, self
.OnHelpAbout
) 
 291         EVT_CHAR(self
.wnd
, self
.OnChar
) 
 293     def OnGameNew(self
, event
): 
 296         self
.SetStatusText("",0) 
 297         self
.wnd
.StartGame(word
) 
 298     def OnGameEnd(self
, event
): 
 299         self
.UpdateAverages(0) 
 301         self
.SetStatusText("",0) 
 303     def OnGameReset(self
, event
=None): 
 309     def OnGameDemo(self
, event
): 
 310         frame 
= HangmanDemoFrame(self
.wf
, self
, -1, wxDefaultPosition
, self
.GetSize()) 
 312     def OnDictFile(self
, event
): 
 313         fd 
= wxFileDialog(self
) 
 314         if (self
.wf
.filename
): 
 315             fd
.SetFilename(self
.wf
.filename
) 
 316         if fd
.ShowModal() == wxID_OK
: 
 318             self
.wf 
= WordFetcher(file) 
 319     def OnDictURL(self
, event
): 
 320         item 
= (event
.GetId() - self
.urloffset
)*2 
 321         print "Trying to open %s at %s" % (self
.urls
[item
], self
.urls
[item
+1]) 
 322         self
.wf 
= URLWordFetcher(self
.urls
[item
+1]) 
 323     def OnDictURLSel(self
, event
): 
 324         msg 
= wxTextEntryDialog(self
, "Enter the URL of the dictionary document", "Enter URL") 
 325         if msg
.ShowModal() == wxID_OK
: 
 327             self
.wf 
= URLWordFetcher(url
) 
 328     def OnDictDump(self
, event
): 
 330     def OnHelpAbout(self
, event
): 
 331         about 
= AboutBox(self
, self
.wf
) 
 333         about
.wnd
.Stop() # that damn timer won't stop! 
 334     def UpdateAverages(self
, has_won
): 
 336             self
.won 
= self
.won 
+ 1 
 337         self
.played 
= self
.played
+1 
 338         self
.history
.append(self
.wnd
.misses
) # ugly 
 340         for m 
in self
.history
: 
 342         self
.average 
= float(total
/len(self
.history
)) 
 343     def OnChar(self
, event
): 
 344         if not self
.in_progress
: 
 347         key 
= event
.KeyCode(); 
 348         if key 
>= ord('A') and key 
<= ord('Z'): 
 349             key 
= key 
+ ord('a') - ord('A') 
 351         if key 
< 'a' or key 
> 'z': 
 354         res 
= self
.wnd
.HandleKey(key
) 
 356             self
.SetStatusText(self
.wnd
.message
) 
 358             self
.UpdateAverages(0) 
 359             self
.SetStatusText("Too bad, you're dead!",0) 
 363             self
.UpdateAverages(1) 
 364             self
.SetStatusText("Congratulations!",0) 
 366             percent 
= (100.*self
.won
)/self
.played
 
 369         self
.SetStatusText("p %d, w %d (%g %%), av %g" % (self
.played
,self
.won
, percent
, self
.average
),1) 
 371     def OnWindowClose(self
, event
): 
 376         if wxPlatform 
== '__WXGTK__': 
 377             defaultfile 
= "/usr/share/games/hangman-words" 
 378         elif wxPlatform 
== '__WXMSW__': 
 379             defaultfile 
= "c:\\windows\\hardware.txt" 
 382         wf 
= WordFetcher(defaultfile
) 
 384         self
.SetTopWindow(frame
) 
 388 if __name__ 
== '__main__':