Project 2 : Using Turtle to Draw a Maze (Python Exercise 18)

Data Processing and Visulisation with Python

"""
Python Exercise 18
for the class of
Data Processing and Visulisation with Python
2020-2021-1

"""

# libraries to be used
import turtle
import random

# initialize
"""
feel free to change these settings and check the output, 
or you could get these settings from user input
"""
maxHeight = 700
maxWidth = 1200
rowCount = 70
columnCount = 120
screenPaddingWidth = 8
screenPaddingHeight = 8
backGroundColor = 'white'
lineColor = 'black'


"""
the following variables are calculated from the above settings
* rowSize is the integer part of maxHeight divided by rowCount
* colSize is the integer part of maxWidth divided by columnCount
* cellHeight and cellWidth are set to the smaller value of rowSize and colSize
* mazeWidth equals columnCount times cellWidth
* mazeHeight equals rowCount times cellHeight
* screenWidth is the sum of mazeWidth and screenPaddingWidth
* screenHeight is the sum of mazeHeight and screenPaddingHeight
"""

#-----------------code section - finish the code below-----------------
rowSize = maxHeight // rowCount
colSize = maxWidth // columnCount
cellHeight = cellWidth = rowSize if rowSize < colSize else colSize
mazeWidth = columnCount*cellWidth+1
mazeHeight = rowCount*cellHeight+1
screenWidth = mazeWidth + screenPaddingWidth
screenHeight = mazeHeight + screenPaddingHeight
#-------------------------end of code section-------------------------

# disjoint sets
"""
the following code implements smart union algorithm 
it will be useful in finding which wall to destroy in order to make a maze
you do not need to do anything with this part, it is ready for your later use
"""
s = [-1] * rowCount * columnCount

def findRoot(x):
    if s[x]<0:
        return x
    else:
        return findRoot(s[x])

def unionSets(c1, c2):
    r1 = findRoot(c1)
    r2 = findRoot(c2)
    if s[r1] < s[r2]:
        s[r2] = r1
    else:
        if s[r1] == s[r2]:
            s[r2] -= 1
        s[r1] = r2

def cellsConnected(x, y):
    return findRoot(x) == findRoot(y)


# window and pen

"""
settings of the screen window and turtle pen
the code finishes the following settings
* define a variable screen as a TurtleScreen instance via turtle.Screen() function
* set the window size as screenWidth and screenHeight by calling screen.setup()
* set the worldcoordinates as (0, 0, screenWidth-1, screenHeight-1) by calling screen.setworldcoordinates()
* set the title of the window to "Maze created by YOUR NAME" by calling screen.title()
  (remember to replace YOUR NAME with your own name)
* set the screen.tracer() to False in order to speed up drawing maze
* define a variable pen as a Turtle instance via turtle.Turtle() function
* hide turtle in window using hideturtle() function

for more details of Turtle and Screen, please visit: 
    https://docs.python.org/3/library/turtle.html#turtle.screensize
    or in Chinese:
    https://docs.python.org/zh-cn/3/library/turtle.html#turtle.screensize
"""

#-----------------code section - finish the code below-----------------
screen = turtle.Screen()
screen.setup(screenWidth, screenHeight)  
screen.setworldcoordinates(0, 0, screenWidth-1, screenHeight-1)
screen.title('Maze created by YE Huanzhuo')
screen.tracer(False)
pen = turtle.Turtle()
# pen.speed(10)
pen.hideturtle()
#-------------------------end of code section-------------------------

# build walls

## store all the walls available to be erased
"""
store all the walls in a full grid into a list, name the list as wallErasable
* the cells in the grid are numbered from 0 to rowCount*columnCount-1 starting from 
  lowerleft of the grid arranged in coloumn first order
* normally, each cell has four walls, but in order not to miss any wall or recount any
  one, we define each cell with two walls, the upper wall and the right wall, except:
  - the upper most row, in which cells do not have upper walls
  - the right most column, in which cells do not have right walls
* each wall is represented by a tuple (cellNo, position), in which
  - cellNo is the serial number of the cell
  - position show where the wall is to the cell, it has only two values:
    # 0: the wall is the upper wall of the cell
    # 1: the wall is the right wall of the cell 
"""

#-----------------code section - finish the code below-----------------
wallErasable = []
for i in range(rowCount*columnCount):
    if i%columnCount != columnCount-1:
        wallErasable.append((i, 1))     # right wall to the cell
    if i < (rowCount-1)*columnCount:
        wallErasable.append((i , 0))    # upper wall to the cell
#-------------------------end of code section-------------------------

## function to find the neighbor cell share the wall (cellNo, position)
"""
this function returns the serial number of the cell which shares the wall
represented by (cellNo, position) with the cell numbered cellNo
"""

def neighbor(cellNo, position):
    #-----------------code section - finish the code below-----------------
    return cellNo + 1*position + columnCount*(1-position)
    #-------------------------end of code section-------------------------


## function to set a wall
"""
the following code calcultes and draws the correspongding line with the current pen color 

this function draws the wall represented by (cellNo, position)
with the settings of columnCount, cellWidth and cellHeight, the pixels or line of 
the wall (cellNo, position) can be easlily calculated
"""

def setWall(cellNo, position):
    #-----------------code section - finish the code below-----------------
    row = cellNo // columnCount
    column = cellNo % columnCount
    if position:
        startPoint = ((column+1)*cellWidth, row*cellHeight)
    else:
        startPoint = (column*cellWidth, (row+1)*cellHeight)
    endPoint = ((column+1)*cellWidth, (row+1)*cellHeight)
    pen.up()
    pen.goto(startPoint)
    pen.down()
    pen.goto(endPoint)
    #-------------------------end of code section-------------------------


## randomly destroy rowCount*columnCount-1 walls to make rowCount*columnCount
## cells connected, thus build a maze
"""
* build an empty list named wallToBuild to store the walls that should not be destroyed
* each time randomly choose a destroyable / erasable wall from list wallErasable
  - find out the two cells sharing this wall
  - find out if the two cells are already connected using cellsConnected() function
    # if they are not connected yet
      + pop this wall out of wallErasable
    # otherwise (if they are already connected)
      + move this wall from wallErasable to wallToBuild
      + find another wall to destroy
* repeat the above steps rowCount*columnCount-1 times to destroy rowCount*columnCount-1 walls
  in that way, rowCount*columnCount cells will be connected and the maze will be formed
* move all the rest walls in wallErasable to wallToBuild
"""

#-----------------code section - finish the code below-----------------
numErased = 0
wallToBuild = []
while numErased < (rowCount*columnCount-1):
    numWall = random.randrange(len(wallErasable))
    cellNo, position = wallErasable[numWall]
    w = wallErasable.pop(numWall)    
    neighborCellNo = neighbor(cellNo, position)
    if not cellsConnected(cellNo, neighborCellNo):
        unionSets(cellNo, neighborCellNo)
        numErased += 1
    else:
        wallToBuild.append(w) 
wallToBuild.extend(wallErasable)
#-------------------------end of code section-------------------------

## build the maze
### build outer frame
"""
* set the pen color to lineColor
* draw the outline border of the maze, a rectangle set by
  - rowCount
  - columnCount
  - cellWidth
  - cellHeight
"""

#-----------------code section - finish the code below-----------------
pen.color(lineColor)
pen.forward(cellWidth*columnCount)
pen.left(90)
pen.forward(cellHeight*rowCount)
pen.left(90)
pen.forward(cellWidth*columnCount)
pen.left(90)
pen.forward(cellHeight*rowCount)
#-------------------------end of code section-------------------------


### build inner walls
"""
take each wall from wallToBuild and draw it with current pen color
"""

#-----------------code section - finish the code below-----------------
for w in wallToBuild:
    setWall(*w)
#-------------------------end of code section-------------------------


### dig out entrance and exit
"""
make an entrance and an exit on the outline border
* set the pen color to backGroundColor
* draw the upper wall of the upperleft cell
* draw the right wall of the lowerright cell
"""

#-----------------code section - finish the code below-----------------
pen.color(backGroundColor)
setWall((rowCount-1)*columnCount, 0)
setWall(columnCount-1, 1)
#-------------------------end of code section-------------------------

# well done
screen.tracer(True)
# screen.exitonclick()
turtle.done()

在这里插入图片描述

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值