2 คะแนน โดย GN⁺ 2024-06-15 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ระหว่างตรวจสอบตารางการใช้เชื้อเพลิงที่เหมาะสมที่สุดสำหรับการลงจอดในเกม 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 ความคิดเห็น

 
GN⁺ 2024-06-15
ความคิดเห็นจาก Hacker News
  • ในปี 2009 มีการตามหาจนพบและสัมภาษณ์ Jim Storer ผู้สร้างเกม Lunar Lander เกมแรก และต่อมาก็ได้รวบรวมประวัติของเกมนี้ไว้ด้วย
    ภายหลังเขายังมอบซอร์สโค้ดให้ด้วย ซึ่งยอดเยี่ยมมาก
    https://technologizer.com/2009/07/19/lunar-lander/index.html
    ส่วนที่ชอบที่สุดคือช่วงที่ Storer พูดว่า “หลังจากเรียนจบมัธยมปลาย ผมไม่เคยคิดถึงเกมนั้นอีกเลย จนกระทั่งเมื่อไม่กี่เดือนก่อนมีคนส่งอีเมลมาหาผมเรื่องนี้ ผมไม่เคยรู้ด้วยซ้ำว่ามีเกม Lunar Lander อื่นนอกจากที่ผมทำตอนมัธยมปลาย”
    • รู้สึกเป็นเกียรติที่ได้ถูกรวมอยู่ในบทความนี้ ผมสร้าง Lander(1990) สำหรับ Windows 2.x ไว้แต่แรก
      ตอนสมัครงานเกี่ยวกับ Lotus Notes ในปี 1989 ผมเอาเกม Lander ไปให้ Tim Halvorsen ผู้สัมภาษณ์ดู และเขาก็บอกว่า “เจ๋งดี ลองรันบน Windows 3 กันเถอะ”
      ตอนแรกผมคิดว่าดีจังจะได้เห็น Windows 3 ที่ยังไม่วางขาย แต่ไม่นานเขาก็บอกว่า “Windows 3 รันทุกอย่างใน protected mode ดังนั้นถ้า pointer ออกนอกขอบเขต มันจะตายทันที” แล้วก็ชวนทดสอบดู
      ผมลุ้นตลอดเวลาที่มันรันอยู่ แต่โชคดีที่ Lander ไม่พัง Tim ก็พอใจ และสุดท้ายผมก็ได้งานนั้น ทำให้เส้นทางอาชีพเปลี่ยนไปเลย
    • ยังมี เกมลงจอดแบบกลไก ที่มาก่อน Lunar Lander อีกด้วย
      หารูปไม่เจอ แต่จากความจำมันคล้ายเครื่องนี้
      https://content.invisioncic.com/r322239/monthly_10_2015/post...
      แต่เครื่องนั้นมีภูมิประเทศและหลุมอยู่ และคุณต้องลงจอดในหลุมที่มีไฟติดอยู่ เมื่อยานกดปุ่มตรงกลางหลุม ไฟจะดับและอีกหลุมหนึ่งจะติดไฟแทน ถ้าเล็งไม่ดีจะชนขอบแล้วเอียงจนล้มเหลว
      คิดอีกที การควบคุมอาจเป็นแบบตู้คีบ UFO คือจัดแนวจากด้านบนแล้วกด “land” ก็ได้ ตู้นี้เคยอยู่ใน Disneyland Main Street Arcade สมัยก่อน
    • Lunar Lander เป็นหนึ่งในเกมยุคแรก ๆ ที่ผมเคยพยายามทำตามตอนเรียนเขียนโปรแกรมสมัยมัธยม: Java applet ตัวนี้ https://github.com/celwell/space-landing
  • บรรทัดที่เป็นปัญหาน่าจะเป็น 08.10
    รู้สึกแปลกนิดหน่อยที่ในบทความพูดซ้ำหลายครั้งว่า “น่าประทับใจสำหรับนักเรียนมัธยมปลายปีสุดท้ายในปี 1969” สำหรับคนสายเทคนิคที่เติบโตมาในยุคอวกาศ เรื่องนี้น่าจะมีอิทธิพลมาก และยังทำให้นึกถึงหนังเก่า October Sky
    ในบทสัมภาษณ์ต้นฉบับบอกว่าผู้สร้างเกมเก่งแคลคูลัส ถ้าสนใจและมีพรสวรรค์ด้านอวกาศหรือจรวดอยู่แล้ว การลองเขียนโปรแกรมเกมลงจอดบนดวงจันทร์ก็ดูเป็นเรื่องธรรมชาติ
    [1]: https://www.cs.brandeis.edu/~storer/LunarLander/LunarLander/...
    • ในปี 1969 นักเรียนมัธยมปลายในสหรัฐที่เข้าถึงคอมพิวเตอร์ได้มีเพียงระดับหลักร้อยโดยประมาณ และคนที่มี ทักษะการใช้คอมพิวเตอร์ ก็มีน้อยยิ่งกว่า
      ยุคอวกาศอาจสร้างแรงบันดาลใจได้ แต่สำหรับคนทั่วไปในเวลานั้น คอมพิวเตอร์แทบเหมือนไม่มีอยู่จริง และการพัฒนาซอฟต์แวร์ก็ยังไม่ใช่อาชีพที่คนรู้จักกันแพร่หลาย เพิ่งมีสาขาวิทยาการคอมพิวเตอร์ในสหรัฐเมื่อปี 1962 เท่านั้น ดังนั้นการเป็นนักเรียนมัธยมปลายปีสุดท้ายในปี 1969 จึงถือว่าน่าจับตาพอสมควร
    • ผมเป็นนักเรียนมัธยมปลายในปี 1969 รู้แคลคูลัสอยู่พอสมควร และสนใจการเขียนโปรแกรมมาก
      ผมเรียนโรงเรียนมัธยมขนาดใหญ่ในเมืองค่อนข้างใหญ่ที่มีมหาวิทยาลัยวิศวกรรมใหญ่ ๆ แต่กำแพงสำคัญที่สุดคือ การเข้าถึงคอมพิวเตอร์
      ที่โรงเรียนมีเครื่อง teletype เชื่อมกับเมนเฟรมระยะไกล และผมกับเพื่อนก็หาเครื่องคอมพิวเตอร์ของมหาวิทยาลัยบางเครื่องที่ใช้ได้ตอนกลางคืน แต่ส่วนใหญ่มีแค่ card reader กับ line printer เท่านั้น ไม่มี graphic terminal เลย
      ในตอนนั้น การมีทั้งทักษะ ความสนใจ และการเข้าถึงพร้อมกัน เป็นการผสมที่ค่อนข้างหาได้ยาก
    • ผมสงสัยว่ามันเขียนด้วยภาษาอะไร พอไปดูบทความเกี่ยวกับเกมนี้ก็พบว่าเป็นภาษา FOCAL
      https://retro365.blog/2021/12/02/bits-from-my-personal-colle...
      Wikipedia เกี่ยวกับ FOCAL:
      https://en.wikipedia.org/wiki/FOCAL_(programming_language)
    • ผมเป็นผู้เขียนบทความต้นฉบับเอง ผมเข้าใจว่าคำว่า “น่าประทับใจสำหรับนักเรียนมัธยมปลายปีสุดท้ายในปี 1969” อาจฟังดูแปลก แต่การจะทำเกมนี้ได้ต้องมีหลายอย่างพอสมควร
      เริ่มจากแผนภาพแรงอิสระในวิชาฟิสิกส์มัธยม ไปจนถึงการจัดการกับแรงสองชนิดคือแรงโน้มถ่วงและแรงขับ แค่นี้นักเรียนทั่วไปที่ได้เกรด A วิชาฟิสิกส์ก็อาจทำได้
      แต่แรงโน้มถ่วงขึ้นอยู่กับระยะถึงศูนย์กลาง ซึ่งเป็นค่าที่เปลี่ยนตลอด ต้องรู้ว่าการเริ่มที่ความสูง 120 ไมล์ แม้ค่าจะเปลี่ยนแต่เปลี่ยนไม่มากพอ จึงประมาณเป็นค่าคงที่ได้
      วิธีที่แรงขับทำงานในฐานะฟังก์ชันของอัตราการเผาไหม้ก็ซับซ้อน เช่น ถ้าเพิ่มอัตราการไหลของเชื้อเพลิงเป็นสองเท่า ความเร็วไอเสียจะเพิ่มเป็นสองเท่าด้วยหรือไม่ แล้ว P กับ T ในกฎแก๊สอุดมคติ PV=nRT เปลี่ยนอย่างไร
      ดังนั้น ถ้าเขาไปถามพ่อที่เป็นนักฟิสิกส์ และค้นจนเจอลักษณะของเครื่องยนต์จรวดกับ สมการจรวดของ Tsiolkovsky เพียงเท่านี้ก็น่าประทับใจแล้วสำหรับนักเรียนมัธยมปลายปีสุดท้าย
      การจะไปจากความเร็วสู่ตำแหน่งต้องอินทิเกรต และผมก็ไม่แน่ใจว่านักเรียนฟิสิกส์ระดับมัธยมทั่วไปจะคิดถึงการแทนการเรียก FLOG() ด้วยอนุกรมเทย์เลอร์แล้วอินทิเกรตทีละพจน์ได้หรือไม่
      รายละเอียดอย่างต้องใช้กี่พจน์ของอนุกรมเทย์เลอร์ หรือมันลู่เข้าหรือไม่ ก็ยังยุ่งยาก ถ้า Jim คิดประเด็นละเอียดอ่อนนี้ไว้ได้ก็สุดยอดมาก หรือไม่เขาอาจแค่เขียนไปเพราะ 5 พจน์ดูเหมือนเยอะพอก็ได้

แม้จะจำลองบริเวณใกล้ดวงจันทร์ได้แล้ว ปัญหาถัดมาคือจะตรวจจับการชนพื้นผิวอย่างไร แทนที่จะหาคำตอบของเวลาที่ความสูงเป็น 0 โดยตรง วิธีดูจุดที่ความเร็วเป็น 0 ซึ่งเกิดขึ้นพอดีหนึ่งครั้งระหว่างการหมุนนั้นค่อนข้างสร้างสรรค์
การกลับสมการจรวดเพื่อหาปริมาณเชื้อเพลิงที่ต้องใช้เมื่อกำหนดเดลตา-V ที่ต้องการ ก็เป็นสิ่งที่ไปไม่ถึงด้วยคณิตศาสตร์มัธยมปลายและแคลคูลัสพื้นฐานเพียงอย่างเดียว ในทางปฏิบัติต้องใช้ฟังก์ชันใหม่อย่าง Lambert W
สุดท้ายต้องแก้อนุกรมเทย์เลอร์ในรูปพหุนามดีกรี 5 จึงต้องตัดสินใจทิ้งพจน์ดีกรี 3, 4, 5 เพื่อให้เหลือสมการกำลังสอง การตัดสินว่าที่นี่สามารถทิ้งพจน์ที่ปกติไม่ทิ้งในงานคำนวณพลวัตได้ แสดงว่าเข้าใจว่าควรใช้ระดับการประมาณที่ต่างกันในสถานการณ์ต่างกัน ซึ่งน่าประทับใจ
อีกทั้งจากการที่เขาพยายามใช้รูปแบบทางเลือกของสมการกำลังสอง ก็ดูเหมือนว่าอาจไม่ได้เป็นแค่การค้นหามาแล้วคัดลอก

  • ถึงจะมีชื่อเสียงในฐานะเกม Lunar Lander เกมแรก แต่ส่วนที่น่าประทับใจจริง ๆ คือ เทคนิคการวิเคราะห์เชิงตัวเลข ที่ใช้
  • กลางทศวรรษ 1970 เขาสร้างเกมลงจอดบนดวงจันทร์แบบ กราฟิกเวกเตอร์ 2D สำหรับเทอร์มินัลกราฟิกของ Adage
    ผู้เล่นต้องพุ่งเข้ามาในแนวนอนด้วยความเร็วสูง จากนั้นชะลอความเร็วด้วยทรัสเตอร์ด้านข้างของ LEM และปุ่มเครื่องยนต์หลักเพื่อให้ลงจอดในแนวดิ่ง หากเร็วเกินไปหรือเชื้อเพลิงหมดก็จะเกิดหลุมอุกกาบาต และจะมีการปักธงชาติสหรัฐฯ หนึ่งผืนหรือมากกว่านั้นตามคุณภาพของการลงจอด
    เมื่อไม่กี่ปีก่อน เขาทิ้งสำเนาเดียวของซอร์สโค้ดไปเพราะคิดว่าไม่มีมูลค่าและคงไม่มีวันถูกนำกลับมาใช้ใหม่ แต่ภายหลังก็ตระหนักว่าเกมนี้เป็นเกมกราฟิกยุคแรกพอสมควรในเชิงประวัติศาสตร์ และสามารถชุบชีวิตกลับมาได้ด้วยการอีมูเลตแบบง่าย ๆ จึงรู้สึกเสียดาย
    • เขาหมายถึง “การลงจอดในแนวดิ่ง” ไม่ใช่ “การลงจอดในแนวนอน”
  • ในหนังสือโปรแกรมมิงเล่มแรกของเขามีเกมนี้เวอร์ชัน BASIC อยู่ แต่เขาไม่เคยรันมันได้อย่างถูกต้อง
    พอกลับมาดูอีกครั้งในอีก 25 ปีต่อมา ก็ต้องตกใจที่มีบั๊กมากมายอย่างไม่น่าเชื่อ และตรรกะก็พันกันยุ่งแบบ “440 IF GOTO 450”
    สุดท้ายเมื่อโตเป็นผู้ใหญ่เขาจึงเขียนมันขึ้นใหม่ [1] แต่ตัวเขาในวัยเด็กไม่มีทางทำสำเร็จได้เลย ทุกวันนี้เขายังสงสัยว่าภายในสำนักพิมพ์สเปนที่ถูกลืมนั้น โค้ดที่เกือบจะใช้งานได้ กลายมาเป็นเวอร์ชันสุดท้ายที่หน้าตาแบบนั้นได้อย่างไร
    [1] https://7c0h.com/blog/new/moon_landing_in_basic.html
    • คำว่า “ไม่มีทางทำสำเร็จ” ยังเบาไปด้วยซ้ำ
      โค้ด BASIC แบบนี้มีรากมาจากยุค 1960–70 และในนิตยสารสิ่งพิมพ์กับรวมเล่มซอร์สโค้ดในเวลานั้น บรรณาธิการมีอำนาจสูงมาก
      ตอนนั้นยังไม่มีความเข้าใจชัดเจนว่าซอร์สโค้ดควรถูกตีพิมพ์โดยไม่เปลี่ยนแม้แต่อักขระเดียว ดังนั้นบรรณาธิการจึงมัก “แก้” ซอร์สโค้ดอย่าง “รอบคอบ” โดยคิดว่าเป็นการแก้คำผิดที่ “เห็นได้ชัด” หรือเป็นดุลยพินิจด้านงานบรรณาธิการ
      กว่าที่ทั้งอุตสาหกรรมจะเริ่มดีขึ้นในทศวรรษ 1980 และเกิดความเข้าใจร่วมกันว่าไม่ควรไปแตะต้องซอร์สโค้ดในสิ่งพิมพ์ บทเรียนนี้ก็ถูกเรียนรู้มาอย่างช้า ๆ และเจ็บปวด
      จึงน่าสงสัยว่าสิ่งนี้อาจช่วยเร่งการเติบโตของ BBS และบั่นทอนอำนาจที่สื่อสิ่งพิมพ์เคยมีเหนือการแจกจ่ายซอร์สโค้ดด้วยหรือไม่ หากผู้มีอำนาจในสื่อสิ่งพิมพ์เปิดให้คนนอกมีสิทธิ์ควบคุมอย่างเด็ดขาดเหนือบางส่วนของคอนเทนต์ “ของตัวเอง” มากกว่านี้ ประวัติศาสตร์อาจออกมาอีกแบบก็ได้
      ตอนเด็ก ๆ เขาเริ่มเขียนโค้ดโดยไม่มีผู้ใหญ่ช่วย อาศัยเพียงหนังสือโปรแกรมมิงไม่กี่เล่มจากโรงเรียนและห้องสมุดท้องถิ่น และก็น่าทึ่งที่เขายังยึดติดกับการเขียนโค้ดต่อไป ทั้งที่โปรแกรมจำนวนมากที่พิมพ์ตามด้วยมือล้วนเต็มไปด้วยข้อผิดพลาดคล้าย ๆ กัน
    • อ่านสนุกดี ตอนเด็ก ๆ ฉันเคยดู C64 โหลดภาพที่เกี่ยวกับเกมด้วยโค้ดเพียงไม่กี่บรรทัดอย่าง “มหัศจรรย์” แล้วคิดว่าภาพเหล่านั้นคงถูกเก็บอยู่ข้างในอยู่แล้วที่ไหนสักแห่ง
      ขอเสริมอีกนิดเรื่องตรรกะพันกันอย่าง “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)
    • น่าจะเป็นผลจากความผิดพลาดแบบคัดลอก/วางในกระบวนการบรรณาธิการ เดดไลน์ และการขาด การประกันคุณภาพ ที่ปะปนกัน
  • กลยุทธ์การลงจอดแบบนุ่มนวลที่ประหยัดเชื้อเพลิงสูงสุดดูเหมือนจะไม่ตรงกับรูปแบบที่แม่นยำของ “suicide burn” จึงถูกมองข้ามไป แต่คาดว่าน่าจะเป็นการใส่ค่า 164.31426784 lbs/second ที่ t=70 วินาที แล้วหลังจากนั้นเปลี่ยนหนึ่งในอินพุต 200 lbs/second เป็น 199.99999999 lbs/second
    ยิ่ง “เล่น” ค่า 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 วินาที ความคลาดเคลื่อนจะสูงมาก
  • ผู้เขียนโพสต์ต้นฉบับเอง ผมก็คาดว่าน่าจะเป็นวิธีแบบง่าย ๆ นั้นเหมือนกัน และในบทความก็อธิบายด้วย Euler method
    ในแง่ความแม่นยำทางฟิสิกส์ โดยเฉพาะใกล้พื้นผิว ถ้าอัตราการเผาไหม้เชื้อเพลิงสูง มวลก็จะเปลี่ยนไปค่อนข้างมาก แต่ในแง่ความยากหรือความสนุกของเกม รวมถึงกลยุทธ์ของผู้เล่น คิดว่าคงไม่ต่างมากนัก
    จริง ๆ แล้วดูเหมือนว่าหนึ่งในซิมูเลชันลงจอดบนดวงจันทร์อื่น ๆ ในหนังสือ BASIC computer games จะใช้แนวทางแบบง่าย ๆ นั้น
    ถ้า 10 วินาทียาวเกินไป ก็อาจคงหนึ่งเทิร์นของส่วนติดต่อผู้ใช้ไว้ที่ 10 วินาทีเหมือนเดิม แต่ภายในแบ่งแต่ละเทิร์นออกเป็นขั้นเวลา 1 วินาที 10 ขั้นแทนได้
    เกมเดิมก็ทำแบบนั้นจริงในบางส่วน จึงทำให้ระบบจำลองฟิสิกส์รับค่าเวลา S แบบใดก็ได้ ไม่ได้จำกัดว่าต้องเป็น 10 วินาทีเต็มเสมอไป
  • ผมสับสนอยู่พักหนึ่งเพราะจำได้ว่าเคยเล่น Spacewar บน PDP-1 ในยุค 1960 และดันจำผิดว่ามีเกมลงจอดด้วย
    แต่จริง ๆ แล้วไม่มีเกมลงจอด และ Storer คือคนแรก ประวัติที่น่าสนใจเกี่ยวกับเรื่องนี้อยู่ที่นี่
    https://www.acriticalhit.com/moonlander-one-giant-leap-for-g...
  • คำพูดที่ว่า “เพราะสมการจรวด suicide burn จึงเป็นวิธีที่เหมาะที่สุด” นั้น ถ้าพูดให้เคร่งครัดแล้วไม่ถูกนัก
    ต่อให้ไม่คำนวณผลจากการที่ยานเบาลงเมื่อเผาเชื้อเพลิงไปแล้ว หรือพูดอีกแบบคือเอาส่วนที่สมการจรวดทำออกไป suicide burn ก็ยังเป็นวิธีที่เหมาะที่สุดอยู่ดี
    เหตุผลจริงคือ suicide burn ช่วยลด gravity loss ให้ต่ำที่สุด
    https://en.wikipedia.org/wiki/Gravity_loss
    • ผู้เขียนโพสต์ต้นฉบับเอง ถูกต้อง ผมพูดแบบย่อเกินไป
      จุดที่ต้องการสื่อคือในพลวัตมีอยู่สองส่วนคือสมการจรวดกับแรงโน้มถ่วง และทั้งสองส่วนนี้บวกกันแบบเชิงเส้น ความเร็วที่เพิ่มขึ้นเพราะแรงโน้มถ่วงต้องถูกลบออกด้วยการเพิ่มเดลตา-V จากสมการจรวด
      เดลตา-V จากแรงโน้มถ่วงคือความเร่งโน้มถ่วงคูณเวลา ดังนั้นจึงต้องทำให้เวลาน้อยที่สุด
      น่าแปลกที่ในสมการจรวดนั้น ใช้เวลานานแค่ไหน ใช้ลำดับการเผาไหม้แบบไหน หรือจะเผาต่อเนื่องด้วยอัตราคงที่หรือเผาเป็นช่วงสั้น ๆ แบบแรง ๆ ล้วนไม่สำคัญ
      ดังนั้นถ้าต้องการลงจอดด้วยความเร็ว 0 โดยใช้เชื้อเพลิงน้อยที่สุด ก็ต้องลงจอดให้ได้ในเวลาสั้นที่สุดเท่าที่เป็นไปได้
  • ผมยังมีม้วนเทปเจาะรูที่น่าจะสำหรับ PDP-11 อยู่ม้วนหนึ่ง และมีคำว่า “Lunar Lander” เขียนอยู่ แต่ไม่รู้ควรยกให้ใครดี
    • น่าจะเป็น Internet Archive หรือ Computer History Museum ที่เหมาะ ถ้าอยากได้คำแนะนำเรื่องสถานที่ที่อาจสนใจ ลองถาม @textfiles ได้
  • ค่อนข้างน่าทึ่ง ผมจำได้ว่าเคยเล่นเกมนี้หลังจากมีคนนำมันไปพอร์ตเป็น Wang 2200 BASIC ในช่วงกลางทศวรรษ 1970
    ผมไม่ได้ค้นพบวิธีลงจอดเอง แต่จำได้ว่ามีคนสาธิตเทคนิคปล่อยให้ยานลอยตามแรงเฉื่อยในช่วงแรกไม่กี่เทิร์น แล้วค่อยเร่งแรงขับสูงสุด ตอนนั้นไม่จำได้ว่าใช้คำว่า “suicide burn” กันหรือไม่ อาจเป็นคำที่มาแพร่หลายในภายหลังหลัง Kerbal Space Program โด่งดังก็ได้
    ผมยังจำได้ว่าในช่วงกลางทศวรรษ 1970 ที่ Lawrence Hall of Science ใน Berkeley ก็มีเกมลงจอดบนดวงจันทร์นี้รันอยู่บนเทอร์มินัลไม่กี่เครื่องด้วย แต่ไม่รู้ว่ารันอยู่บนคอมพิวเตอร์อะไร
    ผมไม่เคยเห็นซอร์สโค้ดของโปรแกรมนี้มาก่อนเลย และก็ไม่เคยรู้ด้วยว่าคณิตศาสตร์ของมันละเอียดขนาดนี้ ตอนนั้นผมยังเด็กเกินกว่าจะเข้าใจ และพูดตรง ๆ ตอนนี้ก็ไม่แน่ใจเหมือนกันว่าจะเข้าใจได้หรือเปล่า
    • ผมจำได้ว่าช่วงต้นปี 1973 ที่ Lawrence น่าจะเล่น Lunar Lander ได้ผ่าน ADM-3 terminal และมักจะมีเด็กผู้ชายวัยรุ่นมามุงกัน
      “ฟีเจอร์” อย่างหนึ่งของโหมดคีออสก์สำหรับเกมคือ ถ้าจับจังหวะ Ctrl-C ได้พอดี ก็สามารถออกจากโหมดคีออสก์ไปเล่นเกมอื่นได้
      นี่เป็นเรื่องบังเอิญ หรือเป็นเหมือนเหยื่อล่อที่โยนไว้ให้แฮ็กเกอร์ยุคแรก ๆ กันแน่นะ?