]>
git.saurik.com Git - wxWidgets.git/blob - utils/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 self
.font
= wxFont(10, wxMODERN
, wxNORMAL
, wxNORMAL
)
110 def StartGame(self
, word
):
118 self
.guess
= map(chr, range(ord('a'),ord('z')+1))
120 def HandleKey(self
, key
):
122 if self
.guess
.count(key
):
123 self
.message
= 'Already guessed %s' % (key
,)
125 self
.guess
.append(key
)
127 self
.tries
= self
.tries
+1
128 if not key
in self
.word
:
129 self
.misses
= self
.misses
+1
134 for letter
in self
.word
:
135 if not self
.guess
.count(letter
):
143 def Draw(self
, dc
= None):
145 dc
= wxClientDC(self
)
146 dc
.SetFont(self
.font
)
148 (x
,y
) = self
.GetSizeTuple()
150 for letter
in self
.word
:
151 if self
.guess
.count(letter
):
152 dc
.DrawText(letter
, x1
, y1
)
154 dc
.DrawText('.', x1
, y1
)
157 dc
.DrawText("tries %d misses %d" % (self
.tries
,self
.misses
),x1
,50)
159 for letter
in self
.guess
:
160 guesses
= guesses
+ letter
161 dc
.DrawText("guessed:", x1
, 70)
162 dc
.DrawText(guesses
[:13], x1
+80, 70)
163 dc
.DrawText(guesses
[13:], x1
+80, 90)
164 dc
.SetUserScale(x
/1000., y
/1000.)
166 def DrawVictim(self
, dc
):
167 dc
.SetPen(wxPen(wxNamedColour('black'), 20))
168 dc
.DrawLines([(10, 980), (10,900), (700,900), (700,940), (720,940),
169 (720,980), (900,980)])
170 dc
.DrawLines([(100,900), (100, 100), (300,100)])
171 dc
.DrawLine(100,200,200,100)
172 if ( self
.misses
== 0 ): return
173 dc
.SetPen(wxPen(wxNamedColour('blue'), 10))
174 dc
.DrawLine(300,100,300,200)
175 if ( self
.misses
== 1 ): return
176 dc
.DrawEllipse(250,200,100,100)
177 if ( self
.misses
== 2 ): return
178 dc
.DrawLine(300,300,300,600)
179 if ( self
.misses
== 3) : return
180 dc
.DrawLine(300,300,250,550)
181 if ( self
.misses
== 4) : return
182 dc
.DrawLine(300,300,350,550)
183 if ( self
.misses
== 5) : return
184 dc
.DrawLine(300,600,350,850)
185 if ( self
.misses
== 6) : return
186 dc
.DrawLine(300,600,250,850)
187 def OnPaint(self
, event
):
191 class HangmanDemo(HangmanWnd
):
192 def __init__(self
, wf
, parent
, id, pos
, size
):
193 HangmanWnd
.__init
__(self
, parent
, id, pos
, size
)
194 self
.StartGame("dummy")
198 self
.timer
= self
.PlayTimer(self
.MakeMove
)
202 self
.StartGame(self
.wf
.Get())
204 self
.left
= list('aaaabcdeeeeefghiiiiijklmnnnoooopqrssssttttuuuuvwxyz')
206 key
= self
.left
[int(random
.random()*len(self
.left
))]
207 while self
.left
.count(key
): self
.left
.remove(key
)
208 self
.start_new
= self
.HandleKey(key
)
209 self
.timer
.Start(self
.delay
)
212 class PlayTimer(wxTimer
):
213 def __init__(self
,func
):
214 wxTimer
.__init
__(self
)
220 class HangmanDemoFrame(wxFrame
):
221 def __init__(self
, wf
, parent
, id, pos
, size
):
222 wxFrame
.__init
__(self
, parent
, id, "Hangman demo", pos
, size
)
223 self
.demo
= HangmanDemo(wf
, self
, -1, wxDefaultPosition
, wxDefaultSize
)
224 def OnCloseWindow(self
, event
):
225 self
.demo
.timer
.Stop()
228 class AboutBox(wxDialog
):
229 def __init__(self
, parent
,wf
):
230 wxDialog
.__init
__(self
, parent
, -1, "About Hangman", wxDefaultPosition
, wxSize(350,450))
231 self
.wnd
= HangmanDemo(wf
, self
, -1, wxPoint(1,1), wxSize(350,150))
232 self
.static
= wxStaticText(self
, -1, __doc__
, wxPoint(1,160), wxSize(350, 250))
233 self
.button
= wxButton(self
, 2001, "OK", wxPoint(150,420), wxSize(50,-1))
234 EVT_BUTTON(self
, 2001, self
.OnOK
)
235 def OnOK(self
, event
):
237 self
.EndModal(wxID_OK
)
239 class MyFrame(wxFrame
):
240 def __init__(self
, wf
):
242 wxFrame
.__init
__(self
, NULL
, -1, "hangman", wxDefaultPosition
, wxSize(400,300))
243 self
.wnd
= HangmanWnd(self
, -1)
245 menu
.Append(1001, "New")
246 menu
.Append(1002, "End")
247 menu
.AppendSeparator()
248 menu
.Append(1003, "Reset")
249 menu
.Append(1004, "Demo...")
250 menu
.AppendSeparator()
251 menu
.Append(1005, "Exit")
252 menubar
= wxMenuBar()
253 menubar
.Append(menu
, "Game")
255 #menu.Append(1010, "Internal", "Use internal dictionary", TRUE)
256 menu
.Append(1011, "ASCII File...")
257 urls
= [ 'wxPython home', 'http://208.240.253.245/wxPython/main.html',
258 'slashdot.org', 'http://slashdot.org/',
259 'cnn.com', 'http://cnn.com',
260 'The new york Times', 'http://www.nytimes.com',
261 'De Volkskrant', 'http://www.volkskrant.nl/frameless/25000006.html']
263 for item
in range(0,len(urls
),2):
264 urlmenu
.Append(1020+item
/2, urls
[item
], urls
[item
+1])
265 urlmenu
.Append(1080, 'Other...', 'Enter an URL')
266 menu
.AppendMenu(1012, 'URL', urlmenu
, 'Use a webpage')
267 menu
.Append(1013, 'Dump', 'Write contents to stdout')
268 menubar
.Append(menu
, "Dictionary")
270 self
.urloffset
= 1020
272 menu
.Append(1090, "About...")
273 menubar
.Append(menu
, "Help")
274 self
.SetMenuBar(menubar
)
275 self
.CreateStatusBar(2)
276 EVT_MENU(self
, 1001, self
.OnGameNew
)
277 EVT_MENU(self
, 1002, self
.OnGameEnd
)
278 EVT_MENU(self
, 1003, self
.OnGameReset
)
279 EVT_MENU(self
, 1004, self
.OnGameDemo
)
280 EVT_MENU(self
, 1005, self
.OnWindowClose
)
281 EVT_MENU(self
, 1011, self
.OnDictFile
)
282 EVT_MENU_RANGE(self
, 1020, 1020+len(urls
)/2, self
.OnDictURL
)
283 EVT_MENU(self
, 1080, self
.OnDictURLSel
)
284 EVT_MENU(self
, 1013, self
.OnDictDump
)
285 EVT_MENU(self
, 1090, self
.OnHelpAbout
)
286 EVT_CHAR(self
.wnd
, self
.OnChar
)
288 def OnGameNew(self
, event
):
291 self
.SetStatusText("",0)
292 self
.wnd
.StartGame(word
)
293 def OnGameEnd(self
, event
):
294 self
.UpdateAverages(0)
296 self
.SetStatusText("",0)
298 def OnGameReset(self
, event
=None):
304 def OnGameDemo(self
, event
):
305 frame
= HangmanDemoFrame(self
.wf
, self
, -1, wxDefaultPosition
, self
.GetSize())
307 def OnDictFile(self
, event
):
308 fd
= wxFileDialog(self
)
309 if (self
.wf
.filename
):
310 fd
.SetFilename(self
.wf
.filename
)
311 if fd
.ShowModal() == wxID_OK
:
313 self
.wf
= WordFetcher(file)
314 def OnDictURL(self
, event
):
315 item
= (event
.GetId() - self
.urloffset
)*2
316 print "Trying to open %s at %s" % (self
.urls
[item
], self
.urls
[item
+1])
317 self
.wf
= URLWordFetcher(self
.urls
[item
+1])
318 def OnDictURLSel(self
, event
):
319 msg
= wxTextEntryDialog(self
, "Enter the URL of the dictionary document", "Enter URL")
320 if msg
.ShowModal() == wxID_OK
:
322 self
.wf
= URLWordFetcher(url
)
323 def OnDictDump(self
, event
):
325 def OnHelpAbout(self
, event
):
326 about
= AboutBox(self
, self
.wf
)
328 about
.wnd
.Stop() # that damn timer won't stop!
329 def UpdateAverages(self
, has_won
):
331 self
.won
= self
.won
+ 1
332 self
.played
= self
.played
+1
333 self
.history
.append(self
.wnd
.misses
) # ugly
335 for m
in self
.history
:
337 self
.average
= float(total
/len(self
.history
))
338 def OnChar(self
, event
):
339 if not self
.in_progress
:
342 key
= event
.KeyCode();
343 if key
>= ord('A') and key
<= ord('Z'):
344 key
= key
+ ord('a') - ord('A')
346 if key
< 'a' or key
> 'z':
349 res
= self
.wnd
.HandleKey(key
)
351 self
.SetStatusText(self
.wnd
.message
)
353 self
.UpdateAverages(0)
354 self
.SetStatusText("Too bad, you're dead!",0)
358 self
.UpdateAverages(1)
359 self
.SetStatusText("Congratulations!",0)
361 percent
= (100.*self
.won
)/self
.played
364 self
.SetStatusText("p %d, w %d (%g %%), av %g" % (self
.played
,self
.won
, percent
, self
.average
),1)
366 def OnWindowClose(self
, event
):
371 if wxPlatform
== '__WXGTK__':
372 defaultfile
= "/usr/share/games/hangman-words"
373 elif wxPlatform
== '__WXMSW__':
374 defaultfile
= "c:\\windows\\hardware.txt"
377 wf
= WordFetcher(defaultfile
)
379 self
.SetTopWindow(frame
)
383 if __name__
== '__main__':