พอผมไปศึกษาเรื่อง Iterative Calculation ใน Excel ก็ได้ไปพบเรื่องเกี่ยวกับ Conway’s Game of Life ซึ่งเป็น Simulation ที่อยู่บนตาราง ที่ให้เราตั้งค่าจุดเริ่มต้นของเกมว่าเริ่มต้นจะให้ช่องไหนมีชีวิตบ้าง (เรียกว่า seed) จากนั้นเกมจะพัฒนาแต่ละ Stage ไปตาม set ของกติกาที่ชัดเจนด้วยตัวมันเอง (คล้ายๆ มันมีชีวิตของมันเอง) ดังนี้
สารบัญ
กติกาการมีชีวิต/ตาย
การตัดสินว่า Stage ถัดไป ช่องนั้นจะเกิดอะไรขึ้น จะดูจากช่องรอบตัวมันเอง ทั้ง 8 ช่อง (ทิศเฉียงด้วย) ดังนี้
- Cell ที่มีชีวิต ถ้ามีเพื่อนรอบด้านที่มีชีวิตเหลือน้อยกว่า 2 ช่อง จะตาย (คนน้อยเกิน)
- Cell ที่มีชีวิต ถ้ามีเพื่อนรอบด้านที่มีชีวิตเหลือ 2-3 ช่อง จะมีชีวิตต่อไป (คนกำลังดี)
- Cell ที่มีชีวิต ถ้ามีเพื่อนรอบด้านที่มีชีวิตเหลือมากกว่า 3 ช่อง จะตาย (คนมากเกิน)
- Cell ที่ตายอยู่ ถ้ารอบด้านมีเพื่อนที่มีชีวิต 3 ช่องพอดี Cell ที่ตายจะกลับมามีชีวิต (ออกลูกใหม่)
ซึ่งถ้าอ่าน Logic จริงๆ มันก็เหลือแค่นี้แหละ
- Cell ที่มีชีวิต ถ้ามีเพื่อนรอบด้านที่มีชีวิตเหลือ 2-3 ช่อง จะมีชีวิตต่อไป (คนกำลังดี)
- Cell ที่ตายอยู่ ถ้ารอบด้านมีเพื่อนที่มีชีวิต 3 ช่องพอดี Cell ที่ตายจะกลับมามีชีวิต (ออกลูกใหม่)
- นอกนั้น 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 เป็นดังนี้
- หาก Cell นี้ที่มีชีวิต ถ้ามีเพื่อนรอบด้านที่มีชีวิตเหลือ 2-3 ช่อง จะมีชีวิตต่อไป (คนกำลังดี)
- หาก Cell นี้ตายอยู่ ถ้ารอบด้านมีเพื่อนที่มีชีวิต 3 ช่องพอดี Cell ที่ตายจะกลับมามีชีวิต (ออกลูกใหม่)
- นอกนั้น 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 นะครับ!