Information about the Thornsweeper game can be found at http://en.wikipedia.org/wiki/Minesweeper_(computer_game)
Create the cells
After the first click place thorns in random locations
Assign number of adjacent thorns to each cell
Game over you won
Let the user mark the thorns by right clicking on them
Create a button to restart the game
def createGrid(gridSize):
rectangle(x=8.24776481523, y=4.94865888914, width=2.29910592609, height=2.29910592609,
name='rectangle1', alias='r1', fillColor=color.grey)
return Grid(obj=rectangle1, rows=gridSize, cols=gridSize, pos=rectangle1.pos)
To test the createGrid use the Python interpreter as shown below.
>>> createGrid(10)
def placeThorns(grid, clickedCell, nThorns, gridSize):
for cell in grid.cells:
cell.thorn = False
choices = range(gridSize)
thorns = 0
while thorns < nThorns:
cell = grid.getCell(random.choice(choices), random.choice(choices))
if cell == clickedCell:
continue
if not cell.thorn:
cell.thorn = True
thorns += 1
To test the placeThorns use the Python interpreter as shown below.
>>> gridSize = 10
>>> nThorns = 15
>>> grid = createGrid(gridSize)
>>> placeThorns(grid, grid.getCell(0, 0), nThorns, gridSize)
>>> for cell in grid.cells:
... if cell.thorn:
... cell.label = 'X'
...
def assignThornNumbers(grid):
for cell in grid.cells:
cell.nThorns = len([x for x in cell.allNeighbors if x.thorn])
To test the assignThornNumbers function we will create a function called revealAll to display the locations of the thorns as well as the number of thorns in the neighboring cells.
def revealAll(grid):
for cell in grid.cells:
if cell.thorn:
cell.label = 'X'
elif cell.nThorns:
cell.label = str(cell.nThorns)
Now we can test the assignThornNumbers function from the interpreter.
>>> gridSize = 10
>>> grid = createGrid(gridSize)
>>> clickedCell = grid.getCell(0, 0)
>>> placeThorns(grid, clickedCell, 15, 10)
>>> assignThornNumbers(grid)
>>> revealAll(grid)
We are going to follow our outline (with minor adjustments) here. A user click is either the first click or not. In these kind of binary situations we can use a flag to retain the desired state information. We are going to name our flag as firstClik and initialize its value to True. Then in the onClick function change its value appropriately as shown below.
firstClick = True
def onClick(event, source):
global firstClick
if firstClick:
placeThorns(grid, source, nThorns, gridSize)
assignThornNumbers(grid)
firstClick = False
reveal(cell)
for cell in grid.cells:
cell.bind(LEFTDOWNON, onClick)
Note
Mekanimo’s event binding mechanism requires the bound function’s first two arguments to be event and source.
Before we can test this, we need to create the reveal function and keep track of firstClick variable.
def reveal(cell):
if cell.thorn:
revealAll()
cell.fillColor = color.red
msgBox('Ouch')
else:
cell.fillColor = color.yellow
if cell.nThorns:
cell.label = str(cell.nThorns)
else:
displayConnectedZeros(cell)
if won():
msgBox('Congratulations!')
def won():
for cell in grid.cells:
if not cell.thorn:
if cell.fillColor != color.yellow:
return False
return True
This is the most interesting part of the whole program and may be worth paying some extra attention especially for beginners.
def findConnectedZeros(cell):
queue = [cell]
zeroes = [ ]
while queue:
curCell = queue.pop()
zeroes.append(curCell)
for zero in [x for x in curCell.allNeighbors if x.nThorns == 0]:
if zero not in zeroes and zero not in queue:
queue.append(zero)
return zeroes
To test the findConnectedZeros function use the Python interpreter as shown below. The results of this test is shown in Figure 4.
>>> gridSize = 10
>>> grid = createGrid(gridSize)
>>> clickedCell = grid.getCell(0, 0)
>>> placeThorns(grid, clickedCell, 15, 10)
>>> assignThornNumbers(grid)
>>> revealAll(grid)
>>> zeroes = findConnectedZeros(grid.getCell(5, 0))
>>> for cell in zeroes:
... cell.fillColor = color.yellow
...
Now we know how to get the connected zeroes the next action is to display these cells as well as their neighbors (colored orange in Figure 5 for clarity).
def displayConnectedZeroes(cell):
zeroes = findConnectedZeroes(cell)
processed = [ ]
for zero in zeroes:
for neighbor in zero.allNeighbors:
if neighbor not in processed:
neighbor.fillColor = color.yellow
if neighbor.nThorns:
neighbor.label = str(neighbor.nThorns)
processed.append(neighbor)
To test the displayConnectedZeroes function use the Python interpreter as shown below. The results of this test is shown in Figure 6.
>>> def testGrid(gridSize):
... grid = createGrid(gridSize)
... placeThorns(grid, clickedCell)
... assignThornNumbers(grid)
... revealAll(grid)
... return grid
...
>>> grid = testGrid(10)
>>> clickedCell = grid.getCell(9, 0)
>>> displayConnectedZeroes(clickedCell)
def onRightClick(event, source):
if source.fillColor == color.grey:
source.label = '' if source.label == 'X' else 'X'
for cell in grid.cells:
cell.bind(RIGHTDOWNON, onRightClick)
def newGame(event, source):
for cell in grid.cells:
cell.label = ''
cell.fillColor = color.grey
firstClick = True
rectangle()
rectangle2.bind(LEFTDOWNON, newGame)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | cellColor = color.grey
revealedColor = color.yellow
thornLabel = 'X'
gridSize = 10
nThorns = 15
def createGrid(gridSize):
rectangle(x=8, y=5, width=2.5, height=2.5, name='rectangle1', alias='r1',
fillColor=cellColor)
return Grid(rectangle1, gridSize, gridSize, pos=rectangle1.pos)
def placeThorns(grid, clickedCell, nThorns, gridSize):
for cell in grid.cells:
cell.thorn = False
choices = range(gridSize)
thorns = 0
while thorns < nThorns:
cell = grid.getCell(random.choice(choices), random.choice(choices))
if cell == clickedCell:
continue
if not cell.thorn:
cell.thorn = True
thorns += 1
def assignThornNumbers(grid):
for cell in grid.cells:
cell.nThorns = len([x for x in cell.allNeighbors if x.thorn])
def findConnectedZeroes(cell):
queue = [cell]
zeroes = [ ]
while queue:
curCell = queue.pop()
zeroes.append(curCell)
for zero in [x for x in curCell.allNeighbors if x.nThorns == 0]:
if zero not in zeroes and zero not in queue:
queue.append(zero)
return zeroes
def displayConnectedZeroes(cell):
zeroes = findConnectedZeroes(cell)
processed = [ ]
for zero in zeroes:
for neighbor in zero.allNeighbors:
if neighbor not in processed:
neighbor.fillColor = revealedColor
neighbor.label = str(neighbor.nThorns) if neighbor.nThorns else ""
processed.append(neighbor)
def revealAll():
for cell in grid.cells:
if cell.thorn:
cell.label = thornLabel
else:
cell.fillColor = revealedColor
cell.label = str(cell.nThorns) if cell.nThorns else ""
def onClick(event, source):
global firstClick
if firstClick:
placeThorns(grid, source, nThorns, gridSize)
assignThornNumbers(grid)
firstClick = False
if source.label != thornLabel:
reveal(source)
def onRightClick(event, source):
if source.fillColor == cellColor:
source.label = '' if source.label == thornLabel else thornLabel
def reveal(cell):
if cell.thorn:
revealAll()
cell.fillColor = color.red
msgBox('Ouch')
else:
cell.fillColor = revealedColor
if cell.nThorns:
cell.label = str(cell.nThorns) if cell.nThorns else ''
else:
displayConnectedZeroes(cell)
if won():
msgBox('Congratulations!')
def won():
for cell in grid.cells:
if not cell.thorn:
if cell.fillColor != revealedColor:
return False
return True
def newGame(event, source):
global firstClick
for cell in grid.cells:
cell.label = ''
cell.fillColor = cellColor
firstClick = True
system.zeroGravity = True
rectangle(x=42.3128547401, y=4.70541933018, width=7.47120015784, height=2.22699235474,
name='restartButton', alias='r101', fillColor=(119, 187, 238, 150))
restartButton.label = 'New Game'
restartButton.bind(LEFTDOWNON, newGame)
grid = createGrid(gridSize)
for cell in grid.cells:
cell.bind(LEFTDOWNON, onClick)
cell.bind(RIGHTDOWNON, onRightClick)
firstClick = True
|