]>
git.saurik.com Git - wxWidgets.git/blob - 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
)
127 EVT_PAINT(self
, self
.OnPaint
)
130 def StartGame(self
, word
):
139 self
.guess
= map(chr, range(ord('a'),ord('z')+1))
142 def HandleKey(self
, key
):
144 if self
.guess
.count(key
):
145 self
.message
= 'Already guessed %s' % (key
,)
147 self
.guess
.append(key
)
149 self
.tries
= self
.tries
+1
150 if not key
in self
.word
:
151 self
.misses
= self
.misses
+1
156 for letter
in self
.word
:
157 if not self
.guess
.count(letter
):
166 def Draw(self
, dc
= None):
168 dc
= wxClientDC(self
)
169 dc
.SetFont(self
.font
)
171 (x
,y
) = self
.GetSizeTuple()
173 for letter
in self
.word
:
174 if self
.guess
.count(letter
):
175 dc
.DrawText(letter
, x1
, y1
)
177 dc
.DrawText('.', x1
, y1
)
180 dc
.DrawText("tries %d misses %d" % (self
.tries
,self
.misses
),x1
,50)
182 for letter
in self
.guess
:
183 guesses
= guesses
+ letter
184 dc
.DrawText("guessed:", x1
, 70)
185 dc
.DrawText(guesses
[:13], x1
+80, 70)
186 dc
.DrawText(guesses
[13:], x1
+80, 90)
187 dc
.SetUserScale(x
/1000.0, y
/1000.0)
190 def DrawVictim(self
, dc
):
191 dc
.SetPen(wxPen(wxNamedColour('black'), 20))
192 dc
.DrawLines([(10, 980), (10,900), (700,900), (700,940), (720,940),
193 (720,980), (900,980)])
194 dc
.DrawLines([(100,900), (100, 100), (300,100)])
195 dc
.DrawLine(100,200,200,100)
196 if ( self
.misses
== 0 ): return
197 dc
.SetPen(wxPen(wxNamedColour('blue'), 10))
198 dc
.DrawLine(300,100,300,200)
199 if ( self
.misses
== 1 ): return
200 dc
.DrawEllipse(250,200,100,100)
201 if ( self
.misses
== 2 ): return
202 dc
.DrawLine(300,300,300,600)
203 if ( self
.misses
== 3) : return
204 dc
.DrawLine(300,300,250,550)
205 if ( self
.misses
== 4) : return
206 dc
.DrawLine(300,300,350,550)
207 if ( self
.misses
== 5) : return
208 dc
.DrawLine(300,600,350,850)
209 if ( self
.misses
== 6) : return
210 dc
.DrawLine(300,600,250,850)
212 def OnPaint(self
, event
):
218 class HangmanDemo(HangmanWnd
):
219 def __init__(self
, wf
, parent
, id, pos
, size
):
220 HangmanWnd
.__init
__(self
, parent
, id, pos
, size
)
221 self
.StartGame("dummy")
225 self
.timer
= self
.PlayTimer(self
.MakeMove
)
230 self
.StartGame(self
.wf
.Get())
232 self
.left
= list('aaaabcdeeeeefghiiiiijklmnnnoooopqrssssttttuuuuvwxyz')
234 key
= self
.left
[int(random
.random()*len(self
.left
))]
235 while self
.left
.count(key
): self
.left
.remove(key
)
236 self
.start_new
= self
.HandleKey(key
)
237 self
.timer
.Start(self
.delay
)
242 class PlayTimer(wxTimer
):
243 def __init__(self
,func
):
244 wxTimer
.__init
__(self
)
253 class HangmanDemoFrame(wxFrame
):
254 def __init__(self
, wf
, parent
, id, pos
, size
):
255 wxFrame
.__init
__(self
, parent
, id, "Hangman demo", pos
, size
)
256 self
.demo
= HangmanDemo(wf
, self
, -1, wxDefaultPosition
, wxDefaultSize
)
257 EVT_CLOSE(self
, self
.OnCloseWindow
)
259 def OnCloseWindow(self
, event
):
260 self
.demo
.timer
.Stop()
265 class AboutBox(wxDialog
):
266 def __init__(self
, parent
,wf
):
267 wxDialog
.__init
__(self
, parent
, -1, "About Hangman", wxDefaultPosition
, wxSize(350,450))
268 self
.wnd
= HangmanDemo(wf
, self
, -1, wxPoint(1,1), wxSize(350,150))
269 self
.static
= wxStaticText(self
, -1, __doc__
, wxPoint(1,160), wxSize(350, 250))
270 self
.button
= wxButton(self
, 2001, "OK", wxPoint(150,420), wxSize(50,-1))
271 EVT_BUTTON(self
, 2001, self
.OnOK
)
273 def OnOK(self
, event
):
275 self
.EndModal(wxID_OK
)
279 class MyFrame(wxFrame
):
280 def __init__(self
, parent
, wf
):
282 wxFrame
.__init
__(self
, parent
, -1, "hangman", wxDefaultPosition
, wxSize(400,300))
283 self
.wnd
= HangmanWnd(self
, -1)
285 menu
.Append(1001, "New")
286 menu
.Append(1002, "End")
287 menu
.AppendSeparator()
288 menu
.Append(1003, "Reset")
289 menu
.Append(1004, "Demo...")
290 menu
.AppendSeparator()
291 menu
.Append(1005, "Exit")
292 menubar
= wxMenuBar()
293 menubar
.Append(menu
, "Game")
295 #menu.Append(1010, "Internal", "Use internal dictionary", TRUE)
296 menu
.Append(1011, "ASCII File...")
297 urls
= [ 'wxPython home', 'http://wxPython.org/',
298 'slashdot.org', 'http://slashdot.org/',
299 'cnn.com', 'http://cnn.com',
300 'The New York Times', 'http://www.nytimes.com',
301 'De Volkskrant', 'http://www.volkskrant.nl/frameless/25000006.html',
302 'Gnu GPL', 'http://www.fsf.org/copyleft/gpl.html',
303 'Bijbel: Genesis', 'http://www.coas.com/bijbel/gn1.htm']
305 for item
in range(0,len(urls
),2):
306 urlmenu
.Append(1020+item
/2, urls
[item
], urls
[item
+1])
307 urlmenu
.Append(1080, 'Other...', 'Enter an URL')
308 menu
.AppendMenu(1012, 'URL', urlmenu
, 'Use a webpage')
309 menu
.Append(1013, 'Dump', 'Write contents to stdout')
310 menubar
.Append(menu
, "Dictionary")
312 self
.urloffset
= 1020
314 menu
.Append(1090, "About...")
315 menubar
.Append(menu
, "Help")
316 self
.SetMenuBar(menubar
)
317 self
.CreateStatusBar(2)
318 EVT_MENU(self
, 1001, self
.OnGameNew
)
319 EVT_MENU(self
, 1002, self
.OnGameEnd
)
320 EVT_MENU(self
, 1003, self
.OnGameReset
)
321 EVT_MENU(self
, 1004, self
.OnGameDemo
)
322 EVT_MENU(self
, 1005, self
.OnWindowClose
)
323 EVT_MENU(self
, 1011, self
.OnDictFile
)
324 EVT_MENU_RANGE(self
, 1020, 1020+len(urls
)/2, self
.OnDictURL
)
325 EVT_MENU(self
, 1080, self
.OnDictURLSel
)
326 EVT_MENU(self
, 1013, self
.OnDictDump
)
327 EVT_MENU(self
, 1090, self
.OnHelpAbout
)
328 EVT_CHAR(self
.wnd
, self
.OnChar
)
331 def OnGameNew(self
, event
):
334 self
.SetStatusText("",0)
335 self
.wnd
.StartGame(word
)
337 def OnGameEnd(self
, event
):
338 self
.UpdateAverages(0)
340 self
.SetStatusText("",0)
343 def OnGameReset(self
, event
=None):
350 def OnGameDemo(self
, event
):
351 frame
= HangmanDemoFrame(self
.wf
, self
, -1, wxDefaultPosition
, self
.GetSize())
354 def OnDictFile(self
, event
):
355 fd
= wxFileDialog(self
)
356 if (self
.wf
.filename
):
357 fd
.SetFilename(self
.wf
.filename
)
358 if fd
.ShowModal() == wxID_OK
:
360 self
.wf
= WordFetcher(file)
362 def OnDictURL(self
, event
):
363 item
= (event
.GetId() - self
.urloffset
)*2
364 print "Trying to open %s at %s" % (self
.urls
[item
], self
.urls
[item
+1])
365 self
.wf
= URLWordFetcher(self
.urls
[item
+1])
367 def OnDictURLSel(self
, event
):
368 msg
= wxTextEntryDialog(self
, "Enter the URL of the dictionary document", "Enter URL")
369 if msg
.ShowModal() == wxID_OK
:
371 self
.wf
= URLWordFetcher(url
)
372 def OnDictDump(self
, event
):
375 def OnHelpAbout(self
, event
):
376 about
= AboutBox(self
, self
.wf
)
378 about
.wnd
.Stop() # that damn timer won't stop!
380 def UpdateAverages(self
, has_won
):
382 self
.won
= self
.won
+ 1
383 self
.played
= self
.played
+1
384 self
.history
.append(self
.wnd
.misses
) # ugly
386 for m
in self
.history
:
388 self
.average
= float(total
/len(self
.history
))
390 def OnChar(self
, event
):
391 if not self
.in_progress
:
395 key
= event
.KeyCode();
397 if key
>= ord('A') and key
<= ord('Z'):
398 key
= key
+ ord('a') - ord('A')
400 if key
< 'a' or key
> 'z':
403 res
= self
.wnd
.HandleKey(key
)
405 self
.SetStatusText(self
.wnd
.message
)
407 self
.UpdateAverages(0)
408 self
.SetStatusText("Too bad, you're dead!",0)
412 self
.UpdateAverages(1)
413 self
.SetStatusText("Congratulations!",0)
415 percent
= (100.*self
.won
)/self
.played
418 self
.SetStatusText("p %d, w %d (%g %%), av %g" % (self
.played
,self
.won
, percent
, self
.average
),1)
420 def OnWindowClose(self
, event
):
427 if wxPlatform
== '__WXGTK__':
428 defaultfile
= "/usr/share/games/hangman-words"
429 elif wxPlatform
== '__WXMSW__':
430 defaultfile
= "c:\\windows\\hardware.txt"
433 wf
= WordFetcher(defaultfile
)
434 frame
= MyFrame(None, wf
)
435 self
.SetTopWindow(frame
)
441 if __name__
== '__main__':
446 #----------------------------------------------------------------------
451 def runTest(frame
, nb
, log
):
452 if wxPlatform
== '__WXGTK__' or wxPlatform
== '__WXMOTIF__':
453 defaultfile
= "/usr/share/games/hangman-words"
454 elif wxPlatform
== '__WXMSW__':
455 defaultfile
= "c:\\windows\\hardware.txt"
458 wf
= WordFetcher(defaultfile
)
459 win
= MyFrame(frame
, wf
)
464 #----------------------------------------------------------------------