猫史档案馆


【Python作品分享】maze

用户:红石小蝈红石小蝈查看:0 回复:2 评论:0 创建时间:2019-06-05T21:59:09


【作品展示】

center_image

 

【作品介绍】

maze generator

v1.0.0

迷宫生成器

由于海龟制图的原因,迷宫生成较慢

注释见代码

 

【作品源代码】

import random
import turtle
from time import sleep

# constants
BG_COLOR = '#66ccff'
EX_COLOR = '#ee0000'
ED_COLOR = '#000000'
SIZE = 32
WIDTH = 0.00625*SIZE
LENTH = 0.055*SIZE
WI2 = 0.01*SIZE
UP = 1j
DN = -1j
RT = 1
LT = -1
##
turtle.bgcolor(BG_COLOR)


class Line(turtle.Turtle):  # main classes
    '''a line class based on turtle.Turtle
    sides of blocks'''

    def __init__(self, x, y, is_ver, expected):
        self.p = False
        self.is_ver = is_ver
        self.expected = expected
        turtle.Turtle.__init__(self, shape='喵', visible=False)
        self.pu()
        self.speed(0)
        self.position = (x, y)
        self.shapesize(WIDTH, LENTH, WI2)
        self.ORIGINAL_STATE = expected
        if expected:
            self.color(EX_COLOR)
        if self.is_ver:
            self.goto(x*SIZE, y*SIZE-SIZE/2)
        else:
            self.goto(x*SIZE-SIZE/2, y*SIZE)
            self.rt(90)
        self.st()

    def pass_(self):
        '''make the line passable'''
        self.p = True
        self.ht()
        self.expected = False

    def erase(self):
        '''do this when delete the line from the list'''
        self.expected = False
        self.color(ED_COLOR)

    def reset(self):
        '''reset the line'''
        self.expected = self.ORIGINAL_STATE
        self.st()
        if self.expected:
            self.color(EX_COLOR)
        else:
            self.color(ED_COLOR)

    def __bool__(self):
        return self.p

    def __repr__(self):
        return 'Line({},{},{})'.format(self.position, self.p, self.expected)


class Block:
    '''a block class, have 4 lines as sides
    '''

    def __init__(self, u_bound, l_bound, r_bound, d_bound, x, y):
        self.up = u_bound
        self.lt = l_bound
        self.rt = r_bound
        self.dn = d_bound
        self.l_setup()
        self.called = False
        self.d = {UP: self.up,
                  LT: self.lt,
                  RT: self.rt,
                  DN: self.dn}
        self.x = x
        self.y = y

    def open_from(self, way):
        '''open the block from the way'''
        self.d[-way].pass_()
        self.called = True
        if way in self.l:
            self.l.remove(way)

    def open_to(self, way):
        '''open the block to the way'''
        if way in self.l:
            self.l.remove(way)

    def unable_side(self, way):
        '''delete the side'''
        self.d[way].erase()
        self.l.remove(way)

    def reset(self):
        '''reset all the sides and the block'''
        for _x in self.d.values():
            _x.reset()
        self.l_setup()
        self.called = False

    def l_setup(self):
        '''setup the list'''
        self.l = []
        if self.up.expected:
            self.l.append(UP)
        if self.lt.expected:
            self.l.append(LT)
        if self.rt.expected:
            self.l.append(RT)
        if self.dn.expected:
            self.l.append(DN)

    def __repr__(self):
        return 'Block({},{},{})'.format(self.x, self.y, self.d)


class Grid:
    ''' a grid class,
    lenth 2*x+1
    width 2*y+1
    '''

    def __init__(self, x, y):
        self.l = []
        self.ver = 2*x+1
        self.hor = 2*y+1
        for _x in range(-x, x+1):
            self.l.append([])
            for _y in range(-y, y+1):
                if _x == -x:
                    lt = Line(_x, _y, False, False)
                else:
                    lt = self.l[-2][_y+y].rt
                ##
                if _y == -y:
                    dn = Line(_x, _y, True, False)
                else:
                    dn = self.l[-1][-1].up
                ##
                up = (Line(_x, _y+1, True, _y != y))
                rt = (Line(_x+1, _y, False, _x != x))
                self.l[-1].append(Block(up, lt, rt, dn,
                                        len(self.l)-1, len(self.l[-1])))
        self._0 = self.l[0][0]
        '''
        self._0.lt.pass_()
        self._0.dn.pass_()
        '''

    def open_from_to(self, x, y, way):
        '''open from (x,y) to the ...'''
        # print(way)
        b0 = self.l[x][y]
        try:
            if way == UP:
                b1 = self.l[x][y+1]
            elif way == LT:
                b1 = self.l[x-1][y]
            elif way == RT:
                b1 = self.l[x+1][y]
            else:
                b1 = self.l[x][y-1]
            # print(b1)
        except IndexError:
            raise IndexError('u r opening from a side block to outside')
        else:
            if not (-1 <= b1.x-b0.x <= 1 and -1 <= b1.x-b0.x <= 1):
                raise IndexError('u r opening from a side block to outside')
        if b1.called:
            b0.unable_side(way)
        else:
            b0.open_to(way)
            b1.open_from(way)
            return b1

    def maze1(self):
        '''make a maze using BFS'''
        recent_call = [self._0]
        while len(recent_call) > 0:
            _x = random.choice(recent_call)
            # print(_x)
            try:
                new_call = self.open_from_to(_x.x, _x.y,
                                             random.choice(_x.l))
                if not new_call is None:
                    recent_call.append(new_call)
            except IndexError:
                # print(_x)
                recent_call.remove(_x)
        '''
        self.l[-1][-1].up.pass_()
        self.l[-1][-1].rt.pass_()
        '''
        return 'Done!'

    def maze2(self):
        '''make a maze using DFS'''
        recent_call = [self._0]
        while len(recent_call) > 0:
            _x = random.choice(recent_call)
            while True:
                # print(_x)
                try:
                    new_call = self.open_from_to(_x.x, _x.y,
                                                 random.choice(_x.l))
                    if not new_call is None:
                        recent_call.append(new_call)
                        _x = new_call
                    else:
                        break  # continue
                except IndexError:
                    # print(_x)
                    recent_call.remove(_x)
                    break
        # self.l[-1][-1].dn.pass_()
        # self.l[-1][-1].rt.pass_()
        return 'Done!'

    def reset(self):
        for _x in self.l:
            for _y in _x:
                _y.reset()


class AI_Player(turtle.Turtle):
    def __init__(self, maze):
        turtle.Turtle.__init__(self, 'turtle', visible=False)
        self.maze = maze
        self.track = []
        self.position = complex()
        self.pu()
        self.speed(0)
        self.block = maze._0
        p = self.block.up.pos()
        self.goto(p[0], p[1]-SIZE/2)
        self.facing = 1+0j
        self.st()
        self.pd()
    '''
    def wall_on_left(self):
        self.maze.l[int(self.position.real)]\
        [int(self.position.imag)].d[self.facing*1j]
    '''

    def main(self):
        # while self.pos!=complex(self.maze.ver-1,self.maze.hor-1):
        for _x in range(20):
            while True:
                if self.maze.l[int(self.position.real)][int(self.position.imag)].d[self.facing]:
                    print('break1')
                    break
                else:
                    self.facing *= -1j
                    self.lt(90)
                sleep(1)
            self.position += self.facing
            self.fd(SIZE)
            if self.position in self.track:
                while self.track[-1] != self.position:
                    self.track.pop()
                self.facing *= 1j
            else:
                self.track.append(self.position)


if __name__ == '__main__':
    g = Grid(4, 4)
    msg = g.maze2()
    print(msg)
    # p=AI_Player(g)

 

【提示】

部分含有Python第三方库相关内容的作品,在海龟编辑器网页端无法运行哦!如遇到这种情况,可以打开下面的链接,下载海龟编辑器客户端:

https://python.codemao.cn


回复

上一页1 页 / 共 1下一页
红石小蝈红石小蝈

可通过调整倒数第4行的两个数字改变迷宫的大小

 

点赞0


评论


天马神坑_真天马神坑_真

6

点赞0


评论