I'm practicing in Python, PySide and some algorithms. You can find a simple maze generator/solver below.
from PySide.QtCore import * from PySide.QtGui import * import sys import random class Maze(QWidget): def __init__(self, width, height, boxsize=7): QWidget.__init__(self) self.setMazeSize(width, height, boxsize) self.generateMazeDFS() def setMazeSize(self, width, height, boxsize): self.maze_width = width self.maze_height = height self.boxsize = boxsize self.setFixedSize(width * boxsize + 10, height * boxsize + 10) def generateMazeDumb(self, width=None, height=None, sparseness=None): if width is None: width = self.maze_width if height is None: height = self.maze_height if sparseness is None: sparseness = 2 self.vwall = [[random.randint(0,sparseness) for x in range(0, width+1)] for y in range(0, height)] self.hwall = [[random.randint(0,sparseness) for x in range(0, width)] for y in range(0, height+1)] for x in range(0, width): self.hwall[0][x] = 0 self.hwall[height][x] = 0 for y in range(0, height): self.vwall[y][0] = 0 self.vwall[y][width] = 0 def generateMazeDFS(self, width=None, height=None, seed_point=None): if width is None: width = self.maze_width if height is None: height = self.maze_height if seed_point is None: seed_point = (random.randint(0, width-1), random.randint(0, height-1)) self.vwall = [[0 for x in range(0, width+1)] for y in range(0, height)] self.hwall = [[0 for x in range(0, width)] for y in range(0, height+1)] maze = [[0 for x in range(0, self.maze_width)] for y in range(0, self.maze_height)] path = [seed_point] while True: possible_moves = [] x, y = path[-1] if x > 0 and maze[y][x-1] == 0: possible_moves.append('left') if x < width-1 and maze[y][x+1] == 0: possible_moves.append('right') if y > 0 and maze[y-1][x] == 0: possible_moves.append('up') if y < height-1 and maze[y+1][x] == 0: possible_moves.append('down') if len(possible_moves) > 0: next_move = random.choice(possible_moves) maze[y][x] = 1 if next_move == 'left': self.vwall[y][x] = 1 path.append((x-1, y)) continue elif next_move == 'right': self.vwall[y][x+1] = 1 path.append((x+1, y)) continue elif next_move == 'up': self.hwall[y][x] = 1 path.append((x, y-1)) continue elif next_move == 'down': self.hwall[y+1][x] = 1 path.append((x, y+1)) continue else: maze[y][x] = -1 path.pop() if len(path) == 0: break def paintEvent(self, event): qp = QPainter() qp.begin(self) qp.fillRect(0, 0, self.maze_width * self.boxsize + 10, self.maze_height * self.boxsize + 10, Qt.black) qp.translate(QPoint(5.5, 5.5)) qp.setPen(Qt.white) b = self.boxsize # vertical walls y = 0 for row in self.vwall: x = 0 for w in row: if w == 0: qp.drawLine(x*b, y*b, x*b, (y+1)*b) x += 1 y += 1 # horizontal walls y = 0 for row in self.hwall: x = 0 for w in row: if w == 0: qp.drawLine(x*b, y*b, (x+1)*b, y*b) x += 1 y += 1 # path prev = None for point in self.path: x1 = point[0] y1 = point[1] if prev: x2 = prev[0] y2 = prev[1] qp.fillRect(b*min(x1,x2) + 2, b*min(y1,y2) + 2, b*abs(x1-x2)+b-4, b*abs(y1-y2)+b-4, Qt.green) else: qp.fillRect(x*b+2, y*b+2, b-4, b-4, Qt.green) prev = point # visited cells y = 0 for row in self.maze: x = 0 for m in row: if m == -1: qp.fillRect(x*b+2, y*b+2, b-3, b-3, Qt.gray) x += 1 y += 1 # target x, y = self.target qp.fillRect(x*b+2, y*b+2, b-3, b-3, Qt.red) # status if self.status: qp.setPen(Qt.white) qp.setFont(QFont("sans", 72, QFont.Normal)) qp.drawText(QRect(0, 0, self.maze_width * b, self.maze_height * b), Qt.AlignCenter | Qt.AlignVCenter, self.status) qp.end() def step(self): self.step_num += 1 x, y = self.path[-1] if (x, y) == self.target: self.status = "win" return False if self.step_select == 'random': order_list = ['u', 'r', 'd', 'l'] random.shuffle(order_list) else: order_list = self.step_select for order in order_list: if order == 'u': # try step up if y > 0 and self.hwall[y][x] != 0 and self.maze[y-1][x] == 0: self.path.append((x, y-1)) self.maze[y-1][x] = self.step_num return True elif order == 'r': # try step right if x < self.maze_width-1 and self.vwall[y][x+1] != 0 and self.maze[y][x+1] == 0: self.path.append((x+1, y)) self.maze[y][x+1] = self.step_num return True elif order == 'd': # try step down if y < self.maze_height-1 and self.hwall[y+1][x] != 0 and self.maze[y+1][x] == 0: self.path.append((x, y+1)) self.maze[y+1][x] = self.step_num return True elif order == 'l': # try step left if x > 0 and self.vwall[y][x] != 0 and self.maze[y][x-1] == 0: self.path.append((x-1, y)) self.maze[y][x-1] = self.step_num return True # step back self.maze[y][x] = -1 self.path.pop() if len(self.path) == 0: self.status = "loss" return False return True def init(self): self.maze = [[0 for x in range(0, self.maze_width)] for y in range(0, self.maze_height)] self.path = [(0, 0)] self.step_num = 1 x, y = self.path[0] self.maze[y][x] = 1 self.target = (self.maze_width-1, self.maze_height-1) self.status = False class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.setWindowTitle("Maze") self.maze = Maze(150, 80, 7) hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 10, 0) hbox.addWidget(self.maze) vbox = QVBoxLayout() vbox.setContentsMargins(0, 10, 0, 0) hbox.addLayout(vbox) self.le_w = QLineEdit("150") vbox.addWidget(QLabel("maze width:")) vbox.addWidget(self.le_w) self.le_h = QLineEdit("80") vbox.addWidget(QLabel("maze height:")) vbox.addWidget(self.le_h) self.le_b = QLineEdit("7") vbox.addWidget(QLabel("cell size:")) vbox.addWidget(self.le_b) self.dm_sparse = QLineEdit("2") vbox.addWidget(QLabel("Dumb mode sparseness:")) vbox.addWidget(self.dm_sparse) self.maze_type = QButtonGroup() rb_1 = QRadioButton("Dumb random maze") rb_1.setChecked(True) rb_2 = QRadioButton("DFS maze generator") self.maze_type.addButton(rb_1, 0) self.maze_type.addButton(rb_2, 1) vbox.addWidget(rb_1) vbox.addWidget(rb_2) self.btn_generate = QPushButton("Generate") self.btn_generate.clicked.connect(self.generateMaze) vbox.addWidget(self.btn_generate) self.step_order = QLineEdit("random") self.step_order.setPlaceholderText("step order") vbox.addWidget(self.step_order) self.btn_solve = QPushButton("Solve") self.btn_solve.clicked.connect(self.startSolving) vbox.addWidget(self.btn_solve) self.btn_stop = QPushButton("Stop") self.btn_stop.setEnabled(False) self.btn_stop.clicked.connect(self.stopSolving) vbox.addWidget(self.btn_stop) vbox.addStretch() proxy_widget = QWidget() proxy_widget.setLayout(hbox) self.setCentralWidget(proxy_widget) self.maze.init() def doStep(self): for k in range(0, 50): if not self.maze.step(): self.timer.stop() self.stopSolving() break self.maze.repaint() def startSolving(self): self.btn_solve.setEnabled(False) self.btn_stop.setEnabled(True) self.btn_generate.setEnabled(False) self.maze.init() self.maze.step_select = self.step_order.text() if self.maze.step_select == '': self.maze.step_select = 'random' self.timer = QTimer(self) self.timer.timeout.connect(self.doStep) self.timer.setInterval(50) self.timer.start() def stopSolving(self): self.btn_stop.setEnabled(False) self.btn_solve.setEnabled(True) self.btn_generate.setEnabled(True) self.timer.stop() def generateMaze(self): w = max(2, int(self.le_w.text())) h = max(2, int(self.le_h.text())) b = max(5, int(self.le_b.text())) sparseness = max(0, int(self.dm_sparse.text())) self.maze.setMazeSize(w, h, b) self.maze.init() if self.maze_type.checkedId() == 0: self.maze.generateMazeDumb(sparseness=sparseness) elif self.maze_type.checkedId() == 1: self.maze.generateMazeDFS() self.maze.repaint() app = QApplication(sys.argv) mw = MainWindow() mw.show() sys.exit(app.exec_())
thank you so much for your post, but could you add more comment to your code?
ОтветитьУдалитьI don't see any place that should be commented. If you look for deep-first search algorithm, try searching wikipedia. It has nice short description of DFS.
ОтветитьУдалить