Buffered painting with restart

I don't know if it's because I'm tired or what, but I can't seem to
get the "New Game" function in my card game to work. The canvas won't
refresh. All I'm doing is reinitializing all the data and classes,
but it doesn't seem to work until I use wx.ClientDC. I think that
there may be other problems in the reinitialization, but I'm not
concerned about that (however, if you want to look through it for
other bugs, please go ahead). Please excuse the mess: the comments
are all jumbled and there are a lot of direct references to far-
removed methods and such.

···

#------------------------------------------------------------------------------

#!/usr/bin/python

import wx
import sys
from whist import *

class CardPlacement:
  def __init__(self, clientSize, deckSize=26, cardsize=(73,97),
humanAmount=13, computerAmount=13):
    self.clientSize = clientSize
    self.deckSize = deckSize
    self.cardsize = cardsize
    self.amountCardscomputer = computerAmount
    self.amountCardshuman = humanAmount
    self.overlapSpace = 20
    self.computerbeginPos = (self.clientSize[0]/2 -
(self.overlapSpace*(self.amountCardscomputer-1)-self.cardsize[0]), 15)
    self.humanbeginPos = (self.clientSize[0]/2 -
(self.overlapSpace*(self.amountCardshuman-1)-self.cardsize[0]),
self.clientSize[1] - 15 - self.cardsize[1])

class CardGraphics(wx.Window):
  def __init__(self, parent):
    wx.Window.__init__(self, parent)
    self.parent = parent
    self.size = (parent.size[0], parent.size[1] - 50)
    self.backimage = wx.Image("cards/b.gif").ConvertToBitmap()
    self.InitBuffer()
    self.Bind(wx.EVT_PAINT, self.OnPaint)
    self.Bind(wx.EVT_LEFT_DOWN, self.Click)
    self.Bind(wx.EVT_LEFT_UP, self.offClick)
    self.Bind(wx.EVT_MOTION, self.Motion)
    self.dealt = False
    self.data = CardPlacement(self.size)
    self.I = False
  def updatePos(self, player):
    if player == "human":
      for i in range(len(self.parent.human.hand.cards)):
        if self.parent.human.hand.cards[i].position[1] ==
self.data.humanbeginPos[1]:
          self.parent.human.hand.cards[i].position =
(self.data.humanbeginPos[0] + i*self.data.overlapSpace,
self.data.humanbeginPos[1])
    elif player == "computer":
      for i in range(len(self.parent.computer.hand.cards)):
        if self.parent.computer.hand.cards[i].position[1] ==
self.data.computerbeginPos[1]:
          self.parent.computer.hand.cards[i].position =
(self.data.computerbeginPos[0] + i*self.data.overlapSpace,
self.data.computerbeginPos[1])
  def Click(self, evt):
    x = evt.GetX()
    y = evt.GetY()
    for i in range(len(self.parent.human.hand.cards)):
      if self.parent.human.hand.cards[i].position[0] < x <
self.parent.human.hand.cards[i].position[0]+self.data.overlapSpace and
self.parent.human.hand.cards[i].position[1] < y <
self.parent.human.hand.cards[i].position[1] +
self.parent.human.hand.cards[i].size[1] or
(i==len(self.parent.human.hand.cards)-1 and
self.parent.human.hand.cards[-1].position[0] < x <
self.parent.human.hand.cards[-1].position[0] +
self.parent.human.hand.cards[-1].size[0]):
         #select the card, but only if it is human's turn
         if self.parent.turn == "human":
           if not self.parent.first:
             available =
self.parent.human.hand.inSuit(self.parent.lead.suit)
            if not available:
              available = self.parent.human.hand.cards
            if self.parent.human.hand.cards[i] in available:
              self.parent.storeHposition =
self.parent.human.hand.cards[i].position
              self.parent.human.hand.cards[i].position = ((self.size[0] +
self.parent.human.hand.cards[i].size[0])/2.5 + 40, self.size[1]*.4)
              self.parent.Hcard = self.parent.human.hand.cards[i]
              if self.parent.Hcard.suit == self.parent.trump.suit:
                self.parent.trumpPlayed = True
              self.parent.timer.Start(1000)
              #return
            else:
              self.parent.human.hand.cards[i].inverted = True
              self.I = True
              #return
          else:
            if self.parent.human.hand.cards[i].suit !=
self.parent.trump.suit or self.parent.trumpPlayed:
              self.parent.storeHposition =
self.parent.human.hand.cards[i].position
              self.parent.human.hand.cards[i].position = ((self.size[0] +
self.parent.human.hand.cards[i].size[0])/2.5, self.size[1]*.4)
              self.parent.lead = self.parent.Hcard =
self.parent.human.hand.cards[i]
              self.parent.turn = "computer"
              self.parent.timer.Start(1000)
              #return
            else:
              self.parent.human.hand.cards[i].inverted = True
              self.I = True
              #return
           dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
          self.DrawEverything(dc)
          return

  def offClick(self, evt):
    x = evt.GetX()
    y = evt.GetY()
    if self.I == True:
      for i in range(len(self.parent.human.hand.cards)):
        if self.parent.human.hand.cards[i].inverted:
           self.parent.human.hand.cards[i].inverted = False
           self.I = False
      dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
      self.DrawEverything(dc)
  def Motion(self, evt):
    x = evt.GetX()
    y = evt.GetY()
    hitTest = False
    if self.I == True:
      for i in range(len(self.parent.human.hand.cards)):
        if self.parent.human.hand.cards[i].inverted and (not
self.data.humanbeginPos[0] < x < self.data.humanbeginPos[0] +
(len(self.parent.human.hand.cards)-1)*self.data.overlapSpace +
self.data.cardsize[0] or not self.data.humanbeginPos[1] < y <
self.data.humanbeginPos[1] + self.data.cardsize[1]):
           self.parent.human.hand.cards[i].inverted = False
           self.I = False
           dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
          self.DrawEverything(dc)
  def InitBuffer(self):
    self.buffer = wx.EmptyBitmap(*self.size)
    dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
    brush = wx.Brush((0x00, 0xaa, 0x00))
    dc.SetBackground(brush)
    dc.Clear()
  def DrawEverything(self, dc):
    brush = wx.Brush((0x00, 0xaa, 0x00))
    dc.SetBackground(brush)
    dc.Clear()
    self.DrawCards(dc, self.parent.human.hand.cards,
self.parent.computer.hand.cards)
    self.DrawDeck(dc)
  def OnPaint(self, evt):
    dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
  def DrawCards(self, dc, humanCards, computerCards):

    #print computerCards[0].position
    #print humanCards[0].position
    #draw computer cards
    if self.parent.first:
      self.DrawHumanCards(dc, humanCards)
      self.DrawComputerCards(dc, computerCards)
    else:
      self.DrawComputerCards(dc, computerCards)
      self.DrawHumanCards(dc, humanCards)

    #draw human cards
    #pass
  def DrawHumanCards(self, dc, humanCards):
    if humanCards:
      for i in range(len(humanCards)):
        cardImage = wx.Image("cards/"+Card.RANK[humanCards[i].rank]
[0]+Card.SUIT[humanCards[i].suit][0]+".gif").ConvertToBitmap()
        if humanCards[i].inverted:
          dc.SetLogicalFunction(wx.SRC_INVERT)
        else:
          dc.SetLogicalFunction(wx.COPY)
        dc.DrawBitmap(cardImage, humanCards[i].position[0],
humanCards[i].position[1])
  def DrawComputerCards(self, dc, computerCards):
    if computerCards:
      for i in range(len(computerCards)):
        if not computerCards[i].showFace:
          dc.DrawBitmap(self.backimage, computerCards[i].position[0],
computerCards[i].position[1])
        else:
          cardImage = wx.Image("cards/"+Card.RANK[computerCards[i].rank]
[0]+Card.SUIT[computerCards[i].suit][0]+".gif").ConvertToBitmap()
          dc.DrawBitmap(cardImage, computerCards[i].position[0],
computerCards[i].position[1])
  def DrawDeck(self, dc, top=None):
    #draw deck
    #print self.data.deckSize
    if self.parent.deck.deck:
      if top:
        self.top = top
      startdeck = (self.size[0]*.24, self.size[1]*.4)
      if self.data.deckSize >= 6:
        for x in range(5):
          dc.DrawBitmap(self.backimage, startdeck[0]+x*2, startdeck[1])
      else:
        for x in range(self.data.deckSize-1):
            dc.DrawBitmap(self.backimage, startdeck[0]+x*2, startdeck[1])
      face = wx.Image("cards/"+Card.RANK[self.parent.top.rank]
[0]+Card.SUIT[self.parent.top.suit][0]+".gif").ConvertToBitmap()
      dc.DrawBitmap(face, startdeck[0]+5*2, startdeck[1])

class MainWindow(wx.Frame):
  def __init__(self):
    wx.Frame.__init__(self, None, title="German Whist", size=(640,480))
    self.size = self.GetClientSizeTuple()
    self.SetMaxSize(self.size)
    self.SetMinSize(self.size)
    self.statusbar = self.CreateStatusBar()
    menuBar = wx.MenuBar()
          menu = wx.Menu()
          new = menu.Append(-1, "&New", "Start a new game")
          exit = menu.Append(-1, "E&xit", "Exit the game")
          menuBar.Append(menu, "&File")
          self.SetMenuBar(menuBar)
          self.Bind(wx.EVT_MENU, self.OnExit, exit)
          self.Bind(wx.EVT_MENU, self.newGame, new)
    self.init_all()
  def init_all(self):
    self.trumpPlayed = False
    self.first = True
    self.lead = None
    self.Hcard = None
    self.Ccard = None
    self.Hwin = None
    self.Cwin = None
    self.storeHposition = None
    self.storeCposition = None
    self.deck = Deck()
          self.human = Player(self.trumpPlayed)
          self.computer = ComputerPlayer(self.trumpPlayed)
          self.turn = "human"
          self.statusbar.SetStatusText("Your turn")
          self.Draw = CardGraphics(self)
    self.deal()
    self.Draw.dealt = True
    self.trump = self.top = self.deck.turnTop()
    self.computer.hand.organize(self.trump)
    self.human.hand.organize(self.trump)
    self.Draw.updatePos("human")
    self.Draw.updatePos("computer")
    self.Draw.data.deckSize = len(self.deck.deck) + 1
    dc = wx.BufferedDC(wx.ClientDC(self.Draw), self.Draw.buffer)
    self.Draw.DrawEverything(dc)
    self.timer = wx.Timer(self)
    self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
    self.timer.Start(1000)
  def newGame(self, evt):
    #self.deck = None
    #self.human = None
    #self.computer = None
    #self.Draw.buffer = None
    #self.Draw = None
    self.init_all()
  def OnExit(self, evt):
    self.Close()
  def OnTimer(self, evt):
    if self.turn != "human" and not self.Ccard:
      self.Ccard = self.computer.selectCard(self.lead, self.trump,
self.top)
      for i, x in enumerate(self.computer.memory.usedCards):
        if x.name == self.Ccard.name:
          del self.computer.memory.pickedUp[i]

      for i, c in enumerate(self.computer.hand.cards):
        #having problems here?
        #that's because the card is being removed from the computer hand
        #to fix it, don't remove it from the computer hand until after
        if c.name == self.Ccard.name:
          #wx.MessageBox("It's a tie.", "Game outcome", wx.OK)
          c.showFace = True
          if self.first:
            self.storeCposition = c.position
            self.computer.hand.cards[i].position = ((self.Draw.size[0] +
self.computer.hand.cards[i].size[0])/2.5 + 40, self.Draw.size[1]*.4)
            dc = wx.BufferedDC(wx.ClientDC(self.Draw), self.Draw.buffer)
            self.Draw.DrawEverything(dc)
          else:
            self.lead = self.Ccard
            self.storeCposition = c.position
            self.computer.hand.cards[i].position = ((self.Draw.size[0] +
self.computer.hand.cards[i].size[0])/2.5, self.Draw.size[1]*.4)
            self.turn = "human"
            self.statusbar.SetStatusText("Your turn")
            dc = wx.BufferedDC(wx.ClientDC(self.Draw), self.Draw.buffer)
            self.Draw.DrawEverything(dc)
    elif self.Ccard and self.Hcard:
      self.lead = None
      if self.Hcard.suit == self.Ccard.suit: #same suit
        if self.Ccard.rank > self.Hcard.rank: #higher card wins
          self.Cwin = True
          self.Hwin = False
        else:
          self.Cwin = False
          self.Hwin = True
      elif self.first:
        if self.Hcard.suit != self.trump.suit: #p1 did not trump, p0
wins regardless
          self.Cwin = True
          self.Hwin = False
        else:
          self.Cwin = False
          self.Hwin = True
      elif not self.first:
        if self.Ccard.suit != self.trump.suit: #p1 did not trump, p0
wins regardless
          self.Cwin = False
          self.Hwin = True
        else:
          self.Cwin = True
          self.Hwin = False

      if self.Cwin:
        #wx.MessageBox(self.Ccard.name+", "+self.Hcard.name+": computer is
best", "Game outcome", wx.OK)
        self.first = False
        self.turn = "computer"
        self.statusbar.SetStatusText("")
        if not self.top:
          self.computer.wonTrick()
        else:
          self.computer.receiveCard(self.top)
          self.computer.hand.cards[-1].position = self.storeCposition
          self.computer.memory.addpickedUp(self.top)
          self.human.receiveCard(self.deck.draw())
          self.human.hand.cards[-1].position = self.storeHposition

      elif self.Hwin:
        #wx.MessageBox(self.Ccard.name+", "+self.Hcard.name+": you are
best", "Game outcome", wx.OK)
        self.first = True
        self.turn = "human"
        self.statusbar.SetStatusText("Your turn")
        if not self.top:
          self.human.wonTrick()
        else:
          self.human.receiveCard(self.top)
          self.human.hand.cards[-1].position = self.storeHposition
          self.computer.receiveCard(self.deck.draw())
          self.computer.hand.cards[-1].position = self.storeCposition

      self.computer.hand.cards[-1].showFace = False
      self.computer.hand.remove(self.Ccard.name)
      self.human.hand.remove(self.Hcard.name)
      self.computer.memory.addDiscarded(self.Ccard)
      self.computer.memory.addDiscarded(self.Hcard)

      self.Cwin = None
      self.Hwin = None
      self.Ccard = None
      self.Hcard = None
      self.human.hand.organize(self.trump)
      self.computer.hand.organize(self.trump)
      self.Draw.updatePos("human")
      self.Draw.updatePos("computer")
      if self.deck.deck:
        self.top = self.deck.turnTop()
        self.Draw.data.deckSize = len(self.deck.deck) + 1
      else:
        self.statusbar.SetStatusText(self.statusbar.GetStatusText() + ": "
+ "Playing for the trick")
      dc = wx.BufferedDC(wx.ClientDC(self.Draw), self.Draw.buffer)
      self.Draw.DrawEverything(dc)
      if not self.human.hand.cards and not self.computer.hand.cards:
        if self.human.tricks > self.computer.tricks:
          wx.MessageBox("You win.", "Game outcome", wx.OK)
        elif self.computer.tricks > self.human.tricks:
          wx.MessageBox("Computer wins.", "Game outcome", wx.OK)
        else:
          wx.MessageBox("It's a tie.", "Game outcome", wx.OK)
        self.statusbar.SetStatusText("Game completed")
        self.timer.Stop()

  def deal(self):
    self.deck.shuffle()
    for i in range(13): #each player gets 13 cards
      self.human.receiveCard(self.deck.draw())
      self.Draw.data.amountCardshuman = len(self.human.hand.cards)
      self.human.hand.cards[i].position =
(self.Draw.data.humanbeginPos[0] + i*self.Draw.data.overlapSpace,
self.Draw.data.humanbeginPos[1])
      self.computer.receiveCard(self.deck.draw())
      self.Draw.data.amountCardscomputer = len(self.computer.hand.cards)
      self.computer.hand.cards[i].position =
(self.Draw.data.computerbeginPos[0] + i*self.Draw.data.overlapSpace,
self.Draw.data.computerbeginPos[1])
      self.computer.hand.cards[i].showFace = False

if __name__== "__main__":
  app = wx.PySimpleApp()
  frame = MainWindow()
  frame.Show()
  app.MainLoop()

#------------------------------------------------------------------------------

Maybe there's another way to handle this, but I can't think of
anything...

Jason Benjamin wrote:

I don't know if it's because I'm tired or what, but I can't seem to
get the "New Game" function in my card game to work. The canvas won't
refresh. All I'm doing is reinitializing all the data and classes,
but it doesn't seem to work until I use wx.ClientDC. I think that
there may be other problems in the reinitialization, but I'm not
concerned about that (however, if you want to look through it for
other bugs, please go ahead).

I don't know about bugs, but when I see this:

self.parent.human.hand.cards[i].inverted = True

I think yow! serious need for refactoring! Read up on the "Law of Demeter"

Please excuse the mess:

You really need to:

http://wiki.wxpython.org/MakingSampleApps

make it easy for us to help you!

From a glance, it looks like you should be able to call DrawEverything() with a memory DC with self.buffer, then call self.Refresh() and self.Update()

I can't say more without wading deeper through that code...

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

With the word-wrap that happened to your code it is practically useless. In the future if you want to send code to the list please attach it to the email instead of copy/pasting it.

If you're doing buffered drawing then the typical reinit sequence would be to clear your buffer, redraw everything to it in the initial state, and then do a Refresh() so a new paint event will be triggered and let your OnPaint draw the new buffer bitmap. Did you forget the refresh?

···

On 9/21/10 5:58 AM, Jason Benjamin wrote:

I don't know if it's because I'm tired or what, but I can't seem to
get the "New Game" function in my card game to work. The canvas won't
refresh. All I'm doing is reinitializing all the data and classes,
but it doesn't seem to work until I use wx.ClientDC. I think that
there may be other problems in the reinitialization, but I'm not
concerned about that (however, if you want to look through it for
other bugs, please go ahead). Please excuse the mess: the comments
are all jumbled and there are a lot of direct references to far-
removed methods and such.

--
Robin Dunn
Software Craftsman