conways game of life

มาสร้าง Simulation ชื่อว่า Conway’s Game of Life ใน Excel กัน

พอผมไปศึกษาเรื่อง Iterative Calculation ใน Excel ก็ได้ไปพบเรื่องเกี่ยวกับ Conway’s Game of Life ซึ่งเป็น Simulation ที่อยู่บนตาราง ที่ให้เราตั้งค่าจุดเริ่มต้นของเกมว่าเริ่มต้นจะให้ช่องไหนมีชีวิตบ้าง (เรียกว่า seed) จากนั้นเกมจะพัฒนาแต่ละ Stage ไปตาม set ของกติกาที่ชัดเจนด้วยตัวมันเอง (คล้ายๆ มันมีชีวิตของมันเอง) ดังนี้

กติกาการมีชีวิต/ตาย

การตัดสินว่า Stage ถัดไป ช่องนั้นจะเกิดอะไรขึ้น จะดูจากช่องรอบตัวมันเอง ทั้ง 8 ช่อง (ทิศเฉียงด้วย) ดังนี้

  1. Cell ที่มีชีวิต ถ้ามีเพื่อนรอบด้านที่มีชีวิตเหลือน้อยกว่า 2 ช่อง จะตาย (คนน้อยเกิน)
  2. Cell ที่มีชีวิต ถ้ามีเพื่อนรอบด้านที่มีชีวิตเหลือ 2-3 ช่อง จะมีชีวิตต่อไป (คนกำลังดี)
  3. Cell ที่มีชีวิต ถ้ามีเพื่อนรอบด้านที่มีชีวิตเหลือมากกว่า 3 ช่อง จะตาย (คนมากเกิน)
  4. Cell ที่ตายอยู่ ถ้ารอบด้านมีเพื่อนที่มีชีวิต 3 ช่องพอดี Cell ที่ตายจะกลับมามีชีวิต (ออกลูกใหม่)

ซึ่งถ้าอ่าน Logic จริงๆ มันก็เหลือแค่นี้แหละ

  1. Cell ที่มีชีวิต ถ้ามีเพื่อนรอบด้านที่มีชีวิตเหลือ 2-3 ช่อง จะมีชีวิตต่อไป (คนกำลังดี)
  2. Cell ที่ตายอยู่ ถ้ารอบด้านมีเพื่อนที่มีชีวิต 3 ช่องพอดี Cell ที่ตายจะกลับมามีชีวิต (ออกลูกใหม่)
  3. นอกนั้น Cell จะตาย

เตรียมพื้นที่ใน Excel

ก่อนอื่น ให้สร้าง Excel ไฟล์เปล่า ขึ้นมา 2 sheet คือ output (แสดงผลลัพธ์) กับ seed (เราตั้งค่าจุดเริ่มต้นที่นี่) แล้วเปลี่ยนความกว้างคอลัมน์ให้พอๆ กับ row (เช่น 28px) (เราทำทั้ง 2 ชีทพร้อมกันได้ ด้วยการเลือกทั้ง 2 sheet ไว้ก่อน)

จากนั้นสร้างขอบเลขของพื้นที่ ว่าจะให้ Simulation กินพื้นที่ใหญ่ได้แค่ไหน ของผมเอาซัก 40×40 ละกัน ดังนั้นให้ตีกรอบนอกเอาไว้ โดยให้พื้นที่ข้างในเป็น 40×40 ช่องซะ (ทำทั้ง 2 ชีทนะ)

กำหนด seed เริ่มต้น

จากนั้นไปกำหนด seed เริ่มต้น ว่าจะให้ช่องไหนมีชีวิตบ้าง ซึ่งตรงนี้เราต้องคิดสัญลักษณ์ก่อนว่า อะไรแปลว่ามีชีวิต อะไรแปลว่าตาย ซึ่งผมจะให้สัญลักษณ์เป็น 1=มีชีวิต กับ blank=ไม่มีชีวิต แล้วกัน

ทีนี้ก็ใส่เลข 1 มั่วๆ ไปตามต้องการได้เลย เช่น ผมใส่แบบนี้น้อยๆ ก่อน เพื่อทำความเข้าใจสูตร

ทำความเข้าใจกติกาก่อน

สร้างชีทใหม่อีกอัน เพื่อทำความเข้าใจกติกาก่อน หากพิจารณาทีละช่องวา่าควรมีชีวิต หรือตาย มันจะได้ตามนี้

ตั้งค่า Option Excel

ตั้งค่า Option Excel เป็น Iterative Calculation เพื่อให้รองรับการคำนวณแบบงูกินหางได้ และตั้งค่า Iterate ทีละ 1 step จะได้เห็นผลลัพธ์ทีละขั้นได้ง่ายๆ

เขียนสูตรที่ sheet Output

จากนั้นเรากลับไปที่ Output แล้วจะมาเขียน Condition กัน

(หลักการผมศึกษามาจากเว็บ http://dailydoseofexcel.com/archives/2011/04/06/conways-game-of-life-simulation-in-excel/
แต่ผมแก้สุตรให้ง่ายขึ้นมาก)

Logic เบื้องต้นคือ เราจะเขียนสวิตที่เอาไว้ reset เกมขึ้นมาซักช่องนึงใน Output เช่น D1 (ตั้งชื่อ defined name ว่า reset ก็ได้) ถ้าค่า reset เป็น Y ก็ให้เอาค่าเริ่มต้นจาก seed มาได้ทันทีโดยไม่ต้องใช้กติกาเกม แต่ถ้า reset ไม่ใช่ Y ก็ให้ดำเนินการตามกติกาของเกมต่อไปได้เลย

ดังนั้นผมจะเขียนสูตรที่มุมซ้ายของกระดาน 40×40 ของเราแบบนี้

=IF(reset="Y",IF(seed!C3="","",seed!C3),rules)

ทีนี้เราก็ต้องมากำหนดกติกาการมีชีวิต ว่าจะให้คำนวณยังไง ซึ่ง logic เป็นดังนี้

  1. หาก Cell นี้ที่มีชีวิต ถ้ามีเพื่อนรอบด้านที่มีชีวิตเหลือ 2-3 ช่อง จะมีชีวิตต่อไป (คนกำลังดี)
  2. หาก Cell นี้ตายอยู่ ถ้ารอบด้านมีเพื่อนที่มีชีวิต 3 ช่องพอดี Cell ที่ตายจะกลับมามีชีวิต (ออกลูกใหม่)
  3. นอกนั้น Cell จะตาย

ซึ่งหากพิจารณาใน C3 แต่ละข้อจะเขียนสูตรได้ดังนี้

=IF(C3=1,IF(OR(SUM(B2:D4)-1=2,SUM(B2:D4)-1=3),1,""),กรณี2)

ตรง SUM(B2:D4)-1 ผม -1 เพื่อให้ไม่นับตัวมันเองนะครับ เพราะมั่นใจได้ว่าตัวมันเองเป็น 1 เลย -1 ได้เลย

=IF(C3<>1,IF(SUM(B2:D4)=3,1,""),กรณี3)
=""

พอรวมกันก็จะเป็น rules แบบนี้

=IF(C3=1,IF(OR(SUM(B2:D4)-1=2,SUM(B2:D4)-1=3),1,""),
 IF(C3<>1,IF(SUM(B2:D4)=3,1,""),""))

พอรวมกับการ reset ด้วยจะเป็นแบบนี้

=IF(reset="Y",IF(seed!C3="","",seed!C3),
 IF(C3=1,IF(OR(SUM(B2:D4)-1=2,SUM(B2:D4)-1=3),1,""),
 IF(C3<>1,IF(SUM(B2:D4)=3,1,""),"")))

จากนั้น Copy สูตรไปให้ครอบคลุมทั้งตาราง

ทดสอบสูตร

ตอนนี้ กด F9 ไปก็จะยังไม่มีอะไรเปลี่ยนแปลง เพราะ Reset ยังเป็น Y อยู่

ลองเปลี่ยน Reset ไม่ใช่ Y เช่น ให้เป็น N แทน ค่าที่ได้จะเปลี่ยนไป แต่มันไม่ออกมาเป็นอย่างที่คิด!!

ผลลัพธ์ที่ถูกต้อง ควรจะมีเลข 1 ออกมาในกรอบสีแดงที่ผมตีไว้เท่านั้น ช่องอื่นจะต้องหายไปทั้งหมด (เหมือนที่เราทำความเข้าใจ)

แต่ทำไมผลลัพธ์ถึงไม่ใช่ตามที่เราคิด????

สาเหตุเป็นเพราะ Excel ทำการคำนวณทีละช่องว่าควรมีค่าเท่าไหร่ โดยที่มันไม่ได้จำภาพ Stage เดิมเอาไว้ แต่มันเอาสถานะที่เปลี่ยนไปแล้ว มาเป็นจุดตั้งต้นสำหรับ cell อื่น คำตอบมันก็เลยเพี้ยนไป…

แล้วจะแก้ไขปัญหายังไง?

คำตอบก็คือ เราต้องสร้าง Board ของหน้า Output ขึ้นมาเป็น 3 บอร์ด เพื่อให้มันจำภาพ Stage ที่แล้วเอาไว้ให้ได้ก่อน แล้วค่อยคำนวณต่อ

แก้ปัญหามันไม่จำ Stage ก่อนหน้า

ให้สร้างบอร์ดใน sheet output ทั้งหมด 3 บอร์ด ดังนี้

หลักการคือ

  • Board ทด 1 ถ้า reset= Y จะอ่านค่าจาก Seed ถ้า Reset ไม่ใช่ Y จะอ่านค่าจาก Board ทด 2 แล้วทำตามกติกา
  • Board ทด 1 ถ้า reset=Y จะใส่ค่า Blank ไป ถ้าไม่ใช่ Y จะอ่านค่าจาก Board ทด 1 แล้วทำตามกติกา

โดยผมจะสร้าง cell ที่ชื่อ stage ขึ้นมาก่อน เพื่อบอกว่ามันคือการคำนวณครั้งที่เท่าไหร่ สูตรคือ

=IF(reset="Y",0,stage+1)

และผมจะต้องมีการทดก่อนว่า การทำงานครั้งนั้นๆ เป็นการคำนวณบอร์ดไหน โดยผมจะสร้าง cell ที่ชื่อว่า board ขึ้นมาโดยใส่สูตรดังนี้

=MOD(stage,2)+1

เพื่อให้พอ reset แล้ว จะใช้ Board1 ก่อน พอกด F9 ปุ๊ปก็จะสลับเป็น board2 และ board1 สลับไปมาเรื่อยๆ

ทีนี้พอเราสร้าง cell ที่คิดเรื่อง board ที่จะใช้เสร็จแล้ว ก็จะไปเขียนสูตรที่แต่ละ Board อีกที

ดังนั้นสูตรที่มุมซ้ายบนของ Board ทด 1 จะเปลี่ยนจากการอ้างอิงตัวเอง ไปอ้างอิงบอร์ดทด 2 แทน ดังนี้ แต่ต้องเขียน Condition ด้วยว่าถ้า cell board เป็น 2 (กำลังคำนวณ Board 2 อยู่) ให้คงค่าตัวเองเอาไว้ก่อน

=IF(reset="Y",IF(seed!C3="","",seed!C3),
   IF(board=2,C3,
IF(C46=1,IF(OR(SUM(B45:D47)-1=2,SUM(B45:D47)-1=3),1,""),
   IF(C46<>1,IF(SUM(B45:D47)=3,1,""),""))))

จากนั้น Copy สูตรให้ทั่ว Board ทด 1

แล้วช่องซ้ายบนของ Board 2 ก็แก้ เป็นดังนี้

=IF(reset="Y","",
 IF(board=1,C46,
  IF(C3=1,IF(OR(SUM(B2:D4)-1=2,SUM(B2:D4)-1=3),1,""),
  IF(C3<>1,IF(SUM(B2:D4)=3,1,""),""))))

จากนั้น Copy สูตรให้ทั่ว Board ทด 2

จากนั้นพอเปลี่ยนย Reset เป็น N มันก็จะทำตามกติกา จะเห็นว่า Board 2 แสดงค่าได้ถูกต้องแล้ว

กำหนดการแสดงผลใน Output สุดท้าย

จากนั้นเราก็ไปที่ Board Output สุดท้าย เพื่อเขียนเงื่อนไขว่า ถ้า board=1 ให้เอากระดานบน นอกนั้นเอากระดานล่าง ที่ช่องซ้ายบนสุดจะได้สูตรแบบนี้ แล้วก็ Copy ให้ทั่ว Board

=IF(board=1,C3,C46)

จากนั้นเพื่อความสวยงาม เราจะกำหนด Conditional Format ใน Board Output จริงๆ ว่า ถ้าค่าใน Cell เป็น 1 ให้ถมสี

คราวนี้พอกด F9 มันก็จะทำการคำนวณ และสลับ Board ไปมา แต่ปรากฎว่า ตอนที่ผมเปลี่ยน Reset จาก Y เป็น N ค่าใน Board Final มันหายไป!!

สาเหตุเพราะว่ามันดันไปอ้างอิงบอร์ดที่ยังไม่ได้ทันคำนวณค่า (เราต้องให้มันคำนวณค่าบอร์ดทดทั้ง 1 กับ 2 ให้เสร็จก่อน)

ดังนั้นผมจะต้องย้าย Board Output ไปอยู่ข้างล่างของ Board ทด 2 แทน เพื่อให้มั่นใจว่ามันคำนวณหลังสุดแน่ๆ (อยู่ล่างหรืออยู่ขวาก็ได้)

คราวนี้กด F9 ไปเรื่อยๆ ก็จะได้เกมที่ Logic เสร็จสมบูรณ์แล้วล่ะ ทีนี้ก็ถึงเวลาแก้ seed แล้ว

แก้ Seed ให้จุดเริ่มต้นเปลี่ยนไป

ผมลองทำการแก้ Seed เป็นดังนี้

จากนั้นกลับมาที่ Output แลว้ซ่อน Row ของ board ทดทั้ง 1 และ 2 ไปซะ

สภาพตั้งต้นจะเป็นดังนี้

พอเปลี่ยน Reset เป็น N จะเข้าสู่ Stage 1 และจะได้ผลดังนี้ (ค่าไม่หายแล้ว)

พแกด F9 อีกทีจะได้ดังนี้

ถ้าลองทำเป็นภาพเคลื่อนไหวเลยจะได้ดังนี้

จะเห็นว่าบางรูปแบบมันจะคงที่ไม่เปลี่ยน (ถ้าไม่มีตัวอื่นวิ่งมาชนมันนะ) บางอันก็วน Loop บางรูปแบบมันวิ่งไปได้เรื่อยๆ ได้ ถ้าสนใจลองดูรูปแบบต่างๆใน Wiki ได้เลย

ขอให้สนุกกับการทำ Simulation นะครับ!