613 lines
19 KiB
Python
613 lines
19 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from sys import exit
|
|
import pygame
|
|
import random
|
|
|
|
# Parameters
|
|
WIDTH = 960
|
|
WAIT = 2000
|
|
SIZE = 15
|
|
WALL_COLOR = pygame.Color('#8F8F8FFF')
|
|
EXIT_COLOR = pygame.Color('#FF7F00FF')
|
|
SOFT_EDGE_COLOR = pygame.Color('#AFAFAFFF')
|
|
SHARP_EDGE_COLOR = pygame.Color('#5F5F9FFF')
|
|
FLOOR_COLOR = pygame.Color('#0F0F0FFF')
|
|
SEEN_COLOR = pygame.Color('#0F0F0FFF')
|
|
WIN_COLOR = pygame.Color('#FF0000FF')
|
|
START_COLOR = pygame.Color('#00FF00FF')
|
|
PLAYER_COLOR = pygame.Color('#0000FFFF')
|
|
UP = (-1, 0)
|
|
RIGHT = (0, 1)
|
|
DOWN = (1, 0)
|
|
LEFT = (0, -1)
|
|
FONT_FACE = 'Serif'
|
|
KP_NUMS = [pygame.K_KP0, pygame.K_KP1, pygame.K_KP2, pygame.K_KP3, pygame.K_KP4,
|
|
pygame.K_KP5, pygame.K_KP6, pygame.K_KP7, pygame.K_KP8, pygame.K_KP9]
|
|
|
|
# Secondary parameters
|
|
HEIGHT = 10*WIDTH//16
|
|
CENTERX = WIDTH // 2
|
|
CENTERY = HEIGHT // 3
|
|
WIDTHS = [(5 * WIDTH / (7 * (2 * depth + 1))) // 2 for depth in range(0, SIZE)]
|
|
WIDTHS.insert(0, 3 * WIDTHS[0] // 2)
|
|
HEIGHTS = [(6 * HEIGHT / (7 * (2 * depth + 1))) // 3 for depth in range(0, SIZE)]
|
|
HEIGHTS.insert(0, 3 * HEIGHTS[0] // 2)
|
|
FONT_SIZE = WIDTHS[1] // 15
|
|
DIRECTIONS = (UP, RIGHT, DOWN, LEFT)
|
|
ANGLESYX = ((UP, RIGHT), (DOWN, RIGHT), (DOWN, LEFT), (UP, LEFT))
|
|
SEEN_SIZE = max((SIZE * SIZE) // 50, 1)
|
|
|
|
def debug(message, maze = None, path = None):
|
|
return
|
|
print('-----------------')
|
|
print(message)
|
|
if maze is not None:
|
|
for row in range(0, len(maze)):
|
|
r = maze[row]
|
|
s = ''
|
|
sr = ''
|
|
for col in range(0, 2 * SIZE + 1):
|
|
sr += '1' if r & 1<<col else '0'
|
|
if (row % 2) or (col % 2):
|
|
if r & (1<<col):
|
|
if (row % 2) and (col % 2):
|
|
if path is not None and (row, col) in path:
|
|
s += 'O' if (row, col) == path[0] else 'o'
|
|
else:
|
|
s += '+'
|
|
else:
|
|
s += '*'
|
|
else:
|
|
s += '.'
|
|
else:
|
|
s += ' '
|
|
print(s, sr)
|
|
|
|
def back_dir(dir):
|
|
if dir is UP: return DOWN
|
|
if dir is DOWN: return UP
|
|
if dir is RIGHT: return LEFT
|
|
if dir is LEFT: return RIGHT
|
|
|
|
def shift_path(path, yx):
|
|
for i in range(0, len(path)):
|
|
p = path[i]
|
|
path[i] = (p[0] + yx[0], p[1] + yx[1])
|
|
|
|
def grow_maze(maze, path, yx = None, bdir = None, recurs = 1):
|
|
if yx is None:
|
|
for yx in range(0, len(path)):
|
|
grow_maze(maze, path, path[yx], None, 1)
|
|
return
|
|
debug(str(recurs) + ': growing', maze, path)
|
|
dontgo_dontblock = [bdir]
|
|
go_on = True
|
|
while go_on:
|
|
exits = []
|
|
for d in DIRECTIONS:
|
|
if d not in dontgo_dontblock:
|
|
d2 = d
|
|
if d is UP and yx[0] == 1:
|
|
if len(maze) < 2 * SIZE:
|
|
for row in (1, 2): maze.insert(0, 0)
|
|
shift_path(path, (2, 0))
|
|
yx = (yx[0] + 2, yx[1])
|
|
debug(str(recurs) + '...Expand UP.', maze, path)
|
|
else:
|
|
maze[0] |= 1<<(yx[1])
|
|
debug(str(recurs) + '...No UP.')
|
|
d2 = None
|
|
if d is RIGHT and yx[1] == 2 * SIZE - 1:
|
|
maze[yx[0]] |= 1<<(2 * SIZE)
|
|
debug(str(recurs) + '...No RIGHT')
|
|
d2 = None
|
|
if d is DOWN and yx[0] == len(maze) - 2:
|
|
if len(maze) < 2 * SIZE:
|
|
maze.extend([0, 0])
|
|
debug(str(recurs) + '...Expand DOWN.', maze, path)
|
|
else:
|
|
maze[2 * SIZE] |= 1<<(yx[1])
|
|
debug(str(recurs) + '...No DOWN')
|
|
d2 = None
|
|
if d is LEFT and yx[1] == 1:
|
|
if any(row & 1<<(2 * SIZE - 1) for row in maze):
|
|
maze[yx[0]] |= 1
|
|
debug(str(recurs) + '...No LEFT')
|
|
d2 = None
|
|
else:
|
|
for r in range(0, len(maze)): maze[r] = maze[r] << 2
|
|
shift_path(path, (0, 2))
|
|
yx = (yx[0], yx[1] + 2)
|
|
debug(str(recurs) + '...Expand LEFT.', maze, path)
|
|
if d2 is not None \
|
|
and not maze[yx[0] + d2[0]] & 1<<(yx[1] + d2[1]) \
|
|
and not maze[yx[0] + 2 * d2[0]] & 1<<(yx[1] + 2 * d2[1]):
|
|
debug(str(recurs) + '...exit added: ' + str(d2))
|
|
exits.append(d2)
|
|
else:
|
|
debug(str(recurs) + '...exit discarded: ' + str(d2))
|
|
if len(exits) == 0:
|
|
go_on = False
|
|
else:
|
|
d = exits[random.randrange(0, len(exits))]
|
|
debug(str(recurs) + '...Grow ' + str(d))
|
|
maze[yx[0] + 2 * d[0]] |= 1<<(yx[1] + 2 * d[1])
|
|
dontgo_dontblock.append(d)
|
|
for (y, x) in ANGLESYX:
|
|
if not maze[yx[0] + y[0]] & 1<<(yx[1]) and not maze[yx[0]] & 1<<(yx[1] + x[1]) \
|
|
and maze[yx[0] + 2 * y[0]] & 1<<(yx[1]) and maze[yx[0]] & 1<<(yx[1] + 2 * x[1]) \
|
|
and not (maze[yx[0] + 2 * y[0]] & 1<<(yx[1] + x[1]) and maze[yx[0] + y[0]] & 1<<(yx[1] + 2 * x[1])):
|
|
if (yx[0], yx[1]) in path:
|
|
action = 0
|
|
elif y in dontgo_dontblock and x in dontgo_dontblock:
|
|
action = 0
|
|
elif maze[yx[0] + 2 * y[0]] & 1<<(yx[1] + 2 * x[1]):
|
|
if y in dontgo_dontblock:
|
|
action = 2
|
|
elif x in dontgo_dontblock:
|
|
action = 1
|
|
elif not maze[yx[0] + 2 * y[0]] & 1<<(yx[1] + x[1]):
|
|
action = 1
|
|
elif not maze[yx[0] + y[0]] & 1<<(yx[1] + 2 * x[1]):
|
|
action = 2
|
|
else:
|
|
action = random.randrange(1, 3)
|
|
elif y in dontgo_dontblock:
|
|
action = random.randrange(2, 4)
|
|
elif x in dontgo_dontblock:
|
|
action = random.randrange(0, 2)
|
|
else:
|
|
action = random.randrange(0, 3)
|
|
if action == 1:
|
|
maze[yx[0] + y[0]] |= 1<<(yx[1])
|
|
elif action == 2:
|
|
maze[yx[0]] |= 1<<(yx[1] + x[1])
|
|
else:
|
|
maze[yx[0] + y[0]] |= 1<<(yx[1] + 2 * x[1])
|
|
maze[yx[0] + 2 * y[0]] |= 1<<(yx[1] + x[1])
|
|
if go_on:
|
|
yx2 = (yx[0] + 2 * d[0], yx[1] + 2 * d[1])
|
|
bdir2 = back_dir(d)
|
|
if bdir2 is not UP and (yx2[0] - 2, yx2[1]) in path:
|
|
maze[yx2[0] - 1] |= 1<<(yx2[1])
|
|
if bdir2 is not RIGHT and (yx2[0], yx2[1] + 2) in path:
|
|
maze[yx2[0]] |= 1<<(yx2[1] + 1)
|
|
if bdir2 is not DOWN and (yx2[0] + 2, yx2[1]) in path:
|
|
maze[yx2[0] + 1] |= 1<<(yx2[1])
|
|
if bdir2 is not LEFT and (yx2[0], yx2[1] - 2) in path:
|
|
maze[yx2[0]] |= 1<<(yx2[1] - 1)
|
|
oldstart = path[0]
|
|
grow_maze(maze, path, yx2, bdir2, recurs + 1)
|
|
newstart = path[0]
|
|
yx = (yx[0] + newstart[0] - oldstart[0], yx[1] + newstart[1] - oldstart[1])
|
|
|
|
def create_maze(recurs = 1, maze = None, yx = None, bdir = None, path = None):
|
|
if maze == None:
|
|
# bits are considered to be from bit 0 = LEFT to heaviest bit = RIGHT!
|
|
maze = [0, 2, 0] # 3 rows of 3 bits (for a start)
|
|
yx = (1, 1)
|
|
bdir = None
|
|
path = [yx]
|
|
debug(str(recurs) + ': coming from ' + str(bdir), maze, path)
|
|
exits = []
|
|
for d in (UP, RIGHT, DOWN, LEFT):
|
|
if d is bdir:
|
|
d2 = back_dir(d)
|
|
else:
|
|
d2 = d
|
|
if not maze[yx[0] + d2[0]] & 1<<(yx[1] + d2[1]):
|
|
exits.append(d2)
|
|
while len(exits) > 0:
|
|
d = exits[random.randrange(0, len(exits))]
|
|
exits.remove(d)
|
|
debug(str(recurs) + '...Try' + str(d))
|
|
nmaze = maze[:]
|
|
nyx = yx
|
|
npath = path[:]
|
|
if d is UP:
|
|
if nyx[0] == 1:
|
|
for row in (1, 2): nmaze.insert(0, 0)
|
|
shift_path(npath, (2, 0))
|
|
nyx = (nyx[0] + 2, nyx[1])
|
|
nmaze[nyx[0] - 2] |= 1<<(nyx[1])
|
|
npath.append((nyx[0] - 2, nyx[1]))
|
|
if nyx[1] > 1 and nmaze[nyx[0] - 2] & 1<<(nyx[1] - 2):
|
|
nmaze[nyx[0] - 2] |= 1<<(nyx[1] - 1)
|
|
if nmaze[nyx[0] - 2] & 1<<(nyx[1] + 2):
|
|
nmaze[nyx[0] - 2] |= 1<<(nyx[1] + 1)
|
|
if nyx[0] > 3 and nmaze[nyx[0] - 4] & 1<<(nyx[1]):
|
|
nmaze[nyx[0] - 3] |= 1<<(nyx[1])
|
|
if bdir is LEFT:
|
|
nmaze[nyx[0] - 1] |= 1<<(nyx[1] - 2)
|
|
nmaze[nyx[0] - 2] |= 1<<(nyx[1] - 1)
|
|
if bdir is RIGHT:
|
|
nmaze[nyx[0] - 1] |= 1<<(nyx[1] + 2)
|
|
nmaze[nyx[0] - 2] |= 1<<(nyx[1] + 1)
|
|
if len(nmaze) == 2 * SIZE + 1:
|
|
return nmaze, npath
|
|
nmaze, npath = create_maze(recurs + 1, nmaze, (nyx[0] - 2, nyx[1]), DOWN, npath)
|
|
if nmaze is not None:
|
|
return nmaze, npath
|
|
if d is RIGHT:
|
|
nmaze[nyx[0]] |= 1<<(nyx[1] + 2)
|
|
npath.append((nyx[0], nyx[1] + 2))
|
|
if nyx[0] > 1 and nmaze[nyx[0] - 2] & 1<<(nyx[1] + 2):
|
|
nmaze[nyx[0] - 1] |= 1<<(nyx[1] + 2)
|
|
if nyx[0] < len(nmaze) - 2 and nmaze[nyx[0] + 2] & 1<<(nyx[1] + 2):
|
|
nmaze[nyx[0] + 1] |= 1<<(nyx[1] + 2)
|
|
if nmaze[nyx[0]] & 1<<(nyx[1] + 4):
|
|
nmaze[nyx[0]] |= 1<<(nyx[1] + 3)
|
|
if bdir is UP:
|
|
nmaze[nyx[0] - 1] |= 1<<(nyx[1] + 2)
|
|
nmaze[nyx[0] - 2] |= 1<<(nyx[1] + 1)
|
|
if bdir is DOWN:
|
|
nmaze[nyx[0] + 1] |= 1<<(nyx[1] + 2)
|
|
nmaze[nyx[0] + 2] |= 1<<(nyx[1] + 1)
|
|
if any(row & 1<<(2 * SIZE - 1) for row in nmaze):
|
|
return nmaze, npath
|
|
nmaze, npath = create_maze(recurs + 1, nmaze, (nyx[0], nyx[1] + 2), LEFT, npath)
|
|
if nmaze is not None:
|
|
return nmaze, npath
|
|
if d is DOWN:
|
|
if nyx[0] == len(nmaze) - 2:
|
|
nmaze.extend([0, 0])
|
|
nmaze[nyx[0] + 2] |= 1<<(nyx[1])
|
|
npath.append((nyx[0] + 2, nyx[1]))
|
|
if nyx[1] > 1 and nmaze[nyx[0] + 2] & 1<<(nyx[1] - 2):
|
|
nmaze[nyx[0] + 2] |= 1<<(nyx[1] - 1)
|
|
if nmaze[nyx[0] + 2] & 1<<(nyx[1] + 2):
|
|
nmaze[nyx[0] + 2] |= 1<<(nyx[1] + 1)
|
|
if nyx[0] < len(nmaze) - 4 and nmaze[nyx[0] + 4] & 1<<(nyx[1]):
|
|
nmaze[nyx[0] + 3] |= 1<<(nyx[1])
|
|
if bdir is LEFT:
|
|
nmaze[nyx[0] + 1] |= 1<<(nyx[1] - 2)
|
|
nmaze[nyx[0] + 2] |= 1<<(nyx[1] - 1)
|
|
if bdir is RIGHT:
|
|
nmaze[nyx[0] + 1] |= 1<<(nyx[1] + 2)
|
|
nmaze[nyx[0] + 2] |= 1<<(nyx[1] + 1)
|
|
if len(nmaze) == 2 * SIZE + 1:
|
|
return nmaze, npath
|
|
nmaze, npath = create_maze(recurs + 1, nmaze, (nyx[0] + 2, nyx[1]), UP, npath)
|
|
if nmaze is not None:
|
|
return nmaze, npath
|
|
if d is LEFT:
|
|
if nyx[1] == 1:
|
|
for r in range(0, len(nmaze)): nmaze[r] = nmaze[r] << 2
|
|
shift_path(npath, (0, 2))
|
|
nyx = (nyx[0], nyx[1] + 2)
|
|
nmaze[nyx[0]] |= 1<<(nyx[1] - 2)
|
|
npath.append((nyx[0], nyx[1] - 2))
|
|
if nyx[0] > 1 and nmaze[nyx[0] - 2] & 1<<(nyx[1] - 2):
|
|
nmaze[nyx[0] - 1] |= 1<<(nyx[1] - 2)
|
|
if nyx[0] < len(nmaze) - 2 and nmaze[nyx[0] + 2] & 1<<(nyx[1] - 2):
|
|
nmaze[nyx[0] + 1] |= 1<<(nyx[1] - 2)
|
|
if nyx[1] > 3 and nmaze[nyx[0]] & 1<<(nyx[1] - 4):
|
|
nmaze[nyx[0]] |= 1<<(nyx[1] - 3)
|
|
if bdir is UP:
|
|
nmaze[nyx[0] - 1] |= 1<<(nyx[1] - 2)
|
|
nmaze[nyx[0] - 2] |= 1<<(nyx[1] - 1)
|
|
if bdir is DOWN:
|
|
nmaze[nyx[0] + 1] |= 1<<(nyx[1] - 2)
|
|
nmaze[nyx[0] + 2] |= 1<<(nyx[1] - 1)
|
|
if any(row & 1<<(2 * SIZE - 1) for row in nmaze):
|
|
return nmaze, npath
|
|
nmaze, npath = create_maze(recurs + 1, nmaze, (nyx[0], nyx[1] - 2), RIGHT, npath)
|
|
if nmaze is not None:
|
|
return nmaze, npath
|
|
return None, None
|
|
|
|
def relative(dir, rel):
|
|
if dir is UP:
|
|
return rel
|
|
elif rel is UP:
|
|
return dir
|
|
elif rel is DOWN:
|
|
if dir is RIGHT:
|
|
return LEFT
|
|
elif dir is LEFT:
|
|
return RIGHT
|
|
else:
|
|
return UP
|
|
elif rel == dir:
|
|
return DOWN
|
|
elif dir is DOWN:
|
|
if rel is RIGHT:
|
|
return LEFT
|
|
else:
|
|
return RIGHT
|
|
else:
|
|
return UP
|
|
|
|
def is_exit(path, pos, dir):
|
|
return (pos[0] + dir[0] == 0 or pos[0] + dir[0] == 2 * SIZE \
|
|
or pos[1] + dir[1] == 0 or pos[1] + dir[1] == 2 * SIZE) \
|
|
and (pos[0], pos[1]) == path[-1]
|
|
|
|
def is_wall(maze, pos, dir):
|
|
return maze[pos[0] + dir[0]] & 1<<(pos[1] + dir[1])
|
|
|
|
def new_pos(pos, dir):
|
|
return (pos[0] + 2 * dir[0], pos[1] + 2 * dir[1])
|
|
|
|
def rotate_dir(dir, left_or_right):
|
|
return DIRECTIONS[(DIRECTIONS.index(dir) + left_or_right[1]) % 4]
|
|
|
|
def draw_maze(maze, path, game, seen, pos, dir, shift = None, depth = None, clip = None):
|
|
s = pygame.display.get_surface()
|
|
if clip is None:
|
|
fake_path = [pos, new_pos(pos, dir)]
|
|
debug('played:', maze, fake_path)
|
|
s.set_clip(None)
|
|
s.fill(FLOOR_COLOR)
|
|
draw_maze(maze, path, game, seen, pos, dir, 0, 1, s.get_rect())
|
|
pygame.display.update()
|
|
s.set_clip(None)
|
|
return
|
|
# Inner/Outer - Width/Height/X/Y
|
|
iw = WIDTHS[depth]
|
|
ow = WIDTHS[depth - 1]
|
|
ih = HEIGHTS[depth]
|
|
oh = HEIGHTS[depth - 1]
|
|
ix = CENTERX + 2 * shift * iw
|
|
ox = CENTERX + 2 * shift * ow
|
|
iy = oy = CENTERY
|
|
if not pygame.Rect(ox - ow, oy - oh, 2 * ow + 1, 3 * oh + 1).colliderect(clip) \
|
|
and not pygame.Rect(ix - iw, iy - ih, 2 * iw + 1, 3 * ih + 1).colliderect(clip):
|
|
return
|
|
it = [None, (ix + iw, iy - ih), (ix - iw, iy - ih)]
|
|
ib = [None, (ix + iw, iy + ih * 2), (ix - iw, iy + ih * 2)]
|
|
ot = [None, (ox + ow, oy - oh), (ox - ow, oy - oh)]
|
|
ob = [None, (ox + ow, oy + oh * 2), (ox - ow, oy + oh * 2)]
|
|
# floor
|
|
if seen != 0 and pos in game:
|
|
alpha = game[::-1].index(pos)
|
|
if seen < 0:
|
|
alpha = 255 - 171 * alpha / len(game)
|
|
elif alpha > seen - 1:
|
|
alpha = -1
|
|
else:
|
|
alpha = 255 - 190 * alpha / seen
|
|
else:
|
|
alpha = -1
|
|
if alpha >= 0:
|
|
s.set_clip(clip)
|
|
p = pygame.Surface(((iw + ow) // 2, (oy + 2 * oh - iy - 2 * ih) // 2))
|
|
p.fill(FLOOR_COLOR)
|
|
p.set_colorkey(FLOOR_COLOR)
|
|
pygame.draw.ellipse(p, PLAYER_COLOR, p.get_rect())
|
|
p.set_alpha(alpha)
|
|
s.blit(p, ((2 * ix + 2 * ox - iw -ow) // 4, (3 * iy / 2 + 3 * ih + oy / 2 + oh) // 2))
|
|
# ahead
|
|
if is_wall(maze, pos, dir):
|
|
s.set_clip(clip)
|
|
pygame.draw.polygon(s, EXIT_COLOR if is_exit(path, pos, dir) else WALL_COLOR, [ib[1], it[1], it[-1], ib[-1]])
|
|
pygame.draw.line(s, SHARP_EDGE_COLOR, it[-1], it[1])
|
|
pygame.draw.line(s, SHARP_EDGE_COLOR, ib[-1], ib[1])
|
|
pygame.draw.line(s, SOFT_EDGE_COLOR, it[-1], ib[-1])
|
|
pygame.draw.line(s, SOFT_EDGE_COLOR, it[1], ib[1])
|
|
else:
|
|
r = pygame.Rect(ix - iw, iy - ih, 2 * iw + 1, 3 * ih + 1).clip(clip)
|
|
if r.width > 0 and r.height > 0:
|
|
draw_maze(maze, path, game, seen, new_pos(pos, dir), dir, shift, depth + 1, r)
|
|
# sides
|
|
for d in (LEFT, RIGHT):
|
|
tmpdir = relative(d, dir)
|
|
s.set_clip(clip)
|
|
if (d is LEFT and shift > 0) or (d is RIGHT and shift < 0):
|
|
if not is_wall(maze, pos, tmpdir):
|
|
pygame.draw.line(s, SHARP_EDGE_COLOR, ot[-1 * d[1]], ob[-1 * d[1]])
|
|
elif is_wall(maze, pos, tmpdir):
|
|
pygame.draw.polygon(s, EXIT_COLOR if is_exit(path, pos, tmpdir) else WALL_COLOR, [ib[d[1]], it[d[1]], ot[d[1]], ob[d[1]]])
|
|
pygame.draw.line(s, SHARP_EDGE_COLOR, it[d[1]], ot[d[1]])
|
|
pygame.draw.line(s, SHARP_EDGE_COLOR, ib[d[1]], ob[d[1]])
|
|
pygame.draw.line(s, SOFT_EDGE_COLOR, it[d[1]], ib[d[1]])
|
|
pygame.draw.line(s, SOFT_EDGE_COLOR, ot[d[1]], ob[d[1]])
|
|
else:
|
|
tmppos = new_pos(pos, tmpdir)
|
|
r = pygame.Rect(ix + iw if d is RIGHT else ox - ow, 0, d[1] * (ox + d[1] * ow) - d[1] * (ix + d[1] * iw) + 1, HEIGHT).clip(clip)
|
|
if r.width > 0 and r.height > 0:
|
|
draw_maze(maze, path, game, seen, tmppos, dir, shift + d[1], depth, r)
|
|
if not is_wall(maze, tmppos, dir):
|
|
s.set_clip(clip)
|
|
pygame.draw.line(s, SHARP_EDGE_COLOR, it[d[1]], ib[d[1]])
|
|
|
|
def get_help_surface(maze, path = None):
|
|
size = HEIGHT // SIZE
|
|
s = pygame.Surface((SIZE * size, SIZE * size)).convert()
|
|
for row in range(0, SIZE):
|
|
for col in range(0, SIZE):
|
|
yx = (2 * row + 1, 2 * col + 1)
|
|
if path and yx == path[0]:
|
|
color = START_COLOR
|
|
elif path and yx == path[-1]:
|
|
color = EXIT_COLOR
|
|
else:
|
|
color = FLOOR_COLOR
|
|
pygame.draw.rect(s, color, pygame.Rect(col * size + 1, row * size + 1, size - 2, size - 2))
|
|
if is_wall(maze, yx, UP):
|
|
color = SHARP_EDGE_COLOR
|
|
else:
|
|
color = FLOOR_COLOR
|
|
pygame.draw.line(s, color, (col * size, row * size), ((col + 1) * size - 1, row * size))
|
|
if is_wall(maze, yx, RIGHT):
|
|
color = SHARP_EDGE_COLOR
|
|
else:
|
|
color = FLOOR_COLOR
|
|
pygame.draw.line(s, color, ((col + 1) * size - 1, row * size), ((col + 1) * size - 1, (row + 1) * size - 1))
|
|
if is_wall(maze, yx, DOWN):
|
|
color = SHARP_EDGE_COLOR
|
|
else:
|
|
color = FLOOR_COLOR
|
|
pygame.draw.line(s, color, (col * size, (row + 1) * size - 1), ((col + 1) * size - 1, (row + 1) * size - 1))
|
|
if is_wall(maze, yx, LEFT):
|
|
color = SHARP_EDGE_COLOR
|
|
else:
|
|
color = FLOOR_COLOR
|
|
pygame.draw.line(s, color, (col * size, row * size), (col * size, (row + 1) * size - 1))
|
|
return s
|
|
|
|
def get_player_surface():
|
|
size = HEIGHT // SIZE
|
|
p = pygame.Surface((size, size)).convert()
|
|
p.fill(WALL_COLOR)
|
|
pygame.draw.line(p, PLAYER_COLOR, (size // 3, 2 * size // 3), (size // 2, size // 3))
|
|
pygame.draw.line(p, PLAYER_COLOR, (2 * size // 3, 2 * size // 3), (size // 2, size // 3))
|
|
p.set_colorkey(WALL_COLOR)
|
|
return p
|
|
|
|
def draw_help(helpmap, pos = None, dir = None, player = None):
|
|
s = pygame.display.get_surface()
|
|
s.fill(WALL_COLOR)
|
|
s.blit(helpmap, (CENTERX - helpmap.get_width() // 2, 0))
|
|
if pos:
|
|
size = HEIGHT // SIZE
|
|
x = CENTERX - helpmap.get_width() // 2 + ((pos[1] - 1) / 2) * size
|
|
y = ((pos[0] - 1) / 2) * size
|
|
if dir is RIGHT:
|
|
p = pygame.transform.rotate(player, -90)
|
|
elif dir is LEFT:
|
|
p = pygame.transform.rotate(player, 90)
|
|
elif dir is DOWN:
|
|
p = pygame.transform.rotate(player, 180)
|
|
else:
|
|
p = player
|
|
s.blit(p, (x + 1, y + 1))
|
|
pygame.display.update()
|
|
|
|
def draw_end(helpmap, path, game):
|
|
txt = pygame.font.SysFont(FONT_FACE, FONT_SIZE)\
|
|
.render(str(len(game) - 1) + ' STEPS (+ ' + str(len(game) - len(path)) + ')', True, WIN_COLOR)
|
|
pygame.display.get_surface().blit(txt, (CENTERX - txt.get_width() // 2, CENTERY - txt.get_height() // 2))
|
|
pygame.display.update()
|
|
pygame.time.wait(WAIT)
|
|
size = HEIGHT // SIZE
|
|
player = pygame.Surface((size, size)).convert()
|
|
player.fill(WALL_COLOR)
|
|
pygame.draw.circle(player, PLAYER_COLOR, (size // 2, size // 2), size // 3)
|
|
shadow = pygame.Surface((size, size)).convert()
|
|
shadow.blit(player, (0, 0))
|
|
player.set_colorkey(WALL_COLOR)
|
|
shadow.set_colorkey(WALL_COLOR)
|
|
shadow.set_alpha(84)
|
|
endwait = True
|
|
while endwait and len(game):
|
|
yx = game.pop(0)
|
|
y = ((yx[0] - 1) / 2) * size
|
|
x = ((yx[1] - 1) / 2) * size
|
|
helpmap.blit(shadow, (x, y))
|
|
draw_help(helpmap, yx, UP, player)
|
|
pygame.time.wait(200)
|
|
for evt in pygame.event.get():
|
|
if evt.type == pygame.QUIT:
|
|
endwait = False
|
|
elif evt.type == pygame.KEYUP and evt.key == pygame.K_ESCAPE:
|
|
endwait = False
|
|
if endwait:
|
|
pygame.time.wait(WAIT)
|
|
|
|
def draw_fake_maze():
|
|
high = 1
|
|
low = 1
|
|
for i in range(0, SIZE):
|
|
high = (high<<2) | 3
|
|
low = (low<<2) | 1
|
|
fake = [high]
|
|
for i in range(0, SIZE):
|
|
fake.extend([low, high])
|
|
draw_help(get_help_surface(fake))
|
|
|
|
# Pygame initialisation
|
|
pygame.init()
|
|
pygame.event.set_allowed([pygame.QUIT, pygame.KEYUP])
|
|
pygame.display.set_mode((WIDTH, HEIGHT))
|
|
pygame.display.set_caption('Laby')
|
|
pygame.mouse.set_visible(0)
|
|
|
|
# Choose maze size
|
|
draw_fake_maze()
|
|
redraw = False
|
|
while True:
|
|
evt = pygame.event.wait()
|
|
if evt.type == pygame.QUIT:
|
|
exit()
|
|
elif evt.type == pygame.KEYUP:
|
|
if evt.key == pygame.K_ESCAPE:
|
|
exit()
|
|
elif evt.key == pygame.K_KP_PLUS:
|
|
SIZE += 5
|
|
redraw = True
|
|
elif evt.key == pygame.K_KP_MINUS:
|
|
SIZE -= 5
|
|
redraw = True
|
|
else:
|
|
break
|
|
if redraw:
|
|
draw_fake_maze()
|
|
redraw = False
|
|
|
|
# Maze creation
|
|
maze, path = create_maze()
|
|
debug('PATH ', maze, path)
|
|
grow_maze(maze, path)
|
|
debug('GROWN ', maze, path)
|
|
|
|
# Player variables
|
|
play_pos = path[0]
|
|
play_dir = DIRECTIONS[random.randrange(0, 4)]
|
|
game = [play_pos]
|
|
helpmap = get_help_surface(maze, path)
|
|
heading = get_player_surface()
|
|
|
|
# Main loop
|
|
seen = 0
|
|
endwait = True
|
|
help = False
|
|
run = True
|
|
draw_maze(maze, path, game, seen, play_pos, play_dir)
|
|
while run:
|
|
evt = pygame.event.wait()
|
|
if evt.type == pygame.QUIT:
|
|
run = False
|
|
endwait = False
|
|
elif evt.type == pygame.KEYUP:
|
|
if evt.key == pygame.K_ESCAPE:
|
|
run = False
|
|
endwait = False
|
|
elif evt.key == pygame.K_h:
|
|
help = not help
|
|
elif evt.key == pygame.K_UP:
|
|
rel_dir = relative(UP, play_dir)
|
|
if is_exit(path, play_pos, rel_dir):
|
|
run = False
|
|
elif not is_wall(maze, play_pos, rel_dir):
|
|
play_pos = new_pos(play_pos, rel_dir)
|
|
game.append(play_pos)
|
|
elif evt.key == pygame.K_RIGHT:
|
|
play_dir = rotate_dir(play_dir, RIGHT)
|
|
elif evt.key == pygame.K_DOWN:
|
|
rel_dir = relative(DOWN, play_dir)
|
|
if is_exit(path, play_pos, rel_dir):
|
|
run = False
|
|
elif not is_wall(maze, play_pos, rel_dir):
|
|
play_pos = new_pos(play_pos, rel_dir)
|
|
game.append(play_pos)
|
|
elif evt.key == pygame.K_LEFT:
|
|
play_dir = rotate_dir(play_dir, LEFT)
|
|
elif evt.key in KP_NUMS:
|
|
seen = SEEN_SIZE * KP_NUMS.index(evt.key)
|
|
elif evt.key == pygame.K_KP_MULTIPLY:
|
|
seen = -SEEN_SIZE
|
|
elif evt.key == pygame.K_KP_PLUS:
|
|
seen += 5 * SEEN_SIZE
|
|
elif evt.key == pygame.K_KP_MINUS:
|
|
seen -= 5 * SEEN_SIZE
|
|
if help:
|
|
draw_help(helpmap, play_pos, play_dir, heading)
|
|
else:
|
|
draw_maze(maze, path, game, seen, play_pos, play_dir)
|
|
|
|
if endwait:
|
|
draw_end(helpmap, path, game)
|