Dùng đệ quy (recursive) để vẽ tam giác Sierpinski



  • Chúng ta sẽ dùng thư viện turtle của python và thuật toán đệ quy để vẽ một hình như sau:

    alt text

    Thuật toán:

    Bắt đầu với 1 tam giác lớn to nhất, sau đó chia nhỏ tam giác lớn đó thành 4 tam giác nhỏ bằng cách nối trung điểm của các cạnh tam giác lớn với nhau. Sau đó cứ lặp lại như trên đối với các tam giác nhỏ đó (đây là lý do vì sao dùng đệ quy).

    Triển khai:

    Bước 1: Vẽ tam giác lớn bằng hàm drawTriangle() dựa vào việc nối 3 điểm lại với nhau, hàm này sẽ có 3 biến là points (một list chứa tọa độ các điểm), color (tô màu cho tam giác), myTurtle (có thể coi như là cái bút của chúng ta)

    def drawTriangle( points, color, myTurtle ):
        myTurtle.fillcolor(color)
        myTurtle.up()
        myTurtle.goto( points[0][0], points[0][1] )
        myTurtle.down()
        myTurtle.begin_fill()
        myTurtle.goto( points[1][0], points[1][1] )
        myTurtle.goto( points[2][0], points[2][1] )
        myTurtle.goto( points[0][0], points[0][1] )
        myTurtle.end_fill()
    

    Đầu tiên dùng fillcolor() method để xác định màu cho nét vẽ, các method up() nghĩa là nhấc "ngòi bút" lên khỏi mặt "giấy" để khi di chuyển nó không tạo ra nét vẽ, còn down() là đặt ngòi bút xuống để tạo ra nét vẽ. Hàm drawTriangle sẽ thực hiên như sau: nhấc ngòi bút lên và đưa về vị trí có tọa độ (points[0][0], points[0][1]) chính là điểm bottom-left của tam giác, sau đó ngòi bút sẽ đi đến điểm top rồi đến bottom-right.
    (begin_fill() và end_fill() là để tô màu cho tam giác vừa vẽ xong)

    Bước 2: Lấy trung điểm của các cạnh tam giác

    def getMidPoint( point1,point2 ):
        return ( (point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2 )
    

    Bước 3: Dùng đệ quy để vẽ tiếp các tam giác nhỏ

    def sierpinski( points, n, myTurtle ):
        colors = ['blue', 'red', 'green', 'white', 'yellow', 'violet', 'orange']
        drawTriangle( points, colors[n], myTurtle )
    
        if n > 0:
            sierpinski( [points[0], 
                            getMidPoint( points[0], points[1] ), 
                            getMidPoint( points[0], points[2] )],
                        n-1, myTurtle )
    
            sierpinski( [points[1],
                            getMidPoint( points[0], points[1 ]),
                            getMidPoint( points[1], points[2] )],
                        n-1, myTurtle )
    
            sierpinski( [points[2],
                            getMidPoint( points[2], points[1] ),
                            getMidPoint( points[0], points[2] )],
                        n-1, myTurtle )
    

    Ở đây chúng ta sử dụng biến n để biểu diễn số lần vẽ tam giác, cứ vẽ xong 1 tam giác thì n sẽ giảm xuống 1 đơn vị, khi nào n = 0 thì ngừng vẽ và kết thúc. List colors để quy định các màu cho tam giác.
    Xong!!!

    Code hoàn chỉnh:

    import turtle
    
    def drawTriangle(points,color,myTurtle):
        myTurtle.fillcolor(color)
        myTurtle.up()
        myTurtle.goto(points[0][0],points[0][1])
        myTurtle.down()
        myTurtle.begin_fill()
        myTurtle.goto(points[1][0],points[1][1])
        myTurtle.goto(points[2][0],points[2][1])
        myTurtle.goto(points[0][0],points[0][1])
        myTurtle.end_fill()
    
    def getMidPoint( point1,point2 ):
        return( (point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2 )
    
    def sierpinski( points, n, myTurtle ):
        colors = ['blue', 'red', 'green', 'white', 'yellow', 'violet', 'orange']
    
    drawTriangle( points, colors[n], myTurtle )
    	
    if n > 0:
        sierpinski( [points[0],
                            getMidPoint( points[0], points[1]),
                            getMidPoint( points[0], points[2])],
                       n-1, myTurtle )
    				   
        sierpinski( [points[1],
                            getMidPoint( points[0], points[1]),
                            getMidPoint( points[1], points[2])],
                       n-1, myTurtle )
    				   
        sierpinski( [points[2],
                            getMidPoint( points[2], points[1]),
                            getMidPoint( points[0], points[2])],
                       n-1, myTurtle )
    
    
    def main():
        myTurtle = turtle.Turtle()    #Tạo "ngòi bút", muốn vẽ cái gì thì phải tạo cái ngòi bút trước.
        myWin = turtle.Screen()
        myPoints = [[-100,-50],[0,100],[100,-50]]
        sierpinski(myPoints, 4,myTurtle)
        myWin.exitonclick()
    
    main()
    

    Dòng myWin.exitonclick() là để khi chương trình chạy xong thì click vào màn hình chương trình để thoát.

    Happy coding!! (Nhớ căn thụt đầu dòng cho chuẩn không là không chạy đừng kêu nhé) :)


  • administrators

    Bài viết hay quá. Cảm ơn Mod nhé.



  • @Khanh-Nguyen : Tập viết tut xem m.ng có hiểu được không thôi anh :D


Hãy đăng nhập để trả lời
 

Có vẻ như bạn đã mất kết nối tới Cộng đồng Python Việt Nam, vui lòng đợi một lúc để chúng tôi thử kết nối lại.