Use a more neutral algorithm to generate maze (#6)

This commit is contained in:
Nguyễn Gia Phong 2018-06-24 00:00:50 +07:00
parent 654a1a2c5e
commit e7d04930b3
5 changed files with 46 additions and 50 deletions

View File

@ -26,7 +26,7 @@ from sys import modules
from .constants import (
TANGO, HERO_HP, SFX_HEART, HEAL_SPEED, MIN_BEAT, ATTACK_SPEED, ENEMY,
ENEMY_SPEED, ENEMY_HP, SFX_SLASH_HERO, MIDDLE, WALL, FIRANGE, AROUND_HERO,
ADJACENTS, EMPTY, FG_COLOR, SQRT2, MINW)
ADJACENTS, EMPTY, SQRT2, MINW)
from .misc import sign, cosin, randsign, regpoly, fill_aapolygon, choices, play
from .weapons import Bullet

View File

@ -44,11 +44,12 @@ if mixer is None: pygame.mixer.quit()
SQRT2 = 2 ** 0.5
INIT_SCORE = 5**0.5/2 + 0.5 # golden mean
MAZE_SIZE = 10
ROAD_WIDTH = 5 # grids
CELL_WIDTH = ROAD_WIDTH * 2 # grids
MIDDLE = (MAZE_SIZE + MAZE_SIZE%2 - 1)*ROAD_WIDTH + ROAD_WIDTH//2
LAST_ROW = (MAZE_SIZE-1) * ROAD_WIDTH * 2
ROAD_WIDTH = 3 # grids
WALL_WIDTH = 4 # grids
CELL_WIDTH = WALL_WIDTH + ROAD_WIDTH*2 # grids
CELL_NODES = ROAD_WIDTH, ROAD_WIDTH + WALL_WIDTH, 0
MAZE_SIZE = 10 # cells
MIDDLE = MAZE_SIZE // 2 * CELL_WIDTH
HEAL_SPEED = 1 # HP/s
HERO_SPEED = 5 # grid/s
ENEMY_SPEED = 6 # grid/s

View File

@ -17,7 +17,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with Brutal Maze. If not, see <https://www.gnu.org/licenses/>.
__version__ = '0.7.4'
__version__ = '0.7.5'
import re
from argparse import ArgumentParser, FileType, RawTextHelpFormatter

View File

@ -19,42 +19,22 @@
__doc__ = 'Brutal Maze module for the maze class'
from collections import deque, defaultdict
from collections import defaultdict, deque
from math import pi, log
from random import choice, getrandbits, uniform
from random import choice, sample, uniform
import pygame
from .characters import Hero, new_enemy
from .constants import (
EMPTY, WALL, HERO, ENEMY, ROAD_WIDTH, MAZE_SIZE, MIDDLE, INIT_SCORE,
ENEMIES, MINW, MAXW, SQRT2, SFX_SPAWN, SFX_SLASH_ENEMY, SFX_LOSE,
ADJACENTS, TANGO_VALUES, BG_COLOR, FG_COLOR, CELL_WIDTH, LAST_ROW,
EMPTY, WALL, HERO, ENEMY, ROAD_WIDTH, WALL_WIDTH, CELL_WIDTH, CELL_NODES,
MAZE_SIZE, MIDDLE, INIT_SCORE, ENEMIES, MINW, MAXW, SQRT2, SFX_SPAWN,
SFX_SLASH_ENEMY, SFX_LOSE, ADJACENTS, TANGO_VALUES, BG_COLOR, FG_COLOR,
HERO_HP, ENEMY_HP, ATTACK_SPEED, HERO_SPEED, BULLET_LIFETIME)
from .misc import round2, sign, around, regpoly, fill_aapolygon, play
from .weapons import Bullet
def new_cell(bit, upper=True):
"""Return a half of a cell of the maze based on the given bit."""
if bit: return deque([WALL]*ROAD_WIDTH + [EMPTY]*ROAD_WIDTH)
if upper: return deque([WALL] * (ROAD_WIDTH<<1))
return deque([EMPTY] * (ROAD_WIDTH<<1))
def new_column():
"""Return a newly generated column of the maze."""
column = deque()
upper, lower = deque(), deque()
for _ in range(MAZE_SIZE):
b = getrandbits(1)
upper.extend(new_cell(b))
lower.extend(new_cell(b, False))
for _ in range(ROAD_WIDTH): column.append(upper.__copy__())
for _ in range(ROAD_WIDTH): column.append(lower.__copy__())
return column
class Maze:
"""Object representing the maze, including the characters.
@ -99,8 +79,10 @@ class Maze:
self.rangey = list(range(MIDDLE - h, MIDDLE + h + 1))
self.score = INIT_SCORE
self.map = deque()
for _ in range(MAZE_SIZE): self.map.extend(new_column())
self.map = deque(deque(EMPTY for _ in range(MAZE_SIZE * CELL_WIDTH))
for _ in range(MAZE_SIZE * CELL_WIDTH))
for x in range(MAZE_SIZE):
for y in range(MAZE_SIZE): self.new_cell(x, y)
self.vx = self.vy = 0.0
self.rotatex = self.rotatey = 0
self.bullets, self.enemies = [], []
@ -117,6 +99,24 @@ class Maze:
self.sfx_slash = SFX_SLASH_ENEMY
self.sfx_lose = SFX_LOSE
def new_cell(self, x, y):
"""Draw on the map a new cell whose coordinates are given.
For the sake of performance, cell corners are NOT redrawn.
"""
def draw_bit(bit, dx=0, dy=0):
startx, starty = x + CELL_NODES[dx], y + CELL_NODES[dy]
height = ROAD_WIDTH if dy else WALL_WIDTH
for i in range(ROAD_WIDTH if dx else WALL_WIDTH):
for j in range(height): self.map[startx + i][starty + j] = bit
x, y = x * CELL_WIDTH, y * CELL_WIDTH
draw_bit(WALL)
walls = set(sample(ADJACENTS, 2))
walls.add(choice(ADJACENTS))
for i, j in ADJACENTS:
draw_bit((WALL if (i, j) in walls else EMPTY), i, j)
def add_enemy(self):
"""Add enough enemies."""
walls = [(i, j) for i in self.rangex for j in self.rangey
@ -212,21 +212,14 @@ class Maze:
# Regenerate the maze
if abs(self.rotatex) == CELL_WIDTH:
self.rotatex = 0
for _ in range(CELL_WIDTH): self.map.pop()
self.map.extend(new_column())
for i in range(-CELL_WIDTH, 0):
self.map[i].rotate(self.rotatey)
for i in range(CELL_WIDTH): self.map[i].rotate(-self.rotatey)
for i in range(MAZE_SIZE): self.new_cell(0, i)
for i in range(CELL_WIDTH): self.map[i].rotate(self.rotatey)
if abs(self.rotatey) == CELL_WIDTH:
self.rotatey = 0
for i in range(MAZE_SIZE):
b, c = getrandbits(1), (i-1)*CELL_WIDTH + self.rotatex
for j, grid in enumerate(new_cell(b)):
for k in range(ROAD_WIDTH):
self.map[c + k][LAST_ROW + j] = grid
c += ROAD_WIDTH
for j, grid in enumerate(new_cell(b, False)):
for k in range(ROAD_WIDTH):
self.map[c + k][LAST_ROW + j] = grid
self.map.rotate(-self.rotatex)
for i in range(MAZE_SIZE): self.new_cell(i, 0)
self.map.rotate(self.rotatex)
def get_distance(self, x, y):
"""Return the distance from the center of the maze to the point
@ -437,8 +430,10 @@ class Maze:
"""Open new game."""
self.centerx, self.centery = self.w / 2.0, self.h / 2.0
self.score = INIT_SCORE
self.map = deque()
for _ in range(MAZE_SIZE): self.map.extend(new_column())
self.map = deque(deque(EMPTY for _ in range(MAZE_SIZE * CELL_WIDTH))
for _ in range(MAZE_SIZE * CELL_WIDTH))
for x in range(MAZE_SIZE):
for y in range(MAZE_SIZE): self.new_cell(x, y)
self.map[MIDDLE][MIDDLE] = HERO
self.destx = self.desty = MIDDLE
self.stepx = self.stepy = 0

View File

@ -7,7 +7,7 @@ with open('README.rst') as f:
setup(
name='brutalmaze',
version='0.7.4',
version='0.7.5',
description='A minimalist TPS game with fast-paced action',
long_description=long_description,
url='https://github.com/McSinyx/brutalmaze',