You are not logged in.
from tkinter import *
from tkinter import ttk
from random import sample
setWidth = 10
setHeight = 10
numberOfMines = 10
def createBoard(sWidth, sHeight):
for y in range(0, sHeight):
for x in range(0, sWidth):
# border images -- setHeight and setWidth have 1 subtracted (set*-1),
# so that they are placed correctly...
if x == 0 and y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgTL)
elif x == 0 and y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgBL)
elif x == sWidth-1 and y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgTR)
elif x == sWidth-1 and y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgBR)
elif x == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgL)
elif x == sWidth-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgR)
elif y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgT)
elif y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgB)
# main squares covering mines
else:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=SqImgU, activeimage=SqImgA, disabledimage=SqImg0)
def generateMines(sWidth, sHeight, numMines):
mineList = sample((fieldCanvas.find_enclosed(25, 25, (sWidth-1)*25, (sHeight-1)*25)), numMines)
for mine in mineList:
fieldCanvas.itemconfigure(mine, tag='mine')
def bindSquares(sWidth, sHeight):
for square in fieldCanvas.find_enclosed(25, 25, (sWidth-1)*25, (sHeight-1)*25):
fieldCanvas.tag_bind(square, '<Enter>', squareCheck())
def squareReveal(event):
sqImgResult = squareCheck(event)
sWidth = setWidth*25
sHeight = setHeight*25
if event.x in range(25, sWidth*25) and event.y in range(25, sHeight*25):
fieldCanvas.itemconfigure((fieldCanvas.find_closest(event.x, event.y)), state=DISABLED, disabledimage=sqImgResult)
def squareCheck(event):
# sqID is the ID of the object clicked on.
sqID = int((fieldCanvas.find_closest(event.x, event.y))[0])
#***IF SELECTED SQUARE IS A MINE***
if 'mine' in fieldCanvas.gettags(sqID):
sqImgResult = SqImgM
return sqImgResult
#***IF SELECTED SQUARE HAS MINES ADJACENT TO IT***
s = setWidth
surroundingSquares = []
surroundingSquares.extend([sqID, sqID-s-1, sqID-s, sqID-s+1, sqID+1, sqID+s+1, sqID+s, sqID+s-1, sqID-1])
surroundingTags = []
for square in surroundingSquares:
surroundingTags.append(fieldCanvas.gettags(square))
surroundingMineCount = 0
for tags in surroundingTags:
if 'mine' in tags:
surroundingMineCount += 1
if surroundingMineCount > 0:
variableDict = {
'SqImg1': SqImg1,
'SqImg2': SqImg2,
'SqImg3': SqImg3,
'SqImg4': SqImg4,
'SqImg5': SqImg5,
'SqImg6': SqImg6,
'SqImg7': SqImg7,
'SqImg8': SqImg8
}
sqImgResult = variableDict['SqImg%s' % (surroundingMineCount)]
return sqImgResult
#***IF SELECTED SQUARE HAS NO ADJACENT MINES***
else:
#need to clear surrounding squares....
sqImgResult = SqImg0
return sqImgResult
root = Tk()
root.title('SnakeSweeper')
fieldFrame = ttk.Frame(root, padding='0')
fieldFrame.grid(column=0, row=2, sticky='nesw')
SqImgU = PhotoImage(file='SqImgU.gif')
SqImgA = PhotoImage(file='SqImgA.gif')
SqImgM = PhotoImage(file='SqImgM.gif')
SqImg0 = PhotoImage(file='SqImg0.gif')
SqImg1 = PhotoImage(file='SqImg1.gif')
SqImg2 = PhotoImage(file='SqImg2.gif')
SqImg3 = PhotoImage(file='SqImg3.gif')
SqImg4 = PhotoImage(file='SqImg4.gif')
SqImg5 = PhotoImage(file='SqImg5.gif')
SqImg6 = PhotoImage(file='SqImg6.gif')
SqImg7 = PhotoImage(file='SqImg7.gif')
SqImg8 = PhotoImage(file='SqImg8.gif')
# BdrImg's are numbered clockwise starting from the top left.
BdrImgT = PhotoImage(file='BdrImgT.gif')
BdrImgR = PhotoImage(file='BdrImgR.gif')
BdrImgB = PhotoImage(file='BdrImgB.gif')
BdrImgL = PhotoImage(file='BdrImgL.gif')
BdrImgTR = PhotoImage(file='BdrImgTR.gif')
BdrImgBR = PhotoImage(file='BdrImgBR.gif')
BdrImgBL = PhotoImage(file='BdrImgBL.gif')
BdrImgTL = PhotoImage(file='BdrImgTL.gif')
fieldCanvas = Canvas(fieldFrame, width=(setWidth*25), height=(setHeight*25))
fieldCanvas.grid(column=0, row=0, sticky='nesw')
createBoard(setWidth, setHeight)
#bindSquares(setWidth, setHeight)
generateMines(setWidth, setHeight, numberOfMines)
fieldCanvas.tag_bind(CURRENT, '<Button-1>', squareReveal)
root.mainloop()
lacking most features, but! im doing pretty good so far. code has NOT been cleaned, so lots of useless characters/repetition... and like i said, many features are missing, so there are placeholders for testing (setWidth, numberOfMines, etc.)
i've run into a slight major problem . how would i go about automatically clearing empty mine squares after one (empty one) has been clicked? i can make it clear the ones adjacent, but i need it to clear in all directions as far as possible... any ideas? i assume i'll need some sort of an 'until' function...?
btw if you wanted to see it border images unfinished. pretty snazzy for tk.
Last edited by jtkiv (2011-03-25 20:46:44)
Offline
Nice graphics. Make a recursive function.
Offline
It's easily implemented recursively. You have a function clear(L) that takes a grid location L as a parameter. First, set the square at L to cleared. Then, for each location L' adjacent to L at which the number of adjacent mines is 0, call clear(L').
// stqn got it.
Last edited by Peasantoid (2011-03-25 21:26:07)
Offline
It is easily done iteratively too, when an empty square is cleared mark it's unclear neigbours, then in a loop clear all marked squares as well as
marking the unclear neighbours of any newly cleared empty squares. Iterate until you have no marked squares.
Last edited by tlvb (2011-03-26 00:07:12)
I need a sorted list of all random numbers, so that I can retrieve a suitable one later with a binary search instead of having to iterate through the generation process every time.
Offline
in the works...
from tkinter import *
from tkinter import ttk
from random import sample
setWidth = 50
setHeight = 20
numberOfMines = 100
def createBoard(sWidth, sHeight):
for y in range(0, sHeight):
for x in range(0, sWidth):
# border images -- setHeight and setWidth have 1 subtracted (set*-1),
# so that they are placed correctly...
if x == 0 and y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgTL)
elif x == 0 and y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgBL)
elif x == sWidth-1 and y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgTR)
elif x == sWidth-1 and y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgBR)
elif x == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgL)
elif x == sWidth-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgR)
elif y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgT)
elif y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgB)
# main squares covering mines
else:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=SqImgU, activeimage=SqImgA, disabledimage=SqImg0)
def generateMines(sWidth, sHeight, numMines):
mineList = sample((fieldCanvas.find_enclosed(25, 25, (sWidth-1)*25, (sHeight-1)*25)), numMines)
for mine in mineList:
fieldCanvas.itemconfigure(mine, tag='mine')
def bindSquares(sWidth, sHeight):
for square in fieldCanvas.find_enclosed(25, 25, (sWidth-1)*25, (sHeight-1)*25):
fieldCanvas.tag_bind(square, '<Enter>', squareCheck())
def squareReveal(event):
sqID = int((fieldCanvas.find_closest(event.x, event.y))[0])
sqImgResult = squareDirect(sqID)
sWidth = setWidth*25
sHeight = setHeight*25
if event.x in range(25, sWidth*25) and event.y in range(25, sHeight*25):
fieldCanvas.itemconfigure((fieldCanvas.find_closest(event.x, event.y)), state=DISABLED, disabledimage=sqImgResult)
def squareDirect(sqID):
print(sqID)
if 'mine' in fieldCanvas.gettags(sqID):
return squareClear('M')
else:
return squareCheck(sqID)
def squareCheck(sqID):
print(sqID)
s = setWidth
surroundingSquares = []
surroundingSquares.extend([sqID-s-1, sqID-s, sqID-s+1, sqID+1, sqID+s+1, sqID+s, sqID+s-1, sqID-1])
surroundingTags = []
for square in surroundingSquares:
surroundingTags.append(fieldCanvas.gettags(square))
surroundingMineCount = 0
for tag in surroundingTags:
if 'mine' in tag:
surroundingMineCount += 1
if surroundingMineCount == 0:
emptySquares(surroundingSquares)
return squareClear(surroundingMineCount)
else:
return squareClear(surroundingMineCount)
def squareClear(mineCount):
variableDict = {
'SqImgM': SqImgM,
'SqImg0': SqImg0,
'SqImg1': SqImg1,
'SqImg2': SqImg2,
'SqImg3': SqImg3,
'SqImg4': SqImg4,
'SqImg5': SqImg5,
'SqImg6': SqImg6,
'SqImg7': SqImg7,
'SqImg8': SqImg8
}
sqImgResult = variableDict['SqImg%s' % (mineCount)]
return sqImgResult
def emptySquares(surroundingSquares):
for square in surroundingSquares:
squareDirect(square)
#fieldCanvas.itemconfigure(square, state=DISABLED, disabledimage=SqImg0)
#funcSqId = sqID
#fieldCanvas.itemconfigure(funcSqId, state=DISABLED, disabledimage=SqImg0)
root = Tk()
root.title('SnakeSweeper')
fieldFrame = ttk.Frame(root, padding='0')
fieldFrame.grid(column=0, row=2, sticky='nesw')
SqImgU = PhotoImage(file='SqImgU.gif')
SqImgA = PhotoImage(file='SqImgA.gif')
SqImgM = PhotoImage(file='SqImgM.gif')
SqImg0 = PhotoImage(file='SqImg0.gif')
SqImg1 = PhotoImage(file='SqImg1.gif')
SqImg2 = PhotoImage(file='SqImg2.gif')
SqImg3 = PhotoImage(file='SqImg3.gif')
SqImg4 = PhotoImage(file='SqImg4.gif')
SqImg5 = PhotoImage(file='SqImg5.gif')
SqImg6 = PhotoImage(file='SqImg6.gif')
SqImg7 = PhotoImage(file='SqImg7.gif')
SqImg8 = PhotoImage(file='SqImg8.gif')
# BdrImg's are numbered clockwise starting from the top left.
BdrImgT = PhotoImage(file='BdrImgT.gif')
BdrImgR = PhotoImage(file='BdrImgR.gif')
BdrImgB = PhotoImage(file='BdrImgB.gif')
BdrImgL = PhotoImage(file='BdrImgL.gif')
BdrImgTR = PhotoImage(file='BdrImgTR.gif')
BdrImgBR = PhotoImage(file='BdrImgBR.gif')
BdrImgBL = PhotoImage(file='BdrImgBL.gif')
BdrImgTL = PhotoImage(file='BdrImgTL.gif')
fieldCanvas = Canvas(fieldFrame, width=(setWidth*25), height=(setHeight*25))
fieldCanvas.grid(column=0, row=0, sticky='nesw')
createBoard(setWidth, setHeight)
#bindSquares(setWidth, setHeight)
generateMines(setWidth, setHeight, numberOfMines)
fieldCanvas.tag_bind(CURRENT, '<Button-1>', squareReveal)
root.mainloop()
going into an infinite loop when i click an empty square... im not sure what to do
squares with mines or surrounding mines work fine...
Last edited by jtkiv (2011-03-26 01:19:32)
Offline
from tkinter import *
from tkinter import ttk
from random import sample
setWidth = 10
setHeight = 10
numberOfMines = 10
def createBoard(sWidth, sHeight):
for y in range(0, sHeight):
for x in range(0, sWidth):
# border images -- setHeight and setWidth have 1 subtracted (set*-1),
# so that they are placed correctly...
if x == 0 and y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgTL)
elif x == 0 and y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgBL)
elif x == sWidth-1 and y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgTR)
elif x == sWidth-1 and y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgBR)
elif x == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgL)
elif x == sWidth-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgR)
elif y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgT)
elif y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgB)
# main squares covering mines
else:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=SqImgU, activeimage=SqImgA, disabledimage=SqImg0)
def generateMines(sWidth, sHeight, numMines):
mineList = sample((fieldCanvas.find_enclosed(25, 25, (sWidth-1)*25, (sHeight-1)*25)), numMines)
for mine in mineList:
fieldCanvas.itemconfigure(mine, tag='mine')
def squareReveal(event):
sqID = int((fieldCanvas.find_closest(event.x, event.y))[0])
sqImgResult = squareDirect(sqID)
sWidth = setWidth*25
sHeight = setHeight*25
if event.x in range(25, sWidth*25) and event.y in range(25, sHeight*25):
fieldCanvas.itemconfigure((fieldCanvas.find_closest(event.x, event.y)), state=DISABLED, disabledimage=sqImgResult)
def squareDirect(sqID):
print('squareDirect', sqID)
if 'mine' in fieldCanvas.gettags(sqID):
return squareClear('M')
else:
return squareCheck(sqID)
def squareCheck(sqID):
print('squareCheck-justEntered', sqID)
s = setWidth
surroundingSquares = []
surroundingSquares.extend([sqID-s-1, sqID-s, sqID-s+1, sqID+1, sqID+s+1, sqID+s, sqID+s-1, sqID-1])
surroundingTags = []
for square in surroundingSquares:
print('squareCheck-forSquareInSurroundingSquares', square)
surroundingTags.append(fieldCanvas.gettags(square))
surroundingMineCount = 0
for tag in surroundingTags:
if 'mine' in tag:
surroundingMineCount += 1
print(tag, surroundingMineCount)
if surroundingMineCount == 0:
emptySquares(surroundingSquares)
return squareClear(surroundingMineCount)
else:
return squareClear(surroundingMineCount)
def squareClear(mineCount):
variableDict = {
'SqImgM': SqImgM,
'SqImg0': SqImg0,
'SqImg1': SqImg1,
'SqImg2': SqImg2,
'SqImg3': SqImg3,
'SqImg4': SqImg4,
'SqImg5': SqImg5,
'SqImg6': SqImg6,
'SqImg7': SqImg7,
'SqImg8': SqImg8
}
sqImgResult = variableDict['SqImg%s' % (mineCount)]
return sqImgResult
def emptySquares(surroundingSquares):
for square in surroundingSquares:
squareCheck(square)
#fieldCanvas.itemconfigure(square, state=DISABLED, disabledimage=SqImg0)
#funcSqId = sqID
#fieldCanvas.itemconfigure(funcSqId, state=DISABLED, disabledimage=SqImg0)
root = Tk()
root.title('SnakeSweeper')
fieldFrame = ttk.Frame(root, padding='0')
fieldFrame.grid(column=0, row=2, sticky='nesw')
SqImgU = PhotoImage(file='SqImgU.gif')
SqImgA = PhotoImage(file='SqImgA.gif')
SqImgM = PhotoImage(file='SqImgM.gif')
SqImg0 = PhotoImage(file='SqImg0.gif')
SqImg1 = PhotoImage(file='SqImg1.gif')
SqImg2 = PhotoImage(file='SqImg2.gif')
SqImg3 = PhotoImage(file='SqImg3.gif')
SqImg4 = PhotoImage(file='SqImg4.gif')
SqImg5 = PhotoImage(file='SqImg5.gif')
SqImg6 = PhotoImage(file='SqImg6.gif')
SqImg7 = PhotoImage(file='SqImg7.gif')
SqImg8 = PhotoImage(file='SqImg8.gif')
# BdrImg's are numbered clockwise starting from the top left.
BdrImgT = PhotoImage(file='BdrImgT.gif')
BdrImgR = PhotoImage(file='BdrImgR.gif')
BdrImgB = PhotoImage(file='BdrImgB.gif')
BdrImgL = PhotoImage(file='BdrImgL.gif')
BdrImgTR = PhotoImage(file='BdrImgTR.gif')
BdrImgBR = PhotoImage(file='BdrImgBR.gif')
BdrImgBL = PhotoImage(file='BdrImgBL.gif')
BdrImgTL = PhotoImage(file='BdrImgTL.gif')
fieldCanvas = Canvas(fieldFrame, width=(setWidth*25), height=(setHeight*25))
fieldCanvas.grid(column=0, row=0, sticky='nesw')
createBoard(setWidth, setHeight)
generateMines(setWidth, setHeight, numberOfMines)
fieldCanvas.tag_bind(CURRENT, '<Button-1>', squareReveal)
root.mainloop()
slightly reorganized, still infinite loop --
here's what's coming out in the IDLE shell...
squareDirect 12
squareDirect 13
squareCheck-justEntered 13
squareCheck-forSquareInSurroundingSquares 2
squareCheck-forSquareInSurroundingSquares 3
squareCheck-forSquareInSurroundingSquares 4
squareCheck-forSquareInSurroundingSquares 14
squareCheck-forSquareInSurroundingSquares 24
squareCheck-forSquareInSurroundingSquares 23
squareCheck-forSquareInSurroundingSquares 22
squareCheck-forSquareInSurroundingSquares 12
() 0
() 0
() 0
() 0
() 0
() 0
() 0
('mine',) 1
squareDirect 23
squareCheck-justEntered 23
squareCheck-forSquareInSurroundingSquares 12
squareCheck-forSquareInSurroundingSquares 13
squareCheck-forSquareInSurroundingSquares 14
squareCheck-forSquareInSurroundingSquares 24
squareCheck-forSquareInSurroundingSquares 34
squareCheck-forSquareInSurroundingSquares 33
squareCheck-forSquareInSurroundingSquares 32
squareCheck-forSquareInSurroundingSquares 22
('mine',) 1
() 1
() 1
() 1
() 1
() 1
('mine',) 2
() 2
squareDirect 22
squareCheck-justEntered 22
squareCheck-forSquareInSurroundingSquares 11
squareCheck-forSquareInSurroundingSquares 12
squareCheck-forSquareInSurroundingSquares 13
squareCheck-forSquareInSurroundingSquares 23
squareCheck-forSquareInSurroundingSquares 33
squareCheck-forSquareInSurroundingSquares 32
squareCheck-forSquareInSurroundingSquares 31
squareCheck-forSquareInSurroundingSquares 21
() 0
('mine',) 1
() 1
() 1
() 1
('mine',) 2
() 2
() 2
squareDirect 14
squareCheck-justEntered 14
squareCheck-forSquareInSurroundingSquares 3
squareCheck-forSquareInSurroundingSquares 4
squareCheck-forSquareInSurroundingSquares 5
squareCheck-forSquareInSurroundingSquares 15
squareCheck-forSquareInSurroundingSquares 25
squareCheck-forSquareInSurroundingSquares 24
squareCheck-forSquareInSurroundingSquares 23
squareCheck-forSquareInSurroundingSquares 13
() 0
() 0
() 0
('mine',) 1
() 1
() 1
() 1
() 1
squareDirect 24
squareCheck-justEntered 24
squareCheck-forSquareInSurroundingSquares 13
squareCheck-forSquareInSurroundingSquares 14
squareCheck-forSquareInSurroundingSquares 15
squareCheck-forSquareInSurroundingSquares 25
squareCheck-forSquareInSurroundingSquares 35
squareCheck-forSquareInSurroundingSquares 34
squareCheck-forSquareInSurroundingSquares 33
squareCheck-forSquareInSurroundingSquares 23
() 0
() 0
('mine',) 1
() 1
() 1
() 1
() 1
() 1
squareDirect 15
squareDirect 25
squareCheck-justEntered 25
squareCheck-forSquareInSurroundingSquares 14
squareCheck-forSquareInSurroundingSquares 15
squareCheck-forSquareInSurroundingSquares 16
squareCheck-forSquareInSurroundingSquares 26
squareCheck-forSquareInSurroundingSquares 36
squareCheck-forSquareInSurroundingSquares 35
squareCheck-forSquareInSurroundingSquares 34
squareCheck-forSquareInSurroundingSquares 24
() 0
('mine',) 1
() 1
('mine',) 2
('mine',) 3
() 3
() 3
() 3
squareDirect 16
squareCheck-justEntered 16
squareCheck-forSquareInSurroundingSquares 5
squareCheck-forSquareInSurroundingSquares 6
squareCheck-forSquareInSurroundingSquares 7
squareCheck-forSquareInSurroundingSquares 17
squareCheck-forSquareInSurroundingSquares 27
squareCheck-forSquareInSurroundingSquares 26
squareCheck-forSquareInSurroundingSquares 25
squareCheck-forSquareInSurroundingSquares 15
() 0
() 0
() 0
() 0
() 0
('mine',) 1
() 1
('mine',) 2
squareDirect 26
squareDirect 34
squareCheck-justEntered 34
squareCheck-forSquareInSurroundingSquares 23
squareCheck-forSquareInSurroundingSquares 24
squareCheck-forSquareInSurroundingSquares 25
squareCheck-forSquareInSurroundingSquares 35
squareCheck-forSquareInSurroundingSquares 45
squareCheck-forSquareInSurroundingSquares 44
squareCheck-forSquareInSurroundingSquares 43
squareCheck-forSquareInSurroundingSquares 33
() 0
() 0
() 0
() 0
() 0
() 0
() 0
() 0
squareCheck-justEntered 23
squareCheck-forSquareInSurroundingSquares 12
squareCheck-forSquareInSurroundingSquares 13
squareCheck-forSquareInSurroundingSquares 14
squareCheck-forSquareInSurroundingSquares 24
squareCheck-forSquareInSurroundingSquares 34
squareCheck-forSquareInSurroundingSquares 33
squareCheck-forSquareInSurroundingSquares 32
squareCheck-forSquareInSurroundingSquares 22
('mine',) 1
() 1
() 1
() 1
('current',) 1
() 1
('mine',) 2
() 2
squareCheck-justEntered 24
squareCheck-forSquareInSurroundingSquares 13
squareCheck-forSquareInSurroundingSquares 14
squareCheck-forSquareInSurroundingSquares 15
squareCheck-forSquareInSurroundingSquares 25
squareCheck-forSquareInSurroundingSquares 35
squareCheck-forSquareInSurroundingSquares 34
squareCheck-forSquareInSurroundingSquares 33
squareCheck-forSquareInSurroundingSquares 23
() 0
() 0
('mine',) 1
() 1
() 1
('current',) 1
() 1
() 1
squareCheck-justEntered 25
squareCheck-forSquareInSurroundingSquares 14
squareCheck-forSquareInSurroundingSquares 15
squareCheck-forSquareInSurroundingSquares 16
squareCheck-forSquareInSurroundingSquares 26
squareCheck-forSquareInSurroundingSquares 36
squareCheck-forSquareInSurroundingSquares 35
squareCheck-forSquareInSurroundingSquares 34
squareCheck-forSquareInSurroundingSquares 24
() 0
('mine',) 1
() 1
('mine',) 2
('mine',) 3
() 3
('current',) 3
() 3
squareCheck-justEntered 35
squareCheck-forSquareInSurroundingSquares 24
squareCheck-forSquareInSurroundingSquares 25
squareCheck-forSquareInSurroundingSquares 26
squareCheck-forSquareInSurroundingSquares 36
squareCheck-forSquareInSurroundingSquares 46
squareCheck-forSquareInSurroundingSquares 45
squareCheck-forSquareInSurroundingSquares 44
squareCheck-forSquareInSurroundingSquares 34
() 0
() 0
('mine',) 1
('mine',) 2
('mine',) 3
() 3
() 3
('current',) 3
squareCheck-justEntered 45
squareCheck-forSquareInSurroundingSquares 34
squareCheck-forSquareInSurroundingSquares 35
squareCheck-forSquareInSurroundingSquares 36
squareCheck-forSquareInSurroundingSquares 46
squareCheck-forSquareInSurroundingSquares 56
squareCheck-forSquareInSurroundingSquares 55
squareCheck-forSquareInSurroundingSquares 54
squareCheck-forSquareInSurroundingSquares 44
('current',) 0
() 0
('mine',) 1
('mine',) 2
() 2
() 2
() 2
() 2
squareCheck-justEntered 44
squareCheck-forSquareInSurroundingSquares 33
squareCheck-forSquareInSurroundingSquares 34
squareCheck-forSquareInSurroundingSquares 35
squareCheck-forSquareInSurroundingSquares 45
squareCheck-forSquareInSurroundingSquares 55
squareCheck-forSquareInSurroundingSquares 54
squareCheck-forSquareInSurroundingSquares 53
squareCheck-forSquareInSurroundingSquares 43
() 0
('current',) 0
() 0
() 0
() 0
() 0
() 0
() 0
squareCheck-justEntered 33
squareCheck-forSquareInSurroundingSquares 22
squareCheck-forSquareInSurroundingSquares 23
squareCheck-forSquareInSurroundingSquares 24
squareCheck-forSquareInSurroundingSquares 34
squareCheck-forSquareInSurroundingSquares 44
squareCheck-forSquareInSurroundingSquares 43
squareCheck-forSquareInSurroundingSquares 42
squareCheck-forSquareInSurroundingSquares 32
() 0
() 0
() 0
('current',) 0
() 0
() 0
() 0
('mine',) 1
...and on and on and on
// found it (i think)...
if surroundingMineCount == 0:
emptySquares(surroundingSquares)
return squareClear(surroundingMineCount)
problem is im checking to see if surrounding squares are empty without ever clearing the ones that ARE empty...
2nd problem is i need to check the loop and return the value. the loop will be infinite without the return, and the return will prevent the loop from starting.
Last edited by jtkiv (2011-03-26 02:20:33)
Offline
i quickly glanced at the code, other than the problem you already mentioned i think you may also be forgetting to make sure you're not checking on adjacent squares that are out of the range on the grid (ie don't check for adjacent squares to the left of any squares in the leftmost column on the grid). using an x,y pair instead of a single index for the position of a square in the grid will make range checking easier.
here's some psuedo code loosely based on your current code, it uses a recursive function like the one Peasantoid described and the one you already had:
square_direct(curPos)
if !out_of_range(curPos) and is_mine(curPos)
# mine hit
square_clear(curPos)
square_set(curPos, 'M')
else
square_set_all(curPos)
square_set_all(curPos)
if out_of_range(curPos) or is_cleared(curPos) or is_mine(curPos)
return
# offset list to determine positions of adjacent squares
offsetList = [(1,0), (1,1), (0,1), (-1,1), (-1,0), (-1,-1), (0,-1), (1,-1)]
mines = 0
for i in offsetList
nextPos = curPos + i
if !out_of_range(nextPos) and is_mine(nextPos)
mines += 1
# mark the current square as cleared so if this square is checked again
# (by an adjacent square) the function will return immediately.
square_clear(curPos)
square_set(curPos, mines)
if mines = 0
for i in offsetList
nextPos = curPos + i
square_set_all(nextPos)
Offline
@e_tank - haven't implemented it yet, but i had the same thought last night ~1a.m. i think that they might be the same problem... not sure, i'll get back to you.
Offline
##SnakeSweeper in the works.
##Thomas Kirkpatrick (jtkiv)
from tkinter import *
from tkinter import ttk
from random import sample
##TMP variables as placeholders for non-existent functions/controls...
setWidth = 10
setHeight = 10
numberOfMines = 10
##functions! :(
##create the board thing.
def createBoard(sWidth, sHeight):
for y in range(0, sHeight):
for x in range(0, sWidth):
# border images -- setHeight and setWidth have 1 subtracted (set*-1),
# so that they are placed correctly...
if x == 0 and y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgTL)
elif x == 0 and y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgBL)
elif x == sWidth-1 and y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgTR)
elif x == sWidth-1 and y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgBR)
elif x == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgL)
elif x == sWidth-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgR)
elif y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgT)
elif y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgB)
# main squares covering mines
else:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=SqImgU, activeimage=SqImgA, disabledimage=SqImg0)
##randomly place mines in the board. they are tagged with >> 'mine' (creative i know)
def generateMines(sWidth, sHeight, numMines):
mineList = sample((fieldCanvas.find_enclosed(25, 25, (sWidth-1)*25, (sHeight-1)*25)), numMines)
for mine in mineList:
fieldCanvas.itemconfigure(mine, tag='mine')
##these functions mark the beginning of the 'game loop'...
##or whatever you want to call it. the process should be:
##.-->what was clicked? > was it a mine? YES> game over
##| NO> how many mines adjacent? (1-8)> set SqImg[x]
##| (0)> set SqImg0 > whats around the squares that are around it? -.
##'--------------------------------------------------------------------------------------------------------------------------------------'
#this is the function that sets the images for clicked squares.
def squareClear(squareID, mineCount):
variableDict = {
'SqImgM': SqImgM,
'SqImg0': SqImg0,
'SqImg1': SqImg1,
'SqImg2': SqImg2,
'SqImg3': SqImg3,
'SqImg4': SqImg4,
'SqImg5': SqImg5,
'SqImg6': SqImg6,
'SqImg7': SqImg7,
'SqImg8': SqImg8
}
sqImgResult = variableDict['SqImg%s' % (mineCount)]
fieldCanvas.itemconfigure(squareID, state=DISABLED, disabledimage=sqImgResult)
#answers the question: "what was clicked?"
def squareClicked(event):
sWidth = setWidth*25
sHeight = setHeight*25
#another question: "is it on the board?"
if event.x in range(25, sWidth-25) and event.y in range(25, sHeight-25):
#ok, checks out... now: "what is it's ID?" and direct it!
squareDirect(int((fieldCanvas.find_closest(event.x, event.y))[0]))
#answers the question: "was the clicked square a mine?"
def squareDirect(squareID):
#yep! it was a mine!
if 'mine' in fieldCanvas.gettags(squareID):
print('this beast was a mine!')
#code for end-game will go here later...
#replace the square with a 'mine' image...
squareClear(squareID, 'M')
#no way!!! why would i click a mine?!?
else:
print('no mine here... taking', squareID, 'to squareCheck')
squareCheck(squareID)
#first part of the question: "*how* *many* mines *adjacent?*"
# 'ID' is the same number as squareID, just shorter to type...
def surroundingCollect(ID):
surroundingCollection = []
w = setWidth
h = setHeight
#some squareIDs will be off the board or part of the border, and therefore
#invalid. so "validIDs" stores a list of all valid squareIDs...
validIDs = []
for x in range(2, w):
for i in range(1, (w-1)):
y = h*i
validIDs.append(x+y)
#let's find the IDs of the surrounding squares...
expectedLocations = [ID-w-1, ID-w, ID-w+1, ID+1, ID+w+1, ID+w, ID+w-1, ID-1]
for location in expectedLocations:
#let's also only accept valid locations...
if location in validIDs:
surroundingCollection.append(location)
return surroundingCollection
#with info from "surroundingCollect", answers the question: "how many mines adjacent?"
def squareCheck(squareID):
s = setWidth
surroundingSquares = surroundingCollect(squareID)
print(surroundingSquares, 'made it to surroundingSquares in squareCheck')
surroundingMineCount = 0
for square in surroundingSquares:
if 'mine' in fieldCanvas.gettags(square):
surroundingMineCount += 1
print(surroundingMineCount, 'made it out of for loop in squareCheck')
if surroundingMineCount == 0:
print('headed to squareClear (0) with', squareID, surroundingMineCount)
squareClear(squareID, '0')
print('headed to emptySquares with', surroundingSquares)
emptySquares(surroundingSquares)
else:
print('headed to squareClear with', squareID, surroundingMineCount)
squareClear(squareID, surroundingMineCount)
#if there are no mines adjacent, this function is here to help.
#answers question: "what's around the squares around me?"
def emptySquares(surroundingSquares):
print('made it to surroundingSquares with', surroundingSquares)
for square in surroundingSquares:
print('taking', square, 'to squareDirect!!!')
squareDirect(square)
#gui code...
root = Tk()
root.title('SnakeSweeper')
fieldFrame = ttk.Frame(root, padding='0')
fieldFrame.grid(column=0, row=2, sticky='nesw')
SqImgU = PhotoImage(file='SqImgU.gif')
SqImgA = PhotoImage(file='SqImgA.gif')
SqImgM = PhotoImage(file='SqImgM.gif')
SqImg0 = PhotoImage(file='SqImg0.gif')
SqImg1 = PhotoImage(file='SqImg1.gif')
SqImg2 = PhotoImage(file='SqImg2.gif')
SqImg3 = PhotoImage(file='SqImg3.gif')
SqImg4 = PhotoImage(file='SqImg4.gif')
SqImg5 = PhotoImage(file='SqImg5.gif')
SqImg6 = PhotoImage(file='SqImg6.gif')
SqImg7 = PhotoImage(file='SqImg7.gif')
SqImg8 = PhotoImage(file='SqImg8.gif')
# BdrImg's are numbered clockwise starting from the top left.
BdrImgT = PhotoImage(file='BdrImgT.gif')
BdrImgR = PhotoImage(file='BdrImgR.gif')
BdrImgB = PhotoImage(file='BdrImgB.gif')
BdrImgL = PhotoImage(file='BdrImgL.gif')
BdrImgTR = PhotoImage(file='BdrImgTR.gif')
BdrImgBR = PhotoImage(file='BdrImgBR.gif')
BdrImgBL = PhotoImage(file='BdrImgBL.gif')
BdrImgTL = PhotoImage(file='BdrImgTL.gif')
fieldCanvas = Canvas(fieldFrame, width=(setWidth*25), height=(setHeight*25))
fieldCanvas.grid(column=0, row=0, sticky='nesw')
createBoard(setWidth, setHeight)
generateMines(setWidth, setHeight, numberOfMines)
fieldCanvas.tag_bind(CURRENT, '<Button-1>', squareClicked)
root.mainloop()
shell...
no mine here... taking 12 to squareCheck
[13, 23, 22] made it to surroundingSquares in squareCheck
1 made it out of for loop in squareCheck
headed to squareClear with 12 1
no mine here... taking 13 to squareCheck
[14, 24, 23, 22, 12] made it to surroundingSquares in squareCheck
1 made it out of for loop in squareCheck
headed to squareClear with 13 1
no mine here... taking 14 to squareCheck
[15, 25, 24, 23, 13] made it to surroundingSquares in squareCheck
1 made it out of for loop in squareCheck
headed to squareClear with 14 1
no mine here... taking 15 to squareCheck
[16, 26, 25, 24, 14] made it to surroundingSquares in squareCheck
0 made it out of for loop in squareCheck
#
# the first empty square to be clicked...
#
headed to squareClear (0) with 15 0
headed to emptySquares with [16, 26, 25, 24, 14]
made it to surroundingSquares with [16, 26, 25, 24, 14]
taking 16 to squareDirect!!!
no mine here... taking 16 to squareCheck
[17, 27, 26, 25, 15] made it to surroundingSquares in squareCheck
0 made it out of for loop in squareCheck
headed to squareClear (0) with 16 0
headed to emptySquares with [17, 27, 26, 25, 15]
made it to surroundingSquares with [17, 27, 26, 25, 15]
taking 17 to squareDirect!!!
no mine here... taking 17 to squareCheck
[18, 28, 27, 26, 16] made it to surroundingSquares in squareCheck
0 made it out of for loop in squareCheck
headed to squareClear (0) with 17 0
headed to emptySquares with [18, 28, 27, 26, 16]
made it to surroundingSquares with [18, 28, 27, 26, 16]
taking 18 to squareDirect!!!
no mine here... taking 18 to squareCheck
[19, 29, 28, 27, 17] made it to surroundingSquares in squareCheck
0 made it out of for loop in squareCheck
headed to squareClear (0) with 18 0
headed to emptySquares with [19, 29, 28, 27, 17]
made it to surroundingSquares with [19, 29, 28, 27, 17]
taking 19 to squareDirect!!!
no mine here... taking 19 to squareCheck
[29, 28, 18] made it to surroundingSquares in squareCheck
0 made it out of for loop in squareCheck
headed to squareClear (0) with 19 0
headed to emptySquares with [29, 28, 18]
made it to surroundingSquares with [29, 28, 18]
taking 29 to squareDirect!!!
no mine here... taking 29 to squareCheck
[18, 19, 39, 38, 28] made it to surroundingSquares in squareCheck
2 made it out of for loop in squareCheck
headed to squareClear with 29 2
taking 28 to squareDirect!!!
no mine here... taking 28 to squareCheck
[17, 18, 19, 29, 39, 38, 37, 27] made it to surroundingSquares in squareCheck
2 made it out of for loop in squareCheck
headed to squareClear with 28 2
taking 18 to squareDirect!!!
no mine here... taking 18 to squareCheck
[19, 29, 28, 27, 17] made it to surroundingSquares in squareCheck
0 made it out of for loop in squareCheck
headed to squareClear (0) with 18 0
headed to emptySquares with [19, 29, 28, 27, 17]
made it to surroundingSquares with [19, 29, 28, 27, 17]
taking 19 to squareDirect!!!
no mine here... taking 19 to squareCheck
[29, 28, 18] made it to surroundingSquares in squareCheck
0 made it out of for loop in squareCheck
headed to squareClear (0) with 19 0
headed to emptySquares with [29, 28, 18]
made it to surroundingSquares with [29, 28, 18]
taking 29 to squareDirect!!!
no mine here... taking 29 to squareCheck
[18, 19, 39, 38, 28] made it to surroundingSquares in squareCheck
2 made it out of for loop in squareCheck
headed to squareClear with 29 2
taking 28 to squareDirect!!!
no mine here... taking 28 to squareCheck
[17, 18, 19, 29, 39, 38, 37, 27] made it to surroundingSquares in squareCheck
2 made it out of for loop in squareCheck
headed to squareClear with 28 2
taking 18 to squareDirect!!!
no mine here... taking 18 to squareCheck
[19, 29, 28, 27, 17] made it to surroundingSquares in squareCheck
0 made it out of for loop in squareCheck
headed to squareClear (0) with 18 0
headed to emptySquares with [19, 29, 28, 27, 17]
made it to surroundingSquares with [19, 29, 28, 27, 17]
taking 19 to squareDirect!!!
no mine here... taking 19 to squareCheck
[29, 28, 18] made it to surroundingSquares in squareCheck
0 made it out of for loop in squareCheck
headed to squareClear (0) with 19 0
headed to emptySquares with [29, 28, 18]
made it to surroundingSquares with [29, 28, 18]
taking 29 to squareDirect!!!
no mine here... taking 29 to squareCheck
[18, 19, 39, 38, 28] made it to surroundingSquares in squareCheck
2 made it out of for loop in squareCheck
headed to squareClear with 29 2
taking 28 to squareDirect!!!
no mine here... taking 28 to squareCheck
[17, 18, 19, 29, 39, 38, 37, 27] made it to surroundingSquares in squareCheck
2 made it out of for loop in squareCheck
headed to squareClear with 28 2
taking 18 to squareDirect!!!
no mine here... taking 18 to squareCheck
[19, 29, 28, 27, 17] made it to surroundingSquares in squareCheck
0 made it out of for loop in squareCheck
headed to squareClear (0) with 18 0
headed to emptySquares with [19, 29, 28, 27, 17]
made it to surroundingSquares with [19, 29, 28, 27, 17]
taking 19 to squareDirect!!!
no mine here... taking 19 to squareCheck
[29, 28, 18] made it to surroundingSquares in squareCheck
0 made it out of for loop in squareCheck
headed to squareClear (0) with 19 0
headed to emptySquares with
#TERMINATED HERE
so even with the reorganized code (which is much faster), i'm still not getting it to work. i know its going to do lots of calculations, but good lands, there's only 100 possible squares (in this setup).
----
and even in 100, it still go in circles forever unless i tell it not to check what has already been checked. probably the problem...
any ideas?
Offline
##SnakeSweeper in the works.
##Thomas Kirkpatrick (jtkiv)
from tkinter import *
from tkinter import ttk
from random import sample
##TMP variables as placeholders for non-existent functions/controls...
setWidth = 10
setHeight = 10
numberOfMines = 10
##functions! :)
##create the board thing.
def createBoard(sWidth, sHeight):
for y in range(0, sHeight):
for x in range(0, sWidth):
# border images -- setHeight and setWidth have 1 subtracted (set*-1),
# so that they are placed correctly...
if x == 0 and y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgTL)
elif x == 0 and y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgBL)
elif x == sWidth-1 and y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgTR)
elif x == sWidth-1 and y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgBR)
elif x == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgL)
elif x == sWidth-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgR)
elif y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgT)
elif y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgB)
# main squares covering mines
else:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=SqImgU, activeimage=SqImgA, disabledimage=SqImg0)
##randomly place mines in the board. they are tagged with >> 'mine' (creative i know)
def generateMines(sWidth, sHeight, numMines):
mineList = sample((fieldCanvas.find_enclosed(25, 25, (sWidth-1)*25, (sHeight-1)*25)), numMines)
for mine in mineList:
fieldCanvas.itemconfigure(mine, tag='mine')
##these functions mark the beginning of the 'game loop'...
##or whatever you want to call it. the process should be:
##.-->what was clicked? > was it a mine? YES> game over
##| NO> how many mines adjacent? (1-8)> set SqImg[x]
##| (0)> set SqImg0 > whats around the squares that are around it? -.
##'--------------------------------------------------------------------------------------------------------------------------------------'
#this is the function that sets the images for clicked squares.
def squareClear(squareID, mineCount):
variableDict = {
'SqImgM': SqImgM,
'SqImg0': SqImg0,
'SqImg1': SqImg1,
'SqImg2': SqImg2,
'SqImg3': SqImg3,
'SqImg4': SqImg4,
'SqImg5': SqImg5,
'SqImg6': SqImg6,
'SqImg7': SqImg7,
'SqImg8': SqImg8
}
sqImgResult = variableDict['SqImg%s' % (mineCount)]
fieldCanvas.itemconfigure(squareID, tag='lame', state=DISABLED, disabledimage=sqImgResult)
#answers the question: "what was clicked?"
def squareClicked(event):
sWidth = setWidth*25
sHeight = setHeight*25
#another question: "is it on the board?"
if event.x in range(25, sWidth-25) and event.y in range(25, sHeight-25):
#ok, checks out... now: "what is it's ID?" and direct it!
squareDirect(int((fieldCanvas.find_closest(event.x, event.y))[0]))
#answers the question: "was the clicked square a mine?"
def squareDirect(squareID):
#yep! it was a mine!
if 'mine' in fieldCanvas.gettags(squareID):
#code for end-game will go here later...
#replace the square with a 'mine' image...
squareClear(squareID, 'M')
#no way!!! why would i click a mine?!?
else:
squareCheck(squareID)
#first part of the question: "*how* *many* mines *adjacent?*"
# 'ID' is the same number as squareID, just shorter to type...
def surroundingCollect(ID):
surroundingCollection = []
w = setWidth
h = setHeight
#some squareIDs will be off the board or part of the border, and therefore
#invalid. so "validIDs" stores a list of all valid squareIDs...
validIDs = []
for x in range(2, w):
for i in range(1, (w-1)):
y = h*i
validIDs.append(x+y)
#let's find the IDs of the surrounding squares...
expectedLocations = [ID-w-1, ID-w, ID-w+1, ID+1, ID+w+1, ID+w, ID+w-1, ID-1]
for location in expectedLocations:
#let's also only accept valid locations...
if location in validIDs and 'lame' not in fieldCanvas.gettags(location):
surroundingCollection.append(location)
return surroundingCollection
#with info from "surroundingCollect", answers the question: "how many mines adjacent?"
def squareCheck(squareID):
s = setWidth
surroundingSquares = surroundingCollect(squareID)
surroundingMineCount = 0
for square in surroundingSquares:
if 'mine' in fieldCanvas.gettags(square):
surroundingMineCount += 1
if surroundingMineCount == 0:
squareClear(squareID, '0')
emptySquares(surroundingSquares)
else:
squareClear(squareID, surroundingMineCount)
#if there are no mines adjacent, this function is here to help.
#answers question: "what's around the squares around me?"
def emptySquares(surroundingSquares):
for square in surroundingSquares:
squareDirect(square)
#gui code...
root = Tk()
root.title('SnakeSweeper')
fieldFrame = ttk.Frame(root, padding='0')
fieldFrame.grid(column=0, row=2, sticky='nesw')
SqImgU = PhotoImage(file='SqImgU.gif')
SqImgA = PhotoImage(file='SqImgA.gif')
SqImgM = PhotoImage(file='SqImgM.gif')
SqImg0 = PhotoImage(file='SqImg0.gif')
SqImg1 = PhotoImage(file='SqImg1.gif')
SqImg2 = PhotoImage(file='SqImg2.gif')
SqImg3 = PhotoImage(file='SqImg3.gif')
SqImg4 = PhotoImage(file='SqImg4.gif')
SqImg5 = PhotoImage(file='SqImg5.gif')
SqImg6 = PhotoImage(file='SqImg6.gif')
SqImg7 = PhotoImage(file='SqImg7.gif')
SqImg8 = PhotoImage(file='SqImg8.gif')
# BdrImg's are numbered clockwise starting from the top left.
BdrImgT = PhotoImage(file='BdrImgT.gif')
BdrImgR = PhotoImage(file='BdrImgR.gif')
BdrImgB = PhotoImage(file='BdrImgB.gif')
BdrImgL = PhotoImage(file='BdrImgL.gif')
BdrImgTR = PhotoImage(file='BdrImgTR.gif')
BdrImgBR = PhotoImage(file='BdrImgBR.gif')
BdrImgBL = PhotoImage(file='BdrImgBL.gif')
BdrImgTL = PhotoImage(file='BdrImgTL.gif')
fieldCanvas = Canvas(fieldFrame, width=(setWidth*25), height=(setHeight*25))
fieldCanvas.grid(column=0, row=0, sticky='nesw')
createBoard(setWidth, setHeight)
generateMines(setWidth, setHeight, numberOfMines)
fieldCanvas.tag_bind(CURRENT, '<Button-1>', squareClicked)
root.mainloop()
i was right. a simple tag, 'lame', keeps it from counting whats already been counted.
now for the snake... gonna need help with this one. how to start?
----
doesn't work if its 30x30...
RuntimeError: maximum recursion depth exceeded while calling a Python object
is this solvable in python/tkinter?
----
should be able to avoid this ^ if i keep the mine percentage realistic. that is, if the board never needs *major* clearing. (runs into a mine soon enough)
i don't quite like that though... is this from the Canvas object or python?
Last edited by jtkiv (2011-03-26 18:04:07)
Offline
ok, i'll help you out a little bit with a few things here:
1. your code has some errors, at the end of this post is a copy of your source file with the ones i saw corrected. do a diff on this file and your original to see what you were doing wrong.
2. regarding the recursion problem, you can transform the recursive function into an iterative / pseudo recursive function, which won't have the same limitations in python as a standard recursive function, by using a list to simulate an argument stack and a while loop that keeps going until the stack is empty. i've implemented this for you in the function named squareCheck2 in the source file below.
3. your method of checking if an index is within bounds by using multiple lists is very inefficient, if speed is important then you should be using purely integer comparisons to determine if the index is within bounds. i've also implemented this for you in the function named squareCheck3 in the source file below.
4. if the mines are going to be static on the grid you should calculate the number of surrounding mines for each square during initialization, not when you go to click a square (right after the mines have been placed).
5. and finally, this isn't necessary but, you should really consider separating your game code logic from the code used to display it. things are going to get confusing very fast if you don't (imo your code is already a bit messy and confusing). you could start by creating an array/list of objects/structs for each grid cell which will represent the game grid (instead of attaching your variables on to gui objects like you're doing now), each one should have variables similar to the following:
int numMines // number of surrounding mines
bool isMine
bool isCleared // set to true when clicked on
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
##SnakeSweeper in the works.
##Thomas Kirkpatrick (jtkiv)
from tkinter import *
from tkinter import ttk
from random import sample
##TMP variables as placeholders for non-existent functions/controls...
setWidth = 10
setHeight = 10
numberOfMines = 10
##functions! :)
##create the board thing.
def createBoard(sWidth, sHeight):
for y in range(0, sHeight):
for x in range(0, sWidth):
# border images -- setHeight and setWidth have 1 subtracted (set*-1),
# so that they are placed correctly...
if x == 0 and y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgTL)
elif x == 0 and y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgBL)
elif x == sWidth-1 and y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgTR)
elif x == sWidth-1 and y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgBR)
elif x == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgL)
elif x == sWidth-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgR)
elif y == 0:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgT)
elif y == sHeight-1:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=BdrImgB)
# main squares covering mines
else:
fieldCanvas.create_image(x*25, y*25, anchor=NW, image=SqImgU, activeimage=SqImgA, disabledimage=SqImg0)
##randomly place mines in the board. they are tagged with >> 'mine' (creative i know)
def generateMines(sWidth, sHeight, numMines):
mineList = sample((fieldCanvas.find_enclosed(25, 25, (sWidth-1)*25, (sHeight-1)*25)), numMines)
print(mineList)
for mine in mineList:
fieldCanvas.itemconfigure(mine, tag='mine')
##these functions mark the beginning of the 'game loop'...
##or whatever you want to call it. the process should be:
##.-->what was clicked? > was it a mine? YES> game over
##| NO> how many mines adjacent? (1-8)> set SqImg[x]
##| (0)> set SqImg0 > whats around the squares that are around it? -.
##'--------------------------------------------------------------------------------------------------------------------------------------'
#this is the function that sets the images for clicked squares.
def squareClear(squareID, mineCount):
variableDict = {
'SqImgM': SqImgM,
'SqImg0': SqImg0,
'SqImg1': SqImg1,
'SqImg2': SqImg2,
'SqImg3': SqImg3,
'SqImg4': SqImg4,
'SqImg5': SqImg5,
'SqImg6': SqImg6,
'SqImg7': SqImg7,
'SqImg8': SqImg8
}
sqImgResult = variableDict['SqImg%s' % (mineCount)]
if mineCount == 'M':
fieldCanvas.itemconfigure(squareID, state=DISABLED, disabledimage=sqImgResult)
else:
fieldCanvas.itemconfigure(squareID, tag='lame', state=DISABLED, disabledimage=sqImgResult)
#answers the question: "what was clicked?"
def squareClicked(event):
sWidth = setWidth*25
sHeight = setHeight*25
#another question: "is it on the board?"
if event.x in range(25, sWidth-25) and event.y in range(25, sHeight-25):
#ok, checks out... now: "what is it's ID?" and direct it!
squareDirect(int((fieldCanvas.find_closest(event.x, event.y))[0]))
#answers the question: "was the clicked square a mine?"
def squareDirect(squareID):
if 'mine' in fieldCanvas.gettags(squareID):
#yep! it was a mine!
#code for end-game will go here later...
#replace the square with a 'mine' image...
squareClear(squareID, 'M')
else:
#no way!!! why would i click a mine?!?
squareCheck3(squareID)
#first part of the question: "*how* *many* mines *adjacent?*"
# 'ID' is the same number as squareID, just shorter to type...
def surroundingCollect(ID):
surroundingCollection = []
w = setWidth
h = setHeight
#some squareIDs will be off the board or part of the border, and therefore
#invalid. so "validIDs" stores a list of all valid squareIDs...
validIDs = []
for y in range(1, (h-1)):
for x in range(1, (w-1)):
i = (y*w)+x
validIDs.append(i+1)
#let's find the IDs of the surrounding squares...
expectedLocations = [ID-w-1, ID-w, ID-w+1, ID+1, ID+w+1, ID+w, ID+w-1, ID-1]
for location in expectedLocations:
#let's also only accept valid locations...
if location in validIDs:
surroundingCollection.append(location)
return surroundingCollection
#with info from "surroundingCollect", answers the question: "how many mines adjacent?"
def squareCheck(squareID):
s = setWidth
surroundingSquares = surroundingCollect(squareID)
surroundingMineCount = 0
for square in surroundingSquares:
if 'mine' in fieldCanvas.gettags(square):
surroundingMineCount += 1
if surroundingMineCount == 0:
squareClear(squareID, '0')
for square in surroundingSquares:
if 'mine' not in fieldCanvas.gettags(square) and 'lame' not in fieldCanvas.gettags(square):
squareCheck(square)
else:
squareClear(squareID, surroundingMineCount)
# pseudo recursive version (recursive through use of a list used as an argument stack and a while loop)
def squareCheck2(squareID):
# init psuedo stack
stack = [squareID]
while len(stack) > 0:
squareID = stack.pop()
surroundingSquares = surroundingCollect(squareID)
surroundingMineCount = 0
for square in surroundingSquares:
if 'mine' in fieldCanvas.gettags(square):
surroundingMineCount += 1
if surroundingMineCount == 0:
squareClear(squareID, 0)
for square in surroundingSquares:
if 'mine' not in fieldCanvas.gettags(square) and 'lame' not in fieldCanvas.gettags(square) and square not in stack:
stack.append(square)
else:
squareClear(squareID, surroundingMineCount)
# faster version of squareCheck2, does bounds checking within function
# game grid is range(1,(w*h)+1), border elements are considered out of bounds
# index i is in bound if:
# i is not in first or last row: i in range(w+1, (h-1)*w)
# (note that the above also excludes the last element in the last row, which is in the last col)
# i is not in the first or last col: i%w > 1
def squareCheck3(squareID):
# init psuedo stack
w = setWidth
h = setHeight
offsets = [-w-1, -w, -w+1, 1, w+1, w, w-1, -1]
stack = [squareID]
while len(stack) > 0:
squareID = stack.pop()
surroundingMineCount = 0
for i in offsets:
nextID = squareID+i
if nextID in range(w+1, (h-1)*w) and (nextID%w) > 1 and 'mine' in fieldCanvas.gettags(nextID):
surroundingMineCount += 1
if surroundingMineCount == 0:
squareClear(squareID, 0)
for i in offsets:
nextID = squareID+i
if nextID in range(w+1, (h-1)*w) and (nextID%w) > 1 and nextID not in stack and 'mine' not in fieldCanvas.gettags(nextID) and 'lame' not in fieldCanvas.gettags(nextID):
stack.append(nextID)
else:
squareClear(squareID, surroundingMineCount)
#gui code...
root = Tk()
root.title('SnakeSweeper')
fieldFrame = ttk.Frame(root, padding='0')
fieldFrame.grid(column=0, row=2, sticky='nesw')
SqImgU = PhotoImage(file='SqImgU.gif')
SqImgA = PhotoImage(file='SqImgA.gif')
SqImgM = PhotoImage(file='SqImgM.gif')
SqImg0 = PhotoImage(file='SqImg0.gif')
SqImg1 = PhotoImage(file='SqImg1.gif')
SqImg2 = PhotoImage(file='SqImg2.gif')
SqImg3 = PhotoImage(file='SqImg3.gif')
SqImg4 = PhotoImage(file='SqImg4.gif')
SqImg5 = PhotoImage(file='SqImg5.gif')
SqImg6 = PhotoImage(file='SqImg6.gif')
SqImg7 = PhotoImage(file='SqImg7.gif')
SqImg8 = PhotoImage(file='SqImg8.gif')
# BdrImg's are numbered clockwise starting from the top left.
BdrImgT = PhotoImage(file='BdrImgT.gif')
BdrImgR = PhotoImage(file='BdrImgR.gif')
BdrImgB = PhotoImage(file='BdrImgB.gif')
BdrImgL = PhotoImage(file='BdrImgL.gif')
BdrImgTR = PhotoImage(file='BdrImgTR.gif')
BdrImgBR = PhotoImage(file='BdrImgBR.gif')
BdrImgBL = PhotoImage(file='BdrImgBL.gif')
BdrImgTL = PhotoImage(file='BdrImgTL.gif')
fieldCanvas = Canvas(fieldFrame, width=(setWidth*25), height=(setHeight*25))
fieldCanvas.grid(column=0, row=0, sticky='nesw')
createBoard(setWidth, setHeight)
generateMines(setWidth, setHeight, numberOfMines)
fieldCanvas.tag_bind(CURRENT, '<Button-1>', squareClicked)
root.mainloop()
Offline
1. other than the recursive/iterative difference (which is considerably different), im not seeing much...
2. thanks for the iterative function. i read a little and found that was mostly likely my solution (other is recursive depth, but that seems to be like avoiding the problem), but couldn't find any good examples to study. i think i get it now. does it generally improve speed to combine as many functions as possible?
3. alright. numbers > 'strings'
4. wouldn't that just mean doing exactly what the program is doing now except for have it tag the objects rather than process them? i.e. i still have to count mines, count for adjacent, etc...
5. thats why i included a flow chart
##.-->what was clicked? > was it a mine? YES> game over
##| NO> how many mines adjacent? (1-8)> set SqImg[x]
##| (0)> set SqImg0 > whats around the squares that are around it? -.
##'--------------------------------------------------------------------------------------------------------------------------------------'
lol... is this best done with classes? i haven't learned much of that yet.
Last edited by jtkiv (2011-03-27 19:05:27)
Offline
i have implemented a class. called square.
##SnakeSweeper in the works.
##Thomas Kirkpatrick (jtkiv)
from tkinter import *
from tkinter import ttk
from random import randint
from math import floor
boardWidth = 9
boardHeight = 9
minePercentage = .12
adj = {
'tl': [-1, -1],
'tt': [-1, 0],
'tr': [-1, 1],
'rr': [0, 1],
'br': [1, 1],
'bb': [1, 0],
'bl': [1, -1],
'll': [0, -1]
}
class square():
isCleared = False
isFlagged = False
isSuspect = False
isMine = False
minesAdjacent = 0
def generateSquares(width, height):
global squareIndex
squareIndex = {}
for y in range(height):
squareIndex[y] = []
for x in range(width):
squareIndex[y].append(square())
def generateMines(width, height, minePercentage):
minesToPlace = round(width*height*minePercentage)
while minesToPlace != 0:
row = randint(0, height-1)
col = randint(0, width-1)
if squareIndex[row][col].isMine == False:
squareIndex[row][col].isMine = True
minesToPlace -= 1
def countMines(width, height):
for row in range(height):
for col in range(width):
minesSurrounding = 0
for loc in adj:
if row+adj[loc][0] > -1 and col+adj[loc][1] > -1 and row+adj[loc][0] < height and col+adj[loc][1] < width:
if squareIndex[(row+adj[loc][0])][(col+adj[loc][1])].isMine:
minesSurrounding += 1
squareIndex[row][col].minesAdjacent = minesSurrounding
def prepareGame(width, height, minePercentage):
generateSquares(width, height)
generateMines(width, height, minePercentage)
countMines(width, height)
def drawBoard(width, height):
for r in range(0, height+2):
for c in range(0, width+2):
##DO NOT BE CONFUSED BY r 0 AND c 0 BEING ON THE BORDER!!!
##IN OTHER FUNCTIONS, r 0 AND c 0 CONTAIN ACTIVE SQUARES!!
if r == 0 or c == 0 or r == height+1 or c == width+1:
fieldCanvas.create_image(r*25, c*25, anchor=NW, state=DISABLED, disabledimage=imgIndex['B'])
else:
fieldCanvas.create_image(r*25, c*25, anchor=NW, image=imgIndex['U'], activeimage=imgIndex['A'])
def squareMaster(event):
pixelWidth = (boardWidth*25)+50
pixelHeight = (boardHeight*25)+50
if event.x in range(25, pixelWidth-25) and event.y in range(25, pixelHeight-25):
squareID = int((fieldCanvas.find_closest(event.x, event.y))[0])
row = floor(event.y/25) - 1
col = floor(event.x/25) - 1
if squareIndex[row][col].isMine:
fieldCanvas.itemconfigure(squareID, state=DISABLED, disabledimage=imgIndex['M'])
##ENDGAME
else:
squareClear(row, col)
def squareClear(row, col):
surrounding = [[row, col]]
while len(surrounding) > 0:
square = surrounding.pop()
squareID = int((fieldCanvas.find_closest((square[1]+1)*25, (square[0]+1)*25))[0])
squareIndex[(square[0])][(square[1])].isCleared = True
if squareIndex[(square[0])][(square[1])].minesAdjacent > 0:
fieldCanvas.itemconfigure(squareID, state=DISABLED, disabledimage=imgIndex[(squareIndex[(square[0])][(square[1])].minesAdjacent)])
else:
fieldCanvas.itemconfigure(squareID, state=DISABLED, disabledimage=imgIndex[(squareIndex[(square[0])][(square[1])].minesAdjacent)])
for loc in adj:
neighbor = [square[0]+adj[loc][0], square[1]+adj[loc][1]]
if neighbor[0] >= 0 and neighbor[1] >= 0 and neighbor[0] < boardHeight and neighbor[1] < boardWidth and squareIndex[neighbor[0]][neighbor[1]].isCleared == False and squareIndex[neighbor[0]][neighbor[1]].isMine == False and neighbor not in surrounding:
surrounding.append(neighbor)
##code for the tk display and key bindings to start functions
root = Tk()
root.title('SnakeSweeper')
fieldFrame = ttk.Frame(root, padding=0)
fieldFrame.grid(column=0, row=2, sticky='nesw')
imgIndex = {
0: PhotoImage(file='SqImg0.gif'),
1: PhotoImage(file='SqImg1.gif'),
2: PhotoImage(file='SqImg2.gif'),
3: PhotoImage(file='SqImg3.gif'),
4: PhotoImage(file='SqImg4.gif'),
5: PhotoImage(file='SqImg5.gif'),
6: PhotoImage(file='SqImg6.gif'),
7: PhotoImage(file='SqImg7.gif'),
8: PhotoImage(file='SqImg8.gif'),
'U': PhotoImage(file='SqImgU.gif'),
'A': PhotoImage(file='SqImgA.gif'),
'M': PhotoImage(file='SqImgM.gif'),
'F': PhotoImage(file='SqImgF.gif'),
'B': PhotoImage(file='SqImgB.gif')
}
fieldCanvas = Canvas(fieldFrame, width=((boardWidth*25)+50), height=((boardHeight*25)+50))
fieldCanvas.grid(column=0, row=0, sticky='nesw')
drawBoard(boardWidth, boardHeight)
prepareGame(boardWidth, boardHeight, minePercentage)
fieldCanvas.tag_bind(CURRENT, '<Button-1>', squareMaster)
root.mainloop()
improvement over all or not? further suggestions?
Offline