[Learning Ruby 3] unfairRandom

*หมายเหตุ: โพสต์นี้เขียนวันที่ 5 มกราคม 2556 แต่ delay การ publish ไว้*

@winwanwon [โยนคำถาม](http://twitter.yfrog.com/z/obem2rdp)มาครับ เป็นคำถามมาจากค่าย [IT CAMP 9](http://itcamp.in.th/camp9/) ค่ายย่อย Modern Developer ถามว่า

>มีฟังก์ชัน `unfairRandom()` มาให้ ซึ่งมีโอกาส 60% ที่จะให้ผลลัพธ์เป็นตัวเลข 0 และ 40% ให้ผลลัพธ์เป็นตัวเลข 1 จงหาวิธีสร้างฟังก์ชัน `fairRandom()` ซึ่งจะต้องสุ่มเลข 0 และ 1 อย่างยุติธรรมที่สุด ( โอกาส 50-50 ) โดยห้ามใช้ฟังก์ชันสุ่มอื่นๆ ที่นอกเหนือจาก `unfairRandom()`?

ตอนแรกก็จะใช้ Python ล่ะครับ แต่เรียนรูบี้อยู่ ลองดูสักตั้ง

~~~~~~
def unfair_rand
rand < 0.6 ? 0 : 1 end ~~~~~~ ฟังก์ชั่นนี้ก็ง่ายๆ ครับ คือ `rand` จะคืนค่าทศนิยมในช่วง [0-1) ออกมา สมมุติว่าฟังก์ชั่นนี้เป็นฟังก์ชั่นสุ่มที่มีความยุติธรรมแล้วกันนะครับ ก็ถ้ามันสุ่มมาได้น้อยกว่า 0.6 ก็ตอบ 0 ถ้ามากกว่าก็ตอบ 1 เสร็จแล้วก็ต้องมาตรวจคำตอบครับ ~~~~~~~ def random_check(x,times=1000.0) arr=[] times.to_i.times do arr << x.call; end (arr.count 0)/times end ~~~~~~~ ฟังก์ชั่น `random_check` จะตรวจสอบความยุติธรรมของฟังก์ชั่นที่มีคำตอบเป็น 0 และค่าอื่นอีก 1 ค่า (ในที่นี้คือ 1) เท่านั้นนะครับ โดยใช้วิธีทำการเรียกฟังก์ชั่นสุ่มตามจำนวนครั้งที่กำหนดไว้คือ 1,000 ครั้ง แล้วหาจำนวนเหตุการณ์ที่ออก 0 ทีนี้มันมีปัญหาละครับ ใน Ruby เนี่ย การเรียก function เหมือนตัวแปร มันไม่ได้เป็นการส่งตัวฟังก์ชั่นเข้าไปเป็น argument แต่มันเป็นการส่งผลของฟังก์ชั่นนั้นเข้าไป แล้วเราจะส่ง `unfair_rand` เข้าไปยังไงดี? ผมไป Google หาคำตอบมาครับ ก็เจอกับ[คำตอบ](http://alan.dipert.org/post/339368222/passing-methods-like-blocks-in-ruby) ~~~~~~ puts random_check(method(:unfair_rand)) ~~~~~~ ทีนี้ `random_check` ก็จะได้คลาส `Method` เข้าไปครับ เพียงแค่ใช้คำสั่ง `call` เข้าไปก็สามารถเรียกใช้ `Method` นั้นๆ ได้แล้ว สำหรับผลก็เป็นไปตามคาดครับ รันปุ๊บ คำตอบออกมาทันทีว่า 0.605 ค่อนข้างใกล้เคียงกับผลที่คาดไว้คือ 0.6 ทีนี้จะแก้ความแฟร์ยังไงดี ผมก็นั่งนึกอยู่หลายวิธีครับ เช่นว่าให้สุ่มหลายๆ ครั้งแล้วนับจำนวนครั้งที่ได้ 0 หรือ 1 ถ้าน้อยกว่าค่าหนึ่งก็ให้ตอบ 0 หรือตอบ 1 แต่มันก็ยังไม่ถูกเท่าไร จนกระทั่งวิธีนึงที่อยู่ดีๆ ปิ๊งออกมา ~~~~~ def fair_rand unfair_rand == unfair_rand ? 0 : 1 end ~~~~~ ลองเช็คดูด้วย `random_check` ผลออกมาได้ 0.52096 ใกล้เคียงกับคำตอบที่ต้องการคือ 0.5 อีกแล้ว ทีนี้มานั่งนึกๆ ดูครับว่าทำไมคำตอบถึงเป็นแบบนี้... เวลาสั่ง `unfair_rand` คำตอบที่ได้คือ 0 และ 1 ใช่ไหมล่ะครับ โดยโอกาสออก 0 มี 0.6 โอกาสออก 1 มี 0.4 ทีนี้ถ้าเราสุ่มสองครั้ง เหตุการณ์ที่เลขสองตัวออกเหมือนกันจะมีสองแบบคือ ออก 0 ทั้งคู่ และออก 1 ทั้งคู่ โดยโอกาสออก 0 ทั้งคู่ก็คือ `0.6 * 0.6 = 0.36` และโอกาสที่ออก 1 ทั้งคู่คือ `0.4 * 0.4 = 0.16` โอกาสที่เลขทั้งสองตัวออกมาเหมือนกัน อาจเป็นได้ทั้ง 0 และ 1 เหมือนกัน ก็จะมีค่าเท่ากับ `0.16 + 0.36 = 0.52` นั่นเอง ตรงกับคำตอบของโปรแกรมเลย *(อันที่จริงคำตอบของโปรแกรมเมื่อสักครู่นี้ผมปรับจำนวนรอบของ `random_check` เพิ่มขึ้นครับ ถ้ารอบน้อยๆ คำตอบออกมา 0.499 ยังมีเลย)* ผมไม่ค่อยชอบปัญหาพวกนี้นะ มันเหมือนปัญหาโปรแกรม แต่มันคือปัญหาเลขที่ใช้โปรแกรมแก้ ผมไม่ใช่นักคณิตศาสตร์ แต่บางทีเจอแล้วมันก็ติดกับนั่งทำอยู่เหมือนกัน เขียนพวกแสดง text เป็นกังหัน เป็นต้นไม้ เป็นดาว อะไรพวกนี้สนุกกว่า **สิ่งที่ได้จากโปรแกรมนี้:** - การส่งฟังก์ชั่นเข้าไปในฟังก์ชั่นด้วย `method`

[FCC 11] Puzzle Agent 2

ผมเป็นแฟน TTG มาตั้งแต่ Sam & Max แล้วครับ แต่ว่าเพิ่งจะมีของแท้ก็เกมนี้แหละ ผมได้มาจาก Indie Royale ครับ ส่วนภาคแรกมาจาก MacHeist (เป็นแอพพัลเซิลฟรีในไอโฟน เล่นผ่านแล้วจะได้ Steam Key ของ Puzzle Agent 1 ครับ)

ที่เล่นภาคสองก่อน เพราะว่าภาคหนึ่งเล่นจบไปแล้วในไอแพดครับ แต่ตามกฎ Challenge ต้องมาเล่นอีกครั้งหนึ่งบนคอม

เนื้อเรื่องคร่าวๆ คือมีโรงงานยางลบถูกปิดเพราะอุบัติเหตุ แต่ยางลบจากโรงงานนี้นั้นถูกใช้ในทำเนียบขาว ทาง FBI จึงส่ง Nelson Tethers เจ้าหน้าที่ฝ่ายแก้พัลเซิล (เอ่อ..) ไปตรวจสอบ

เกมนี้บรรยากาศค่อนข้างตึงเครียดและน่ากลัวครับ ผมยังสงสัยอยู่เลยว่าเล่นเกมนี้แล้วกลัวนี่ Amnesia ผมจะเป็นยังไง คือมันไม่มีตัวอะไรที่มองแล้วน่ากลัวนะครับ แต่เพลงกับการตัดภาพมันเหมือนหนังผีอะไรแบบนั้น

ตัวพัลเซิลของภาคนี้ก็มีพัลเซิลง่ายยากคละๆ กันไปครับ ตั้งแต่ปัญหาเลื่อนช่อง (คล้ายๆ เกมรถติด) ต่อเขาวงกต วางกระจกสะท้อน ไปจนถึงอนุกรมเลขคณิต

ตัวอย่างเช่นในภาพข้างบนนี้ครับ ปริศนามีอยู่ว่าให้จัดที่นอนให้คนทั้ง 6 คน โดยมีเงื่อนไขต่างๆ ดังนี้

1. Larue จะอยู่ชั้นก่อนคุณ Maxwell
2. Blesson กับ Carlman อยู่ชั้นเดียวกัน
3. Dimpleton ไม่อยู่ในชั้นที่มีผู้ชาย มากกว่าผู้หญิง

ถ้าติดในพัลเซิลใดๆ ตัวเกมจะมี Hint ให้พัลเซิลละ 3 อันครับ โดยต้องใช้ไอเทมปลดล็อค (ซึ่งก็มีทั่วไปในฉาก ฉากไหนเก็บแล้วเข้าไปในตึกหรือเปลี่ยนไปฉากอื่นแล้วกลับออกมาก็มาเพิ่ม)

นอกจากนี้ถ้าเล่นผ่านแต่ยังไม่แน่ใจว่าทำอะไรไปถึงผ่าน ตัวเกมก็จะมีวิธีคิดให้ด้วยครับ

อีกสักพัซเซิลในเกมให้ไปคิดดูครับ เป็นปัญหาโบนัส (ไม่ต้องเล่นก็ผ่านเกมได้) ให้หาลำดับถัดไปในอนุกรมนี้ครับ

>31 41 59 26

Storyline ภาคนี้ลึกลับซับซ้อนซ่อนเงื่อนและหักมุมไปมากยิ่งกว่าภาคหนึ่งครับ แต่เล่นจบแล้วก็ยังอารมณ์แบบว่าไม่เก็ต 100% เหมือนดู 5 Centimeters per Second อะไรแบบนั้น

**คะแนน:** 9/10

หักเพราะกราฟฟิคมันแตกเท่านั้นแหละครับ เข้าใจว่าเค้าจะล้อหนังสือการ์ตูนภาพก็เลยจงใจทำแบบนี้ แต่ผมเล่นแล้วรู้สึกมัน unpolished นะ ถ้าซูมเข้าหน้าตัวละครก็น่าจะเอา model ละเอียดมาสิ

(ผมเข้าใจว่าเค้าใช้ Telltale Tool ตัวเดียวกับเกม Sam & Max ทำแล้วมันเลยทำให้ตัวเกมต้องเป็น 3D ทั้งเกม ถึงจะจงใจทำเกมแบนเป็นหนังสือการ์ตูนก็เถอะ แล้วการสลับ model แบบนี้ก็เลยทำไม่ได้ด้วยข้อจำกัดของเอนจิ้น)

**คำแนะนำ:** เกมแนวนี้เขียนแนะนำยากครับ ถ้าชอบพัซเซิลลับสมอง (ไม่ใช่พัซเซิลแบบ Portal 2 อะไรแบบนั้นนะ) และ Storyline น่าสนใจ ผมว่าเกมที่มีสองอย่างนี้นี่หายากมากครับ ฉะนั้นไม่ควรพลาด