]>
git.saurik.com Git - wxWidgets.git/blob - utils/wxPython/demo/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 *
23 builtin_words
= ' albatros banana electrometer eggshell'
25 def __init__(self
, filename
, min_length
= 5):
26 self
.min_length
= min_length
27 print "Trying to open file %s" % (filename
,)
29 f
= open(filename
, "r")
31 print "Couldn't open dictionary file %s, using builtins" % (filename
,)
32 self
.words
= self
.builtin_words
36 self
.filename
= filename
37 print "Got %d bytes." % (len(self
.words
),)
39 def SetMinLength(min_length
):
40 self
.min_length
= min_length
43 reg
= re
.compile('\s+([a-zA-Z]+)\s+')
44 n
= 50 # safety valve; maximum number of tries to find a suitable word
46 index
= int(random
.random()*len(self
.words
))
47 m
= reg
.search(self
.words
[index
:])
48 if m
and len(m
.groups()[0]) >= self
.min_length
: break
50 if n
: return string
.lower(m
.groups()[0])
60 class URLWordFetcher(WordFetcher
):
61 def __init__(self
, url
):
63 WordFetcher
.__init
__(self
, "hangman_dict.txt")
68 def RetrieveAsFile(self
, host
, path
=''):
69 from httplib
import HTTP
73 self
.logprint("Failed to create HTTP connection to %s... is the network available?" % (host
))
75 h
.putrequest('GET',path
)
76 h
.putheader('Accept','text/html')
77 h
.putheader('Accept','text/plain')
79 errcode
, errmsg
, headers
= h
.getreply()
81 self
.logprint("HTTP error code %d: %s" % (errcode
, errmsg
))
86 def OpenURL(self
,url
):
87 from htmllib
import HTMLParser
90 m
= re
.match('http://([^/]+)(/\S*)\s*', url
)
95 m
= re
.match('http://(\S+)\s*', url
)
98 self
.logprint("Invalid or unsupported URL: %s" % (url
))
102 f
= self
.RetrieveAsFile(host
,path
)
104 self
.logprint("Could not open %s" % (url
))
106 self
.logprint("Receiving data...")
108 tmp
= open('hangman_dict.txt','w')
109 fmt
= formatter
.AbstractFormatter(formatter
.DumbWriter(tmp
))
111 self
.logprint("Parsing data...")
118 class HangmanWnd(wxWindow
):
119 def __init__(self
, parent
, id, pos
=wxDefaultPosition
, size
=wxDefaultSize
):
120 wxWindow
.__init
__(self
, parent
, id, pos
, size
)
121 self
.SetBackgroundColour(wxNamedColour('white'))
122 if wxPlatform
== '__WXGTK__':
123 self
.font
= wxFont(12, wxMODERN
, wxNORMAL
, wxNORMAL
)
125 self
.font
= wxFont(10, wxMODERN
, wxNORMAL
, wxNORMAL
)
128 def StartGame(self
, word
):
137 self
.guess
= map(chr, range(ord('a'),ord('z')+1))
140 def HandleKey(self
, key
):
142 if self
.guess
.count(key
):
143 self
.message
= 'Already guessed %s' % (key
,)
145 self
.guess
.append(key
)
147 self
.tries
= self
.tries
+1
148 if not key
in self
.word
:
149 self
.misses
= self
.misses
+1
154 for letter
in self
.word
:
155 if not self
.guess
.count(letter
):
164 def Draw(self
, dc
= None):
166 dc
= wxClientDC(self
)
167 dc
.SetFont(self
.font
)
169 (x
,y
) = self
.GetSizeTuple()
171 for letter
in self
.word
:
172 if self
.guess
.count(letter
):
173 dc
.DrawText(letter
, x1
, y1
)
175 dc
.DrawText('.', x1
, y1
)
178 dc
.DrawText("tries %d misses %d" % (self
.tries
,self
.misses
),x1
,50)
180 for letter
in self
.guess
:
181 guesses
= guesses
+ letter
182 dc
.DrawText("guessed:", x1
, 70)
183 dc
.DrawText(guesses
[:13], x1
+80, 70)
184 dc
.DrawText(guesses
[13:], x1
+80, 90)
185 dc
.SetUserScale(x
/1000.0, y
/1000.0)
188 def DrawVictim(self
, dc
):
189 dc
.SetPen(wxPen(wxNamedColour('black'), 20))
190 dc
.DrawLines([(10, 980), (10,900), (700,900), (700,940), (720,940),
191 (720,980), (900,980)])
192 dc
.DrawLines([(100,900), (100, 100), (300,100)])
193 dc
.DrawLine(100,200,200,100)
194 if ( self
.misses
== 0 ): return
195 dc
.SetPen(wxPen(wxNamedColour('blue'), 10))
196 dc
.DrawLine(300,100,300,200)
197 if ( self
.misses
== 1 ): return
198 dc
.DrawEllipse(250,200,100,100)
199 if ( self
.misses
== 2 ): return
200 dc
.DrawLine(300,300,300,600)
201 if ( self
.misses
== 3) : return
202 dc
.DrawLine(300,300,250,550)
203 if ( self
.misses
== 4) : return
204 dc
.DrawLine(300,300,350,550)
205 if ( self
.misses
== 5) : return
206 dc
.DrawLine(300,600,350,850)
207 if ( self
.misses
== 6) : return
208 dc
.DrawLine(300,600,250,850)
210 def OnPaint(self
, event
):
216 class HangmanDemo(HangmanWnd
):
217 def __init__(self
, wf
, parent
, id, pos
, size
):
218 HangmanWnd
.__init
__(self
, parent
, id, pos
, size
)
219 self
.StartGame("dummy")
223 self
.timer
= self
.PlayTimer(self
.MakeMove
)
228 self
.StartGame(self
.wf
.Get())
230 self
.left
= list('aaaabcdeeeeefghiiiiijklmnnnoooopqrssssttttuuuuvwxyz')
232 key
= self
.left
[int(random
.random()*len(self
.left
))]
233 while self
.left
.count(key
): self
.left
.remove(key
)
234 self
.start_new
= self
.HandleKey(key
)
235 self
.timer
.Start(self
.delay
)
240 class PlayTimer(wxTimer
):
241 def __init__(self
,func
):
242 wxTimer
.__init
__(self
)
251 class HangmanDemoFrame(wxFrame
):
252 def __init__(self
, wf
, parent
, id, pos
, size
):
253 wxFrame
.__init
__(self
, parent
, id, "Hangman demo", pos
, size
)
254 self
.demo
= HangmanDemo(wf
, self
, -1, wxDefaultPosition
, wxDefaultSize
)
256 def OnCloseWindow(self
, event
):
257 self
.demo
.timer
.Stop()
262 class AboutBox(wxDialog
):
263 def __init__(self
, parent
,wf
):
264 wxDialog
.__init
__(self
, parent
, -1, "About Hangman", wxDefaultPosition
, wxSize(350,450))
265 self
.wnd
= HangmanDemo(wf
, self
, -1, wxPoint(1,1), wxSize(350,150))
266 self
.static
= wxStaticText(self
, -1, __doc__
, wxPoint(1,160), wxSize(350, 250))
267 self
.button
= wxButton(self
, 2001, "OK", wxPoint(150,420), wxSize(50,-1))
268 EVT_BUTTON(self
, 2001, self
.OnOK
)
270 def OnOK(self
, event
):
272 self
.EndModal(wxID_OK
)
276 class MyFrame(wxFrame
):
277 def __init__(self
, parent
, wf
):
279 wxFrame
.__init
__(self
, parent
, -1, "hangman", wxDefaultPosition
, wxSize(400,300))
280 self
.wnd
= HangmanWnd(self
, -1)
282 menu
.Append(1001, "New")
283 menu
.Append(1002, "End")
284 menu
.AppendSeparator()
285 menu
.Append(1003, "Reset")
286 menu
.Append(1004, "Demo...")
287 menu
.AppendSeparator()
288 menu
.Append(1005, "Exit")
289 menubar
= wxMenuBar()
290 menubar
.Append(menu
, "Game")
292 #menu.Append(1010, "Internal", "Use internal dictionary", TRUE)
293 menu
.Append(1011, "ASCII File...")
294 urls
= [ 'wxPython home', 'http://alldunn.com/wxPython/main.html',
295 'slashdot.org', 'http://slashdot.org/',
296 'cnn.com', 'http://cnn.com',
297 'The New York Times', 'http://www.nytimes.com',
298 'De Volkskrant', 'http://www.volkskrant.nl/frameless/25000006.html',
299 'Gnu GPL', 'http://www.fsf.org/copyleft/gpl.html',
300 'Bijbel: Genesis', 'http://www.coas.com/bijbel/gn1.htm']
302 for item
in range(0,len(urls
),2):
303 urlmenu
.Append(1020+item
/2, urls
[item
], urls
[item
+1])
304 urlmenu
.Append(1080, 'Other...', 'Enter an URL')
305 menu
.AppendMenu(1012, 'URL', urlmenu
, 'Use a webpage')
306 menu
.Append(1013, 'Dump', 'Write contents to stdout')
307 menubar
.Append(menu
, "Dictionary")
309 self
.urloffset
= 1020
311 menu
.Append(1090, "About...")
312 menubar
.Append(menu
, "Help")
313 self
.SetMenuBar(menubar
)
314 self
.CreateStatusBar(2)
315 EVT_MENU(self
, 1001, self
.OnGameNew
)
316 EVT_MENU(self
, 1002, self
.OnGameEnd
)
317 EVT_MENU(self
, 1003, self
.OnGameReset
)
318 EVT_MENU(self
, 1004, self
.OnGameDemo
)
319 EVT_MENU(self
, 1005, self
.OnWindowClose
)
320 EVT_MENU(self
, 1011, self
.OnDictFile
)
321 EVT_MENU_RANGE(self
, 1020, 1020+len(urls
)/2, self
.OnDictURL
)
322 EVT_MENU(self
, 1080, self
.OnDictURLSel
)
323 EVT_MENU(self
, 1013, self
.OnDictDump
)
324 EVT_MENU(self
, 1090, self
.OnHelpAbout
)
325 EVT_CHAR(self
.wnd
, self
.OnChar
)
328 def OnGameNew(self
, event
):
331 self
.SetStatusText("",0)
332 self
.wnd
.StartGame(word
)
334 def OnGameEnd(self
, event
):
335 self
.UpdateAverages(0)
337 self
.SetStatusText("",0)
340 def OnGameReset(self
, event
=None):
347 def OnGameDemo(self
, event
):
348 frame
= HangmanDemoFrame(self
.wf
, self
, -1, wxDefaultPosition
, self
.GetSize())
351 def OnDictFile(self
, event
):
352 fd
= wxFileDialog(self
)
353 if (self
.wf
.filename
):
354 fd
.SetFilename(self
.wf
.filename
)
355 if fd
.ShowModal() == wxID_OK
:
357 self
.wf
= WordFetcher(file)
359 def OnDictURL(self
, event
):
360 item
= (event
.GetId() - self
.urloffset
)*2
361 print "Trying to open %s at %s" % (self
.urls
[item
], self
.urls
[item
+1])
362 self
.wf
= URLWordFetcher(self
.urls
[item
+1])
364 def OnDictURLSel(self
, event
):
365 msg
= wxTextEntryDialog(self
, "Enter the URL of the dictionary document", "Enter URL")
366 if msg
.ShowModal() == wxID_OK
:
368 self
.wf
= URLWordFetcher(url
)
369 def OnDictDump(self
, event
):
372 def OnHelpAbout(self
, event
):
373 about
= AboutBox(self
, self
.wf
)
375 about
.wnd
.Stop() # that damn timer won't stop!
377 def UpdateAverages(self
, has_won
):
379 self
.won
= self
.won
+ 1
380 self
.played
= self
.played
+1
381 self
.history
.append(self
.wnd
.misses
) # ugly
383 for m
in self
.history
:
385 self
.average
= float(total
/len(self
.history
))
387 def OnChar(self
, event
):
388 if not self
.in_progress
:
391 key
= event
.KeyCode();
392 if key
>= ord('A') and key
<= ord('Z'):
393 key
= key
+ ord('a') - ord('A')
395 if key
< 'a' or key
> 'z':
398 res
= self
.wnd
.HandleKey(key
)
400 self
.SetStatusText(self
.wnd
.message
)
402 self
.UpdateAverages(0)
403 self
.SetStatusText("Too bad, you're dead!",0)
407 self
.UpdateAverages(1)
408 self
.SetStatusText("Congratulations!",0)
410 percent
= (100.*self
.won
)/self
.played
413 self
.SetStatusText("p %d, w %d (%g %%), av %g" % (self
.played
,self
.won
, percent
, self
.average
),1)
415 def OnWindowClose(self
, event
):
422 if wxPlatform
== '__WXGTK__':
423 defaultfile
= "/usr/share/games/hangman-words"
424 elif wxPlatform
== '__WXMSW__':
425 defaultfile
= "c:\\windows\\hardware.txt"
428 wf
= WordFetcher(defaultfile
)
429 frame
= MyFrame(NULL
, wf
)
430 self
.SetTopWindow(frame
)
436 if __name__
== '__main__':
441 #----------------------------------------------------------------------
446 def runTest(frame
, nb
, log
):
447 if wxPlatform
== '__WXGTK__' or wxPlatform
== '__WXMOTIF__':
448 defaultfile
= "/usr/share/games/hangman-words"
449 elif wxPlatform
== '__WXMSW__':
450 defaultfile
= "c:\\windows\\hardware.txt"
453 wf
= WordFetcher(defaultfile
)
454 win
= MyFrame(frame
, wf
)
459 #----------------------------------------------------------------------