บทที่ 6: While Loops


ในบางครั้ง ผู้ใช้มีความต้องการที่จะให้โปรแกรมทำงานบางอย่างซ้ำๆ แต่ไม่สามารถระบุจำนวนรอบที่ต้องการทำซ้ำ คำสั่ง for ก็เลยไม่เหมาะที่จะใช้กับงานวนลูปในลักษณะที่ไม่รู้จำนวนรอบที่แน่นอน จึงมีอีกคำสั่งที่ใช้การตรวจสอบเงื่อนไขบางอย่าง นั่นก็คือคำสั่ง while ยกตัวอย่างปัญหา เช่น ถ้าต้องการให้หุ่นยนต์คาเรล เดินตรงไปเรื่อยๆ จนกระทั่งเจอกำแพงแล้วจึงค่อยหยุดการทำงาน และต้องการใช้คำสั่งเดียวกันในการให้คาเรลทำการเดินหากำแพงที่โลกขนาดใดๆ ก็ได้ ลองกดปุ่ม “Run Program” เพื่อดูการทำงานของหุ่นยนต์คาเรล

ตัวอย่างเช่น หากเราต้องการเขียนโปรแกรมเพื่อให้คาเรลเคลื่อนที่ไปยังกำแพง แต่ไม่ต้องการให้โปรแกรมนี้ทำงานโดยที่มีรอบการเคลื่อนที่ที่แน่นอน เช่น สั่งให้คาเรลเดินทั้งหมด 3 ก้าว และหากทำการเปลี่ยนแผนที่ไปโปรแกรมดังที่บอกไปข้างต้นจะไม่สามารถทำงานได้ทันที เป็นต้น ดังนั้น เราควรจะเขียนโปรแกรมให้ครอบคลุมกับทุกแผนที่ที่สร้างขึ้น

ลองเปลี่ยนขนาดโลกของคาเรลโดยคลิกที่ “Change World” แล้วเปลี่ยนมิติขนาดโลกของคาเรล แล้วลองกดปุ่ม “Run Program” อีกครั้งเพื่อดูการทำงาน จะสังเกตได้ว่าผู้ใช้จะไม่สามารถสั่งงานที่ต้องการวนซ้ำแบบนี้ด้วยคำสั่ง for

พื้นฐาน While Loop

สำหรับคาเรล คำสั่ง while ถูกใช้สำหรับการสั่งการให้ทำงานซ้ำๆ ไปเรื่อยๆ จนกว่าจะผิดเงื่อนไขบางอย่าง จึงค่อยหยุดการทำงานคำสั่ง while โครงสร้างภาษาไพธอนสำหรับคำสั่ง while คือ while loop แทน โดยจะมีรูปแบบการเขียนโปรแกรมดังนี้ :

while test:
statements to be repeated

ผู้ใช้สามารถใช้คำสั่ง while โดยใส่เงื่อนไขที่ต้องการไปแทนใน “test” คำสั่ง while จะทำการตรวจสอบเงื่อนไข test ถ้าเป็นจริง จะทำงานตามคำสั่งที่อยู่ใน code block ของ while แล้วกลับไปตรวจสอบเงื่อนไข test ต่อไป ถ้าผลการตรวจสอบเป็นเท็จ ก็จะทำการข้ามคำสั่งที่อยู่ใน code block ของ while ไปทำคำสั่งอื่นๆ ที่อยู่นอก code block ของคำสั่ง while ต่อไป หุ่นยนต์คาเรลมีชุดคำสั่งให้เลือกใช้ สำหรับใช้ในการ test ซึ่งจะกล่าวถึงในบทถัดไป สำหรับบทนี้ ขอให้เข้าใจว่า คำสั่ง front_is_clear() จะคืนค่า “true” ทำให้เงื่อนไขเป็นจริง ก็ต่อเมื่อไม่มีกำแพงอยู่ข้างหน้าหุ่นยนต์คาเรล

Fencepost Bug

ลองปรับโปรแกรมจากด้านบนให้น่าสนใจมากขึ้น โดยให้คาเรลวางเหรียญ beeper ทุกๆ ตำแหน่งที่เคยอยู่ และทดสอบโปรแกรมกับโลกของคาเรลหลายๆ ขนาดด้วย

จากโปรแกรม BeeperLineBug คาเรลสามารถวางเหรียญได้ตามทางที่เดินไป แต่ติดปัญหาตรงที่คาเรลไม่ได้วางเหรียญที่ตำแหน่งสุดท้ายตอนที่เดินเจอกำแพง เพราะหลังจากที่คาเรลเจอกำแพง ก็จะไม่ทำงานใน code block ของคำสั่ง while จากตัวอย่างข้างบน โลกของคาเรลมีมิติ 7x7 คาเรลควรจะวางเหรียญ 7 เหรียญ และควรทำการเดิน 6 ครั้ง ผู้ใช้จะแก้ปัญหาอย่างไรได้บ้าง

ข้อผิดพลาดในโปรแกรมนี้เป็นตัวอย่างของปัญหาที่เจอบ่อยในการเขียนโปรแกรมที่เรียกว่า Fencepost Bug ซึ่งชื่อนี้มาจากความจริงที่ว่า ถ้าเราต้องการสร้างรั้วและแผงกั้น เราจะต้องใช้จำนวนเสา มากกว่าจำนวนแผงกั้น 1 ต้น ถ้าต้องการสร้างรั้วที่มีแผงกั้น 10 แผง ก็จะต้องใช้เสา 11 ต้น

หลังจากที่รู้ที่มาของปัญหา ข้อผิดพลาดนี้สามารถแก้ไขได้ค่อนข้างง่าย โดยให้คาเรลวางเหรียญสุดท้ายก่อนที่จะหยุดการทำงานเพิ่มอีก 1 เหรียญ


บทถัดไป