641 lines
24 KiB
Python
641 lines
24 KiB
Python
|
#! /usr/bin/env python3
|
||
|
|
||
|
# this module is under licence MIT @ Tiemen DUVILLARD 2020
|
||
|
# for all questions, comments, bugs: duvillard.tiemen@gmail.com
|
||
|
|
||
|
from random import choice, randrange
|
||
|
|
||
|
# Representation of maze :
|
||
|
# A labyrinth is a set of 2 door panels.
|
||
|
# For a maze 5*5 :
|
||
|
# Theory : ## Example :
|
||
|
# L = [[[a, b, c, d], # vertical doors ## L = [[[1, 1, 1, 1], # vertical doors
|
||
|
# [e, f, g, h], ## [1, 0, 1, 0],
|
||
|
# [i, j, k, l], ## [0, 1, 0, 1],
|
||
|
# [m, n, o, p], ## [0, 0, 0, 0],
|
||
|
# [q, r, s, t]], ## [0, 1, 0, 0]],
|
||
|
# [[A, B, C, D, E], # horizontal doors ## [[0, 0, 0, 0, 0], # horizontal doors
|
||
|
# [F, G, H, I, J], ## [0, 0, 0, 0, 1],
|
||
|
# [K, L, M, N, O], ## [0, 1, 1, 1, 0],
|
||
|
# [P, Q, R, S, T]]] ## [0, 1, 0, 1, 1]]]
|
||
|
# ##
|
||
|
# ==>> ## ==>>
|
||
|
# X 0 1 2 3 4 ## X 0 1 2 3 4
|
||
|
# Y ┌───┬───┬───┬───┬───┐ ## Y ┌───┬───┬───┬───┬───┐
|
||
|
# 0 │ ∙ a ∙ b ∙ c ∙ d ∙ │ ## 0 │ ∙ │ ∙ │ ∙ │ ∙ │ ∙ │
|
||
|
# ├─A─┼─B─┼─C─┼─D─┼─E─┤ ## │ │ │ │ │ │
|
||
|
# 1 │ ∙ e ∙ f ∙ g ∙ h ∙ │ ## 1 │ ∙ │ ∙ ∙ │ ∙ ∙ │
|
||
|
# ├─F─┼─G─┼─H─┼─I─┼─J─┤ ## │ │ │ │ ┌───┤
|
||
|
# 2 │ ∙ i ∙ j ∙ k ∙ l ∙ │ ## 2 │ ∙ ∙ │ ∙ ∙ │ ∙ │
|
||
|
# ├─K─┼─L─┼─M─┼─N─┼─O─┤ ## │ ╶───┴───────┘ │
|
||
|
# 3 │ ∙ m ∙ n ∙ o ∙ p ∙ │ ## 3 │ ∙ ∙ ∙ ∙ ∙ │
|
||
|
# ├─P─┼─Q─┼─R─┼─S─┼─T─┤ ## │ ╶───┐ ╶───────│
|
||
|
# 4 │ ∙ q ∙ r ∙ s ∙ t ∙ │ ## 4 │ ∙ ∙ │ ∙ ∙ ∙ │
|
||
|
# └───┴───┴───┴───┴───┘ ## └───────┴───────────┘
|
||
|
|
||
|
def kruskal(x, y):
|
||
|
global ID
|
||
|
ID = 0
|
||
|
|
||
|
class case:
|
||
|
"""Little class for union-find"""
|
||
|
def __init__(self,x,y):
|
||
|
self.x = x
|
||
|
self.y = y
|
||
|
self.is_repr = True
|
||
|
self.repr = None
|
||
|
global ID
|
||
|
self.ID = ID
|
||
|
ID += 1
|
||
|
|
||
|
def represent(self):
|
||
|
if self.is_repr:
|
||
|
return self
|
||
|
else:
|
||
|
L = [self.repr]
|
||
|
while not L[0].is_repr:
|
||
|
L[0] = L[0].repr
|
||
|
return L[0]
|
||
|
|
||
|
def __eq__(self,other):
|
||
|
return self.represent().ID == other.represent().ID
|
||
|
|
||
|
def union(self,other):
|
||
|
a = self.represent()
|
||
|
b = other.represent()
|
||
|
if not (a == b):
|
||
|
b.is_repr = False
|
||
|
b.repr = a
|
||
|
|
||
|
# set of doors
|
||
|
doors = []
|
||
|
# verticals doors result
|
||
|
verti = []
|
||
|
# horizontals doors result
|
||
|
horiz = []
|
||
|
# set of cases
|
||
|
cases = []
|
||
|
## initialize vertical doors
|
||
|
for j in range(y):
|
||
|
l = []
|
||
|
for i in range(x-1):
|
||
|
l.append(1)
|
||
|
doors.append([i,j,'v'])
|
||
|
verti.append(l)
|
||
|
## initialize horizontal doors
|
||
|
for j in range(y-1):
|
||
|
l = []
|
||
|
for i in range(x):
|
||
|
l.append(1)
|
||
|
doors.append([i,j,'h'])
|
||
|
horiz.append(l)
|
||
|
|
||
|
## initialize cases
|
||
|
for i in range(y):
|
||
|
l = []
|
||
|
for j in range(x):
|
||
|
l.append(case(x,y))
|
||
|
cases.append(l)
|
||
|
|
||
|
cpt = x*y -1 # nb of openings in perfect maze
|
||
|
while cpt > 0:
|
||
|
# I choose a door
|
||
|
idoor = randrange(len(doors))
|
||
|
dx, dy, dd = doors[idoor]
|
||
|
cx1, cy1 = dx, dy
|
||
|
if dd == 'h' : cx2, cy2 = cx1, cy1+1
|
||
|
else : cx2, cy2 = cx1+1, cy1
|
||
|
|
||
|
C1 = cases[cy1][cx1]
|
||
|
C2 = cases[cy2][cx2]
|
||
|
# if the 2 cases separate by my door are not in same set
|
||
|
if not C1 == C2:
|
||
|
C1.union(C2)
|
||
|
cpt -= 1
|
||
|
# i modify my result
|
||
|
if dd == "v": verti[dy][dx] = 0
|
||
|
else: horiz[dy][dx] = 0
|
||
|
# i delete the door
|
||
|
del doors[idoor]
|
||
|
|
||
|
return verti,horiz
|
||
|
|
||
|
def recursive_backtrack(x, y):
|
||
|
# Initialisation of my variables
|
||
|
labyrinthe = []
|
||
|
for i in range(y): labyrinthe.append([0] * x)
|
||
|
horiz = []
|
||
|
for i in range(y-1): horiz.append([1] * x)
|
||
|
verti = []
|
||
|
for i in range(y): verti.append([1] * (x-1))
|
||
|
|
||
|
# I choose a random start
|
||
|
X_pos = randrange(x)
|
||
|
Y_pos = randrange(y)
|
||
|
labyrinthe[Y_pos][X_pos] = 1
|
||
|
historique = [[X_pos,Y_pos]]
|
||
|
|
||
|
# I explore a tree with deep parcours
|
||
|
while len(historique) != 0:
|
||
|
X = historique[-1][0]
|
||
|
Y = historique[-1][1]
|
||
|
|
||
|
possibilite = []
|
||
|
if (Y-1 >= 0) and (labyrinthe[Y-1][X] == 0): possibilite.append(0)
|
||
|
if (X+1 < x) and (labyrinthe[Y][X+1] == 0): possibilite.append(1)
|
||
|
if (Y+1 < y) and (labyrinthe[Y+1][X] == 0): possibilite.append(2)
|
||
|
if (X-1 >= 0) and (labyrinthe[Y][X-1] == 0): possibilite.append(3)
|
||
|
|
||
|
if len(possibilite) == 0:
|
||
|
del historique[-1]
|
||
|
else:
|
||
|
d = choice(possibilite)
|
||
|
if d == 0:
|
||
|
X1,Y1 = X, Y-1
|
||
|
horiz[Y-1][X] = 0
|
||
|
if d == 1:
|
||
|
X1,Y1 = X+1, Y
|
||
|
verti[Y][X] = 0
|
||
|
if d == 2:
|
||
|
X1,Y1 = X, Y+1
|
||
|
horiz[Y][X] = 0
|
||
|
if d == 3:
|
||
|
X1,Y1 = X-1, Y
|
||
|
verti[Y][X-1] = 0
|
||
|
labyrinthe[Y1][X1] = 1
|
||
|
historique.append([X1,Y1])
|
||
|
|
||
|
return verti, horiz
|
||
|
|
||
|
|
||
|
def recursive_chamber(x, y):
|
||
|
# Initialisation of my variables
|
||
|
def recursive_chamber_recu(VERTI,HORIZ,xA,yA,xB,yB):
|
||
|
if (xB - xA <= 1):
|
||
|
return
|
||
|
elif (yB - yA <= 1):
|
||
|
return
|
||
|
else :
|
||
|
dx = xB-xA
|
||
|
dy = yB-yA
|
||
|
v = randrange(0,dx+dy)
|
||
|
if v < dx :
|
||
|
x = randrange(xA,xB-1)
|
||
|
y = randrange(yA,yB)
|
||
|
for i in range(yA,yB):
|
||
|
if i != y:
|
||
|
VERTI[i][x] = 1
|
||
|
recursive_chamber_recu(VERTI,HORIZ,xA,yA,x+1,yB)
|
||
|
recursive_chamber_recu(VERTI,HORIZ,x+1,yA,xB,yB)
|
||
|
else:
|
||
|
x = randrange(xA,xB)
|
||
|
y = randrange(yA,yB-1)
|
||
|
for i in range(xA,xB):
|
||
|
if i != x:
|
||
|
HORIZ[y][i] = 1
|
||
|
recursive_chamber_recu(VERTI,HORIZ,xA,yA,xB,y+1)
|
||
|
recursive_chamber_recu(VERTI,HORIZ,xA,y+1,xB,yB)
|
||
|
|
||
|
|
||
|
horiz = []
|
||
|
for i in range(y-1): horiz.append([0] * x)
|
||
|
verti = []
|
||
|
for i in range(y): verti.append([0] * (x-1))
|
||
|
|
||
|
# appel recursif
|
||
|
recursive_chamber_recu(verti,horiz,0,0,x,y)
|
||
|
|
||
|
return verti, horiz
|
||
|
|
||
|
# a empty maze
|
||
|
def empty(x, y):
|
||
|
verti = []
|
||
|
for i in range(y):
|
||
|
verti.append([0] * (x-1))
|
||
|
|
||
|
horiz = []
|
||
|
for i in range(y-1):
|
||
|
horiz.append([0] * x)
|
||
|
return verti, horiz
|
||
|
|
||
|
# a full maze
|
||
|
def full(x, y):
|
||
|
verti = []
|
||
|
for i in range(y):
|
||
|
verti.append([1] * (x-1))
|
||
|
|
||
|
horiz = []
|
||
|
for i in range(y-1):
|
||
|
horiz.append([1] * x)
|
||
|
return verti, horiz
|
||
|
|
||
|
|
||
|
|
||
|
class MazeLib:
|
||
|
"""This Class define a Maze object"""
|
||
|
def __init__(self, X=5, Y=5, algorithm="empty"):
|
||
|
"""Use : m = Maze(X:int,Y:int, algorithm:string)"""
|
||
|
self.X = X # width
|
||
|
self.Y = Y # height
|
||
|
self.verti = [] # table of vertical doors
|
||
|
self.horiz = [] # table of horizontal doors
|
||
|
algorithm = algorithm.lower()
|
||
|
|
||
|
if algorithm in ("kruskal","k") :
|
||
|
self.verti, self.horiz = kruskal(self.X,self.Y)
|
||
|
self.doors = self.nbDoors()
|
||
|
self.algorithm = "kruskal"
|
||
|
self.perfect = True
|
||
|
|
||
|
elif algorithm in ("recursive_backtrack","rb") :
|
||
|
self.verti, self.horiz = recursive_backtrack(self.X,self.Y)
|
||
|
self.doors = self.nbDoors()
|
||
|
self.algorithm = "recursive_backtrack"
|
||
|
self.perfect = True
|
||
|
|
||
|
elif algorithm in ("empty","e") :
|
||
|
self.verti, self.horiz = empty(self.X,self.Y)
|
||
|
self.doors = self.nbDoors()
|
||
|
self.algorithm = "empty"
|
||
|
self.perfect = False
|
||
|
|
||
|
elif algorithm in ("full","f") :
|
||
|
self.verti, self.horiz = full(self.X,self.Y)
|
||
|
self.doors = self.nbDoors()
|
||
|
self.algorithm = "full"
|
||
|
self.perfect = False
|
||
|
|
||
|
elif algorithm in ("recursive_chamber","rc") :
|
||
|
self.verti, self.horiz = recursive_chamber(self.X,self.Y)
|
||
|
self.doors = self.nbDoors()
|
||
|
self.algorithm = "recursive_chamber"
|
||
|
self.perfect = False
|
||
|
|
||
|
else :
|
||
|
raise("Algorithm not recognized. Algorithm must be in ['kruskal','recursive_backtrack','empty','full']")
|
||
|
|
||
|
def __str__(self):
|
||
|
"""Return information about maze"""
|
||
|
s = "Size of maze : {}*{}\nGenerate by : {}\nNb of doors : {}\nPerfect : {}"
|
||
|
s = s.format(self.X,self.Y,self.algorithm,self.doors,self.perfect)
|
||
|
return s
|
||
|
|
||
|
def nbDoors(self):
|
||
|
"""Return number of doors in my maze. If maze is perfect, it equals to (self.X-1)*(self.Y-1)"""
|
||
|
S = 0
|
||
|
for k in self.verti: S += sum(k)
|
||
|
for k in self.horiz: S += sum(k)
|
||
|
return S
|
||
|
|
||
|
def verticalDoors(self):
|
||
|
"""Iterate on vertical doors"""
|
||
|
for i in range(len(self.verti)):
|
||
|
for j in range(len(self.verti[i])):
|
||
|
yield i,j, bool(self.verti[i][j])
|
||
|
|
||
|
def horizontalDoors(self):
|
||
|
"""Iterate on horizontal doors"""
|
||
|
for i in range(len(self.horiz)):
|
||
|
for j in range(len(self.horiz[i])):
|
||
|
yield i,j, bool(self.horiz[i][j])
|
||
|
|
||
|
def canMove(self, x, y, direction) :
|
||
|
"""return if i can move in a direction since (x,y) """
|
||
|
if direction in ["down","d",0] : # down
|
||
|
if y == self.Y-1 :return False
|
||
|
return not self.horiz[y][x]
|
||
|
if direction in ["up","u",2] : # up
|
||
|
if y == 0 : return False
|
||
|
return not self.horiz[y-1][x]
|
||
|
if direction in ["left","l",3] : # left
|
||
|
if x == 0 : return False
|
||
|
return not self.verti[y][x-1]
|
||
|
if direction in ["right","r",1] : # right
|
||
|
if x == self.X-1 : return False
|
||
|
return not self.verti[y][x]
|
||
|
return False
|
||
|
|
||
|
def move(self, x, y, direction) :
|
||
|
"""return new cord after one move in direction"""
|
||
|
if direction in ["down","d",0] : # down
|
||
|
return x,y+1
|
||
|
if direction in ["up","u",2] : # up
|
||
|
return x,y-1
|
||
|
if direction in ["left","l",3] : # left
|
||
|
return x-1,y
|
||
|
if direction in ["right","r",1] : # right
|
||
|
return x+1,y
|
||
|
return x,y
|
||
|
|
||
|
def liberty(self, x, y):
|
||
|
"""return all cases accessible from (x,y)"""
|
||
|
r = []
|
||
|
for d in ["down","up","left","right"]:
|
||
|
if self.canMove(x,y,d):
|
||
|
r.append(d)
|
||
|
return d
|
||
|
|
||
|
def toSquare(self):
|
||
|
"""return another representation of maze, a List of List of case in {0,1} """
|
||
|
RET = []
|
||
|
for i in range(self.Y*2+1):
|
||
|
l = []
|
||
|
for j in range(self.X*2+1):
|
||
|
if i == 0 or i == self.Y*2 or j == 0 or j == self.X*2 :
|
||
|
l.append(1)
|
||
|
else :
|
||
|
if (i%2==0 and j%2==0) :
|
||
|
l.append(1)
|
||
|
elif (i%2==1 and j%2==1):
|
||
|
l.append(0)
|
||
|
elif (i%2==0 and j%2==1):
|
||
|
l.append(self.horiz[(i-1)//2][(j-1)//2])
|
||
|
elif (i%2==1 and j%2==0):
|
||
|
l.append(self.verti[(i-1)//2][(j-1)//2])
|
||
|
RET.append(l)
|
||
|
return RET
|
||
|
|
||
|
def solve(self, xa, ya, xb, yb):
|
||
|
"""return a list of direction for link (xa,ya) -> (xb,yb). Null"""
|
||
|
Sol = []
|
||
|
Pile = [(xa,ya)]
|
||
|
laby = []
|
||
|
for i in range(self.Y):
|
||
|
laby.append(['new'] * self.X)
|
||
|
|
||
|
while len(Pile) != 0 and Pile[-1] != (xb,yb):
|
||
|
pos = Pile[-1]
|
||
|
x,y = pos[0],pos[1]
|
||
|
if laby[y][x] == 'new':
|
||
|
possibilite = []
|
||
|
for d in ['down',"left","up","right"]:
|
||
|
if self.canMove(pos[0],pos[1],d) :
|
||
|
nx,ny = self.move(pos[0],pos[1],d)
|
||
|
if laby[ny][nx] == 'new' :
|
||
|
possibilite.append(d)
|
||
|
|
||
|
laby[y][x] = possibilite
|
||
|
elif laby[y][x] == "old":
|
||
|
del Pile[-1]
|
||
|
if len(Sol) != 0:
|
||
|
del Sol[-1]
|
||
|
elif type(laby[y][x]) == list:
|
||
|
if len(laby[y][x]) == 0:
|
||
|
laby[y][x] = "old"
|
||
|
else:
|
||
|
ichoix = -1#randrange(len(laby[y][x]))
|
||
|
choix = laby[y][x][ichoix]
|
||
|
Pile.append(self.move(x,y,choix))
|
||
|
Sol.append(choix)
|
||
|
del laby[y][x][ichoix]
|
||
|
|
||
|
return Sol
|
||
|
|
||
|
def furthestBox(self, xa, ya):
|
||
|
"""return the case furtest of the case (xa,ya)"""
|
||
|
Sol = []
|
||
|
dmax = len(Sol)
|
||
|
pmax = Sol.copy()
|
||
|
cmax = (xa,ya)
|
||
|
|
||
|
Pile = [(xa,ya)]
|
||
|
laby = []
|
||
|
for i in range(self.Y):
|
||
|
laby.append(['new'] * self.X)
|
||
|
|
||
|
while len(Pile) != 0:
|
||
|
pos = Pile[-1]
|
||
|
x,y = pos[0],pos[1]
|
||
|
if laby[y][x] == 'new':
|
||
|
possibilite = []
|
||
|
for d in ['down',"left","up","right"]:
|
||
|
if self.canMove(pos[0],pos[1],d) :
|
||
|
nx,ny = self.move(pos[0],pos[1],d)
|
||
|
if laby[ny][nx] == 'new' :
|
||
|
possibilite.append(d)
|
||
|
|
||
|
laby[y][x] = possibilite
|
||
|
elif laby[y][x] == "old":
|
||
|
if len(Sol) > dmax:
|
||
|
dmax = len(Sol)
|
||
|
pmax = Sol.copy()
|
||
|
cmax = (x,y)
|
||
|
del Pile[-1]
|
||
|
if len(Sol) != 0:
|
||
|
del Sol[-1]
|
||
|
elif type(laby[y][x]) == list:
|
||
|
if len(laby[y][x]) == 0:
|
||
|
laby[y][x] = "old"
|
||
|
else:
|
||
|
ichoix = -1#randrange(len(laby[y][x]))
|
||
|
choix = laby[y][x][ichoix]
|
||
|
Pile.append(self.move(x,y,choix))
|
||
|
Sol.append(choix)
|
||
|
del laby[y][x][ichoix]
|
||
|
|
||
|
return pmax, cmax
|
||
|
|
||
|
def longestWay(self):
|
||
|
Xa = randrange(self.X)
|
||
|
Ya = randrange(self.Y)
|
||
|
p,B = self.furthestBox(Xa,Ya)
|
||
|
path,C = self.furthestBox(B[0],B[1])
|
||
|
return B,path,C
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
def save(self):
|
||
|
"""Return a string contain's all information. it can be save in file, print, etc.."""
|
||
|
s = "{};{};{};{};{};{};{}".format(self.X, self.Y, self.doors, self.algorithm, self.perfect, self.verti, self.horiz)
|
||
|
return s
|
||
|
|
||
|
def load(self, st):
|
||
|
"""Load a Maze since a string of format save"""
|
||
|
cont = st.split(";")
|
||
|
self.X = int(cont[0])
|
||
|
self.Y = int(cont[1])
|
||
|
self.doors = int(cont[2])
|
||
|
self.algorithm = cont[3]
|
||
|
self.perfect = bool(cont[4])
|
||
|
self.verti = cont[5].split("], [")
|
||
|
for i in range(len(self.verti)):
|
||
|
self.verti[i] = self.verti[i].split(',')
|
||
|
for j in range(len(self.verti[i])):
|
||
|
self.verti[i][j] = self.verti[i][j].replace("[","")
|
||
|
self.verti[i][j] = self.verti[i][j].replace("]","")
|
||
|
self.verti[i][j] = self.verti[i][j].replace(" ","")
|
||
|
self.verti[i][j] = int(self.verti[i][j])
|
||
|
|
||
|
self.horiz = cont[6].split("], [")
|
||
|
for i in range(len(self.horiz)):
|
||
|
self.horiz[i] = self.horiz[i].split(',')
|
||
|
for j in range(len(self.horiz[i])):
|
||
|
self.horiz[i][j] = self.horiz[i][j].replace("[","")
|
||
|
self.horiz[i][j] = self.horiz[i][j].replace("]","")
|
||
|
self.horiz[i][j] = self.horiz[i][j].replace(" ","")
|
||
|
self.horiz[i][j] = int(self.horiz[i][j])
|
||
|
|
||
|
def toTxt(self, centre=False, coord=False, basic= False):
|
||
|
"""return a txt representation of maze in ASCII art"""
|
||
|
if type(centre) == bool:
|
||
|
if centre : centre = "*"
|
||
|
else : centre = " "
|
||
|
else:
|
||
|
centre = centre[0]
|
||
|
|
||
|
if basic :
|
||
|
if coord:
|
||
|
R = " X"
|
||
|
for i in range(self.X):
|
||
|
R += " {} ".format(i%10)
|
||
|
R += "\n"
|
||
|
R += "Y +"
|
||
|
r = "0 |"
|
||
|
else:
|
||
|
R = "+"
|
||
|
r = "|"
|
||
|
for j in range(self.X-1):
|
||
|
if self.verti[0][j]:
|
||
|
R += "---+"
|
||
|
r += " {} |".format(centre)
|
||
|
else:
|
||
|
R += "----"
|
||
|
r += " {} ".format(centre)
|
||
|
R += "---+\n"
|
||
|
r += " {} |\n".format(centre)
|
||
|
R += r
|
||
|
for i in range(self.Y-1):
|
||
|
if coord:
|
||
|
if self.horiz[i][0]:
|
||
|
l1 = " +"
|
||
|
else:
|
||
|
l1 = " |"
|
||
|
l2 = "{} |".format((i+1)%10)
|
||
|
else:
|
||
|
if self.horiz[i][0]:
|
||
|
l1 = "+"
|
||
|
else:
|
||
|
l1 = "|"
|
||
|
l2 = "|"
|
||
|
for j in range(self.X-1):
|
||
|
inter = "+"
|
||
|
if self.horiz[i][j] and self.horiz[i][j+1] and not self.verti[i][j] and not self.verti[i+1][j] : inter = "-"
|
||
|
if not self.horiz[i][j] and not self.horiz[i][j+1] and self.verti[i][j] and self.verti[i+1][j] : inter = "|"
|
||
|
if not self.horiz[i][j] and not self.horiz[i][j+1] and not self.verti[i][j] and not self.verti[i+1][j] : inter = " "
|
||
|
|
||
|
if self.horiz[i][j]:
|
||
|
l1 += "---"+inter
|
||
|
else:
|
||
|
l1 += " "+inter
|
||
|
|
||
|
if self.verti[i+1][j]:
|
||
|
l2 += " {} |".format(centre)
|
||
|
else:
|
||
|
l2 += " {} ".format(centre)
|
||
|
if self.horiz[i][-1]:
|
||
|
l1 += "---+"
|
||
|
else:
|
||
|
l1 += " |"
|
||
|
l2 += " {} |".format(centre)
|
||
|
|
||
|
R += l1 + "\n"
|
||
|
R += l2 + "\n"
|
||
|
if coord:
|
||
|
r = " +"
|
||
|
else:
|
||
|
r = "+"
|
||
|
for j in range(self.X-1):
|
||
|
if self.verti[-1][j]:
|
||
|
r += "---+"
|
||
|
else:
|
||
|
r += "----"
|
||
|
r += "---+"
|
||
|
R += r
|
||
|
return R
|
||
|
|
||
|
else :
|
||
|
if coord:
|
||
|
R = " X"
|
||
|
for i in range(self.X):
|
||
|
R += " {} ".format(i%10)
|
||
|
R += "\n"
|
||
|
R += "Y ┌"
|
||
|
r = "0 │"
|
||
|
else:
|
||
|
R = "┌"
|
||
|
r = "│"
|
||
|
for j in range(self.X-1):
|
||
|
if self.verti[0][j]:
|
||
|
R += "───┬"
|
||
|
r += " {} │".format(centre)
|
||
|
else:
|
||
|
R += "────"
|
||
|
r += " {} ".format(centre)
|
||
|
R += "───┐\n"
|
||
|
r += " {} │\n".format(centre)
|
||
|
R += r
|
||
|
for i in range(self.Y-1):
|
||
|
if coord:
|
||
|
if self.horiz[i][0]:
|
||
|
l1 = " ├"
|
||
|
else:
|
||
|
l1 = " │"
|
||
|
l2 = "{} │".format((i+1)%10)
|
||
|
else:
|
||
|
if self.horiz[i][0]:
|
||
|
l1 = "├"
|
||
|
else:
|
||
|
l1 = "│"
|
||
|
l2 = "│"
|
||
|
for j in range(self.X-1):
|
||
|
# 4 door
|
||
|
if self.horiz[i][j] and self.horiz[i][j+1] and self.verti[i][j] and self.verti[i+1][j] : inter = "┼"
|
||
|
# 3 door
|
||
|
if self.horiz[i][j] and self.horiz[i][j+1] and self.verti[i][j] and not self.verti[i+1][j] : inter = "┴"
|
||
|
if self.horiz[i][j] and self.horiz[i][j+1] and not self.verti[i][j] and self.verti[i+1][j] : inter = "┬"
|
||
|
if self.horiz[i][j] and not self.horiz[i][j+1] and self.verti[i][j] and self.verti[i+1][j] : inter = "┤"
|
||
|
if not self.horiz[i][j] and self.horiz[i][j+1] and self.verti[i][j] and self.verti[i+1][j] : inter = "├"
|
||
|
# 2 door
|
||
|
if self.horiz[i][j] and self.horiz[i][j+1] and not self.verti[i][j] and not self.verti[i+1][j] : inter = "─"
|
||
|
if self.horiz[i][j] and not self.horiz[i][j+1] and self.verti[i][j] and not self.verti[i+1][j] : inter = "┘"
|
||
|
if not self.horiz[i][j] and self.horiz[i][j+1] and self.verti[i][j] and not self.verti[i+1][j] : inter = "└"
|
||
|
if self.horiz[i][j] and not self.horiz[i][j+1] and not self.verti[i][j] and self.verti[i+1][j] : inter = "┐"
|
||
|
if not self.horiz[i][j] and self.horiz[i][j+1] and not self.verti[i][j] and self.verti[i+1][j] : inter = "┌"
|
||
|
if not self.horiz[i][j] and not self.horiz[i][j+1] and self.verti[i][j] and self.verti[i+1][j] : inter = "│"
|
||
|
# 1 door
|
||
|
if not self.horiz[i][j] and not self.horiz[i][j+1] and not self.verti[i][j] and self.verti[i+1][j] : inter = "╷"
|
||
|
if not self.horiz[i][j] and not self.horiz[i][j+1] and self.verti[i][j] and not self.verti[i+1][j] : inter = "╵"
|
||
|
if not self.horiz[i][j] and self.horiz[i][j+1] and not self.verti[i][j] and not self.verti[i+1][j] : inter = "╶"
|
||
|
if self.horiz[i][j] and not self.horiz[i][j+1] and not self.verti[i][j] and not self.verti[i+1][j] : inter = "╴"
|
||
|
# 0 door
|
||
|
if not self.horiz[i][j] and not self.horiz[i][j+1] and not self.verti[i][j] and not self.verti[i+1][j] : inter = " "
|
||
|
if self.horiz[i][j]:
|
||
|
l1 += "───"+inter
|
||
|
else:
|
||
|
l1 += " "+inter
|
||
|
|
||
|
if self.verti[i+1][j]:
|
||
|
l2 += " {} │".format(centre)
|
||
|
else:
|
||
|
l2 += " {} ".format(centre)
|
||
|
if self.horiz[i][-1]:
|
||
|
l1 += "───┤"
|
||
|
else:
|
||
|
l1 += " │"
|
||
|
l2 += " {} │".format(centre)
|
||
|
|
||
|
R += l1 + "\n"
|
||
|
R += l2 + "\n"
|
||
|
if coord:
|
||
|
r = " └"
|
||
|
else:
|
||
|
r = "└"
|
||
|
for j in range(self.X-1):
|
||
|
if self.verti[-1][j]:
|
||
|
r += "───┴"
|
||
|
else:
|
||
|
r += "────"
|
||
|
r += "───┘"
|
||
|
R += r
|
||
|
return R
|