# puzzle_game.pyw game by leonardo maffi, v.1.3, Sep 14 2005. # Requires the Python interterpreter import Tkinter, random, tkMessageBox class GameButton(object): movesCount = 0 # class variables firstError = True hole = 0 correctPositions = range(1, 16) + [hole] def __init__(self, parent, value): self.button = Tkinter.Button(parent, width=3, command=self.manageClick) self.set(value) self.button.grid(column=value%4, row=value/4) def set(self, value): self.value = value if value == GameButton.hole: self.label = "" relief = "flat" else: self.label = str(value) relief = "raised" self.button.configure(text=self.label, relief=relief) def _holeToMove(self, pos): posRow = pos // 4 posCol = pos % 4 for r,c in (posRow-1,posCol), (posRow+1,posCol), (posRow,posCol-1), (posRow,posCol+1): if 4>r>=0 and 4>c>=0 and buttons[c+r*4].value==GameButton.hole: return c+r*4 def manageClick(self): moveFrom = buttons.index(self) moveTo = self._holeToMove(moveFrom) if moveTo is None and GameButton.firstError: tkMessageBox.Message(icon='error', type='ok', message=gameRules, title='Error').show() GameButton.firstError = False if moveTo is not None: GameButton.movesCount += 1 oldLabel = self.label buttons[moveTo].set(self.value) self.set(GameButton.hole) if [b.value for b in buttons] == GameButton.correctPositions: endingMessage = "You completed the puzzle in %s moves" % GameButton.movesCount tkMessageBox.Message(type='ok', message=endingMessage, title='Game finished').show() scrambleButtonsAndReset() def scrambleButtonsAndReset(): # Generate a SOLVABLE random disposition (move parity must be correct) randomPositions = list(GameButton.correctPositions) holePosition = 15 for i in xrange(500): posR = holePosition // 4 posC = holePosition % 4 positions = (posR-1,posC), (posR+1,posC), (posR,posC-1), (posR,posC+1) # Here a repeat-until can be quite useful: ro,co = random.choice( positions ) while not( 4>ro>=0 and 4>co>=0 ): ro,co = random.choice( positions ) move = co + ro*4 # Swap randomPositions[holePosition], randomPositions[move] = randomPositions[move], randomPositions[holePosition] holePosition = move # randomPositions = range(1,15) + [0, 15] # For game end testing. for n,button in enumerate(buttons): button.set(randomPositions[n]) GameButton.movesCount = 0 gameRules = """Click on a button next to the empty space to move it into that space. Do this until all buttons are in order and the hole is the last one.""" root = Tkinter.Tk() root.title("Puzzle game") buttons = [GameButton(root, bu) for bu in range(16)] root.resizable(0,0) scrambleButtonsAndReset() root.mainloop()