พบบั๊กอายุ 55 ปีในเกม Lunar Lander เกมแรก
(martincmartin.com)- ระหว่างตรวจสอบตารางการใช้เชื้อเพลิงที่เหมาะสมที่สุดสำหรับการลงจอดในเกม Lunar Landing เกมแรกที่ Jim Storer นักเรียนมัธยมปลายสร้างไว้ในปี 1969 ได้พบบั๊กที่ทำให้เกมตัดสินผิดว่า ยานยังอยู่ระหว่างการบิน ทั้งที่จริงควรลงจอดแล้ว
- กลยุทธ์ที่เป็นปัญหาคือ suicide burn: ปิดเครื่องยนต์ 70 วินาที จากนั้นเผาเชื้อเพลิง 10 วินาทีที่ 164.31426784 lbs/sec แล้วค่อยเร่งเต็มที่ที่ 200 lbs/sec โดยเกมกลับพลาดการลงจอดนุ่มนวลที่ควรอยู่ระหว่างการลงจอดกระแทกกับการพุ่งกลับขึ้นโดยไม่ได้แตะพื้น
- โค้ดต้นฉบับไม่ได้ใช้ Euler integration แบบง่าย ๆ แต่ใช้ สมการจรวดของ Tsiolkovsky และอนุกรม Taylor เพื่อคำนวณการเคลื่อนที่ในแต่ละเทิร์น 10 วินาที ซึ่งถือว่าละเอียดมากสำหรับผลงานของนักเรียนมัธยมในสภาพแวดล้อม PDP-8 ปี 1969
- สาเหตุของบั๊กคือ ในสมการประมาณจุดต่ำสุดของวิถีก่อนสัมผัสพื้น มีการตกหล่นการ หารด้วย 2 ในส่วนของตัวส่วนภายในเครื่องหมายรากที่สอง ทำให้เวลาที่คำนวณว่าจะถึงจุดต่ำสุดถูกประเมินต่ำกว่าจริงอย่างสม่ำเสมอ
- เมื่อแก้ factor of two ที่หายไปและเอาการชดเชย 0.05 วินาทีออก ผลของ suicide burn ดีขึ้นเป็น 1.66 MPH แต่การลงจอดสมบูรณ์แบบที่ต่ำกว่า 1 MPH ยังติดข้อจำกัดจากการประมาณอนุกรม Taylor แบบ 2 พจน์และข้อจำกัดในการคำนวณเวลาลงจอดซ้ำ
Lunar Landing ปี 1969 และการค้นหาการลงจอดที่เหมาะสมที่สุด
- Jim Storer เขียนเกม Lunar Landing เกมแรกในช่วงไม่กี่เดือนหลัง Neil Armstrong ลงจอดบนดวงจันทร์ ขณะเป็นนักเรียนที่ Lexington High School ในรัฐ Massachusetts
- ภายในปี 1973 เกมนี้แพร่หลายมากจนถูกเรียกว่า “by far and away the single most popular computer game”
- เกมเป็นแบบข้อความ และการเคลื่อนที่ทั้งหมดของยานลงจอดบนดวงจันทร์มีเฉพาะในแนว ตั้งฉาก เท่านั้น
- ผู้เล่นต้องกำหนดปริมาณเชื้อเพลิงที่จะเผาในแต่ละช่วง 10 วินาทีของการจำลอง และพยายามลงจอดบนพื้นผิวดวงจันทร์ให้เบาที่สุด
- ระหว่างค้นหาตารางเชื้อเพลิงที่เหมาะสมที่สุด พบว่ากลยุทธ์ที่ดีที่สุดในทางทฤษฎีกลับทำงานไม่ถูกต้องในเกม
- ในความเป็นจริง ยานลงจอดแตะพื้นแล้ว
- แต่เกมกลับตัดสินผิดว่ายังไม่แตะพื้น
- สาเหตุสุดท้ายคือ การหารด้วยสองที่หายไป ซึ่งแทบไม่มีใครสังเกตเห็นมาเกือบ 55 ปี
การลงจอดแบบใช้เชื้อเพลิงน้อยที่สุดและ suicide burn
- หากต้องการลงจอดโดยใช้เชื้อเพลิงน้อยที่สุด ต้องลงให้ได้ภายในเวลา สั้นที่สุดเท่าที่จะเป็นไปได้
- กลยุทธ์ที่เหมาะสมคือ ปล่อยให้เครื่องยนต์ดับในช่วงแรกเพื่อเพิ่มความเร็ว แล้วรอจนถึงวินาทีสุดท้ายที่ยังเป็นไปได้ก่อนจะลดความเร็วด้วยแรงขับสูงสุด เพื่อให้ความเร็วใกล้ศูนย์ที่สุดตอนแตะพื้น
- ชุมชน Kerbal Space Program เรียกกลยุทธ์แบบนี้ว่า suicide burn
- เพราะจังหวะต้องแม่นมากและแทบไม่มีพื้นที่ให้ผิดพลาด
- ตารางที่หาได้ด้วยการลองผิดลองถูกและ binary search แบบทำมือมีดังนี้
- ไม่เผาเชื้อเพลิงเป็นเวลา 70 วินาที
- เผาเชื้อเพลิงที่ 164.31426784 lbs/sec ใน 10 วินาทีถัดไป
- จากนั้นเผาเชื้อเพลิงที่ค่าสูงสุด 200 lbs/sec
- เกมถือว่าความเร็วต่ำกว่า 1 MPH เป็นการลงจอดสมบูรณ์แบบ
- แต่ด้วยตารางนี้กลับลงจอดที่ความเร็วเกิน 3.5 MPH และได้ผลลัพธ์ว่า “could be better”
- ที่แปลกคือ ถ้าเผาเชื้อเพลิงเพิ่มขึ้นอีกเพียง 0.00000001 lbs/sec ยานจะไม่แตะพื้นเลยและกลับพุ่งขึ้นด้วยความเร็ว 114 MPH
- นั่นหมายความว่า การตัดสินว่าลงจอดนุ่มนวลซึ่งควรอยู่ระหว่าง การลงจอดกระแทก กับ การพุ่งกลับขึ้นโดยไม่แตะพื้น ได้หายไปจากเกม
การคำนวณฟิสิกส์ที่ละเอียดกว่าที่คาด
- ตอนแรกคาดว่าเกมคงใช้ Euler integration แบบที่ยังพบได้ทั่วไปแม้ในเกมปัจจุบัน
- คำนวณแรงที่จุดเริ่มต้นของช่วงเวลา
- หาอัตราเร่งจาก F=ma
- สมมติว่าอัตราเร่งคงที่ตลอดช่วงเวลานั้น
- แต่โค้ดจริงของ Lunar Landing ซับซ้อนกว่านั้น
- Jim Storer ใช้คำตอบที่แม่นยำของ Tsiolkovsky rocket equation
- สำหรับการคำนวณลอการิทึม เขาใชั การขยายอนุกรม Taylor
- ค่าสูงสุดของอาร์กิวเมนต์คือ 0.1212
- ใช้ 5 พจน์ก็ให้ความแม่นยำมากกว่า 6 หลัก
- ยังมีการย่อรูปพีชคณิตเพื่อลดความคลาดเคลื่อนจากการปัดเศษด้วย
- Jim Storer จำได้ว่าในเวลานั้นเขาคุ้นเคยกับแนวคิดอย่างแคลคูลัสและอนุกรม Taylor แล้ว และพ่อซึ่งเป็นนักฟิสิกส์ก็ช่วยในการหาอนุพันธ์ของสมการ
- เหตุผลที่ suicide burn เป็นกลยุทธ์ที่เหมาะสมที่สุดก็มาจากสมการจรวดนี้เอง และไม่ได้เป็นต้นเหตุของบั๊ก
ทำไมการตัดสินการสัมผัสพื้นถึงยาก
- สมการจรวดทำงานได้ดีจนกระทั่งยานแตะพื้น
- การชนกันของวัตถุแข็งเป็นปัญหาที่ยากในเอนจินพลวัต และ Lunar Landing ก็เจออุปสรรคใหญ่ที่สุดตรงการตัดสินการสัมผัสพื้นนี่เอง
- การดูแค่ต้นและปลายของแต่ละเทิร์น 10 วินาทีไม่เพียงพอ
- ตอนเริ่มอาจกำลังตกลง
- ตอนจบอาจกำลังลอยขึ้น
- และอาจเคยต่ำกว่าพื้นผิวในช่วงกลางแล้วค่อยดีดกลับขึ้นมา
- ในกรณีนี้ โปรแกรมต้องย้อนเวลากลับไปหาเวลาที่สัมผัสพื้นซึ่งเกิดขึ้นก่อนหน้านั้น
- จุดตรวจสอบที่เป็นธรรมชาติคือ จุดต่ำสุดของวิถี ซึ่งเป็นจุดที่ความเร็วเท่ากับ 0
- สำหรับสมการจรวด ไม่สามารถเขียนจุดต่ำสุดนี้ให้อยู่ในรูปปิดด้วยฟังก์ชันคณิตศาสตร์พื้นฐานเพียงอย่างเดียวได้
- เชิงอรรถอธิบายว่าต้องใช้ Lambert W
- แต่สามารถประมาณได้ด้วยการใช้เพียงไม่กี่พจน์แรกของอนุกรม Taylor ของลอการิทึม
- ถ้าใช้แค่ 2 พจน์แรก ปัญหาจะลดรูปเป็นสมการกำลังสอง
- และสามารถใช้ quadratic formula ระดับมัธยมปลายได้
- ในช่วงเทิร์น 10 วินาที คาดหวังความแม่นยำได้ภายในราว 0.1%
รูปแบบอื่นของสูตรกำลังสองและเสถียรภาพเชิงตัวเลข
- ในโค้ดของ Jim Storer มีรูปแบบที่เครื่องหมายรากที่สองอยู่ใน ตัวส่วน ไม่ใช่ตัวเศษ
- นี่ไม่ใช่ quadratic formula แบบทั่วไป แต่ตรงกับ รูปแบบทางเลือกของ quadratic formula ที่มีรากที่สองอยู่ด้านล่าง
- รูปแบบทางเลือกนี้มีข้อดีสำคัญในเชิงตัวเลข
- แม้ตอนตรวจพบการสัมผัสพื้นแล้ว ตอนจะหาเวลาที่สัมผัสจริงก็ยังใช้การตัดอนุกรม Taylor จนได้สมการกำลังสองเช่นกัน
- รูปแบบทั่วไปจะมีปัญหาหารด้วยศูนย์เมื่อสัมประสิทธิ์ของพจน์กำลังสองเป็น 0
- สถานการณ์นี้เกิดได้เมื่อแรงขับของจรวดสมดุลกับแรงโน้มถ่วงพอดี
- ซึ่งอาจพบได้บ่อยกับผู้เล่นที่ลอยอยู่ใกล้พื้นหรือกำลังค่อย ๆ ลดระดับลง
- เมื่อแรงขับใกล้เคียงแรงโน้มถ่วง รูปแบบทั่วไปจะเกิด catastrophic cancellation ที่ตัวเศษ และตัวส่วนที่เล็กจะขยายความผิดพลาดให้รุนแรงขึ้น
- ส่วนรูปแบบทางเลือกยังทำงานได้ดีแม้กรณีสมการเชิงเส้นที่พจน์กำลังสองหายไป
- เมื่อคิดว่าโค้ดนี้มาจากนักเรียนมัธยมในปี 1969 การที่เขาจะอนุมานใหม่เองหรือเคยเรียนรู้รูปแบบนี้มาก่อนจึงน่าประทับใจมาก
บั๊กที่แท้จริง: factor of two ที่หายไป
- เมื่อผู้เขียนบทความลองหาอนุพันธ์ของสมการเองแล้วนำมาเทียบ ก็พบว่าเกือบเหมือนกับโค้ดของ Jim Storer ทุกประการ ยกเว้นว่ามี 2 ที่ควรอยู่ในตัวส่วนภายในรากที่สองหายไป
- ความตกหล่นนี้น่าจะเป็นความผิดพลาดธรรมดาที่เกิดระหว่างการหาอนุพันธ์ของสมการหรือระหว่างพิมพ์ลงคอมพิวเตอร์
- ในเวลานั้น MACSYMA เพิ่งถือกำเนิดมาได้เพียง 1 ปี และก็ไม่ใช่สิ่งที่โรงเรียนมัธยมจะเข้าถึงได้ ดังนั้นการหาอนุพันธ์ต้องทำด้วยกระดาษกับดินสอ
- บั๊กนี้ทำให้เวลาที่คำนวณว่าจะถึงจุดต่ำสุดถูก ประเมินต่ำไป อย่างสม่ำเสมอ
- โค้ดพยายามชดเชยด้วยสองวิธี
- เพิ่มเวลา 0.05 วินาที
- แล้วประมาณซ้ำอีกครั้งจากตำแหน่งใหม่ที่ใกล้กว่า
- แต่ในสถานการณ์ suicide burn บางแบบ การชดเชยนี้กลับทำให้พลาดเวลาลงจอด
- การประมาณครั้งแรกยังเป็นช่วงที่ยานอยู่เหนือพื้นและยังคงกำลังลดระดับ
- การประมาณครั้งที่สองกลับอยู่หลังผ่านจุดต่ำสุดไปแล้วและกำลังไต่ขึ้น
- ช่วงเวลาระหว่างสองจุดนี้อาจสั้นกว่า 0.05 วินาทีได้
ผลลัพธ์หลังแก้ไขและข้อจำกัดที่ยังเหลือ
- เมื่อเติม factor of two ที่หายไปและลบการชดเชย 0.05 วินาทีออก ผลของ suicide burn ก็ดีขึ้น
- หลังแก้ไข suicide burn ที่ดีที่สุดให้ความเร็วตอนลงจอด 1.66 MPH
- นั่นหมายความว่าเข้าใกล้การลงจอดสมบูรณ์แบบต่ำกว่า 1 MPH ไปได้ประมาณสามในสี่ของทางแล้ว
- สาเหตุที่ยังไม่สมบูรณ์แบบคือยังใช้เพียง 2 พจน์แรกของอนุกรม Taylor อยู่
- หลังจากตัดสินว่าจุดต่ำสุดอยู่ใต้พื้นผิวแล้ว ก็ยังต้องย้อนกลับไปหาเวลาที่แตะพื้นครั้งแรกอีก
- กระบวนการนี้ก็ใช้การประมาณคล้ายกัน
- การทำซ้ำเพิ่มอาจช่วยได้
- เมื่อแก้บั๊กแล้ว การคำนวณเวลาจะกลายเป็น ประเมินสูงเกินไป จึงอาจต้องย้อนเวลากลับ
- ในกรณีนี้อาจต้องเลือกอีกคำตอบหนึ่งของสมการกำลังสอง
- วิธีที่ง่ายกว่านั้นคือใช้เพียงพจน์แรกของอนุกรม Taylor แล้วจัดการด้วยวิธีคล้าย Newton’s method
- อีกทางเลือกคือหยุดเมื่อขนาดความเร็วลดต่ำกว่าค่าขีดหนึ่ง แล้วใช้ความสูง ณ ตอนนั้นตัดสินว่าลงจอดหรือไม่
- อย่างไรก็ตาม การเปลี่ยนแปลงเหล่านี้จะทำให้โค้ดซับซ้อนขึ้น ขณะที่เกมต้นฉบับก็เล่นได้สนุกดีอยู่แล้ว
ทำไมบั๊กถึงอยู่มานานได้
- การลงจอดนุ่มนวลยังคงทำได้อยู่
- จบเทิร์นที่ 14 ด้วยระดับความสูงต่ำและความเร็วต่ำ
- ใช้แรงขับต่ำในเทิร์นที่ 15
- แล้วลงจอดในช่วงใดช่วงหนึ่งหลัง 150 วินาที
- สิ่งที่มีปัญหาจริง ๆ คือ suicide burn แบบแรงขับสูงสุด ตามทฤษฎี ซึ่งจบลงราว 148 วินาที
- โดยรวมแล้ว โค้ดนี้ถือว่าน่าทึ่งมากสำหรับผลงานที่เด็กมัธยมอายุ 18 ปีเขียนบน PDP-8 ในปี 1969
- ในยุคนั้น โรงเรียนมัธยมยังไม่ได้สอนวิทยาการคอมพิวเตอร์กันทั่วไป และแนวคิดด้านการคำนวณเชิงตัวเลขอย่างการปรับปรุงค่าประมาณแบบวนซ้ำด้วยวิธี Newton หรือการกังวลเรื่อง catastrophic cancellation ก็ยังไม่ได้แพร่หลาย
- เหตุผลที่บั๊กนี้แทบไม่มีใครสังเกตเห็นมาเกือบ 55 ปี ก็คือ ถึงจะมีบั๊ก เกมก็ยังยาก สนุก และยังลงจอดนุ่มนวลได้อยู่
- ความพยายามที่จะหามากกว่าแค่ “วิธีชนะ” แต่เป็น กลยุทธ์ที่เหมาะสมที่สุด ต่างหาก ที่นำไปสู่การทำความเข้าใจความไม่สอดคล้องเล็ก ๆ นี้
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ภายหลังเขายังมอบซอร์สโค้ดให้ด้วย ซึ่งยอดเยี่ยมมาก
https://technologizer.com/2009/07/19/lunar-lander/index.html
ส่วนที่ชอบที่สุดคือช่วงที่ Storer พูดว่า “หลังจากเรียนจบมัธยมปลาย ผมไม่เคยคิดถึงเกมนั้นอีกเลย จนกระทั่งเมื่อไม่กี่เดือนก่อนมีคนส่งอีเมลมาหาผมเรื่องนี้ ผมไม่เคยรู้ด้วยซ้ำว่ามีเกม Lunar Lander อื่นนอกจากที่ผมทำตอนมัธยมปลาย”
ตอนสมัครงานเกี่ยวกับ Lotus Notes ในปี 1989 ผมเอาเกม Lander ไปให้ Tim Halvorsen ผู้สัมภาษณ์ดู และเขาก็บอกว่า “เจ๋งดี ลองรันบน Windows 3 กันเถอะ”
ตอนแรกผมคิดว่าดีจังจะได้เห็น Windows 3 ที่ยังไม่วางขาย แต่ไม่นานเขาก็บอกว่า “Windows 3 รันทุกอย่างใน protected mode ดังนั้นถ้า pointer ออกนอกขอบเขต มันจะตายทันที” แล้วก็ชวนทดสอบดู
ผมลุ้นตลอดเวลาที่มันรันอยู่ แต่โชคดีที่ Lander ไม่พัง Tim ก็พอใจ และสุดท้ายผมก็ได้งานนั้น ทำให้เส้นทางอาชีพเปลี่ยนไปเลย
หารูปไม่เจอ แต่จากความจำมันคล้ายเครื่องนี้
https://content.invisioncic.com/r322239/monthly_10_2015/post...
แต่เครื่องนั้นมีภูมิประเทศและหลุมอยู่ และคุณต้องลงจอดในหลุมที่มีไฟติดอยู่ เมื่อยานกดปุ่มตรงกลางหลุม ไฟจะดับและอีกหลุมหนึ่งจะติดไฟแทน ถ้าเล็งไม่ดีจะชนขอบแล้วเอียงจนล้มเหลว
คิดอีกที การควบคุมอาจเป็นแบบตู้คีบ UFO คือจัดแนวจากด้านบนแล้วกด “land” ก็ได้ ตู้นี้เคยอยู่ใน Disneyland Main Street Arcade สมัยก่อน
รู้สึกแปลกนิดหน่อยที่ในบทความพูดซ้ำหลายครั้งว่า “น่าประทับใจสำหรับนักเรียนมัธยมปลายปีสุดท้ายในปี 1969” สำหรับคนสายเทคนิคที่เติบโตมาในยุคอวกาศ เรื่องนี้น่าจะมีอิทธิพลมาก และยังทำให้นึกถึงหนังเก่า October Sky
ในบทสัมภาษณ์ต้นฉบับบอกว่าผู้สร้างเกมเก่งแคลคูลัส ถ้าสนใจและมีพรสวรรค์ด้านอวกาศหรือจรวดอยู่แล้ว การลองเขียนโปรแกรมเกมลงจอดบนดวงจันทร์ก็ดูเป็นเรื่องธรรมชาติ
[1]: https://www.cs.brandeis.edu/~storer/LunarLander/LunarLander/...
ยุคอวกาศอาจสร้างแรงบันดาลใจได้ แต่สำหรับคนทั่วไปในเวลานั้น คอมพิวเตอร์แทบเหมือนไม่มีอยู่จริง และการพัฒนาซอฟต์แวร์ก็ยังไม่ใช่อาชีพที่คนรู้จักกันแพร่หลาย เพิ่งมีสาขาวิทยาการคอมพิวเตอร์ในสหรัฐเมื่อปี 1962 เท่านั้น ดังนั้นการเป็นนักเรียนมัธยมปลายปีสุดท้ายในปี 1969 จึงถือว่าน่าจับตาพอสมควร
ผมเรียนโรงเรียนมัธยมขนาดใหญ่ในเมืองค่อนข้างใหญ่ที่มีมหาวิทยาลัยวิศวกรรมใหญ่ ๆ แต่กำแพงสำคัญที่สุดคือ การเข้าถึงคอมพิวเตอร์
ที่โรงเรียนมีเครื่อง teletype เชื่อมกับเมนเฟรมระยะไกล และผมกับเพื่อนก็หาเครื่องคอมพิวเตอร์ของมหาวิทยาลัยบางเครื่องที่ใช้ได้ตอนกลางคืน แต่ส่วนใหญ่มีแค่ card reader กับ line printer เท่านั้น ไม่มี graphic terminal เลย
ในตอนนั้น การมีทั้งทักษะ ความสนใจ และการเข้าถึงพร้อมกัน เป็นการผสมที่ค่อนข้างหาได้ยาก
https://retro365.blog/2021/12/02/bits-from-my-personal-colle...
Wikipedia เกี่ยวกับ FOCAL:
https://en.wikipedia.org/wiki/FOCAL_(programming_language)
เริ่มจากแผนภาพแรงอิสระในวิชาฟิสิกส์มัธยม ไปจนถึงการจัดการกับแรงสองชนิดคือแรงโน้มถ่วงและแรงขับ แค่นี้นักเรียนทั่วไปที่ได้เกรด A วิชาฟิสิกส์ก็อาจทำได้
แต่แรงโน้มถ่วงขึ้นอยู่กับระยะถึงศูนย์กลาง ซึ่งเป็นค่าที่เปลี่ยนตลอด ต้องรู้ว่าการเริ่มที่ความสูง 120 ไมล์ แม้ค่าจะเปลี่ยนแต่เปลี่ยนไม่มากพอ จึงประมาณเป็นค่าคงที่ได้
วิธีที่แรงขับทำงานในฐานะฟังก์ชันของอัตราการเผาไหม้ก็ซับซ้อน เช่น ถ้าเพิ่มอัตราการไหลของเชื้อเพลิงเป็นสองเท่า ความเร็วไอเสียจะเพิ่มเป็นสองเท่าด้วยหรือไม่ แล้ว P กับ T ในกฎแก๊สอุดมคติ PV=nRT เปลี่ยนอย่างไร
ดังนั้น ถ้าเขาไปถามพ่อที่เป็นนักฟิสิกส์ และค้นจนเจอลักษณะของเครื่องยนต์จรวดกับ สมการจรวดของ Tsiolkovsky เพียงเท่านี้ก็น่าประทับใจแล้วสำหรับนักเรียนมัธยมปลายปีสุดท้าย
การจะไปจากความเร็วสู่ตำแหน่งต้องอินทิเกรต และผมก็ไม่แน่ใจว่านักเรียนฟิสิกส์ระดับมัธยมทั่วไปจะคิดถึงการแทนการเรียก FLOG() ด้วยอนุกรมเทย์เลอร์แล้วอินทิเกรตทีละพจน์ได้หรือไม่
รายละเอียดอย่างต้องใช้กี่พจน์ของอนุกรมเทย์เลอร์ หรือมันลู่เข้าหรือไม่ ก็ยังยุ่งยาก ถ้า Jim คิดประเด็นละเอียดอ่อนนี้ไว้ได้ก็สุดยอดมาก หรือไม่เขาอาจแค่เขียนไปเพราะ 5 พจน์ดูเหมือนเยอะพอก็ได้
แม้จะจำลองบริเวณใกล้ดวงจันทร์ได้แล้ว ปัญหาถัดมาคือจะตรวจจับการชนพื้นผิวอย่างไร แทนที่จะหาคำตอบของเวลาที่ความสูงเป็น 0 โดยตรง วิธีดูจุดที่ความเร็วเป็น 0 ซึ่งเกิดขึ้นพอดีหนึ่งครั้งระหว่างการหมุนนั้นค่อนข้างสร้างสรรค์
การกลับสมการจรวดเพื่อหาปริมาณเชื้อเพลิงที่ต้องใช้เมื่อกำหนดเดลตา-V ที่ต้องการ ก็เป็นสิ่งที่ไปไม่ถึงด้วยคณิตศาสตร์มัธยมปลายและแคลคูลัสพื้นฐานเพียงอย่างเดียว ในทางปฏิบัติต้องใช้ฟังก์ชันใหม่อย่าง Lambert W
สุดท้ายต้องแก้อนุกรมเทย์เลอร์ในรูปพหุนามดีกรี 5 จึงต้องตัดสินใจทิ้งพจน์ดีกรี 3, 4, 5 เพื่อให้เหลือสมการกำลังสอง การตัดสินว่าที่นี่สามารถทิ้งพจน์ที่ปกติไม่ทิ้งในงานคำนวณพลวัตได้ แสดงว่าเข้าใจว่าควรใช้ระดับการประมาณที่ต่างกันในสถานการณ์ต่างกัน ซึ่งน่าประทับใจ
อีกทั้งจากการที่เขาพยายามใช้รูปแบบทางเลือกของสมการกำลังสอง ก็ดูเหมือนว่าอาจไม่ได้เป็นแค่การค้นหามาแล้วคัดลอก
ผู้เล่นต้องพุ่งเข้ามาในแนวนอนด้วยความเร็วสูง จากนั้นชะลอความเร็วด้วยทรัสเตอร์ด้านข้างของ LEM และปุ่มเครื่องยนต์หลักเพื่อให้ลงจอดในแนวดิ่ง หากเร็วเกินไปหรือเชื้อเพลิงหมดก็จะเกิดหลุมอุกกาบาต และจะมีการปักธงชาติสหรัฐฯ หนึ่งผืนหรือมากกว่านั้นตามคุณภาพของการลงจอด
เมื่อไม่กี่ปีก่อน เขาทิ้งสำเนาเดียวของซอร์สโค้ดไปเพราะคิดว่าไม่มีมูลค่าและคงไม่มีวันถูกนำกลับมาใช้ใหม่ แต่ภายหลังก็ตระหนักว่าเกมนี้เป็นเกมกราฟิกยุคแรกพอสมควรในเชิงประวัติศาสตร์ และสามารถชุบชีวิตกลับมาได้ด้วยการอีมูเลตแบบง่าย ๆ จึงรู้สึกเสียดาย
พอกลับมาดูอีกครั้งในอีก 25 ปีต่อมา ก็ต้องตกใจที่มีบั๊กมากมายอย่างไม่น่าเชื่อ และตรรกะก็พันกันยุ่งแบบ “440 IF GOTO 450”
สุดท้ายเมื่อโตเป็นผู้ใหญ่เขาจึงเขียนมันขึ้นใหม่ [1] แต่ตัวเขาในวัยเด็กไม่มีทางทำสำเร็จได้เลย ทุกวันนี้เขายังสงสัยว่าภายในสำนักพิมพ์สเปนที่ถูกลืมนั้น โค้ดที่เกือบจะใช้งานได้ กลายมาเป็นเวอร์ชันสุดท้ายที่หน้าตาแบบนั้นได้อย่างไร
[1] https://7c0h.com/blog/new/moon_landing_in_basic.html
โค้ด BASIC แบบนี้มีรากมาจากยุค 1960–70 และในนิตยสารสิ่งพิมพ์กับรวมเล่มซอร์สโค้ดในเวลานั้น บรรณาธิการมีอำนาจสูงมาก
ตอนนั้นยังไม่มีความเข้าใจชัดเจนว่าซอร์สโค้ดควรถูกตีพิมพ์โดยไม่เปลี่ยนแม้แต่อักขระเดียว ดังนั้นบรรณาธิการจึงมัก “แก้” ซอร์สโค้ดอย่าง “รอบคอบ” โดยคิดว่าเป็นการแก้คำผิดที่ “เห็นได้ชัด” หรือเป็นดุลยพินิจด้านงานบรรณาธิการ
กว่าที่ทั้งอุตสาหกรรมจะเริ่มดีขึ้นในทศวรรษ 1980 และเกิดความเข้าใจร่วมกันว่าไม่ควรไปแตะต้องซอร์สโค้ดในสิ่งพิมพ์ บทเรียนนี้ก็ถูกเรียนรู้มาอย่างช้า ๆ และเจ็บปวด
จึงน่าสงสัยว่าสิ่งนี้อาจช่วยเร่งการเติบโตของ BBS และบั่นทอนอำนาจที่สื่อสิ่งพิมพ์เคยมีเหนือการแจกจ่ายซอร์สโค้ดด้วยหรือไม่ หากผู้มีอำนาจในสื่อสิ่งพิมพ์เปิดให้คนนอกมีสิทธิ์ควบคุมอย่างเด็ดขาดเหนือบางส่วนของคอนเทนต์ “ของตัวเอง” มากกว่านี้ ประวัติศาสตร์อาจออกมาอีกแบบก็ได้
ตอนเด็ก ๆ เขาเริ่มเขียนโค้ดโดยไม่มีผู้ใหญ่ช่วย อาศัยเพียงหนังสือโปรแกรมมิงไม่กี่เล่มจากโรงเรียนและห้องสมุดท้องถิ่น และก็น่าทึ่งที่เขายังยึดติดกับการเขียนโค้ดต่อไป ทั้งที่โปรแกรมจำนวนมากที่พิมพ์ตามด้วยมือล้วนเต็มไปด้วยข้อผิดพลาดคล้าย ๆ กัน
ขอเสริมอีกนิดเรื่องตรรกะพันกันอย่าง “440 IF GOTO 450” ว่า ถึงแม้โค้ดบางส่วนในหนังสือจะควรถูกจัดระเบียบใหม่แน่ ๆ แต่ BASIC ทั่วไปบนคอมพิวเตอร์ตามบ้านในยุคนั้นก็มักจัดการได้แค่เลขบรรทัดและมีคำสั่งแตกแขนงอย่างจำกัดมาก
BASIC ที่ใช้ดูเหมือนจะรองรับ structured programming ซึ่งหาได้ยากมากบนคอมพิวเตอร์ตามบ้านในเวลานั้น ถึงขั้นที่นิตยสาร C64 ในปี 1984 ตีพิมพ์บทความยาวอย่างน้อย 3 ฉบับเพื่อแนะนำความน่าทึ่งของ structured programming ให้ผู้อ่าน
ด้วยข้อจำกัดของคำสั่ง IF การแตกแขนงเชิงเงื่อนไขแบบสไตล์แอสเซมบลีที่ใช้ GOTO จึงพบได้ทั่วไปและแทบจะจำเป็น
การซ้อน IF ทำไม่ได้ และถ้าจะผสม IF หลายตัวเข้าด้วยกัน ก็ต้องกระโดดข้ามส่วนที่ไม่ได้เลือก Commodore/C64 BASIC หรือแทบจะพูดได้ว่า Microsoft BASIC ไม่มีแม้แต่ ELSE จึงมักจำลองแขนง ELSE ด้วยเงื่อนไขปฏิเสธและการกระโดด
C64 BASIC ยังมีพฤติกรรมประหลาดที่คำสั่งอื่นในบรรทัดเดียวกันนับว่าอยู่ภายใต้ THEN ด้วย เช่น
10 IF A=1 THEN PRINT “FOO” : PRINT “BAR”จะพิมพ์ FOO BAR เมื่อ A=1 และถ้าไม่ใช่ก็จะไม่พิมพ์อะไรเลยแน่นอนว่าทำได้เฉพาะเมื่อสามารถยัดทุกคำสั่งลงในบรรทัดจำกัดเส้นเดียวนั้นได้ BASIC สำเนียงอื่นอาจตีความ
PRINT “BAR”ว่าอยู่นอก ELSE ซึ่งสะอาดกว่าในเชิงไวยากรณ์ แต่ก็อาจใช้งานไม่สะดวกกว่าแล้วแต่ฟีเจอร์ที่ภาษาถิ่นนั้นมีความสะดวกและความเข้มงวดที่เรามองว่าเป็นเรื่องปกติทุกวันนี้ยังไม่มีในตอนนั้น C64 BASIC มีลักษณะประหลาดมากมายที่เหมือนเป็นผลผลิตจากรายละเอียดการอิมพลีเมนต์ จึงยิ่งดู “สกปรก” เป็นพิเศษ ตัวอย่างเช่น ทุกฟังก์ชันต้องรับอาร์กิวเมนต์แม้จริง ๆ จะไม่ต้องใช้ก็ตาม ดังนั้นถ้าจะพิมพ์หน่วยความจำที่เหลือ ก็ต้องเขียนอะไรไร้ความหมายอย่าง
?FRE(123)ยิ่ง “เล่น” ค่า 199.99999999 ให้เร็วเท่าไรก็ยิ่งดี ดังนั้นจึงเลือกอินพุตที่เร็วที่สุดซึ่งยังทำให้ลงจอดอย่างนุ่มนวลได้ด้วยการ brute force
เพื่อให้เกมรับรู้การลงจอด ความสูงต้องน้อยกว่า 0 เป็นเวลาราว 0.05 วินาที ถ้าช่วงเวลานั้นแรงขับเป็น 200 หรือ 199 ความเร็ว ณ จุดที่ความสูงเป็น 0 ต้องมากกว่า 1MPH จึงจะทำให้ความสูงติดลบนานขนาดนั้นได้
ต่อให้แก้บั๊กแล้ว โค้ดก็ยังคงแค่ประมาณค่าจุดต่ำสุดเท่านั้น หลังจากตรวจพบการลงจอดแล้ว มันยังต้องคำนวณเวลาลงจอดจริง นั่นคือเวลาที่ความสูงเป็น 0 ไม่ใช่เวลาที่ความเร็วเป็น 0 และจุดนี้ก็ใช้การประมาณเช่นกัน
ดังนั้นเวลาอาจคลาดเคลื่อนได้เล็กน้อย ถ้าในช่วงก้าวเวลาสุดท้ายกำลังเผาไหม้ที่ 200 หรือ 199 ความเร่งจะสูงมาก ทำให้ความคลาดเคลื่อนของเวลาเพียงเล็กน้อยนำไปสู่ความคลาดเคลื่อนของความเร็วที่มากได้
แต่ถ้าเผาไหม้ที่ราว 10 lbs/sec ต่อให้คลาดไปประมาณ 0.08 วินาที ความเร็วก็จะไม่เปลี่ยนมากนัก
สงสัยว่านี่หมายความว่ายิ่งอัตราเฟรมต่ำ ความแม่นยำของวิธีนี้ก็ยิ่งแย่ลงหรือเปล่า หรือเป็นเพราะความสนุกจากการใช้สมการจริงกันแน่
และก็สงสัยด้วยว่าที่อัตราเฟรมเดิม ความแตกต่างระหว่างสองวิธีนี้รู้สึกได้มากแค่ไหน
https://www.cs.brandeis.edu/~storer/LunarLander/LunarLander/...
ถ้าอัปเดตมวลและความเร่งแค่ทุก 10 วินาที ความคลาดเคลื่อนจะสูงมาก
ในแง่ความแม่นยำทางฟิสิกส์ โดยเฉพาะใกล้พื้นผิว ถ้าอัตราการเผาไหม้เชื้อเพลิงสูง มวลก็จะเปลี่ยนไปค่อนข้างมาก แต่ในแง่ความยากหรือความสนุกของเกม รวมถึงกลยุทธ์ของผู้เล่น คิดว่าคงไม่ต่างมากนัก
จริง ๆ แล้วดูเหมือนว่าหนึ่งในซิมูเลชันลงจอดบนดวงจันทร์อื่น ๆ ในหนังสือ BASIC computer games จะใช้แนวทางแบบง่าย ๆ นั้น
ถ้า 10 วินาทียาวเกินไป ก็อาจคงหนึ่งเทิร์นของส่วนติดต่อผู้ใช้ไว้ที่ 10 วินาทีเหมือนเดิม แต่ภายในแบ่งแต่ละเทิร์นออกเป็นขั้นเวลา 1 วินาที 10 ขั้นแทนได้
เกมเดิมก็ทำแบบนั้นจริงในบางส่วน จึงทำให้ระบบจำลองฟิสิกส์รับค่าเวลา S แบบใดก็ได้ ไม่ได้จำกัดว่าต้องเป็น 10 วินาทีเต็มเสมอไป
แต่จริง ๆ แล้วไม่มีเกมลงจอด และ Storer คือคนแรก ประวัติที่น่าสนใจเกี่ยวกับเรื่องนี้อยู่ที่นี่
https://www.acriticalhit.com/moonlander-one-giant-leap-for-g...
ต่อให้ไม่คำนวณผลจากการที่ยานเบาลงเมื่อเผาเชื้อเพลิงไปแล้ว หรือพูดอีกแบบคือเอาส่วนที่สมการจรวดทำออกไป suicide burn ก็ยังเป็นวิธีที่เหมาะที่สุดอยู่ดี
เหตุผลจริงคือ suicide burn ช่วยลด gravity loss ให้ต่ำที่สุด
https://en.wikipedia.org/wiki/Gravity_loss
จุดที่ต้องการสื่อคือในพลวัตมีอยู่สองส่วนคือสมการจรวดกับแรงโน้มถ่วง และทั้งสองส่วนนี้บวกกันแบบเชิงเส้น ความเร็วที่เพิ่มขึ้นเพราะแรงโน้มถ่วงต้องถูกลบออกด้วยการเพิ่มเดลตา-V จากสมการจรวด
เดลตา-V จากแรงโน้มถ่วงคือความเร่งโน้มถ่วงคูณเวลา ดังนั้นจึงต้องทำให้เวลาน้อยที่สุด
น่าแปลกที่ในสมการจรวดนั้น ใช้เวลานานแค่ไหน ใช้ลำดับการเผาไหม้แบบไหน หรือจะเผาต่อเนื่องด้วยอัตราคงที่หรือเผาเป็นช่วงสั้น ๆ แบบแรง ๆ ล้วนไม่สำคัญ
ดังนั้นถ้าต้องการลงจอดด้วยความเร็ว 0 โดยใช้เชื้อเพลิงน้อยที่สุด ก็ต้องลงจอดให้ได้ในเวลาสั้นที่สุดเท่าที่เป็นไปได้
ผมไม่ได้ค้นพบวิธีลงจอดเอง แต่จำได้ว่ามีคนสาธิตเทคนิคปล่อยให้ยานลอยตามแรงเฉื่อยในช่วงแรกไม่กี่เทิร์น แล้วค่อยเร่งแรงขับสูงสุด ตอนนั้นไม่จำได้ว่าใช้คำว่า “suicide burn” กันหรือไม่ อาจเป็นคำที่มาแพร่หลายในภายหลังหลัง Kerbal Space Program โด่งดังก็ได้
ผมยังจำได้ว่าในช่วงกลางทศวรรษ 1970 ที่ Lawrence Hall of Science ใน Berkeley ก็มีเกมลงจอดบนดวงจันทร์นี้รันอยู่บนเทอร์มินัลไม่กี่เครื่องด้วย แต่ไม่รู้ว่ารันอยู่บนคอมพิวเตอร์อะไร
ผมไม่เคยเห็นซอร์สโค้ดของโปรแกรมนี้มาก่อนเลย และก็ไม่เคยรู้ด้วยว่าคณิตศาสตร์ของมันละเอียดขนาดนี้ ตอนนั้นผมยังเด็กเกินกว่าจะเข้าใจ และพูดตรง ๆ ตอนนี้ก็ไม่แน่ใจเหมือนกันว่าจะเข้าใจได้หรือเปล่า
“ฟีเจอร์” อย่างหนึ่งของโหมดคีออสก์สำหรับเกมคือ ถ้าจับจังหวะ Ctrl-C ได้พอดี ก็สามารถออกจากโหมดคีออสก์ไปเล่นเกมอื่นได้
นี่เป็นเรื่องบังเอิญ หรือเป็นเหมือนเหยื่อล่อที่โยนไว้ให้แฮ็กเกอร์ยุคแรก ๆ กันแน่นะ?