How to create a game for wxPython - Part 1 (Phoenix)
Keywords : Tetris, Memory game, Reversi, The Towers of Hanoi, Game, Pygame.
Contents
Demonstrating :
Tested py3.x, wx4.x and Win10.
Are you ready to use some samples ?
Test, modify, correct, complete, improve and share your discoveries !
Tetris
First example
1 # tetris.py
2
3 """
4 ZetCode wxPython tutorial.
5
6 This is Tetris game clone in wxPython.
7
8 Author : Jan Bodnar
9 Website : www.zetcode.com
10 Link : http://zetcode.com/wxpython/thetetrisgame/
11 Last modified : May 2018
12 """
13
14 import wx
15 import random
16
17 # class Tetris
18 # class Board
19 # class Tetrominoes
20 # class Shape
21
22 #---------------------------------------------------------------------------
23
24 class Tetris(wx.Frame):
25 """
26 ...
27 """
28 def __init__(self, parent):
29 style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER ^ wx.MAXIMIZE_BOX
30 wx.Frame.__init__(self, parent, size=(220, 420), style=style)
31
32 self.initFrame()
33
34 #-----------------------------------------------------------------------
35
36 def initFrame(self):
37 """
38 ...
39 """
40
41 self.statusbar = self.CreateStatusBar()
42 self.statusbar.SetStatusText('0')
43 self.board = Board(self)
44 self.board.SetFocus()
45 self.board.start()
46
47 #------------
48
49 # Creating the menubar.
50 menu_bar = wx.MenuBar()
51
52 # Setting up the menu.
53 file_menu = wx.Menu()
54
55 # wx.ID_ABOUT and wx.ID_EXIT are standard IDs provided by wxWidgets.
56 item = file_menu.Append(wx.ID_ABOUT, "&About", "Information about Tetris.")
57 self.Bind(wx.EVT_MENU, self.OnAbout, item)
58 file_menu.AppendSeparator()
59 item = file_menu.Append(wx.ID_EXIT, "E&xit", "Exit Tetris.")
60 self.Bind(wx.EVT_MENU, self.OnQuit, item)
61
62 # Create the "Help" top menu.
63 help_menu = wx.Menu()
64 item = help_menu.Append(wx.ID_HELP, "&Shortcuts", "Shortcuts for Tetris.")
65 self.Bind(wx.EVT_MENU, self.OnHelp, item)
66
67 # Adding the "file_menu" to the menu bar.
68 menu_bar.Append(file_menu, "&File")
69 menu_bar.Append(help_menu, "&Help")
70
71 # Adding the menu bar to the frame content.
72 self.SetMenuBar(menu_bar)
73
74 #------------
75
76 self.SetIcon(wx.Icon(".\icons\wxwin.ico"))
77 self.SetTitle("Tetris")
78
79 #------------
80
81 self.CenterOnScreen(wx.BOTH)
82
83
84 def OnQuit(self, event):
85 self.Destroy()
86
87
88 def OnAbout(self, event):
89 dlg = wx.MessageDialog(self,
90 "This is a small game.\n",
91 "About Tetris",
92 wx.OK | wx.CENTRE | wx.ICON_INFORMATION)
93 dlg.ShowModal()
94 dlg.Destroy()
95
96
97 def OnHelp(self, event):
98 dlg = wx.MessageDialog(self,
99 "AZERTY keyboard :\n"
100 "--------------------\n"
101 "P \t---------> \tPause\n"
102 "S \t---------> \tLEFT\n"
103 "F \t---------> \tRIGHT\n"
104 "D \t---------> \tDOWN (rotated right)\n"
105 "E \t----------> \tUP (rotated left)\n"
106 "SPACE \t----> \tAccelerate\n"
107 "D \t---------> \tOne line down\n",
108 "Shortcuts",
109 wx.OK | wx.CENTRE | wx.ICON_INFORMATION)
110 dlg.ShowModal()
111 dlg.Destroy()
112
113 #---------------------------------------------------------------------------
114
115 class Board(wx.Panel):
116 """
117 ...
118 """
119
120 BoardWidth = 10
121 BoardHeight = 22
122 Speed = 300
123 ID_TIMER = 1
124
125 def __init__(self, *args, **kw):
126 super(Board, self).__init__(*args, **kw)
127
128 self.initBoard()
129
130 #------------
131
132 # Delete flickers.
133 if wx.Platform == "__WXMSW__":
134 self.SetDoubleBuffered(True)
135
136 #-----------------------------------------------------------------------
137
138 def initBoard(self):
139 """
140 ...
141 """
142
143 self.timer = wx.Timer(self, Board.ID_TIMER)
144 self.isWaitingAfterLine = False
145 self.curPiece = Shape()
146 self.nextPiece = Shape()
147 self.curX = 0
148 self.curY = 0
149 self.numLinesRemoved = 0
150 self.board = []
151
152 self.isStarted = False
153 self.isPaused = False
154
155 self.Bind(wx.EVT_PAINT, self.OnPaint)
156 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
157 self.Bind(wx.EVT_TIMER, self.OnTimer, id=Board.ID_TIMER)
158
159 self.clearBoard()
160
161
162 def shapeAt(self, x, y):
163 """
164 ...
165 """
166
167 return self.board[(y * Board.BoardWidth) + x]
168
169
170 def setShapeAt(self, x, y, shape):
171 """
172 ...
173 """
174
175 self.board[(y * Board.BoardWidth) + x] = shape
176
177
178 def squareWidth(self):
179 """
180 ...
181 """
182
183 return self.GetClientSize().GetWidth() // Board.BoardWidth
184
185
186 def squareHeight(self):
187 """
188 ...
189 """
190
191 return self.GetClientSize().GetHeight() // Board.BoardHeight
192
193
194 def start(self):
195 """
196 ...
197 """
198
199 if self.isPaused:
200 return
201
202 self.isStarted = True
203 self.isWaitingAfterLine = False
204 self.numLinesRemoved = 0
205 self.clearBoard()
206
207 self.newPiece()
208 self.timer.Start(Board.Speed)
209
210
211 def pause(self):
212 """
213 ...
214 """
215
216 if not self.isStarted:
217 return
218
219 self.isPaused = not self.isPaused
220 statusbar = self.GetParent().statusbar
221
222 if self.isPaused:
223 self.timer.Stop()
224 statusbar.SetStatusText('paused')
225 else:
226 self.timer.Start(Board.Speed)
227 statusbar.SetStatusText(str(self.numLinesRemoved))
228
229 self.Refresh()
230
231
232 def clearBoard(self):
233 """
234 ...
235 """
236
237 for i in range(Board.BoardHeight * Board.BoardWidth):
238 self.board.append(Tetrominoes.NoShape)
239
240
241 def OnPaint(self, event):
242 """
243 ...
244 """
245
246 dc = wx.PaintDC(self)
247
248 size = self.GetClientSize()
249 boardTop = size.GetHeight() - Board.BoardHeight * self.squareHeight()
250
251 for i in range(Board.BoardHeight):
252 for j in range(Board.BoardWidth):
253
254 shape = self.shapeAt(j, Board.BoardHeight - i - 1)
255
256 if shape != Tetrominoes.NoShape:
257 self.drawSquare(dc,
258 0 + j * self.squareWidth(),
259 boardTop + i * self.squareHeight(), shape)
260
261 if self.curPiece.shape() != Tetrominoes.NoShape:
262
263 for i in range(4):
264
265 x = self.curX + self.curPiece.x(i)
266 y = self.curY - self.curPiece.y(i)
267
268 self.drawSquare(dc, 0 + x * self.squareWidth(),
269 boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(),
270 self.curPiece.shape())
271
272
273 def OnKeyDown(self, event):
274 """
275 ...
276 """
277
278 if not self.isStarted or self.curPiece.shape() == Tetrominoes.NoShape:
279 event.Skip()
280 return
281
282 keycode = event.GetKeyCode()
283 print("Keycode :", keycode)
284
285 if keycode == ord('P') or keycode == ord('p'):
286 self.pause()
287 return
288
289 if self.isPaused:
290 return
291
292 #-----------------
293 # AZERTY keyboard.
294 #-----------------
295 # elif keycode == wx.WXK_LEFT:
296 elif keycode == ord('S') or keycode == ord('s'):
297 self.tryMove(self.curPiece, self.curX - 1, self.curY)
298
299 # elif keycode == wx.WXK_RIGHT:
300 elif keycode == ord('F') or keycode == ord('f'):
301 self.tryMove(self.curPiece, self.curX + 1, self.curY)
302
303 # elif keycode == wx.WXK_DOWN:
304 elif keycode == ord('D') or keycode == ord('d'):
305 self.tryMove(self.curPiece.rotatedRight(), self.curX, self.curY)
306
307 # elif keycode == wx.WXK_UP:
308 elif keycode == ord('E') or keycode == ord('e'):
309 self.tryMove(self.curPiece.rotatedLeft(), self.curX, self.curY)
310
311 elif keycode == wx.WXK_SPACE:
312 self.dropDown()
313
314 elif keycode == ord('R') or keycode == ord('r'):
315 self.oneLineDown()
316
317 else:
318 event.Skip()
319
320
321 def OnTimer(self, event):
322 """
323 ...
324 """
325
326 if event.GetId() == Board.ID_TIMER:
327
328 if self.isWaitingAfterLine:
329 self.isWaitingAfterLine = False
330 self.newPiece()
331
332 else:
333 self.oneLineDown()
334
335 else:
336 event.Skip()
337
338
339 def dropDown(self):
340 """
341 ...
342 """
343
344 newY = self.curY
345
346 while newY > 0:
347 if not self.tryMove(self.curPiece, self.curX, newY - 1):
348 break
349 newY -= 1
350
351 self.pieceDropped()
352
353
354 def oneLineDown(self):
355 """
356 ...
357 """
358
359 if not self.tryMove(self.curPiece, self.curX, self.curY - 1):
360 self.pieceDropped()
361
362
363 def pieceDropped(self):
364 """
365 ...
366 """
367
368 for i in range(4):
369
370 x = self.curX + self.curPiece.x(i)
371 y = self.curY - self.curPiece.y(i)
372 self.setShapeAt(x, y, self.curPiece.shape())
373
374 self.removeFullLines()
375
376 if not self.isWaitingAfterLine:
377 self.newPiece()
378
379
380 def removeFullLines(self):
381 """
382 ...
383 """
384
385 numFullLines = 0
386
387 statusbar = self.GetParent().statusbar
388
389 rowsToRemove = []
390
391 for i in range(Board.BoardHeight):
392 n = 0
393 for j in range(Board.BoardWidth):
394 if not self.shapeAt(j, i) == Tetrominoes.NoShape:
395 n = n + 1
396
397 if n == 10:
398 rowsToRemove.append(i)
399
400 rowsToRemove.reverse()
401
402 for m in rowsToRemove:
403 for k in range(m, Board.BoardHeight):
404 for l in range(Board.BoardWidth):
405 self.setShapeAt(l, k, self.shapeAt(l, k + 1))
406
407 numFullLines = numFullLines + len(rowsToRemove)
408
409 if numFullLines > 0:
410
411 self.numLinesRemoved = self.numLinesRemoved + numFullLines
412 statusbar.SetStatusText(str(self.numLinesRemoved))
413 self.isWaitingAfterLine = True
414 self.curPiece.setShape(Tetrominoes.NoShape)
415 self.Refresh()
416
417
418 def newPiece(self):
419 """
420 ...
421 """
422
423 self.curPiece = self.nextPiece
424 statusbar = self.GetParent().statusbar
425 self.nextPiece.setRandomShape()
426
427 self.curX = Board.BoardWidth // 2 + 1
428 self.curY = Board.BoardHeight - 1 + self.curPiece.minY()
429
430 if not self.tryMove(self.curPiece, self.curX, self.curY):
431
432 self.curPiece.setShape(Tetrominoes.NoShape)
433 self.timer.Stop()
434 self.isStarted = False
435 statusbar.SetStatusText('Game over')
436
437
438 def tryMove(self, newPiece, newX, newY):
439 """
440 ...
441 """
442
443 for i in range(4):
444
445 x = newX + newPiece.x(i)
446 y = newY - newPiece.y(i)
447
448 if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight:
449 return False
450
451 if self.shapeAt(x, y) != Tetrominoes.NoShape:
452 return False
453
454 self.curPiece = newPiece
455 self.curX = newX
456 self.curY = newY
457 self.Refresh()
458
459 return True
460
461
462 def drawSquare(self, dc, x, y, shape):
463 """
464 ...
465 """
466
467 colors = ['#000000', '#CC6666', '#66CC66', '#6666CC',
468 '#CCCC66', '#CC66CC', '#66CCCC', '#DAAA00']
469
470 light = ['#000000', '#F89FAB', '#79FC79', '#7979FC',
471 '#FCFC79', '#FC79FC', '#79FCFC', '#FCC600']
472
473 dark = ['#000000', '#803C3B', '#3B803B', '#3B3B80',
474 '#80803B', '#803B80', '#3B8080', '#806200']
475
476 pen = wx.Pen(light[shape])
477 pen.SetCap(wx.CAP_PROJECTING)
478 dc.SetPen(pen)
479
480 dc.DrawLine(x, y + self.squareHeight() - 1, x, y)
481 dc.DrawLine(x, y, x + self.squareWidth() - 1, y)
482
483 darkpen = wx.Pen(dark[shape])
484 darkpen.SetCap(wx.CAP_PROJECTING)
485 dc.SetPen(darkpen)
486
487 dc.DrawLine(x + 1, y + self.squareHeight() - 1,
488 x + self.squareWidth() - 1, y + self.squareHeight() - 1)
489 dc.DrawLine(x + self.squareWidth() - 1,
490 y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + 1)
491
492 dc.SetPen(wx.TRANSPARENT_PEN)
493 dc.SetBrush(wx.Brush(colors[shape]))
494 dc.DrawRectangle(x + 1, y + 1, self.squareWidth() - 2,
495 self.squareHeight() - 2)
496
497 #---------------------------------------------------------------------------
498
499 class Tetrominoes(object):
500 """
501 ...
502 """
503
504 NoShape = 0
505 ZShape = 1
506 SShape = 2
507 LineShape = 3
508 TShape = 4
509 SquareShape = 5
510 LShape = 6
511 MirroredLShape = 7
512
513 #---------------------------------------------------------------------------
514
515 class Shape(object):
516 """
517 ...
518 """
519
520 coordsTable = (
521 ((0, 0), (0, 0), (0, 0), (0, 0)),
522 ((0, -1), (0, 0), (-1, 0), (-1, 1)),
523 ((0, -1), (0, 0), (1, 0), (1, 1)),
524 ((0, -1), (0, 0), (0, 1), (0, 2)),
525 ((-1, 0), (0, 0), (1, 0), (0, 1)),
526 ((0, 0), (1, 0), (0, 1), (1, 1)),
527 ((-1, -1), (0, -1), (0, 0), (0, 1)),
528 ((1, -1), (0, -1), (0, 0), (0, 1))
529 )
530
531 def __init__(self):
532 self.coords = [[0,0] for i in range(4)]
533 self.pieceShape = Tetrominoes.NoShape
534
535 self.setShape(Tetrominoes.NoShape)
536
537 #-----------------------------------------------------------------------
538
539 def shape(self):
540 """
541 ...
542 """
543
544 return self.pieceShape
545
546
547 def setShape(self, shape):
548 """
549 ...
550 """
551
552 table = Shape.coordsTable[shape]
553 for i in range(4):
554 for j in range(2):
555 self.coords[i][j] = table[i][j]
556
557 self.pieceShape = shape
558
559
560 def setRandomShape(self):
561 """
562 ...
563 """
564
565 self.setShape(random.randint(1, 7))
566
567
568 def x(self, index):
569 """
570 ...
571 """
572
573 return self.coords[index][0]
574
575
576 def y(self, index):
577 """
578 ...
579 """
580
581 return self.coords[index][1]
582
583
584 def setX(self, index, x):
585 """
586 ...
587 """
588
589 self.coords[index][0] = x
590
591
592 def setY(self, index, y):
593 """
594 ...
595 """
596
597 self.coords[index][1] = y
598
599
600 def minX(self):
601 """
602 ...
603 """
604
605 m = self.coords[0][0]
606 for i in range(4):
607 m = min(m, self.coords[i][0])
608
609 return m
610
611
612 def maxX(self):
613 """
614 ...
615 """
616
617 m = self.coords[0][0]
618 for i in range(4):
619 m = max(m, self.coords[i][0])
620
621 return m
622
623
624 def minY(self):
625 """
626 ...
627 """
628
629 m = self.coords[0][1]
630 for i in range(4):
631 m = min(m, self.coords[i][1])
632
633 return m
634
635
636 def maxY(self):
637 """
638 ...
639 """
640
641 m = self.coords[0][1]
642
643 for i in range(4):
644 m = max(m, self.coords[i][1])
645
646 return m
647
648
649 def rotatedLeft(self):
650 """
651 ...
652 """
653
654 if self.pieceShape == Tetrominoes.SquareShape:
655 return self
656
657 result = Shape()
658 result.pieceShape = self.pieceShape
659
660 for i in range(4):
661 result.setX(i, self.y(i))
662 result.setY(i, -self.x(i))
663
664 return result
665
666
667 def rotatedRight(self):
668 """
669 ...
670 """
671
672 if self.pieceShape == Tetrominoes.SquareShape:
673 return self
674
675 result = Shape()
676 result.pieceShape = self.pieceShape
677
678 for i in range(4):
679 result.setX(i, -self.y(i))
680 result.setY(i, self.x(i))
681
682 return result
683
684 #---------------------------------------------------------------------------
685
686 def main():
687 app = wx.App()
688 ex = Tetris(None)
689 ex.Show(True)
690 app.MainLoop()
691
692 #---------------------------------------------------------------------------
693
694 if __name__ == '__main__':
695 main()
Second example
1 # tetris_bis.py
2
3 """
4 wxPython Tetris game.
5
6 Author : Hanming Zhang
7 Link : https://github.com/HanmingZhang/Tetris
8 """
9
10 import wx
11 import random
12
13 # class SplitterFrame
14 # class Info
15 # class Board
16 # class Tetrominoes
17 # class Shape
18
19 #---------------------------------------------------------------------------
20
21 class SplitterFrame(wx.Frame):
22 def __init__(self, parent, id, title):
23 style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER ^ wx.MAXIMIZE_BOX
24 wx.Frame.__init__(self, parent, id, title, size=(600, 600), style=style)
25
26 #------------
27
28 self.SetIcon(wx.Icon(".\icons\wxwin.ico"))
29
30 #------------
31
32 self.initpos = 600
33
34 #------------
35
36 self.sp = wx.SplitterWindow(self)
37 self.board = Board(self.sp, style=wx.SUNKEN_BORDER)
38 self.board.SetBackgroundColour("pink")
39
40 self.info = Info(self.sp, style=wx.SUNKEN_BORDER)
41 self.info.SetBackgroundColour("sky blue")
42
43 self.sp.SplitVertically(self.board, self.info, self.initpos)
44 self.sp.SetMinimumPaneSize(210)
45
46 #------------
47
48 self.ShowNextPiece = Shape()
49 # self.board.SetFocus()
50
51 #------------
52
53 # self.Music = wx.Sound('E:\Lab7\s.mp3')
54
55 #------------
56
57 self.board.Start()
58
59 #------------
60
61 self.CenterOnScreen(wx.BOTH)
62 self.Show(True)
63
64 #---------------------------------------------------------------------------
65
66 class Info(wx.Panel):
67 BoardWidth = 6
68 BoardHeight = 25
69 def __init__(self, parent, style):
70 wx.Panel.__init__(self, parent)
71
72 #------------
73
74 self.upspeedButton = wx.Button(self, -1, "Up Speed", pos=(15, 500))
75 self.lowerButton = wx.Button(self, -1, "Lower Speed", pos=(100, 500))
76
77 if wx.Platform == "__WXMSW__": ###
78 colour = self.GetBackgroundColour()
79 colour.Set(colour.Red(), colour.Green(), colour.Blue(),
80 wx.ALPHA_TRANSPARENT)
81 self.upspeedButton.SetBackgroundColour(colour)
82 self.lowerButton.SetBackgroundColour(colour)
83
84 self.Bind(wx.EVT_BUTTON, self.OnUpSpeed, self.upspeedButton)
85 self.Bind(wx.EVT_BUTTON, self.OnLowerSpeed, self.lowerButton)
86 self.Bind(wx.EVT_PAINT, self.OnPaint)
87
88 #------------
89
90 temp = wx.StaticText(self, -1,"Coming next :", pos=(20, 40))
91 temp.SetFont(wx.Font(18, wx.SCRIPT, wx.NORMAL, wx.NORMAL, False))
92 temp.SetForegroundColour(wx.Colour(255, 255, 255))
93 temp = wx.StaticText(self, -1, "Number of lines removed :", pos=(20, 360))
94 temp.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False))
95 temp = wx.StaticText(self, -1, "Your Score :", pos=(20, 420))
96 temp.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False))
97
98 #-----------------------------------------------------------------------
99
100 def OnUpSpeed(self,event):
101 if Board.Speed >= 100:
102 Board.Speed = Board.Speed -50
103 self.GetParent().GetParent().board.timer.Start(Board.Speed)
104
105
106 def OnLowerSpeed(self,event):
107 Board.Speed = Board.Speed +50
108 self.GetParent().GetParent().board.timer.Start(Board.Speed)
109
110
111 def SquareWidth(self):
112 return self.GetClientSize().GetWidth() / Info.BoardWidth
113
114
115 def SquareHeight(self):
116 return self.GetClientSize().GetHeight() / Info.BoardHeight
117
118
119 def OnPaint(self, event):
120 dc = wx.PaintDC(self)
121 size = self.GetClientSize()
122 boardTop = size.GetHeight() - Info.BoardHeight * self.SquareHeight()
123
124 # dc.DrawText("Coming next:", 20, 40)
125
126 # temp = wx.StaticText(self, -1, "Coming next:", pos=(20, 40))
127 # temp.SetFont(wx.Font(5, wx.SWISS, wx.NORMAL, wx.BOLD, False))
128
129 # dc.DrawText("Number of lines removed:", 5, 380)
130 dc.DrawText("%d" %(self.GetParent().GetParent().board.numLinesRemoved), 90, 400)
131 # dc.DrawText("Your Score:", 5, 420)
132 dc.DrawText("%d" %(self.GetParent().GetParent().board.Score), 90, 460)
133 #linesRemoved=wx.StaticText(self, -1, "", pos=(100, 400))
134 #linesRemoved.SetFont(wx.Font(15, wx.SWISS, wx.NORMAL, wx.BOLD, False))
135 #linesRemoved.SetForegroundColour(wx.Colour(0, 0, 0, 255))
136 #linesRemoved.SetLabel("%d" %(self.GetParent().GetParent().board.numLinesRemoved))
137
138
139 if self.GetParent().GetParent().ShowNextPiece.shape() != Tetrominoes.NoShape:
140 for i in range(4):
141 x = self.GetParent().GetParent().ShowNextPiece.x(i)
142 y = self.GetParent().GetParent().ShowNextPiece.y(i)
143 self.DrawSquare(dc, int(0 + x * self.SquareWidth()+80), ###
144 int((boardTop + (Info.BoardHeight + y - 1)) * int(self.SquareHeight()-400)), ###
145 self.GetParent().GetParent().ShowNextPiece.shape())
146
147
148 def DrawSquare(self, dc, x, y, shape):
149 colors = ['#000000', '#CC6666', '#66CC66', '#6666CC',
150 '#CCCC66', '#CC66CC', '#66CCCC', '#DAAA00']
151
152 light = ['#000000', '#F89FAB', '#79FC79', '#7979FC',
153 '#FCFC79', '#FC79FC', '#79FCFC', '#FCC600']
154
155 dark = ['#000000', '#803C3B', '#3B803B', '#3B3B80',
156 '#80803B', '#803B80', '#3B8080', '#806200']
157
158 pen = wx.Pen(light[shape])
159 pen.SetCap(wx.CAP_PROJECTING)
160 dc.SetPen(pen)
161
162 dc.DrawLine(x, int(y + self.SquareHeight() - 1), x, y)
163 dc.DrawLine(x, y, int(x + self.SquareWidth() - 1), y)
164
165 darkpen = wx.Pen(dark[shape])
166 darkpen.SetCap(wx.CAP_PROJECTING)
167 dc.SetPen(darkpen)
168
169 dc.DrawLine(int(x + 1), int(y + self.SquareHeight() - 1), ###
170 int(x + self.SquareWidth() - 1), int(y + self.SquareHeight() - 1)) ###
171 dc.DrawLine(int(x + self.SquareWidth() - 1), ###
172 int(y + self.SquareHeight() - 1), int(x + self.SquareWidth() - 1), y + 1) ###
173
174 dc.SetPen(wx.TRANSPARENT_PEN)
175 dc.SetBrush(wx.Brush(colors[shape]))
176 dc.DrawRectangle(int(x + 1), int(y + 1), int(self.SquareWidth() - 2), ###
177 int(self.SquareHeight() - 2)) ###
178
179 #---------------------------------------------------------------------------
180
181 class Board(wx.Panel):
182 BoardWidth = 12
183 BoardHeight = 20
184 Speed = 300
185 ID_TIMER = 1
186 def __init__(self, parent, style):
187 wx.Panel.__init__(self, parent, style=wx.WANTS_CHARS)
188 # You can use arrow keys after adding style = wx.WANTS_CHARS.
189
190
191 #------------
192
193 # Delete flickers.
194 if wx.Platform == "__WXMSW__":
195 self.SetDoubleBuffered(True)
196
197 #------------
198
199 self.timer = wx.Timer(self, Board.ID_TIMER)
200 self.isWaitingAfterLine = False
201 self.curPiece = Shape()
202 self.nextPiece = Shape()
203 self.nextPiece.SetRandomShape()
204 self.curX = 0
205 self.curY = 0
206 self.numLinesRemoved = 0
207 self.Score = 0
208 self.board = []
209
210 #------------
211
212 self.isStarted = False
213 self.isPaused = False
214
215 #------------
216
217 self.Bind(wx.EVT_PAINT, self.OnPaint)
218 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
219 self.Bind(wx.EVT_TIMER, self.OnTimer, id=Board.ID_TIMER)
220
221 #------------
222
223 self.ClearBoard()
224
225 #-----------------------------------------------------------------------
226
227 def ShapeAt(self, x, y):
228 return self.board[(int(y) * int(Board.BoardWidth)) + int(x)]
229
230
231 def SetShapeAt(self, x, y, shape):
232 self.board[(int(y) * int(Board.BoardWidth)) + int(x)] = shape
233
234
235 def SquareWidth(self):
236 return self.GetClientSize().GetWidth() / Board.BoardWidth
237
238
239 def SquareHeight(self):
240 return self.GetClientSize().GetHeight() / Board.BoardHeight
241
242
243 def Start(self):
244 if self.isPaused:
245 return
246
247 self.isStarted = True
248 self.isWaitingAfterLine = False
249 self.numLinesRemoved = 0
250 self.Score = 0
251 self.ClearBoard()
252
253 wx.MessageBox("""Hello !\n"""
254 """Welcome to Tetris World.\n\n"""
255 """Here are some information you may need.\n\n"""
256 """Azerty keyboard :\n"""
257 """--------------------\n"""
258 """Z --> Rotate\n"""
259 """Q/D --> Left or Right move\n"""
260 """S --> One line down\n"""
261 """Space --> Drop down\n"""
262 """P --> Pause\n\n"""
263 """Hope you enjoy ! ^.^""",
264 "Tetris",
265 wx.OK | wx.ICON_INFORMATION,
266 self)
267
268 # self.GetParent().GetParent().Music.Play(wx.SOUND_ASYNC)
269
270 self.NewPiece()
271 self.timer.Start(Board.Speed)
272
273
274 def Pause(self):
275 if not self.isStarted:
276 return
277
278 self.isPaused = not self.isPaused
279 # statusbar = self.GetParent().statusbar
280
281 if self.isPaused:
282 self.timer.Stop()
283 # statusbar.SetStatusText('Paused')
284 else:
285 self.timer.Start(Board.Speed)
286 # statusbar.SetStatusText(str(self.numLinesRemoved))
287 self.Refresh()
288
289
290 def ClearBoard(self):
291 for i in range(Board.BoardHeight * Board.BoardWidth):
292 self.board.append(Tetrominoes.NoShape)
293
294
295 def OnPaint(self, event):
296 dc = wx.PaintDC(self)
297
298 size = self.GetClientSize()
299 boardTop = size.GetHeight() - Board.BoardHeight * self.SquareHeight()
300
301 for i in range(Board.BoardHeight):
302 for j in range(Board.BoardWidth):
303 shape = self.ShapeAt(j, Board.BoardHeight - i - 1)
304 if shape != Tetrominoes.NoShape:
305 self.DrawSquare(dc,
306 int(0 + j * self.SquareWidth()), ###
307 int(boardTop + i * self.SquareHeight()), shape) ###
308
309 if self.curPiece.shape() != Tetrominoes.NoShape:
310 for i in range(4):
311 x = self.curX + self.curPiece.x(i)
312 y = self.curY - self.curPiece.y(i)
313 self.DrawSquare(dc, int(0 + x * self.SquareWidth()), ###
314 int((boardTop + (Board.BoardHeight - y - 1)) * (self.SquareHeight())), ###
315 self.curPiece.shape())
316
317
318 def OnKeyDown(self, event):
319 if not self.isStarted or self.curPiece.shape() == Tetrominoes.NoShape:
320 event.Skip()
321 return
322
323 keycode = event.GetKeyCode()
324
325 if keycode == ord('P') or keycode == ord('p'):
326 self.Pause()
327 return
328 if self.isPaused:
329 return
330 elif keycode == ord('Q') or keycode == ord('q'):
331 self.TryMove(self.curPiece, self.curX - 1, self.curY)
332 elif keycode == ord('D') or keycode == ord('d'):
333 self.TryMove(self.curPiece, self.curX + 1, self.curY)
334 #elif keycode == wx.WXK_DOWN:
335 #self.TryMove(self.curPiece.rotatedRight(), self.curX, self.curY)
336 elif keycode == ord('Z') or keycode == ord('z'):
337 self.TryMove(self.curPiece.RotatedLeft(), self.curX, self.curY)
338 elif keycode == ord('S') or keycode == ord('s'):
339 self.OneLineDown()
340 elif keycode == wx.WXK_SPACE:
341 self.DropDown()
342 else:
343 event.Skip()
344
345
346 def OnTimer(self, event):
347 if event.GetId() == Board.ID_TIMER:
348 if self.isWaitingAfterLine:
349 self.isWaitingAfterLine = False
350 self.NewPiece()
351 else:
352 self.OneLineDown()
353 else:
354 event.Skip()
355
356
357 def DropDown(self):
358 newY = self.curY
359 while newY > 0:
360 if not self.TryMove(self.curPiece, self.curX, newY - 1):
361 break
362 newY -= 1
363
364 self.PieceDropped()
365
366
367 def OneLineDown(self):
368 if not self.TryMove(self.curPiece, self.curX, self.curY - 1):
369 self.PieceDropped()
370
371
372 def PieceDropped(self):
373 for i in range(4):
374 x = self.curX + self.curPiece.x(i)
375 y = self.curY - self.curPiece.y(i)
376 self.SetShapeAt(x, y, self.curPiece.shape())
377
378 self.RemoveFullLines()
379
380 if not self.isWaitingAfterLine:
381 self.NewPiece()
382
383
384 def RemoveFullLines(self):
385 numFullLines = 0
386
387 # statusbar = self.GetParent().statusbar
388
389 rowsToRemove = []
390
391 for i in range(Board.BoardHeight):
392 n = 0
393 for j in range(Board.BoardWidth):
394 if not self.ShapeAt(j, i) == Tetrominoes.NoShape:
395 n = n + 1
396
397 if n == 12:
398 rowsToRemove.append(i)
399
400 rowsToRemove.reverse()
401
402 for m in rowsToRemove:
403 for k in range(m, Board.BoardHeight):
404 for l in range(Board.BoardWidth):
405 self.SetShapeAt(l, k, self.ShapeAt(l, k + 1))
406
407 numFullLines = numFullLines + len(rowsToRemove)
408
409
410 if numFullLines > 0:
411 #if numFullLines == 1:
412 #self.Score += 10
413 #else :
414 #self.Score += numFullLines*20
415 #self.numLinesRemoved += numFullLines
416 # statusbar.SetStatusText(str(self.numLinesRemoved))
417 self.isWaitingAfterLine = True
418 self.curPiece.SetShape(Tetrominoes.NoShape)
419 self.Refresh()
420
421 if len(rowsToRemove) != 0:
422 self.numLinesRemoved += len(rowsToRemove)
423 if len(rowsToRemove) == 1:
424 self.Score += 10
425 else:
426 self.Score += len(rowsToRemove)*20
427 self.GetParent().GetParent().info.Refresh()
428
429
430 def NewPiece(self):
431 # self.curPiece = self.nextPiece (it's wrong !)
432 # The original one has problem !!
433 # self.curPiece will always be the same as self.nextPiece
434 # This is the proper way !
435 self.curPiece.SetShape(self.nextPiece.shape())
436 # statusbar = self.GetParent().statusbar
437 self.nextPiece.SetRandomShape()
438
439 self.GetParent().GetParent().ShowNextPiece = self.nextPiece
440 # self.GetParent is a SpiltterWindow, and SpiltterWIndow's parent is SplitterFrame !
441 self.GetParent().GetParent().info.Refresh()
442
443 self.curX = Board.BoardWidth / 2 + 1
444 self.curY = Board.BoardHeight - 1 + self.curPiece.MinY()
445
446 if not self.TryMove(self.curPiece, self.curX, self.curY):
447 self.curPiece.SetShape(Tetrominoes.NoShape)
448 self.timer.Stop()
449 self.isStarted = False
450 wx.MessageBox("Sorry ! Game Over !", "Game Over",
451 wx.OK | wx.ICON_INFORMATION, self)
452 # Once the game is over, the program will quit.
453 self.GetParent().GetParent().Close()
454
455
456 def TryMove(self, NewPiece, newX, newY):
457 for i in range(4):
458 x = newX + NewPiece.x(i)
459 y = newY - NewPiece.y(i)
460 if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight:
461 return False
462 if self.ShapeAt(x, y) != Tetrominoes.NoShape:
463 return False
464
465 self.curPiece = NewPiece
466 self.curX = newX
467 self.curY = newY
468 self.Refresh()
469 return True
470
471
472 def DrawSquare(self, dc, x, y, shape):
473 colors = ['#000000', '#CC6666', '#66CC66', '#6666CC',
474 '#CCCC66', '#CC66CC', '#66CCCC', '#DAAA00']
475
476 light = ['#000000', '#F89FAB', '#79FC79', '#7979FC',
477 '#FCFC79', '#FC79FC', '#79FCFC', '#FCC600']
478
479 dark = ['#000000', '#803C3B', '#3B803B', '#3B3B80',
480 '#80803B', '#803B80', '#3B8080', '#806200']
481
482 pen = wx.Pen(light[shape])
483 pen.SetCap(wx.CAP_PROJECTING)
484 dc.SetPen(pen)
485
486 dc.DrawLine(x, int(y + self.SquareHeight() - 1), x, y) ###
487 dc.DrawLine(x, y, int(x + self.SquareWidth() - 1), y) ###
488
489 darkpen = wx.Pen(dark[shape])
490 darkpen.SetCap(wx.CAP_PROJECTING)
491 dc.SetPen(darkpen)
492
493 dc.DrawLine(x + 1, int(y + self.SquareHeight() - 1), ###
494 int(x + self.SquareWidth() - 1), int(y + self.SquareHeight() - 1)) ###
495 dc.DrawLine(x + int(self.SquareWidth() - 1),
496 int(y + self.SquareHeight() - 1), int(x + self.SquareWidth() - 1), y + 1) ###
497
498 dc.SetPen(wx.TRANSPARENT_PEN)
499 dc.SetBrush(wx.Brush(colors[shape]))
500 dc.DrawRectangle(int(x + 1), int(y + 1), int(self.SquareWidth() - 2),
501 int(self.SquareHeight() - 2)) ###
502
503 #---------------------------------------------------------------------------
504
505 class Tetrominoes(object):
506 NoShape = 0
507 ZShape = 1
508 SShape = 2
509 LineShape = 3
510 TShape = 4
511 SquareShape = 5
512 LShape = 6
513 MirroredLShape = 7
514
515 #---------------------------------------------------------------------------
516
517 class Shape(object):
518 coordsTable = (
519 ((0, 0), (0, 0), (0, 0), (0, 0)),
520 ((0, -1), (0, 0), (-1, 0), (-1, 1)),
521 ((0, -1), (0, 0), (1, 0), (1, 1)),
522 ((0, -1), (0, 0), (0, 1), (0, 2)),
523 ((-1, 0), (0, 0), (1, 0), (0, 1)),
524 ((0, 0), (1, 0), (0, 1), (1, 1)),
525 ((-1, -1), (0, -1), (0, 0), (0, 1)),
526 ((1, -1), (0, -1), (0, 0), (0, 1))
527 )
528 def __init__(self):
529 self.coords = [[0,0] for i in range(4)]
530 self.pieceShape = Tetrominoes.NoShape
531 self.SetShape(Tetrominoes.NoShape)
532
533 #-----------------------------------------------------------------------
534
535 def shape(self):
536 return self.pieceShape
537
538
539 def SetShape(self, shape):
540 table = Shape.coordsTable[shape]
541 for i in range(4):
542 for j in range(2):
543 self.coords[i][j] = table[i][j]
544
545 self.pieceShape = shape
546
547
548 def SetRandomShape(self):
549 self.SetShape(random.randint(1, 7))
550
551
552 def x(self, index):
553 return self.coords[index][0]
554
555
556 def y(self, index):
557 return self.coords[index][1]
558
559
560 def SetX(self, index, x):
561 self.coords[index][0] = x
562
563
564 def SetY(self, index, y):
565 self.coords[index][1] = y
566
567
568 def MinX(self):
569 m = self.coords[0][0]
570 for i in range(4):
571 m = min(m, self.coords[i][0])
572 return m
573
574
575 def MaxX(self):
576 m = self.coords[0][0]
577 for i in range(4):
578 m = max(m, self.coords[i][0])
579 return m
580
581
582 def MinY(self):
583 m = self.coords[0][1]
584 for i in range(4):
585 m = min(m, self.coords[i][1])
586 return m
587
588
589 def MaxY(self):
590 m = self.coords[0][1]
591 for i in range(4):
592 m = max(m, self.coords[i][1])
593 return m
594
595
596 def RotatedLeft(self):
597 if self.pieceShape == Tetrominoes.SquareShape:
598 return self
599
600 result = Shape()
601 result.pieceShape = self.pieceShape
602 for i in range(4):
603 result.SetX(i, self.y(i))
604 result.SetY(i, -self.x(i))
605
606 return result
607
608 #---------------------------------------------------------------------------
609
610 def main():
611 app = wx.App()
612 SplitterFrame(None, -1, 'Tetris')
613 app.MainLoop()
614
615 #---------------------------------------------------------------------------
616
617 if __name__ == '__main__':
618 main()
Memory game
Readme file : memory_README.md
1 # memory_game.py
2
3 """
4 wxPython Memory game.
5 All images should be in folder named "Images".
6 Images used are W : 100px H : 150px, though any size works if all images same size.
7 Line 32 has some commented out code to print the key to terminal for testing.
8
9 Author : Zoenberger
10 Link : https://github.com/zoenberger/Memory-Game-using-wxPython
11 """
12
13 import wx
14 import os
15 import random
16 import time
17
18 # class MemoryGame
19 # def Winner
20 # def GetJpgList
21
22 #---------------------------------------------------------------------------
23
24 class MemoryGame(wx.Frame):
25 def __init__(self):
26 wx.Frame.__init__(self, None, title="")
27
28 #------------
29
30 self.SetIcon(wx.Icon(".\icons\wxwin.ico"))
31 self.SetTitle("Memory game")
32 self.SetSize((900,700))
33
34 #------------
35
36 self.Move((50,25))
37
38 #------------
39
40 self.panel = wx.Panel(self)
41
42 #------------
43
44 # Define how big game is...can be useful
45 # for making skill options later.
46 self.numPairs = 12
47
48 # Get all images in directory called
49 # "Images" & shuffle order
50 self.imageArray = GetJpgList("./images")
51 random.shuffle(self.imageArray)
52
53 # Create array with how many cards needed
54 # and double it to make matched pairs.
55 self.imagePairs = self.imageArray[0:self.numPairs]
56 self.imagePairs = self.imagePairs * 2
57
58 # Because we doubled, we need to re-shuffle order.
59 random.shuffle(self.imagePairs)
60
61 #------------
62
63 # PRINT KEY TO TERMINAL SO YOU CAN QUICKLY SOLVE.
64 # countrow=0
65 # for card in self.imagePairs:
66 # countrow +=1
67 # if countrow%6 == 0:
68 # print card
69 # else:
70 # print card,
71
72 # Create blank card and give name of file name.
73 card = wx.Image('./images/main_card.jpg',wx.BITMAP_TYPE_ANY).ConvertToBitmap()
74 self.blankCards =[]
75 for i in range(len(self.imagePairs)):
76 self.blankCards.append(wx.StaticBitmap(self.panel,wx.ID_ANY, card,name=self.imagePairs[i]))
77
78 # Bind left click to each card that calls check function.
79 for img in self.blankCards:
80 img.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
81
82 #------------
83
84 # Visual Layout.
85 hbox = wx.BoxSizer(wx.HORIZONTAL)
86 gs = wx.GridSizer(4, 6, 15, 15)
87 gs.AddMany(self.blankCards)
88 hbox.Add(gs, proportion=0, flag = wx.LEFT | wx.TOP, border = 10)
89
90 title = wx.StaticText(self.panel, label="Memory Game")
91 hbox.Add(title,proportion=1, flag = wx.LEFT | wx.TOP | wx.RIGHT | wx.EXPAND, border = 10)
92
93 self.panel.SetSizer(hbox)
94 self.Show()
95
96 #------------
97
98 # Keeps track to see if you've won.
99 self.foundMatches= 0
100 # Keeps track of 1st or second click.
101 self.clickCount = 0
102 # Holding spot if it's first click.
103 self.card1 = ''
104 self.totalTries = 0
105
106 #-----------------------------------------------------------------------
107
108 def OnClick(self, event):
109 self.clickCount += 1
110
111 #------------
112
113 # Get card clicked on, swap out blank
114 # image with image by filename.
115 newCard = event.GetEventObject()
116 img = wx.Image(newCard.GetName(), wx.BITMAP_TYPE_ANY)
117 newCard.SetBitmap(wx.Bitmap(img))
118
119 #------------
120
121 if self.clickCount == 1:
122 # Put into holding space if 1st click.
123 self.card1 = newCard
124 self.card1.Unbind(wx.EVT_LEFT_DOWN)
125
126 else:
127 # FOUND MATCH : unbind click events. Update match tracker.
128 self.totalTries += 1
129 if (newCard.GetName() == self.card1.GetName()):
130 for findItem in self.blankCards:
131 if findItem.GetName() == newCard.GetName():
132 findItem.Unbind(wx.EVT_LEFT_DOWN)
133 self.foundMatches += 1
134 print(self.foundMatches)
135 else:
136 # NO MATCH : wait then hide both cards again.
137 # This basically freezes screen, but clicks still captured.
138 time.sleep(1)
139 blankCard = wx.Image('./images/main_card.jpg', wx.BITMAP_TYPE_ANY)
140 newCard.SetBitmap(wx.Bitmap(blankCard))
141 self.card1.SetBitmap(wx.Bitmap(blankCard))
142 self.card1.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
143 self.clickCount = 0
144
145 if self.foundMatches == self.numPairs:
146 Winner()
147 print("Total Tries = " + str(self.totalTries))
148 total = ("Total Tries = " + str(self.totalTries))
149
150 dlg = wx.MessageDialog(self,
151 total,
152 "Winner !",
153 wx.OK | wx.CENTRE | wx.ICON_INFORMATION)
154 dlg.ShowModal()
155 dlg.Destroy()
156
157 #---------------------------------------------------------------------------
158
159 # NOTE : make the winning more exciting. Hahahaha.
160 def Winner():
161 print("WINNER WINNER WINNER !")
162
163 #---------------------------------------------------------------------------
164
165 # Get all JPEGs in a directory that is passed and return image names array.
166 # Note I found this code snippet here :
167 # http ://wiki.wxpython.org/wxStaticBitmap
168 def GetJpgList(loc):
169 jpgs = [f for f in os.listdir(loc) if f[-4:] == ".jpg"]
170 #print "JPGS are:", jpgs
171
172 return [os.path.join(loc, f) for f in jpgs]
173
174 #---------------------------------------------------------------------------
175
176 def main():
177 app = wx.App(False)
178 frame = MemoryGame()
179 app.MainLoop()
180
181 #---------------------------------------------------------------------------
182
183 if __name__ == '__main__':
184 main()
Reversi
1 # reversi.py
2
3 """
4 wxPython Reversi game.
5
6 Author : Hatena
7 Link : https://yatt.hatenablog.jp/entry/20100129/1264791420
8 """
9
10 import wx
11 from copy import deepcopy
12
13 WHITE = -1
14 BLANK = 0
15 BLACK = 1
16
17 # def Notify
18 # class Reversi
19 # class Frame
20
21 #---------------------------------------------------------------------------
22
23 def Notify(caption, message):
24 dialog = wx.MessageDialog(None,
25 message=message,
26 caption=caption,
27 style=wx.OK)
28 dialog.ShowModal()
29 dialog.Destroy()
30
31 #---------------------------------------------------------------------------
32
33 class Reversi(object):
34 def __init__(self):
35
36 #------------
37
38 self.board = [[0]*8 for x in range(8)]
39 self.board[3][3] = WHITE
40 self.board[4][4] = WHITE
41 self.board[3][4] = BLACK
42 self.board[4][3] = BLACK
43 self.turns = 1 # Turn counter.
44 self.current = BLACK # Current player.
45 self.nstone = [2, 60, 2] # white, blank, black.
46 self.nreversed = 0
47 self.passed = None
48 self.over = False
49
50 #-----------------------------------------------------------------------
51
52 def __getitem__(self, i):
53 return self.board[i]
54
55
56 def Stones(self, s):
57 return self.nstone[1 + s]
58
59
60 def Feverseline(self, x, y, dx, dy):
61 if not (0<=x<8) or not (0<=y<8):
62 return False
63
64 elif self[x][y] == BLANK:
65 return False
66
67 elif self[x][y] == self.current:
68 return True
69
70 elif self[x][y] == -self.current:
71 ret = self.Feverseline(x+dx, y+dy, dx, dy)
72 if ret:
73 self[x][y] *= -1 # Reverse.
74 self.nreversed += 1
75 return ret
76
77
78 def Put(self, x, y, validation=False):
79 if self.over or self[x][y] != BLANK:
80 return False
81
82 backup = self[x][y]
83 self[x][y] = self.current
84 self.nreversed = 0
85
86 for dx in [-1, 0, 1]:
87 for dy in [-1, 0, 1]:
88 self.Feverseline(x+dx, y+dy, dx, dy)
89
90 if self.nreversed == 0:
91 self[x][y] = backup
92 return False
93
94 if validation:
95 # Despress changing state but only self.board.
96 return True
97
98 self.nstone[1 + BLANK] -= 1
99 self.nstone[1 + self.current] += self.nreversed + 1
100 self.nstone[1 - self.current] -= self.nreversed
101 self.turns += 1
102 self.current *= -1 # Change turn.
103
104 # Check game is over or not.
105 for s in [WHITE, BLANK, BLACK]:
106 if self.Stones(s) == 0:
107 self.over = True
108 return True
109
110 for i in range(8):
111 for j in range(8):
112 if self.Available(i, j):
113 self.passed = None
114 return True
115
116 self.passed = self.current
117 self.current *= -1
118
119 for i in range(8):
120 for j in range(8):
121 if self.Available(i, j):
122 return True
123 self.current *= -1
124 self.over = True
125 return True
126
127
128 def Available(self, x, y):
129 if self.over:
130 return False
131
132 # Backup board.
133 backup = deepcopy(self.board)
134 ret = self.Put(int(x), int(y), True)
135 # Restore board.
136 self.board = backup
137 return ret
138
139 #---------------------------------------------------------------------------
140
141 class Frame(wx.Frame):
142 def __init__(self):
143 style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER ^ wx.MAXIMIZE_BOX
144 wx.Frame.__init__(self, None, -1, "Reversi", style=style)
145
146 #------------
147
148 self.SetIcon(wx.Icon(".\icons\wxwin.ico"))
149
150 #------------
151
152 # Panel.
153 self.panel = wx.Panel(self)
154 self.panel.SetDoubleBuffered(True) ###
155 self.panel.Bind(wx.EVT_LEFT_DOWN, self.TryPut)
156 self.panel.Bind(wx.EVT_PAINT, self.Refresh)
157
158 #------------
159
160 self.Newgame(None)
161
162 #------------
163
164 # Menubar.
165 menu = wx.Menu()
166 menu.Append(1, "New game")
167 menu.AppendSeparator()
168 menu.Append(2, "Quit")
169 menubar = wx.MenuBar()
170 menubar.Append(menu, "Menu")
171 self.SetMenuBar(menubar)
172
173 self.Bind(wx.EVT_MENU, self.Newgame, id=1)
174 self.Bind(wx.EVT_MENU, self.Quit, id=2)
175
176 #------------
177
178 # Status bar.
179 self.CreateStatusBar()
180
181 #------------
182
183 # Ban resize.
184 # self.Bind(wx.EVT_SIZE, lambda e:e)
185
186 #------------
187
188 self.Show()
189
190 #-----------------------------------------------------------------------
191
192 def Quit(self, event):
193 self.Close()
194
195
196 def Newgame(self, event):
197 # Initialize reversi and Refresh screen.
198 self.reversi = Reversi()
199 self.panel.Refresh()
200
201
202 def TryPut(self, event):
203 if self.reversi.over:
204 return
205
206 # Calculate coordinate from window coordinate.
207 winx,winy = event.GetX(), event.GetY()
208 w,h = self.panel.GetSize()
209 x = winx / (w/8)
210 y = winy / (h/8)
211
212 if not self.reversi.Available(int(x), int(y)):
213 return
214
215 ret = self.reversi.Put(int(x), int(y))
216 self.panel.Refresh()
217
218 # If game is over then display dialog.
219 if self.reversi.over:
220 black = self.reversi.Stones(BLACK)
221 white = self.reversi.Stones(WHITE)
222 mes = "Black : %d\nWhite : %d\n" % (black, white)
223 if black == white:
224 mes += "** draw **"
225 else:
226 mes += "Winner : %s" % ["Black", "White"][black < white]
227 Notify("Game is over !", mes)
228
229 elif self.reversi.passed != None:
230 Notify("Passing turn", "Pass")
231
232
233 def Refresh(self, event):
234 dc = wx.AutoBufferedPaintDCFactory(self.panel)
235 dc = wx.GCDC(dc)
236 self.SetStatusText("Current player is " + ["White", "Black"][self.reversi.current==BLACK])
237 w,h = self.panel.GetSize()
238
239 # Background.
240 dc.SetBrush(wx.Brush("#228b22"))
241 dc.DrawRectangle(0,0,w,h)
242 # Grid.
243 dc.SetBrush(wx.Brush("black"))
244 px,py = w/8,h/8
245
246 for i in range(8):
247 dc.DrawLine(int(i*px),0, int(i*px), h) ###
248 dc.DrawLine(0, int(i*py), w, int(i*py)) ###
249 dc.DrawLine(w-1, 0, w-1, h-1)
250 dc.DrawLine(0, h-1, w-1, h-1)
251
252 # Stones.
253 brushes = {WHITE: wx.Brush("white"), BLACK: wx.Brush("black")}
254 for i in range(8):
255 for j in range(8):
256 c = self.reversi[i][j]
257 if c != BLANK:
258 dc.SetBrush(brushes[c])
259 dc.DrawEllipse(int(i*px), int(j*py), int(px), int(py)) ###
260
261 elif self.reversi.Available(i, j):
262 dc.SetBrush(wx.Brush("red"))
263 dc.DrawCircle(int(i*px+px/2), int(j*py+py/2), 3) ###
264
265 #---------------------------------------------------------------------------
266
267 def main():
268 app = wx.App(False)
269 frame = Frame()
270 frame.SetSize((400, 400))
271 app.MainLoop()
272
273 #---------------------------------------------------------------------------
274
275 if __name__ == '__main__':
276 main()
Towers of hanoi
First example
Readme file : hanoi_README.md
License file : hanoi_LICENSE.md
1 # towers_of_hanoi.py
2
3 """
4 The Towers of Hanoi for wxPython
5 by S. Foster, Jan. 2004
6 Link : https://code.activestate.com/recipes/577511-hanoi-towers-solver-wxpython/
7
8 Based on wxHanoi.cpp
9 By Martin Bernreuther
10 """
11
12 import wx
13
14 COLOURS = ['RED', 'CORAL', 'YELLOW', 'GREEN', 'BLUE', 'MAGENTA', 'PURPLE']
15
16 # class wxHanoiDisc
17 # class wxHanoiFrame
18 # class wxHanoiApp
19
20 #---------------------------------------------------------------------------
21
22 class wxHanoiDisc:
23 """
24 ...
25 """
26 def __init__(self, n, width, height):
27
28 #------------
29
30 self.width = (n + 1) * width
31 self.height = height
32 self.n = n
33 self.brush = wx.Brush(wx.Colour(COLOURS[n % len(COLOURS)]))
34
35 #---------------------------------------------------------------------------
36
37 class wxHanoiFrame(wx.Frame):
38 """
39 ...
40 """
41 def __init__(self, title, size):
42 style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER ^ wx.MAXIMIZE_BOX
43 wx.Frame.__init__(self, None, -1,
44 title, size=size,
45 style=style)
46
47 #------------
48
49 self.SetIcon(wx.Icon(".\icons\wxwin.ico"))
50
51 #------------
52
53 self.sleepTime = 3
54 self.numDiscs = 4
55
56 self.pen = wx.Pen(wx.Colour('BLACK'), 1, wx.SOLID)
57
58 #------------
59
60 self.CreateMenu()
61 self.CreateStatusBar()
62 self.Initialize()
63 self.BindEvents()
64
65 #------------
66
67 self.CenterOnScreen(wx.BOTH)
68 self.Show(True)
69
70 #-----------------------------------------------------------------------
71
72 def CreateMenu(self):
73 def MenuCallback(menu, item, callback):
74 id = wx.NewIdRef()
75 menu.Append(id, item)
76 self.Bind(wx.EVT_MENU, callback, id)
77
78 menuBar = wx.MenuBar()
79
80 menuFile = wx.Menu()
81 MenuCallback(menuFile, 'E&xit...\tCtrl-X', self.OnQuit)
82 menuBar.Append(menuFile, '&File')
83
84 menuPlay = wx.Menu()
85 MenuCallback(menuPlay, '&Number of Discs...', self.OnInpNumDiscs)
86 MenuCallback(menuPlay, '&Time between Moves...', self.OnInpSleepTime)
87 menuPlay.AppendSeparator()
88 MenuCallback(menuPlay, '&Play', self.OnPlay)
89 MenuCallback(menuPlay, '&Reset', self.OnReset)
90 menuBar.Append(menuPlay, '&Play')
91
92 menuHelp = wx.Menu()
93 MenuCallback(menuHelp, '&About...', self.OnAbout)
94 menuBar.Append(menuHelp, '&Help')
95
96 self.SetMenuBar(menuBar)
97
98
99 def Initialize(self):
100 self.width, self.height = self.GetClientSize()
101 maxwidth = self.width / 3
102 w = self.width / 6
103 self.xpos = [i * w for i in [1, 3, 5]]
104
105 height = self.height / self.numDiscs
106 width = maxwidth / self.numDiscs
107 if height > width:
108 height = width
109 self.discheight = height
110 self.discwidthfac = width
111
112 discs = list(range(self.numDiscs))
113 discs.reverse()
114
115 self.pegs = [[wxHanoiDisc(i, width, height) for i in discs], [], []]
116 self.moves = 0
117
118 width, height = self.GetClientSize()
119 self.Draw(wx.ClientDC(self), width, height)
120
121
122 def BindEvents(self):
123 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
124 self.Bind(wx.EVT_PAINT, self.OnPaint)
125
126
127 def OnQuit(self, event):
128 self.Close(True)
129
130
131 def OnCloseWindow(self, event):
132 self.Destroy()
133
134
135 def OnAbout(self, event):
136 wx.MessageBox(__doc__, 'About wxHanoi', wx.OK|wx.ICON_INFORMATION, self)
137
138
139 def OnInpNumDiscs(self, _event):
140 self.numDiscs = wx.GetNumberFromUser('', 'Discs:', 'Number of Discs',
141 self.numDiscs, 1, 25, self)
142 if self.numDiscs == -1:
143 self.SetStatusText("Invalid number entered or dialog cancelled.")
144 else:
145 self.Initialize()
146
147
148 def OnInpSleepTime(self, event):
149 self.sleepTime = wx.GetNumberFromUser('', 'Wait [sec/10]:', 'Time between Moves',
150 self.sleepTime, 0, 10, self)
151 if self.sleepTime == -1:
152 self.SetStatusText("Invalid number entered or dialog cancelled.")
153 else:
154 self.Initialize()
155
156
157 def OnPlay(self, event):
158 self.Initialize()
159 self.SetStatusText('Playing')
160 self.Move(0, 2, 1, self.numDiscs)
161 self.SetStatusText('Finished: %s Moves' % self.moves)
162
163
164 def OnReset(self, event):
165 self.Initialize()
166
167
168 def DrawDisc(self, dc, disc, x, y):
169 assert x <= 2
170 dc.SetPen(self.pen)
171 dc.SetBrush(disc.brush)
172 dc.DrawRectangle(int(self.xpos[x] - (disc.width / 2)),
173 int(self.height - (y * self.discheight)),
174 int(disc.width),
175 int(disc.height))
176
177
178 def Draw(self, dc, width, height):
179 mdc = wx.MemoryDC()
180 mdc.SelectObject(wx.Bitmap(width, height))
181 for x, peg in enumerate(self.pegs):
182 for y, disc in enumerate(peg):
183 self.DrawDisc(mdc, disc, x, y+1)
184 dc.Blit(0, 0, width, height, mdc, 0, 0)
185
186
187 def OnPaint(self, event):
188 width, height = self.GetClientSize()
189 self.Draw(wx.PaintDC(self), width, height)
190
191
192 def MoveDisc(self, src, dst):
193 disc = self.pegs[src].pop()
194 self.pegs[dst].append(disc)
195 self.moves += 1
196 self.SetStatusText('Move %s' % self.moves)
197 width, height = self.GetClientSize()
198 self.Draw(wx.ClientDC(self), width, height)
199 wx.MilliSleep(10 * self.sleepTime)
200
201
202 def Move(self, src, dst, temp, n):
203 if n == 1:
204 self.MoveDisc(src, dst)
205 else:
206 self.Move(src, temp, dst, n-1)
207 self.MoveDisc(src, dst)
208 self.Move(temp, dst, src, n-1)
209
210 #---------------------------------------------------------------------------
211
212 class wxHanoiApp(wx.App):
213 """
214 ...
215 """
216 def OnInit(self):
217
218 #------------
219
220 self.frame = wxHanoiFrame('Towers of Hanoi',
221 wx.Size(450, 350))
222 self.SetTopWindow(self.frame)
223
224 return True
225
226 #---------------------------------------------------------------------------
227
228 def main():
229 app = wxHanoiApp()
230 app.MainLoop()
231
232 #---------------------------------------------------------------------------
233
234 if __name__ == '__main__':
235 main()
Second example
Readme file : hanoi1_README.md
License file : hanoi1_LICENSE.md
1 # towers_of_hanoi_bis.py
2
3 """
4 The Towers of Hanoi
5
6 Author: A. Polino
7 Link : https://code.activestate.com/recipes/577511-hanoi-towers-solver-wxpython/
8 """
9
10 import wx
11 import sys
12
13 # def Gen_hanoi
14 # def Create_plates
15 # class Plate
16 # class HanoiWindow
17 # class HanoiFrame
18 # class HanoiApp
19 # class
20
21 #---------------------------------------------------------------------------
22
23 ## Make sure the windows is focused than press any button, and the program will move a plate. keep ## pressing until the problem is solved
24 ## by default it will display 5 plates. To change this, you have to call the script with a second ## argument, wich is the number of plates (max 10)
25
26 def Gen_hanoi(stack, start=1, temp=2, goal=3):
27 """
28 ...
29 """
30
31 if stack == 2:
32 yield start, temp
33 yield start, goal
34 yield temp, goal
35
36 else:
37 for x in Gen_hanoi(stack - 1, start, goal, temp):
38 yield x
39 yield start, goal
40
41 for x in Gen_hanoi(stack - 1, temp, start, goal):
42 yield x
43
44 #---------------------------------------------------------------------------
45
46 def Create_plates(num):
47 """
48 ...
49 """
50
51 assert num <= 10
52
53 x_start = 10
54 x_len = 100
55 plates = []
56
57 for x in range(num):
58 plates.append(Plate(x_len, x_start))
59 x_len -= 10
60 x_start += 5
61
62 return plates
63
64 #---------------------------------------------------------------------------
65
66 class Plate(object):
67 """
68 ...
69 """
70 def __init__(self, x_len, x_start):
71
72 #------------
73
74 self.x_len = x_len
75 self.x_start = x_start
76
77 #---------------------------------------------------------------------------
78
79 class HanoiWindow(wx.Window):
80 """
81 ...
82 """
83 def __init__(self, parent, num):
84 wx.Window.__init__(self, parent, id=-1, pos=wx.Point(0, 0),
85 size=wx.DefaultSize, style=wx.SUNKEN_BORDER|
86 wx.WANTS_CHARS|wx.FULL_REPAINT_ON_RESIZE)
87
88 #------------
89
90 self.SetBackgroundColour(wx.Colour('#eceade'))
91
92 #------------
93
94 self.BindEvents()
95
96 #------------
97
98 self.towers = [Create_plates(num), [], []]
99 self.solver = Gen_hanoi(num)
100
101 #-----------------------------------------------------------------------
102
103 def BindEvents(self):
104 self.Bind(wx.EVT_PAINT, self.OnPaint)
105 self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
106
107
108 def OnPaint(self, evt):
109 def draw_rect(x_len, x_start, y_start):
110 dc = wx.PaintDC(self)
111 font = dc.GetFont()
112 font.SetPointSize(15)
113 dc.SetFont(font)
114 size, colour = 2, wx.Colour('black')
115 dc.SetPen(wx.Pen(colour, size, wx.SOLID))
116 point = wx.Point(x_start, y_start)
117 dc.DrawLines([point, point + wx.Point(x_len, 0)])
118 dc.DrawLines([point - wx.Point(0, 5), point + wx.Point(x_len, 0) - wx.Point(0, 5)])
119 dc.DrawLines([point, point - wx.Point(0, 5)])
120 dc.DrawLines([point + wx.Point(x_len, 0), point - wx.Point(0, 5) + wx.Point(x_len, 0)])
121
122 w, h = self.GetClientSize()
123 buffer = wx.Bitmap(w, h)
124 dc = wx.PaintDC(self)
125 font = dc.GetFont()
126 font.SetPointSize(15)
127 dc.SetFont(font)
128 msg = 'Hanoi Towers'
129 w, h = dc.GetTextExtent(msg)
130 dc.DrawText(msg, 200, 20)
131 size, colour = 8, wx.Colour('black')
132 dc.SetPen(wx.Pen(colour, size, wx.SOLID))
133 for num in range(len(self.towers)):
134 y_start = 300
135 tower = self.towers[num]
136 num = num * 200 + 10
137 point = wx.Point(num, y_start)
138 dc.DrawLines([point, point + wx.Point(120, 0)]) # Base
139 # Plates
140 for plate in tower:
141 y_start -= 10
142 draw_rect(plate.x_len, num + plate.x_start, y_start)
143
144
145 def OnKeyUp(self, evt):
146 try:
147 from_, to = next(self.solver)
148 self.towers[to-1].append(self.towers[from_-1].pop())
149 self.Refresh()
150 except StopIteration:
151 wx.MessageBox('Problem Solved !', 'Problem solved', wx.OK)
152
153 #---------------------------------------------------------------------------
154
155 class HanoiFrame(wx.Frame):
156 """
157 ...
158 """
159 def __init__(self, title, num):
160 style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER ^ wx.MAXIMIZE_BOX
161 wx.Frame.__init__(self, parent=None, id=-1,
162 title=title, size=(600, 500),
163 pos=(200, 200), style=style)
164
165 #------------
166
167 self.SetIcon(wx.Icon(".\icons\wxwin.ico"))
168
169 #------------
170
171 self.Window = HanoiWindow(self, num)
172
173 #------------
174
175 self.BindEvents()
176
177 #------------
178
179 self.CenterOnScreen(wx.BOTH)
180 self.Show(True)
181
182 #-----------------------------------------------------------------------
183
184 def BindEvents(self):
185 self.Bind(wx.EVT_CLOSE, self.close_frame)
186
187
188 def close_frame(self, evt):
189 # sys.exit(0)
190 self.Destroy()
191
192 #---------------------------------------------------------------------------
193
194 class HanoiApp(wx.App):
195 """
196 ...
197 """
198 def OnInit(self):
199 if len(sys.argv) < 2:
200 num = 5
201 else:
202 num = int(sys.argv[1])
203
204 #------------
205
206 hano = HanoiFrame('Hanoi Towers', num)
207 self.SetTopWindow(hano)
208
209 return True
210
211 #---------------------------------------------------------------------------
212
213 def main():
214 app = HanoiApp()
215 app.MainLoop()
216
217 #---------------------------------------------------------------------------
218
219 if __name__ == '__main__':
220 main()
Download source
Additional Information
Link :
https://wiki.python.org/moin/GameProgramming
http://mientki.ruhosting.nl/data_www/pylab_works/pw_bricks_2d_scene.html
- - - - -
https://wiki.wxpython.org/TitleIndex
Thanks to
Jan Bodnar (tetris.py coding), Hanming Zhang (tetris_bis.py coding), Zoenberger (memory_game.py coding), Hatenablog (reversi.py coding), S. Foster (towers_of_hanoi.py coding), A. Polino (towers_of_hanoi_bis.py coding), ActiveState, the wxPython community...
About this page
Date(d/m/y) Person (bot) Comments :
19/07/20 - Ecco (Created page for wxPython Phoenix).
14/01/23 - Ecco (Updated page and "source.zip" for Python 3.10.5).
Comments
- blah, blah, blah...