IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

pyReversi


précédentsommairesuivant

IX. wxReversi.py

Vous pouvez visualiser le contenu du fichier en cliquant sur le lien wxReversi.py.

Ce fichier contient deux classes wxPlate et wxReversi. La première permet de gérer uniquement le plateau de jeu, la deuxième le reste de l'interface graphique. Vous aurez avec ce fichier un bel exemple d'utilisation de la bibliothèque wxPython.

IX-1. La classe wxPlate

wxPlate gère le plateau de jeu à travers un wx.BufferedDC et wx.BufferedPaintDC. Il existe plusieurs façons de dessiner à l'écran sans que celui-ci soit saccadé. Ici, ce couple est adapté, car on se contente de dessiner à l'écran l'état du plateau sans qu'il y ait d'interaction avec l'utilisateur. Pour mettre cette classe en place, je me suis servi d'un des exemples du livre wxPython in Action que je recommande fortement si vous souhaitez rapidement progresser avec cette bibliothèque. Le tout consiste à dessiner la totalité du plateau de jeu dans un buffer de type wx.BufferedDC puis de l'afficher à l'écran avec un wx.BufferedPaintDC.
Les attributs de la classe wxPlate :

  • parent : parent de type wxReversi ;
  • btmplate : Bitmap du plateau de jeu vide ;
  • btmwhite : Bitmap d'un pion blanc ;
  • btmblack : Bitmap d'un pion noir ;
  • reversi : pointeur sur une instance de Reversi.Reversi pour avoir un accès complet au jeu.

Les méthodes de la classe wxPlate :

  • __init__(self, parent, reversi) : constructeur initialisant les paramètres et affichant le plateau de jeu initial ;
  • OnPaint(self, event = None) : dessine à l'écran le buffer du plateau de jeu lorsqu'un rafraîchissement de l'écran est demandé ;
  • Redraw(self) : permet de forcer le rafraîchissement du plateau à l'écran ;
  • InitBuffer(self) : crée en mémoire le buffer du plateau de jeu avant le dessiner dedans ;
  • DoDrawing(self, dc) : remplit le buffer de la fenêtre du plateau de jeu.

Finalement, le code de cette classe est relativement court et très facile à lire. Dans la fonction InitBuffer, on crée tout d'abord un bitmap vide de la taille du plateau de jeu à l'écran. On va ensuite gérer ce bitmap à travers un wx.BufferedDC dans lequel on dessine le plateau de jeu.
On affiche tout d'abord la grille du plateau ( dc.DrawBitmap(self.btmplate, 0, 0, False) ). On le remplit ensuite avec les différents pions présents sur le plateau.

 
Sélectionnez
class wxPlate(wx.Window):
    """ Created: 2007.10.25 - Updated: 2008.01.08 """
    def __init__(self, parent, reversi):
        """ Created: 2007.10.25 - Updated: 2008.01.08 """
        wx.Window.__init__(self, parent, -1, size = (338, 338))
        self.parent = parent
        self.btmplate = wx.Image('.' + os.sep + 'images' + os.sep + "plate.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap()
        self.btmwhite = wx.Image('.' + os.sep + 'images' + os.sep + "white.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap()
        self.btmblack = wx.Image('.' + os.sep + 'images' + os.sep + "black.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap()
        self.reversi = reversi
        self.InitBuffer()
        self.Bind(wx.EVT_PAINT, self.OnPaint)

    def OnPaint(self, event = None):
        """ Created: 2007.10.25 - Updated: 2008.01.08 """
        dc = wx.BufferedPaintDC(self, self.buffer)

    def Redraw(self):
        """ Created: 2007.10.25 - Updated: 2008.01.08 """
        self.InitBuffer()

    def InitBuffer(self):
        """ Created: 2007.10.25 - Updated: 2008.01.08 """
        self.buffer = wx.EmptyBitmap(338, 338)
        dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
        self.DoDrawing(dc)

    def DoDrawing(self, dc):
        """ Created: 2007.10.25 - Updated: 2008.01.08 """
        dc.Clear()
        dc.DrawBitmap(self.btmplate, 0, 0, False)
        for i in range(1, 9):
            for j in range(1, 9):
                if self.reversi.plate[i*10+j] == 1: dc.DrawBitmap(self.btmblack, 2 + 42 * (j-1), 2 + 42 * (i-1), False)
                elif self.reversi.plate[i*10+j] == 2: dc.DrawBitmap(self.btmwhite, 2 + 42 * (j-1), 2 + 42 * (i-1), False)

IX-2. La classe wxReversi

Comme je ne suis pas fan d'éditeur spécialisé aux IHM, toute l'interface graphique a été créée à la main. Mais cela se fait vraiment très bien une fois qu'on a un peu l'habitude. La classe wxReversi possède une barre de menu ( wx.MenuBar, wx.Menu, wx.MenuItem) et des widgets classiques (wx.StaticText, wx.Gauge, wx.ListBox, wx.Timer). L'agencement des widgets est réalisé à travers des wx.BoxSizer, wx.StaticBox et wx.StaticBoxSizer.

Il vous suffira de lire linéairement la fonction __init__(self, reversi) pour comprendre comment l'interface est construite.
Cette classe possède de nombreuses méthodes qui correspondent toutes à des évènements depuis la barre de menu sauf les deux fonctions pnlPlateLDown(self, event) et pnlPlateMove(self, r, score)). Là encore, vous devriez tout comprendre après une simple lecture du code. Nous allons simplement nous attarder sur ces deux dernières méthodes qui gèrent la pose d'un pion par un joueur humain ( pnlPlateLDown ) ou par un ordinateur (pnlPlateMove)

IX-2-1. pnlPlateLDown(self, event)

Un joueur humain joue son tour de jeu en cliquant avec la souris sur la case sur laquelle il veut poser un pion. On vérifie ainsi tout d'abord qu'un clic correspond bien à un joueur humain qui a la main. On récupère ensuite la case cliquée (X = event.X // 42 + 1 et Y = event.Y // 42 + 1). Si la case cliquée est une case jouable ( TestLeClic(self.reversi.plate, Y*10+ X, self.reversi.playermain.joueur) ), on pose le pion et on change le tour de jeu ( self.reversi.ChangePlayerMain() )

 
Sélectionnez
    def pnlPlateLDown(self, event):
        if (self.reversi.playermain.joueur == 1 and isinstance(self.reversi.player1, Player.Player)) \
        or (self.reversi.playermain.joueur == 2 and isinstance(self.reversi.player2, Player.Player)):
            X = event.X // 42 + 1
            Y = event.Y // 42 + 1

            if TestLeClic(self.reversi.plate, Y*10+ X, self.reversi.playermain.joueur):
                self.timerWhite.Stop()
                self.timerBlack.Stop()
                Reverse(self.reversi.plate, Y*10+ X, self.reversi.playermain.joueur)
                b, w = Score(self.reversi.plate)
                self.lbMove.InsertItems([str(b+w) + '. ' + self.reversi.playermain.couleur.upper()[0] + " - " + chr(64+X) + " "+str(9-Y) + "  0"], 0)
                self.pnlPlate.Redraw()
                self.reversi.lastMove = Y * 10 + X
                glovar['freemove'].remove(Y * 10 + X)
                glovar['platemove'].append(Y * 10 + X)
                self.reversi.ChangePlayerMain()
            event.Skip()

IX-2-2. pnlPlateMove(self, r, score)

Un ordinateur effectue son coup en appelant la fonction pnlPlateMove. Le premier test (TestLeClic(self.reversi.plate, r, self.reversi.playermain.joueur)) n'est utile que pour éviter des effets de bords quand on relance une partie. Le reste de la fonction est identique à ce qu'on peut avoir pour un joueur humain.

 
Sélectionnez
   def pnlPlateMove(self, r, score):
        if TestLeClic(self.reversi.plate, r, self.reversi.playermain.joueur):
            self.timerWhite.Stop()
            self.timerBlack.Stop()            
            Reverse(self.reversi.plate, r, self.reversi.playermain.joueur)
         
            b, w = Score(self.reversi.plate)
            Y, X = divmod(r, 10)
            self.reversi.lastMove = r
            glovar['freemove'].remove(r)
            glovar['platemove'].append(r)
            self.lbMove.InsertItems([str(b+w) + '. ' + self.reversi.playermain.couleur.upper()[0] + " - " + chr(64+X) + " "+str(9-Y) + "  "+str(score)], 0)
            
            self.pnlPlate.Redraw()
            self.reversi.ChangePlayerMain()

précédentsommairesuivant

Copyright © 2008 Guillaume Duriaud. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.