VÒNG LẶP FOR (FOR LOOP)
Trong các chương trước ta đã biết vòng lặp là những việc cần thực hiện lập đi lập lại nhiều lần. Giả sử các bạn muốn hiện ra trên màn hình 4 vòng tròn có bán kính 100 pixels (dots) và mỗi khi vẽ xong 1 vòng tròn thì rẽ trái 90 độ rồi vẽ tiếp vòng tròn kế. Nếu không dùng vòng lặp ta sẽ viết một chương trình như sau:
#Rosette.py import turtle t = turtle.Pen() t.circle(100) # vẽ 1 vòng tròn bán kính 100 pixels t.left(90) # Xong con rùa quẹo trái 90 độ t.circle(100) # vẽ vòng tròn bán kính 100 pixels thứ 2 t.left(90) # Xong con rùa lại quẹo trái 90 độ t.circle(100) # vẽ vòng tròn bán kính 100 pixels thứ 3 t.left(90) # rồi rùa lại quẹo trái 90 độ t.circle(100) #Sau cùng vẽ vòng tròn 100 pixels thứ tư và cuối cùng
Vất vả quá phải không? Nếu phải vẽ 100 vòng tròn như thế ta phải viết 200 dòng lệnh. Cho chạy thử chương trình trên ta sẽ có hình vẽ như sau:
Nhưng nếu ta dùng vòng lặp for … in range() như trong chương trình sau thì chỉ với vài dòng ta cũng đạt kết quả như hình 4-1 trên (nhớ gõ những dòng nằm trong vòng lặp thụt vào một chút, dưới dòng for x in range() : . Thực ra Python sẽ tự động cho xuống hang và thụt vào)
# Rosette4 Import turtle t = turtle.pen() for x in range(3) : # trị số đầu của x là 0, không phải 1, rồi đi từ 0 đến 3 import turtle t.circle(100) t.left(90)
Khi cho Run-> Run Module sẽ thấy kết quả y như hình 4-1. “ Khoẻ” hơn nhiều, phải không? Đó là nhờ bạn biét dùng vòng lặp for. (for loop).
Bài tập: Bạn cho trẻ viết một chương trình vẽ 10 vòng tròn bán kính 50 với lệnh for…in range(50 và rùa quay trái 91 độ ) xem sao?
Giả sử bạn muốn thay vì vẽ một “bông hồng” với 4 vòng tròn như trên , bạn muốn một bông hồng với 6 vòng tròn. Vậy bạn có thể sửa chương trình trên cho range của x là 6 như dưới đây:
# Rosette6.py import turtle t = turtle.Pen() for x in range(6): t.circle(100) t.left(60)
Kết quả:
Trông khá hơn một chút vì có 6 vòng tròn (“cánh hoa” của bạn) . Nhưng hơi cứng nhắc vì bạn cho số vòng tròn là 6 ngay trong chương trình: range(6). Mỗi khi Run chương trình này thì luôn luôn chỉ cho 6 vòng tròn. Muốn linh động hơn, ta cho số vòng tròn nhập vào từ bàn phím và dùng một hộp (hay cửa sổ) bật (pop-op window) như trong chương III. Nhưng vì nhập số (numbers) vòng thì ta không dùng hàm turtle.textinput() mà dùng hàm turtle.numinput().
# RosetteGoneWild.py import turtle t = turtle.Pen() # Hỏi bạn trẻ cho vào số vòng tròn muốn có, định sẵn là 6 number_of_circles = int(turtle.numinput("Number of circles", "How many circles in your rosette?", 6)) for x in range(number_of_circles): t.circle(100) t.left(360/number_of_circles)
Khi bạn cho số vòng vào (dù bạn đã định sẵn là 6) bằng hàm turtle.numinput() thì hàm int() bên ngoài hàm này sẽ chuyển số đưa vào từ bàn phím thành số nguyên (integer) vì số vòng tròn làm sao là số lẻ được?
Thử Run-> Run Module với số vòng tròn là 30 bạn sẽ có hình 4-3:
Chương trình sau đây dựa vào chương trình trên, có thêm màu nền bằng hàm turtle.bgcolor(“black”) là màu đen và dùng 4 màu luân phiên bằng 1 list 4 màu: đỏ, vàng, xanh dương và xanh lá cây. Bạn thử cho, từ keyboard, số 100 khi máy hỏi bạn muốn có bao nhiêu vòng tròn. Cho Run chương trình rồi xem kết quả.
# RosetteGoneWild2.py import turtle t = turtle.Pen() turtle.bgcolor("black") colors = [ "red" , "yellow" , "blue" , "green" ] # Danh sách (List) các màu # Hỏi bạn trẻ cho vào số vòng tròn muốn có, định sẵn (default) là 6 number_of_circles = int(turtle.numinput("Number of circles", "How many circles in your rosette?", 6)) for x in range(number_of_circles): t.pencolor(colors[x%4]) t.circle(100) t.left(360/number_of_circles)
Run->Run Module chương trình này và cho số vòng tròn là 100 sẽ có hình như hình4-3-2:
# ColorfulRosettes_bonus.py import turtle t=turtle.Pen() turtle.bgcolor('black') t.speed(0) t.width(2) # Ask the user for the number of circles in their rosette, default to 20 number_of_circles = int(turtle.numinput("Number of circles", "How many circles in your rosette?",20,2,100)) for x in range(number_of_circles): t.pencolor('blue') t.circle(200) t.pencolor('green') t.circle(150) t.pencolor('orange') t.circle(100) t.pencolor('white') t.circle(50) t.left(360/number_of_circles)
Để khỏi gõ chương trình này trong IDLE, bạn có thể select nó trong word rồi copy và rồi paste nó trong IDLE.
Bài tập: Bạn thử chạy chương trình này và yêu cầu trẻ giải thích mỗi dòng lệnh.
VÒNG LẶP WHILE (WHILE LOOP)
Khác với vòng lặp For..range() vì vòng For chỉ cho lặp lại những dòng lệnh trong đó một số lần nhất định trong range, chẳng hạn 5, 10, 100 lần ….. Vòng lặp While (Trong khi…) lặp lại những dòng lệnh bên trong nó một số vô t ận lần cho đến khi một điều kiện do người sử dụng cho vào. Chẳng hạn lặp lại cho đến khi nào người sử dụng nhấn nút q trên bàn phím để quit thì vòng lặp mới dứt. Hoặc là khi thoả mãn một điều kiện nào đó.
Dạng tổng quát của vòng WHILE như sau:
WHILE condition (điều kiện cần thoả mãn để thôi lặp)
Xin xem thí dụ sau đây để hiểu rõ hơn về công dụng của vòng lặp WHILE LOOP:
# SayOurNames.py – Để in tên trẻ/bạn trên màn hình đến khi bảo thôi # Hỏi tên name = input("What is your name? ") # Tiếp tục in tên cho đến khi bạn muốn quit while name != "": # Print their name 100 times for x in range(100): print(name, end = " ") # sau mỗi tên có một space print() # Sau vòng For Loop cho nhảy xuống dòng kế # Cho tên một bạn khác hay thôi, quit name = input("Type another name, or just hit [ENTER] to quit: ") print("Thanks for playing!")
Dòng lệnh while name != “”: có nghiã trong khi bạn chưa bấm ENTER trên bàn ph ím thì vòng lặp còn lặp lại hoài. Dấu != có nghiã là không bằng (not equal to). Trong khi name chưa chứa một cái gì trong ngoặc kép “” theo Python có nghiã bạn chỉ bấm ENTER thì vòng lặp sẽ ngưng. Bạn “nghỉ chơi”.
Còn nếu bạn cho bất cứ một tên nào vào name từ bàn phím thì máy sẽ tiếp tục. Ví dụ này là: bạn cho tên vào thì nó in 100 lần cái tên ấy bằng vòng lặp For. Xong nó nhảy 1 dòng trắng bằng lệnh print(). Rồi máy sẽ hỏi bạn muốn tiếp tục cho một tên khác không. Nếu có, nó sẽ lặp lại vòng While để in tên người khác 100 lần và cứ như thế. Cho đến khi bạn bấm ENTER thì máy sẽ ngưng. Bạn để ý đây là một ví dụ vòng lặp trong vòng lặp khác. ở đây vòng lặp for nằm trong vòng lặp while.
Bài tập: Sửa đổi ví dụ trên và cho máy chì ngưng khi bạn nhấn chữ q (hay chữ thoi, chữ gì cũng được) trên bàn phím. Mỗi tên in 20 lần thôi.
Tìm hiểu thêm về List (danh sách)
Trong các bài trước bạn đã biết qua về list (danh sách) các màu. Thí dụ:
Các màu ấy có tên trong danh sách, giữa 2 dấu móc (brackets). Và danh sách ấy được gán (assign) cho biến (variable) có tên colors.
Nhưng thực ra list có thể nhận những gì ta gõ từ bàn phím vào rồi gắn chúng lần lượt vào với nhau, cái sau gắn nối (append) vào cái trước và cứ như thế. Ban đầu là ta có một danh sách trống rỗng (empty list) nằm trong 2 ngoặc [] và cho nó vào một biến (variable) với một cái tên. Ví dụ trong bài sau: family = [].
Xem chương trình sau: bạn cho tên bạn mình hay người trong nhà rồi cho “con ruà” vẽ thành những xoắn ốc với những tên ấy, có màu sắc như trong list:
# SpiralFamily.py - cho in (hiện ra trên màn hình) một xoắn ốc màu tên bạn/trẻ import turtle # gọi chương trình turtle vào t = turtle.Pen() turtle.bgcolor("black") colors = ["red", "yellow", "blue", "green", "orange", "purple", "white", "brown", "gray", "pink" ] family = [] # lập một list trống rỗng để cho vào tên các bạn hay người trong nhà # Hỏi cái tên đầu tiên name = turtle.textinput("My friends/family", "Type the name or press ENTER to end:") # Tiếp tục hỏi tên while name != "": # như bài trước # Gắn, chắp thêm vào (append) tên tiếp theo vào list (danh sách) family.append(name) # Hỏi tiếp tên kế hay chấm dứt name = turtle.textinput("My friend/family", "Enter a name, or just hit [ENTER] to end:") # Vẽ một xoắn ốc với tên bạn hay gia đình trên màn hình for x in range(100): t.pencolor(colors[x%len(family)]) # Luân chuyển (rotate) qua các màu trong colors t.penup() # Nhấc bút lên t.forward(x*4) # Cho con rùa nhích tới trên màn hình t.pendown() # Hạ bút xuống để vẽ tên bạn/gia đình kế tiếp t.write(family[x%len(family)], font = ("Arial", int((x+4)/4), "bold") ) # viết tên bạn/gia đình với kiểu chữ, size chữ và in đậm (bold) t.left(360/len(family) + 2) # "con rùa" quẹo trái để lại tiếp tục vẽ xoắn ốc của tên các bạn hay người trong gia đình.
Chú thích: các chữ đậm là để nhấn mạnh những functions cần giải thích rõ, bạn không phải gõ chữ đậm.
Với hàm append() bạn sẽ gắn nối (append) những gì bạn cho từ bàn phím (ở đây là name) vào một list có tên là family: family.append(name).
Cho Run->Run module bạn sẽ có hình vẽ sau, với các tên đưa vào từ bàn phím như: Daddy, Mommy, Rocky, Leo, Alex, Max làm thí dụ:
Bài tập: Phỏng theo bài tập trên, bạn/trẻ đổi variable name thành ten, family thành giadinh và khi máy hỏi tên, bạn/trẻ thử đánh vào các chữ: I love you, Daddy and Mommy, My friends, Every body too rồi ENTER để dứt. Nhờ dòng lệnh nào chữ càng lúc càng to?
VÒNG LẶP TRONG VÒNG LẶP
Có những lúc bạn phải viết chương trình với 2 vòng lặp lồng vào nhau như tổ chim (nested loop). Vòng ngoài được gọi là outer loop và vòng trong là inner loop. Xem thí dụ sau đây: bạn cho vào máy tên một người và máy in tên người đó 5 lần rồi xuống dòng. Bạn làm như vậy cho 10 người rồi thôi.
# forwithinfor.py – in tên 10 người, mỗi người 5 lần # vòng ngoài (outer loop) để đưa tên từng người for x in range(10): name = input("What is your name? ") # vòng trong để in 5 lần cho mỗi người for y in range(5): # dùng biến y cho vòng trong, không dùng x print(name, end = " ") print() # sau khi in 5 lần, thoát ra vòng nhỏ để in 1 dòng trống nên lệnh print() thụt qua trái, không nằm trong vòng for y.
Giải thích: Ở vòng ngoài: với x=0 đầu tiên máy hỏi tên. Sau khi bạn cho tên vào, chương trình cho xuống vòng trong, với y=0 cho in tên người đầu tiên này lần 1; kế đến với y=1 máy in lại tên người này lần 2…đến lần 5 (y=5); sau khi in xong người này máy thoát ra vòng trong rồi in một dòng trắng. Kế đó máy trở lại vòng ngoài và hỏi tên người thứ 2 với x=1. Rồi máy lại vào vòng trong và cũng như người đầu tiên: in tên ấy 5 lần rồi lại thoát ra in một dòng trống rồi trở lên vòng for ngoài với x=2 v.vv.. và cứ thế cho đến khi hết 10 người (khi x=10).
———————————————————————————————————
Vậy, bạn đã hiểu thế nào là nested loop rồi. Bây giờ bạn xem 1 ví dụ phức tạp hơn để hiểu rõ hơn về nested loop và học thêm một số functions hữu dụng khác:
# ViralSpiral.py - xoắn ốc trong xoắn ốc! import turtle t = turtle.Pen() t.penup() # 1 turtle.bgcolor("black") # hỏi người sử dụng muốn bao nhiêu cạnh, định sẵn là 4, ít nhất là 2, nhiều nhất là 6. Số 4 viết đầu tiên là default, số 2 kế đó là số ít nhất (minimum); số 6 sau cùng nghiã là số nhiều nhất (maximum). sides = int(turtle.numinput("Number of sides", "How many sides in your spiral of spirals? (2-6)", 4,2,6)) colors = ["red", "yellow", "white", "green", "blue", "orange"] # Vòng lặp ngoài của xoắn ốc for m in range(100): # 2 t.pencolor("white") t.forward(m*4) position = t.position() # Ghi nhớ tọa độ này của góc xoắn ốc # 3 heading = t.heading() # Ghi nhớ hướng đi tới của rùa (cây bút) mà ruà đã tiến tới # 4 print(position, heading) # Vòng lặp trong của xoắn ốc # Vẽ một xoắn ốc nhỏ ở một góc (khúc quẹo) của xoắn ốc lớn for n in range(int(m/2)): # 5 t.pendown() t.pencolor(colors[n%sides]) t.forward(2*n) t.right(360/sides - 2) t.penup() t.setx(position[0]) # Trở lại vị trí hoành độ x của xoắn ốc lớn # 6 t.sety(position[1]) # Trở lại vị trí tung độ y của xoắn ốc lớn # 7 t.setheading(heading) # "Con rùa chỉ vào đầu của xoắn ốc lớn # 8 t.left(360/sides + 2) # Nhắm tới điểm kế tiếp trên xoắn ốc lớn # 9
Chú thích: những chữ đậm chỉ để chú ý nhiều, không gõ chữ đậm (bold) khi soạn chương trình trong IDLE.
Kết quả: xem hình vẽ 4-5 .
Chúng ta sẽ tìm hiểu những dòng lệnh (statements) cùng những hàm (functions) mới, liên hệ trong chương trình.
Chú thích các comments #:
- Comment # 1: Để nhấc cây bút (pen) của “con rùa” khỏi màn hình với lệnh penup() rồi cho màu nền đen với lệnh bgcolor(“black”) bên dưới. Chữ t là thay cho hàm turtle.Pen() cho gọn.
- Comment # 2, # 3 và #4: Trong vòng lặp ngoài, biến (variable) m đi từ 0 đến 99 (100 lần) và trong vòng đó ta cho “con rùa” nhích tới mX4 dots (pixels) với lệnh forward(m*4). Nhưng khi tới mỗi góc chỗ quẹo (corner) của vòng xoắn lớn ta cho ngừng lại để ghi nhớ vị trí với lệnh t.position() (xem Comment # 3) và hướng đi tới của rùa với lệnh t.heading() (xem comment # 4). Vị trí là toạ độ x,y trên màn hình. Hướng đi (đúng ra là quay) tính bằng góc độ từ 0.0 đến 360.0 độ.
Ở mỗi điểm dọc theo vòng xoắn lớn, con rùa sẽ chuyển hướng để vẽ những vòng xoắn nhỏ hơn, vì thế nó phải trở về vị trí và hướng đi này sau khi chấm dứt mỗi vòng xoắn nhỏ mục đích là để duy trì hình dạng của vòng xoắn lớn.
- Comment # 5: Vòng lặp trong đi từ n=0 đến n=m/2 để cho những vòng xoắn trong nhỏ hơn vòng xoắn ngoài.
- Comment # 6 & 7: Sau khi thực hiện vòng lặp trong (ở dòng comment 5) xong, ta cho con rùa quay lại vị trí mà ta đã lưu ở dòng # comment 3 với các hàm setx(position[0]) và hàm sety(position[1]). 0 là vị trí của hoành độ x và 1 là vị trí tung độ y trên màn hình.
- Comment # 8: ta cho “con rùa” quay về hướng đã lưu trữ ở dòng lệnh của comment # 4 trước khi tiếp tục phần kế của vòng xoắn lớn ở dòng lệnh cuả #comment 9.
BÀI TẬP: Run thử bài trên với size là 2 hoặc 6 và cho quay right.
BÀI TẬP THỬ TÀI 1:
Bạn hãy sửa đổi chương trình nói trên (# VongxoanocTrongVongxoanoc.py) bằng cách thay đổi những vòng xoắn nhỏ trong đó bằng những hoa hồng giống như trong chương trình BonVongtron2 và chương trình SoVongtronLinhdong.py. Mách nước: Đầu tiên bạn thay vòng lặp trong (inner loop) bằng một vòng lặp trong khác mà nó có thể vẽ một hoa hồng. Kế đó cho thêm lệnh thay đổi màu và kích thước của các vòng tròn trong mỗi bông hồng. Thêm nữa, thay đổi chiều rộng của cây bút một chút cho các vòng tròn của bạn to ra. Khi xong, hãy lưu chương trình với tên SpiralRosettes.py. Kết quả: xem hình sau:
Bài giải mẫu:
# Challenge1_SpiralRosettes.py import turtle t=turtle.Pen() t.penup() t.speed(0) # hàm speed(0) để “con rùa” chạy nhanh: số 0 trong 2 ngoặc turtle.bgcolor(“black”) # Ask the user for the number of sides, default to 4, min 2, max 6 sides = int(turtle.numinput("Number of sides", "How many sides in your spiral of rosettes?", 4,2,6)) colors=[“red”, “yellow”, “blue”, “green”, “purple”, “orange”] # Our outer spiral loop for m in range(100): t.forward(m*4) position = t.position() # remember this corner of the spiral heading = t.heading() # remember the direction we were heading # Our 'inner' spiral loop draws a rosette for n in range(sides): t.pendown() t.pencolor(colors[n%sides]) t.circle(m/5) t.right(360/sides - 2) t.width(m/20) t.penup() t.setx(position[0]) # go back to the big spiral's x location t.sety(position[1]) # go back to the big spiral's y location t.setheading(heading) # point in the big spirals direction/heading t.left(360/sides + 2) # move to the next point on the big spiral
BÀI TẬP THỬ TÀI: 2
Hãy vẽ một vòng xoắn của những vòng xoắn của các tên trong gia đình. Xem lại chương trình VongXoanocTen.py rồi xem lại chương trình VongxoanocTrongVongxoanoc.py ở trên. Bạn hãy tạo một vòng lặp trong bên trong vòng lặp for loop trong chương trình VongXoanocTen.py (vòng vẽ vòng xoắn nhỏ). Xong, bạn chỉnh vòng ngoài của bạn để ghi nhớ vị trí và sự chuyển hướng của con ruà trước khi vẽ mỗi vòng xoắn nhỏ và cho nó trở lại trước khi tiếp tục đến vị trí vòng xoắn lớn kế tiếp. Lưu chương trình mới này với tên ViralFamilySpiral.py.
———————————————————————————————————
Bài giải mẫu:
# Challenge2_ViralFamilySpiral.py - - prints a colorful spiral of names import turtle # set up turtle graphics t=turtle.Pen() t.speed(0) turtle.bgcolor(“black”) colors=[“red”, “yellow”, “blue”, “green”, “orange”, “purple”, “white”, “brown”, “gray”, “pink”] family=[] # set up an empty list for family names # ask for the first name name = turtle.textinput("My family", "Enter a name, or just hit [ENTER] to end:") # keep asking for names while name != "": # add their name to the family list family.append(name) # ask for another name, or end name = turtle.textinput("My family", "Enter a name, or just hit [ENTER] to end:") # draw a spiral of the names on the screen # Our outer spiral loop for m in range(100): t.forward(m*4) position = t.position() # remember this corner of the spiral heading = t.heading() # remember the direction we were heading # Our 'inner' spiral loop draws a rosette for n in range(len(family)): t.pendown() t.pencolor(colors[n%len(family)%10]) t.write(family[n%len(family)], font=("Arial", int((m+4)/4), "bold") ) t.right(360/len(family) - 2) t.width(m/20) t.penup() t.forward(m) t.setx(position[0]) # go back to the big spiral's x location t.sety(position[1]) # go back to the big spiral's y location t.setheading(heading) # point in the big spirals direction/heading t.left(360/len(family) + 2) # move to the next point on the big spiral
Cho Run thử 2 chương trình trên và xem kết quả.
HẾT CHƯƠNG IV
Bạn cần chữ này để tiếp tục:
Nhẫn