# snake-demo.py from tkinter import * import random def init(data): data.rows = 8 data.cols = 16 data.margin = 5 data.direction = (0, -1) loadSnakeBoard(data) placeFood(data) data.gameOver = False data.paused = False data.debugMode = False def loadSnakeBoard(data): data.board = [] for row in range(data.rows): data.board += [[0]*data.cols] headRow = (len(data.board)) // 2 headCol = len(data.board[0]) // 2 data.board[headRow][headCol] = 1 data.headRow = headRow data.headCol = headCol def mousePressed(event, data): pass def keyPressed(event, data): if (event.char == "r"): init(data); return elif (event.char == "p"): data.paused = not data.paused; return elif (event.char == "d"): data.debugMode = not data.debugMode if (data.gameOver or data.paused): return if (event.keysym == "Left"): data.direction = (0, -1) elif (event.keysym == "Right"): data.direction = (0, 1) elif (event.keysym == "Up"): data.direction = (-1, 0) elif (event.keysym == "Down"): data.direction = ( 1, 0) takeStep(data) def timerFired(data): if (data.paused or data.gameOver): return takeStep(data) def takeStep(data): (drow, dcol) = data.direction (headRow, headCol) = (data.headRow, data.headCol) (newHeadRow, newHeadCol) = (headRow + drow, headCol + dcol) if ((newHeadRow < 0) or (newHeadRow >= data.rows) or (newHeadCol < 0) or (newHeadCol >= data.cols) or data.board[newHeadRow][newHeadCol] > 0): data.gameOver = True elif data.board[newHeadRow][newHeadCol] == -1: # eat food data.board[newHeadRow][newHeadCol]= data.board[headRow][headCol] + 1 (data.headRow, data.headCol) = (newHeadRow, newHeadCol) placeFood(data) else: # didn't eat, so remove old tail (slither forward) data.board[newHeadRow][newHeadCol] = data.board[headRow][headCol] + 1 (data.headRow, data.headCol) = (newHeadRow, newHeadCol) removeTail(data) def placeFood(data): row = random.randint(0, data.rows - 1) col = random.randint(0, data.cols - 1) while data.board[row][col] != 0: row = random.randint(0, data.rows - 1) col = random.randint(0, data.cols - 1) data.board[row][col] = -1 def removeTail(data): for row in range(data.rows): for col in range(data.cols): if data.board[row][col] > 0: data.board[row][col] -= 1 def drawBoard(canvas, data): for row in range(data.rows): for col in range(data.cols): drawSnakeCell(canvas, data, row, col) def drawSnakeCell(canvas, data, row,col): gridWidth = data.width - 2*data.margin gridHeight = data.height - 2*data.margin cellWidth = gridWidth / data.cols cellHeight = gridHeight / data.rows x0 = data.margin + gridWidth * col / data.cols x1 = data.margin + gridWidth * (col+1) / data.cols y0 = data.margin + gridHeight * row / data.rows y1 = data.margin + gridHeight * (row+1) / data.rows canvas.create_rectangle(x0, y0, x1, y1, fill="white", outline="black") if data.board[row][col] > 0: # draw snake body canvas.create_oval(x0, y0, x1, y1, fill="blue") elif data.board[row][col] == -1: # draw food canvas.create_oval(x0, y0, x1, y1, fill="green") if (data.debugMode): canvas.create_text(x0 + cellWidth/2, y0 + cellHeight/2, text=str(data.board[row][col]), font=("Helvatica", 14, "bold")) def redrawAll(canvas, data): drawBoard(canvas, data) if (data.gameOver): canvas.create_text(data.width/2, data.height/2, text="Game Over!", font=("Helvetica", 32, "bold")) #################################### # use the run function as-is #################################### def run(width=300, height=300): def redrawAllWrapper(canvas, data): canvas.delete(ALL) canvas.create_rectangle(0, 0, data.width, data.height, fill='white', width=0) redrawAll(canvas, data) canvas.update() def mousePressedWrapper(event, canvas, data): mousePressed(event, data) redrawAllWrapper(canvas, data) def keyPressedWrapper(event, canvas, data): keyPressed(event, data) redrawAllWrapper(canvas, data) def timerFiredWrapper(canvas, data): timerFired(data) redrawAllWrapper(canvas, data) # pause, then call timerFired again canvas.after(data.timerDelay, timerFiredWrapper, canvas, data) # Set up data and call init class Struct(object): pass data = Struct() data.width = width data.height = height data.timerDelay = 100 # milliseconds init(data) # create the root and the canvas root = Tk() canvas = Canvas(root, width=data.width, height=data.height) canvas.pack() # set up events root.bind("<Button-1>", lambda event: mousePressedWrapper(event, canvas, data)) root.bind("<Key>", lambda event: keyPressedWrapper(event, canvas, data)) timerFiredWrapper(canvas, data) # and launch the app root.mainloop() # blocks until window is closed print("bye!") run(300, 300)
from tkinter import * import random def init(data): data.rows = 10 data.cols = 10 data.margin = 5 # margin around grid data.snake = [(data.rows/2, data.cols/2)] data.direction = (0, +1) # (drow, dcol) placeFood(data) data.timerDelay = 250 data.gameOver = False data.paused = True # getCellBounds from grid-demo.py def getCellBounds(row, col, data): # aka "modelToView" # returns (x0, y0, x1, y1) corners/bounding box of given cell in grid gridWidth = data.width - 2*data.margin gridHeight = data.height - 2*data.margin x0 = data.margin + gridWidth * col / data.cols x1 = data.margin + gridWidth * (col+1) / data.cols y0 = data.margin + gridHeight * row / data.rows y1 = data.margin + gridHeight * (row+1) / data.rows return (x0, y0, x1, y1) def mousePressed(event, data): data.paused = False def keyPressed(event, data): if (event.keysym == "p"): data.paused = True; return elif (event.keysym == "r"): init(data); return if (data.paused or data.gameOver): return if (event.keysym == "Up"): data.direction = (-1, 0) elif (event.keysym == "Down"): data.direction = (+1, 0) elif (event.keysym == "Left"): data.direction = (0, -1) elif (event.keysym == "Right"): data.direction = (0, +1) # for debugging, take one step on any keypress takeStep(data) def timerFired(data): if (data.paused or data.gameOver): return takeStep(data) def takeStep(data): (drow, dcol) = data.direction (headRow, headCol) = data.snake[0] (newRow, newCol) = (headRow+drow, headCol+dcol) if ((newRow < 0) or (newRow >= data.rows) or (newCol < 0) or (newCol >= data.cols) or ((newRow, newCol) in data.snake)): data.gameOver = True else: data.snake.insert(0, (newRow, newCol)) if (data.foodPosition == (newRow, newCol)): placeFood(data) else: # didn't eat, so remove old tail (slither forward) data.snake.pop() def placeFood(data): data.foodPosition = None row0 = random.randint(0, data.rows-1) col0 = random.randint(0, data.cols-1) for drow in range(data.rows): for dcol in range(data.cols): row = (row0 + drow) % data.rows col = (col0 + dcol) % data.cols if (row,col) not in data.snake: data.foodPosition = (row, col) return def drawBoard(canvas, data): for row in range(data.rows): for col in range(data.cols): (x0, y0, x1, y1) = getCellBounds(row, col, data) canvas.create_rectangle(x0, y0, x1, y1, fill="white") def drawSnake(canvas, data): for (row, col) in data.snake: (x0, y0, x1, y1) = getCellBounds(row, col, data) canvas.create_oval(x0, y0, x1, y1, fill="blue") def drawFood(canvas, data): if (data.foodPosition != None): (row, col) = data.foodPosition (x0, y0, x1, y1) = getCellBounds(row, col, data) canvas.create_oval(x0, y0, x1, y1, fill="green") def drawGameOver(canvas, data): if (data.gameOver): canvas.create_text(data.width/2, data.height/2, text="Game over!", font="Arial 26 bold") def redrawAll(canvas, data): drawBoard(canvas, data) drawSnake(canvas, data) drawFood(canvas, data) drawGameOver(canvas, data) #################################### # use the run function as-is #################################### def run(width=300, height=300): def redrawAllWrapper(canvas, data): canvas.delete(ALL) canvas.create_rectangle(0, 0, data.width, data.height, fill='white', width=0) redrawAll(canvas, data) canvas.update() def mousePressedWrapper(event, canvas, data): mousePressed(event, data) redrawAllWrapper(canvas, data) def keyPressedWrapper(event, canvas, data): keyPressed(event, data) redrawAllWrapper(canvas, data) def timerFiredWrapper(canvas, data): timerFired(data) redrawAllWrapper(canvas, data) # pause, then call timerFired again canvas.after(data.timerDelay, timerFiredWrapper, canvas, data) # Set up data and call init class Struct(object): pass data = Struct() data.width = width data.height = height data.timerDelay = 100 # milliseconds init(data) # create the root and the canvas root = Tk() canvas = Canvas(root, width=data.width, height=data.height) canvas.pack() # set up events root.bind("<Button-1>", lambda event: mousePressedWrapper(event, canvas, data)) root.bind("<Key>", lambda event: keyPressedWrapper(event, canvas, data)) timerFiredWrapper(canvas, data) # and launch the app root.mainloop() # blocks until window is closed print("bye!") run(600, 300)