Toggle Navigation
Hatchery
Eggs
Maze3D
Maze3D.py
Users
Badges
Login
Register
Maze3D.py
raw
Content
### Author: Leiden Tech ### Description: Leiden Tech ### Category: Games ### License: MIT ### Appname: Maze3D ### Built-in: no import display import buttons import machine import math import random import mch22 fgcolor = display.BLACK bgcolor = display.WHITE font = "Roboto_Black22" grid = [] #size of maze w = 5 h = 8 #size of screen - should be able to get this from the system screenX = 320 screenY = 240 #TODO size of wall block - should maybe be abs((screenX - viewX) / (w * 2 + 1)) for variable sized mazes but then viewX, viewY has to be hard-coded pixelW = 6 pixelH = 6 #size of view screen viewX = screenX - (pixelW * (w * 2 + 1) ) - 6 #200 viewY = screenY - 3 #125 #defines x,y compass and array of 3 points for the poly char object dirOffset = [[0, 1, "N", [[-1, 1], [0, -1], [1, 1]]], [-1, 0, "E", [[-1, -1], [1, 0], [-1, 1]]], [0, -1, "S", [[-1, -1], [0, 1], [1, -1]]], [1, 0, "W", [[1, -1], [-1, 0], [1, 1]]]] #character direction - posX,posY set after maze is built direction = 0 posX = 0 posY = 0 compass = dirOffset[direction][2] def Maze3D(): global posX, posY random.seed(int(microseconds)) clearbg() makeMaze() clearStatus() posX = random.randrange(1, w * 2 - 1, 2) posY = random.randrange(1, h * 2 - 1, 2) grid[posX][posY][1] = 1 display.flush() drawDisplay() """ Start at a random cell. Mark the current cell as visited, and get a list of its neighbors. starting with a random neighbor and stepping through neighbors until a valid unvisited one is found: remove the wall between the current cell and that neighbor, and then recurse with that neighbor as the start point. when you hit the end of the recursion, start over with the next valid neighbor """ def makeMaze(): global grid """ sets up an array of WxH grid[x][y] = [wall,status] wall is True/False status is numeric 1) position of char 2) position of exit 3) position of monster 4) position of treasure 5) etc? """ #Set all positions in grid to wall grid = [[[True, 0] for i in range(h * 2 + 1)] for j in range(w * 2 + 1)] #Remove every other one to set up grid grid[x][y] = [wall,status] for x in range(1, w * 2 + 1, 2): ######### for y in range(1, h * 2 + 1, 2): # # # # # grid[x][y] = [False, 0] ######### #start at random cell and walk # # # # # startw = random.randrange(1, w * 2 - 1, 2) ######### starth = random.randrange(1, h * 2 - 1, 2) # # # # # walk(startw, starth, w * 2 - 1, h * 2 - 1) ######### def walk(x, y, ww, hh): global grid #mark current cell as visited grid[x][y][1] = 1 #get list of neighbors neighbors = [(x - 2, y), (x, y + 2), (x + 2, y), (x, y - 2)] #For each random neighbor #going to have to implement my own shuffle here, sigh neighbors = shuffle(neighbors) for (xx, yy) in neighbors: #skip if out of range if xx <= 0 or xx > ww or yy <= 0 or yy > hh: continue #Skip if already visited if grid[xx][yy][1] == 1: continue #if not previously visited, remove the connecting wall if xx == x: if grid[xx][yy][1] == 0: grid[xx][max(y, yy) - 1] = [False, 0] if yy == y: if grid[xx][yy][1] == 0: grid[max(x, xx) - 1][yy] = [False, 0] #recurse using neighbor as start point walk(xx, yy, ww, hh) def shuffle(target): #doesn't exist in micropython apparently, gotta roll my own length = len(target) secondary = -1 if length < 2: #what are you going to shuffle then moron? return for i in range(length): #maybe math.ceil(length/2)+1): primary = random.randint(0, length - 1) while secondary == primary: #no point in shuffling to itself secondary = random.randint(0, length - 1) tmp = target[primary] target[primary] = target[secondary] target[secondary] = tmp return target def clearStatus(): global grid for i in range(0, (w * 2 + 1)): for j in range(0, (h * 2 + 1)): grid[i][j][1] = 0 def drawCompass(): global compass display.drawFill(bgcolor) #compass - has to be set before drawView because that relies on this value compass = dirOffset[direction][2] display.drawText(screenX - (pixelW * (w * 2 + 1)), 100, compass, fgcolor, font) #There is room for status messages here #display.drawText(screenX - (pixelW * (w * 2 + 1)) + 20, 100, str(posX), font, fgcolor) #display.drawText(screenX - (pixelW * (w * 2 + 1)) + 40, 100, str(posY), font, fgcolor) def drawMaze(matrix, startX, startY, fixed = None): charSize = 4 if fixed is None: fixed = direction #offset where to start drawing map for y in range(len(matrix[0])): for x in range(len(matrix)): if matrix[x][y][0] is True: #wall display.drawRect(startX + (pixelW * x), startY + (pixelH * y), pixelW, pixelH,True, fgcolor) if matrix[x][y][1] == 1: #char pos triangle pointing in direction polyArray = resizePoly(dirOffset[fixed][3], charSize) display.drawTri( startX + (pixelW * x) + math.floor(pixelH/2) + polyArray[0][0], startY + (pixelH * y) + math.floor(pixelH/2) + polyArray[0][1], startX + (pixelW * x) + math.floor(pixelH/2) + polyArray[1][0], startY + (pixelH * y) + math.floor(pixelH/2) + polyArray[1][1], startX + (pixelW * x) + math.floor(pixelH/2) + polyArray[2][0], startY + (pixelH * y) + math.floor(pixelH/2) + polyArray[2][1], fgcolor) def resizePoly(array, size): #for variable sized char indicator polyArray = [] for point in array: polyArray.append([point[0]*size, point[1]*size]) return polyArray #These set up the array of what we can see def chunkN(): array = [] column = [] for row in grid[posX-1:posX+2]: column.append(row[:posY+1][::-1]) for i in range(len(column[0])): t = [e[i] for e in column] array.append(t) return array def chunkE(): array = [] for row in grid[posX:]: array.append(row[posY-1:posY+2]) return array def chunkS(): array = [] column = [] for row in grid[posX-1:posX+2]: column.append(row[posY:]) for i in range(len(column[0])): t = [e[i] for e in column] array.append(t[::-1]) return array def chunkW(): array = [] for row in grid[:posX+1]: array.append(row[posY-1:posY+2][::-1]) return array[::-1] def draw3dView(): done = False row = 0 maxDepth = max(w*2,h*2) #This could be calculated on the fly but it's probably not worth the effort offsetArray = [[0, 0], [28, 18], [48, 30], [62, 40], [77, 49], [84, 54], [90, 60]] maxDepth = min(len(offsetArray)-1, maxDepth) posGrid = [] #rotate and slice grid for view matrix if ( compass == "N"): posGrid = chunkN() if ( compass == "E"): posGrid = chunkE() if ( compass == "S"): posGrid = chunkS() if ( compass == "W"): posGrid = chunkW() #drawMaze(posGrid, 0, 0, 1) #draws what view is based on - for debugging #box around view display.drawRect(0, 0, viewX, viewY, False, fgcolor) while not done and row < maxDepth: #foreach depth #calculate the default points based on offset array offsetX = offsetArray[row + 1][0] offsetY = offsetArray[row + 1][1] startLTX = offsetArray[row][0] startLTY = offsetArray[row][1] endLTX = offsetX endLTY = offsetY #previous loop end numbers startLBX = offsetArray[row][0] startLBY = viewY - offsetArray[row][1] endLBX = offsetX endLBY = viewY - offsetY startRTX = viewX - offsetArray[row][0] startRTY = offsetArray[row][1] endRTX = viewX - offsetX endRTY = offsetY startRBX = viewX - offsetArray[row][0] startRBY = viewY - offsetArray[row][1] endRBX = viewX - offsetX endRBY = viewY - offsetY #if left is not wall, lower the start position if posGrid[row][0][0] is False: startLTY = offsetY startLBY = viewY - offsetY #if front is a wall move start right if posGrid[row + 1][1][0] is True: endLTX = viewX - offsetX endLBX = viewX - offsetX #if right is a wall move start to right wall and skip right if posGrid[row][2][0] is False: endLTX = viewX - offsetArray[row][0] endLBX = viewX - offsetArray[row][0] done = True else: #draw left vertical line display.drawLine(endLTX, endLTY, endLBX, endLBY, fgcolor) else: #left is wall #draw left vertical line display.drawLine(endLTX, endLTY, endLBX, endLBY, fgcolor) #draw two lines for that position display.drawLine(startLTX, startLTY, endLTX, endLTY, fgcolor) display.drawLine(startLBX, startLBY, endLBX, endLBY, fgcolor) if done: break #starting right side #if right is not a wall, lower the start position if posGrid[row][2][0] is False: startRTY = offsetY startRBY = viewY - offsetY #if front is a wall move end left if posGrid[row + 1][1][0] is True: endRTX = offsetX endRBX = offsetX done = True else: #draw right vertical line display.drawLine(endRTX, endRTY, endRBX, endRBY, fgcolor) else: #draw right vertical line display.drawLine(endRTX, endRTY, endRBX, endRBY, fgcolor) if posGrid[row + 1][1][0] is True: #draw end wall and finish #this is going to be redundant in some cases I think display.drawLine(endRTX, endRTY, endLTX, endLTY, fgcolor) display.drawLine(endRBX, endRBY, endLBX, endLBY, fgcolor) done = True #draw right lines display.drawLine(startRTX, startRTY, endRTX, endRTY, fgcolor) display.drawLine(startRBX, startRBY, endRBX, endRBY, fgcolor) if done: break row = row + 1 return def drawDisplay(): drawCompass() drawMaze(grid, screenX - (pixelW * (w * 2 + 1)), 0) draw3dView() display.flush() def quit(): display.clear(display.WHITE) display.flush() display.drawText(50, 50, "Quitting", fgcolor, font) display.flush() def clearbg(): global bgcolor display.drawFill(bgcolor) display.flush() def on_action_btn_a(pressed): global bgcolor if pressed: display.drawFill(bgcolor) display.flush() drawDisplay() def on_action_btn_b(pressed): if pressed: drawDisplay() def on_action_btn_up(pressed): global posX, posY if pressed: newX = posX - dirOffset[direction][0] newY = posY - dirOffset[direction][1] if grid[newX][newY][0] is False: grid[posX][posY][1] = 0 grid[newX][newY][1] = 1 posX = newX posY = newY drawDisplay() def on_action_btn_down(pressed): global direction if pressed: for i in range(2): direction = direction + 1 if direction >= len(dirOffset): direction = 0 drawDisplay() def on_action_btn_left(pressed): global direction if pressed: direction = direction - 1 if direction < 0: direction = len(dirOffset) - 1 drawDisplay() def on_action_btn_right(pressed): global direction if pressed: direction = direction+1 if direction >= len(dirOffset): direction = 0 drawDisplay() def on_action_btn_start(pressed): if pressed: mch22.exit_python() def on_action_btn_select(pressed): if pressed: Maze3D() ######## # MAIN # ######## buttons.attach(buttons.BTN_UP, on_action_btn_up) buttons.attach(buttons.BTN_DOWN, on_action_btn_down) buttons.attach(buttons.BTN_LEFT, on_action_btn_left) buttons.attach(buttons.BTN_RIGHT, on_action_btn_right) buttons.attach(buttons.BTN_SELECT, on_action_btn_select) buttons.attach(buttons.BTN_START, on_action_btn_start) buttons.attach(buttons.BTN_A, on_action_btn_a) buttons.attach(buttons.BTN_B, on_action_btn_b) #Default random seed doesn't seem to work - does it work for anyone? [year, month, mday, wday, hour, minute, second, microseconds] = machine.RTC().datetime() Maze3D()