def __init__(self, parent=None, rows=1, cols=1, mines=[]): """ Initialize the grid of mine tiles and the game parameters. """ super().__init__() # reference to the parent object self.parent = parent # define the rows and columns self.rows = rows self.cols = cols # the randomised list of mines self.nmines = mines.count(True) self.mines = mines self.exploded = False # if a bomb has been hit self.gameOver = False # flag for game over - used for cleardown # tally of exposed minefield squares self.exposed = 0 # the number of flags in use self.flags = 0 # tally of number of hints requested self.hints = 0 # a convenient way to keep a reference to all the buttons self.buttons = list() # try to fix the aspect ratio of the grid by using an AspectFrame self.frame = Gtk.AspectFrame(label=None, xalign=0.5, yalign=0.5, ratio=self.cols / self.rows, obey_child=False) self.add(self.frame) # define the grid for the game # TODO: change constructor on upgrade to Ubuntu 12.10 # self.grid = Gtk.Grid() self.grid = Grid() self.grid.set_column_homogeneous(True) self.grid.set_row_homogeneous(True) self.frame.add(self.grid) self.createWidgets()
class GridWindow(Gtk.Frame): """ This class defines the layout of the grid buttons for the game. """ def __init__(self, parent=None, rows=1, cols=1, mines=[]): """ Initialize the grid of mine tiles and the game parameters. """ super().__init__() # reference to the parent object self.parent = parent # define the rows and columns self.rows = rows self.cols = cols # the randomised list of mines self.nmines = mines.count(True) self.mines = mines self.exploded = False # if a bomb has been hit self.gameOver = False # flag for game over - used for cleardown # tally of exposed minefield squares self.exposed = 0 # the number of flags in use self.flags = 0 # tally of number of hints requested self.hints = 0 # a convenient way to keep a reference to all the buttons self.buttons = list() # try to fix the aspect ratio of the grid by using an AspectFrame self.frame = Gtk.AspectFrame(label=None, xalign=0.5, yalign=0.5, ratio=self.cols / self.rows, obey_child=False) self.add(self.frame) # define the grid for the game # TODO: change constructor on upgrade to Ubuntu 12.10 # self.grid = Gtk.Grid() self.grid = Grid() self.grid.set_column_homogeneous(True) self.grid.set_row_homogeneous(True) self.frame.add(self.grid) self.createWidgets() def createWidgets(self): """ Make up the grid of buttons for the game. """ for x in range(self.cols): for y in range(self.rows): # grid button button = GridButton(parent=self, pos=(x, y), mined=self.mines.pop()) self.grid.attach(button, x, y, 1, 1) self.buttons.append(button) def start(self): """ Prepare the grid before the player starts pressing buttons... """ # work out the neighbour bomb counts for this game for button in self.buttons: button.updateNeighbourMines() def incrementExposedCount(self, increment): """ Every time a button is exposed increment the count. When the count is big enough the game has been won. """ # no count required during cleardown if self.gameOver: return self.exposed += increment self.parent.exposedCount.set_text(str(self.exposed)) # test if we have won self.haveWeWonYet() def updateFlags(self, increment): """ Increment or decrement the count of flags used when notified of a change. The Boolean increment argument determines whether we add or remove from the tally. """ if increment: self.flags += 1 else: self.flags -= 1 self.parent.flagCount.set_text(str(self.flags)) # test if we have won if not self.gameOver: self.haveWeWonYet() def haveWeWonYet(self): """ Have we won yet? """ if self.exploded: self.endGame(False) elif not ((self.rows * self.cols) - (self.flags + self.exposed)) \ and not (self.flags - self.nmines): self.endGame(True) def endGame(self, success): """ Finish the game. """ self.gameOver = True # avoids recursion issues during cleardown # clear down the grid for button in self.buttons: if button.exposed: continue elif button.flagged: if button.mined: # button correctly flagged button.set_sensitive(False) else: # incorrect flag - remove it button.flagged = False button.set_active(True) self.updateFlags(False) button.leftMouse(button) else: # 'press' the button button.leftMouse(button) # update the start button image if success: updateImage(self.parent.startImage, 'Win', TOOL_SIZE) else: updateImage(self.parent.startImage, 'Lose', TOOL_SIZE) # update the sensitivity of the other toolbar buttons self.parent.hintButton.set_sensitive(False) self.parent.pbcButton.set_sensitive(True) self.parent.configurationBox.set_button_sensitivity( Gtk.SensitivityType.ON) def giveHint(self): """ Find an unplayed, unmined button near a played button and reveal it. """ # get a randomised list of all the buttons buttons = self.buttons[:] random.shuffle(buttons) # find an unplayed, unmined button for button in buttons: if button.mined or button.exposed or button.flagged: continue # if this is not the start of the game check the button's neighbours if (self.flags + self.exposed): for neighbour in button.neighbourList: if neighbour.exposed or neighbour.flagged: button.leftMouse(button) # increment hint count self.hints += 1 self.parent.hintCount.set_text(str(self.hints)) return # at the start of the game no need to check neighbours else: # look for a button with no neighbour mines if not button.neighbourMines: # left-click the button button.leftMouse(button) return def resize(self, allocation): """ Defines the resize behaviour of the button grid. The allocation is taken from the gridContainer in the parent window. """ # work out the best size for the grid buttons gridWidth = allocation.width gridHeight = allocation.height # subtracting 14 allows for margins and borders on the grid buttons. imageWidth = gridWidth // self.cols - 14 imageHeight = gridHeight // self.rows - 14 imageSize = min(imageWidth, imageHeight) # now tell the buttons to sort themselves out for button in self.buttons: button.resize((imageSize, imageSize))