-
Notifications
You must be signed in to change notification settings - Fork 0
/
primMapMaker.py
111 lines (97 loc) · 5.55 KB
/
primMapMaker.py
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
from objectData import *
import random
# https://www.cs.cmu.edu/~112/notes/notes-2d-lists.html
def make2dList(rows, cols):
return [([0] * cols) for row in range(rows)]
class cell(object):
def __init__(self, row, col):
self.row = row
self.col = col
self.adjacentCells = {(row - 1, col), (row + 1, col), (row, col + 1), (row, col - 1)}
self.contents = None
self.status = False # True if it is a passage/tunnel, false if it is a wall
class level(object):
def __init__(self, difficulty):
self.grid = self.make2dListofCells(difficulty, difficulty)
self.convertToMaze(self.grid)
self.cellStatus = self.testCells(self.grid)
self.fillCells(self.grid)
def make2dListofCells(self, rows, cols):
grid = make2dList(rows, cols)
for row in range(rows):
for col in range(cols):
grid[row][col] = cell(row, col)
if row == 0: # Remove adjacent cells not present in the grid
grid[row][col].adjacentCells.remove((row - 1, col))
if col == 0:
grid[row][col].adjacentCells.remove((row, col - 1))
if rows + 1 == rows:
grid[row][col].adjacentCells.remove((row + 1, col))
if cols + 1 == cols:
grid[row][col].adjacentCells.remove((row, col + 1))
return grid
# Theoretical information from https://en.wikipedia.org/wiki/Maze_generation_algorithm#Randomized_Prim's_algorithm
# More general theoretical information from https://en.wikipedia.org/wiki/Prim%27s_algorithm
# 2-cell frontier idea from https://stackoverflow.com/questions/29739751/implementing-a-randomly-generated-maze-using-prims-algorithm
# 1-cell frontier is possible, but the mazes it generates do not look as nice (see image (not mine): https://i.stack.imgur.com/WG7EV.png)
# Swapped to entirely using cells without walls because it would also make it graphically easier to render without losing the complexity of the maze generator in the process
# Easier to store both cells AND walls as cells in a grid, rather than storing the walls of the grid in a separate data format
def convertToMaze(self, grid): # This is where Prim's algorithm is implemented
startCellRow = 0
startCellCol = 0
grid[startCellRow][startCellCol].status = True # Always start from top left corner - doesn't really change the algorithm, but makes character placement later
frontierCells = set()
neighbors = self.getNeighbors(grid, startCellRow, startCellCol, False)
for neighbor in neighbors:
frontierCells.add(neighbor)
while len(frontierCells) > 0:
frontierList = list(frontierCells) # Slightly inefficient but easiest way to get a random element while maintaining set properties
nextCell = frontierList[random.randint(0, len(frontierList) - 1)]
nextCellPassages = self.getNeighbors(grid, nextCell[0], nextCell[1], True)
passage = nextCellPassages[random.randint(0, len(nextCellPassages) - 1)]
middleCellRow = (nextCell[0] + passage[0]) // 2
middleCellCol = (nextCell[1] + passage[1]) // 2
grid[middleCellRow][middleCellCol].status = True
grid[nextCell[0]][nextCell[1]].status = True
frontierCellNeighbors = self.getNeighbors(grid, nextCell[0], nextCell[1], False)
# states of each cell
for neighbor in frontierCellNeighbors:
frontierCells.add(neighbor)
frontierCells.remove(nextCell)
def getNeighbors(self, grid, row, col, cellType):
neighbors = []
rows = len(grid)
cols = len(grid[0])
for drow in [-2, 0, 2]:
for dcol in [-2, 0, 2]:
if row + drow >= 0 and row + drow < rows and col + dcol >= 0 and col + dcol < cols and (drow == 0 or dcol == 0):
# If it's in the grid, if it's 2 cells in any of the compass directions
if cellType == grid[row + drow][col + dcol].status: # If it matches the type of cell we want - false for walls, true for passages
neighbors.append((row + drow, col + dcol))
return neighbors
def testCells(self, grid):
cells = make2dList(len(grid), len(grid[0]))
for row in range(len(grid)):
for col in range(len(grid[0])):
cells[row][col] = grid[row][col].status
return cells
def fillCells(self, grid):
enemyCountToPlace = len(grid)
heartCountToPlace = len(grid) // 10
weaponCountToPlace = len(grid) // 5
weaponList = [Pistol, Rocket, Sword]
self.placeObjects(grid, Enemy, enemyCountToPlace)
self.placeObjects(grid, Heart, heartCountToPlace)
self.placeObjects(grid, weaponList, weaponCountToPlace)
def placeObjects(self, grid, entity, entityCount):
while entityCount > 0: # Keep randomly placing enemies in cells
cellRow = random.randint(1, len(grid) - 1)
cellCol = random.randint(1, len(grid) - 1)
if grid[cellRow][cellCol].contents is None and grid[cellRow][cellCol].status:
if entity is Enemy:
grid[cellRow][cellCol].contents = entity('Goomba', len(grid))
elif entity is Heart:
grid[cellRow][cellCol].contents = entity(len(grid))
elif isinstance(entity, list):
grid[cellRow][cellCol].contents = entity[random.randint(0, len(entity)-1)](len(grid))
entityCount -= 1