วันเสาร์ปลายเดือนที่แล้วไปงาน BarCamp เชียงใหม่มา ตามธรรมเนียมที่ดีก็ควร blog เก็บไว้หน่อย (หลังจากอู้มา 2 ปีเต็ม)
งานครั้งนี้จัดที่วิศวะ มช. โดยได้โต้โผใหญ่อย่างอาจารย์ @pruet คอยจัดแจงทุกอย่างให้ ก็ขอขอบคุณอีกครั้ง ณ ที่นี้ด้วยครับ -/\-
อันนี้ session ส่วนตัวกับ @kengggg ว่าด้วย FireFox OS ซึ่งนับว่าเป็น session เช้าเพียง session เดียวที่ผมเข้าฟัง เนื่องจากความล้าจากการเดินทางข้ามคืน + ปั่นสไลด์ไม่เสร็จดี ก็ต้องกราบขอโทษทีม @thainetizen ที่ไม่ได้เข้าฟังด้วย
หลังจากหายเหนื่อยก็เดินสำรวจโน่นนี่นั่น และพบว่าตั้งชื่อห้องได้ geek มากๆ
คู่หูดูโอ้ @shr กับ @ckzon มาพูดว่าทำไมถึงไม่ควร aim ว่าจะทำงานเป็น tester ถ้าไม่อยากเขียน code แต่แรก
จบด้วยอาจารย์ @pruet สุดหล่อ ที่จะพาคุณออกเดินทางผ่านปราการด่านสุดท้ายด้วยความเร็วมากกว่าแสง
สำหรับผมเองพูดเรื่อง Tetris ก็แปลกใจอยู่ที่ได้รับความนิยมอย่างล้นหลามจาก geek ฝรั่ง ไม่แน่ใจว่าเป็นเพราะ session ของผมบรรยายเป็นภาษาอังกฤษ (จริงๆ บอกว่าเป็น 2 ภาษาแต่ไม่มีคนไทยมาฟัง) เพียง session เดียวตอนนั้นหรือเปล่า :P
งานนี้สนุกมากครับ เสียดายว่าผมเองไม่ได้ไป after party ต่อเพราะเวลาอยู่เชียงใหม่มีจำกัด อย่างไรก็ตามผมจะพยายามกลับมาพูดที่เชียงใหม่ให้ได้ทุกปีครับ :)
Jul 22, 2013
May 18, 2013
วงที่ได้ดีจากการร้องคำเดิมซ้ำๆ
หลายเดือนก่อนเห็นทวีตนี้ผ่านตา
มานั่งนับๆ ดู เอ่อ มันก็จริงนะ 555+
จี้ จี้ จี้ จี้ เบบี เบบี เบี
โอะ โอะ โอ โอ๊ะ
รัน รั๊น รัน รั๊น รัน
แท๊กซี่ แท๊กซี่ แท๊กซี่ จุชชี่ จุชชี่ จุชชี่
ทร๊อบเบิล ทร๊อบเบิล ทร๊อบเบิล ชุชุ๊ชู ฮุฮุ๊ฮูท
เอคโค่ เอคโค่ เอคโค่
มาแระวา ~ มาแระวา ~ มาแระวา ~ มาแระวา
วั๊นทูทรี ~ วั๊นทูทรี ~ วั๊นทูทรี
บู๊ม บูม บู่ม
ดุ ดู ดุ่ ดุ ดู ดู้ว์ คิสสิงยูว์เบบี้
เกิร์ลบริงเดอะบอยส์เซาท์ เกิร์ลบริงเดอะบอยส์เซาท์ เกิร์ลบริงเดอะบอยส์เซาท์ เกิร์ลบริงเดอะบอยส์เซาท์
ไอก๊อทอะบอยโมจิน ไอก๊อทอะบอยชาคัง ไอก๊อทอะบอยแฮนซัมบอย
จริงๆ แล้วการร้องซ้ำคำ/ท่อนเดิมนี่ไม่ได้ผิดแปลกอะไรหรอก ในทฤษฎีดนตรีเราอาจเรียกว่ามันคือโมทีฟ ซึ่งเป็นส่วนที่โดดเด่นในเพลง เราจะใช้โมทีฟซ้ำๆ/ดัดแปลงมันด้วยวิธีต่างๆ เพื่อให้ส่วนนี้ติดหูคนฟัง ตัวอย่างที่ชัดเจนโน้ตง่ายๆ 4 ตัวใน Beethoven Symphony No.5 นั่นเอง
GIRLS' GENERATION = เจ้าแม่ร้องซ้ำ gee gee gee gee, run run run run run, oh oh oh oh,Taxi Taxi Taxi, Bring the boys out! Bring the boys out!
— เมนผอมได้ฉันก็ผอมได้ (@ffranceee) December 1, 2012
มานั่งนับๆ ดู เอ่อ มันก็จริงนะ 555+
จี้ จี้ จี้ จี้ เบบี เบบี เบี
โอะ โอะ โอ โอ๊ะ
รัน รั๊น รัน รั๊น รัน
แท๊กซี่ แท๊กซี่ แท๊กซี่ จุชชี่ จุชชี่ จุชชี่
ทร๊อบเบิล ทร๊อบเบิล ทร๊อบเบิล ชุชุ๊ชู ฮุฮุ๊ฮูท
เอคโค่ เอคโค่ เอคโค่
มาแระวา ~ มาแระวา ~ มาแระวา ~ มาแระวา
วั๊นทูทรี ~ วั๊นทูทรี ~ วั๊นทูทรี
บู๊ม บูม บู่ม
ดุ ดู ดุ่ ดุ ดู ดู้ว์ คิสสิงยูว์เบบี้
เกิร์ลบริงเดอะบอยส์เซาท์ เกิร์ลบริงเดอะบอยส์เซาท์ เกิร์ลบริงเดอะบอยส์เซาท์ เกิร์ลบริงเดอะบอยส์เซาท์
ไอก๊อทอะบอยโมจิน ไอก๊อทอะบอยชาคัง ไอก๊อทอะบอยแฮนซัมบอย
จริงๆ แล้วการร้องซ้ำคำ/ท่อนเดิมนี่ไม่ได้ผิดแปลกอะไรหรอก ในทฤษฎีดนตรีเราอาจเรียกว่ามันคือโมทีฟ ซึ่งเป็นส่วนที่โดดเด่นในเพลง เราจะใช้โมทีฟซ้ำๆ/ดัดแปลงมันด้วยวิธีต่างๆ เพื่อให้ส่วนนี้ติดหูคนฟัง ตัวอย่างที่ชัดเจนโน้ตง่ายๆ 4 ตัวใน Beethoven Symphony No.5 นั่นเอง
May 12, 2013
Code Jam 2013 รอบ 1B และ 1C
สั้นๆ ครับ ปีนี้ขยันน้อย สมองไม่ค่อยแล่น รอบ 1B และ 1C เลยไม่ได้ส่งซักข้อ Orz
แต่ก็ได้ไอ้นี่มาจากข้อ Pogo (ข้อ B จากรอบ 1C) แม้จะสวยดีแต่ก็ไม่ได้ช่วยตอบคำถามข้อนี้แต่อย่างใด 55+

update: ตอนแรกคิดอออกมาได้ตารางข้างบน แล้วก็เพิ่งมานึกออกว่า algo ผิดเพราะลืมไปว่าการเดินตกจุดเดิมซ้ำด้วย move ที่ไม่เท่ากันนั้นมี่ค่าต่างกันสำหรับการเดินรอบต่อไป เลยแก้ออกมาจนได้รูปด้านล่าง....... กลายเป็นว่าง่ายเลยข้อนี้ T T (เอา 38 คะแนนของตรูคืนมาาาา)

แต่ก็ได้ไอ้นี่มาจากข้อ Pogo (ข้อ B จากรอบ 1C) แม้จะสวยดีแต่ก็ไม่ได้ช่วยตอบคำถามข้อนี้แต่อย่างใด 55+

update: ตอนแรกคิดอออกมาได้ตารางข้างบน แล้วก็เพิ่งมานึกออกว่า algo ผิดเพราะลืมไปว่าการเดินตกจุดเดิมซ้ำด้วย move ที่ไม่เท่ากันนั้นมี่ค่าต่างกันสำหรับการเดินรอบต่อไป เลยแก้ออกมาจนได้รูปด้านล่าง....... กลายเป็นว่าง่ายเลยข้อนี้ T T (เอา 38 คะแนนของตรูคืนมาาาา)

May 11, 2013
เซ็นทรัลลำปาง
เมื่อวานมีโอกาสได้แวะไปลำปางแบบด่วนๆ (ไปเย็นกลับค่ำ) เลยแวะสำรวจเล็กน้อย และพบว่ามันมาทรงเดียวกับเซ็นทรัลพิษณุโลกเลย เพียงแต่สั้นกว่า (มาก)
อันที่จริงแล้วผมเชียร์ให้ลำปางเป็นจุดศูนย์กลางภาคเหนือมากกว่าเชียงใหม่นะ ว่ากันตามภูมิประเทศแล้ว ตรงนี้เป็นจุดยุทธศาสตร์สำคัญเลยเพราะไปได้ทั้งตาก เชียงใหม่ เชียงราย (ลำปางเชียงรายใช้เวลาพอๆ กับเชียงใหม่เชียงราย) แถมการเดินทางจากภาคกลางขึ้นมาจนถึงลำปาง ก็ถือว่าใช้เวลาได้เหมาะสมดี (จากลำปางไปเชียงใหม่ต้องเพิ่มอีก 1.5 ชั่วโมง)
เสียดายที่เชียงใหม่แย่งชิงคนไปได้หมด ซึ่งน่าจะเกิดขึ้นเพราะการตั้งมหาวิทยาลัยเชียงใหม่เมื่อกว่า 40 ปีก่อน ทำให้คนในวัยกำลังเริ่มทำงานเลือกที่จะตั้งหลักปักฐานใกล้กับมหาวิทยาลัยที่จบการศึกษา ด้วยเหตุผลทั้ง connection กับมหาวิทยาลัย, แรงงานจากรุ่นน้องที่ศึกษาอยู่, ความหนาแน่นของผู้คน ฯลฯ
ก็ต้องดูต่อไปว่าการมาของเซ็นทรัลลำปาง จะช่วยชุบชีวิตเมืองนี้ให้กลับมายิ่งใหญ่ได้หรือไม่ครับ
- อย่างไรก็ดี เซ็นทรัลลำปางก็มีข้อดี (?) ที่เหนือกว่าเซ็นทรัลพิษณุโลกอย่างมาก คือตำแหน่งที่ตั้งนั้นอยู่ใจกลางเมืองพอดี แถมยังติดสถานศึกษาอย่างโรงเรียนลำปางกัลยาณีและบุญวาทย์วิทยาลัยแถวๆ นั้นอีก ก็น่าจะดึงคนได้เยอะดีพอสมควร
- แต่คนกลับไม่เยอะอย่างที่คิด ขนาดเป็นวันศุกร์ตอนเย็น ที่จอดรถยังโล่งๆ คนน้อยกว่าเซ็นทรัลกาดสวนแก้วเชียงใหม่อีก (อาจเป็นเพราะสัปดาห์นี้หยุดยาว 3 วันก็ได้)
- ที่งงคือลานจอดรถด้านหลังก็ค่อนข้างใหญ่ แต่ทำไมถึงมาจอดถนนใหญ่หน้าห้างกันเยอะแยะ หรือนี่เป็นเรื่องปรกติของคนลำปางกันไปแล้ว
- ว่าด้วยเรื่องลักษณะอาคาร อย่างที่บอกไปแล้วว่ามันคือเซ็นทรัลพิษณุโลก ก็คือมีส่วนที่เป็นห้าง 3 ชั้น พร้อมชั้นที่คล้ายๆ จะเป็นชั้นใต้ดินไว้จอดรถอีก 1 ชั้น
- โรงหนังที่นี่เป็น SF แฮะ สงสัยจะได้แวะเที่ยวบ่อยๆ ซะแล้ว :P
- มี McDonald, KFC, Yamazaki, Swensens, Shabushi, Sukishi, Santafe, Jeffer แต่ไม่มี Sizzler
- Starbucks ไม่มีคนเลย
- แต่ iStudio คนแวะเข้าออกตลอด
- ของน้อยมาก หา Lego ไม่ค่อยได้เลย เพลงคลาสสิกใน B2S ยิ่งไม่ต้องพูดถึง
อันที่จริงแล้วผมเชียร์ให้ลำปางเป็นจุดศูนย์กลางภาคเหนือมากกว่าเชียงใหม่นะ ว่ากันตามภูมิประเทศแล้ว ตรงนี้เป็นจุดยุทธศาสตร์สำคัญเลยเพราะไปได้ทั้งตาก เชียงใหม่ เชียงราย (ลำปางเชียงรายใช้เวลาพอๆ กับเชียงใหม่เชียงราย) แถมการเดินทางจากภาคกลางขึ้นมาจนถึงลำปาง ก็ถือว่าใช้เวลาได้เหมาะสมดี (จากลำปางไปเชียงใหม่ต้องเพิ่มอีก 1.5 ชั่วโมง)
เสียดายที่เชียงใหม่แย่งชิงคนไปได้หมด ซึ่งน่าจะเกิดขึ้นเพราะการตั้งมหาวิทยาลัยเชียงใหม่เมื่อกว่า 40 ปีก่อน ทำให้คนในวัยกำลังเริ่มทำงานเลือกที่จะตั้งหลักปักฐานใกล้กับมหาวิทยาลัยที่จบการศึกษา ด้วยเหตุผลทั้ง connection กับมหาวิทยาลัย, แรงงานจากรุ่นน้องที่ศึกษาอยู่, ความหนาแน่นของผู้คน ฯลฯ
ก็ต้องดูต่อไปว่าการมาของเซ็นทรัลลำปาง จะช่วยชุบชีวิตเมืองนี้ให้กลับมายิ่งใหญ่ได้หรือไม่ครับ
Apr 27, 2013
Code Jam 2013 รอบ 1A
รอบนี้ตอนแรกว่าจะปล่อยผ่านเพราะอุตสาห์มากทม.ทั้งที อยากไปร่วมฟาร์มเสา 8 กับเหล่า agent ทั้งหลายด้วย
แต่คิดไปคิดมา คราวก่อนก็วืดเพราะมีแต่ไปคาราโอเกะ เลยคิดว่าควรให้ importance และ energy กับการแข่งให้มากที่สุดจะดีกว่า
รอบนี้เหมือนจะเป็น math จ๋าเลย แค่ข้อแรกที่ถามว่าจะระบายธนูได้กี่วง ก็ต้องใช้ความรู้เรื่องพื้นที่วงกลม + สมการกำลังสอง + อนุกรมเข้ามาช่วย
เราเริ่มจากสังเกตว่าวงกลมแรกจะใช้สีระบายไป
แต่เนื่องจากสิ่งที่เรารู้คือ
ก็จะได้ว่า
ถึงตอนนี้ก็แค่แก้สมการข้างบน ได้คำตอบมา 2 อันก็เลือกเอาคำตอบที่มากกว่า 0 แล้วปัดเศษทิ้งครับ
ข้อสองคิดวิธี optimize ไม่ออก เลยเขียน recursive ไป (loop ใหญ่สุดของแบบเล็กคือ 60 ล้าน ก็ยัง brute-force ออกในเวลาที่รับได้) แต่เสียดายที่คิดผิด debug ไม่ทัน
ส่วนข้อสามแนวคิดคือหาตัวคูณร่วมน้อยของเลขทั้ง set ที่เค้าให้ แล้วก็แยกตัวประกอบมันออกมาเป็น list นึง ทีนี้ถ้า list มันใหญ่กว่าขนาดของการ์ดทั้งหมดก็ merge ตัวเลขใน list นี้ด้วยการคูณจนกว่ามันจะมีขนาดเท่ากับการ์ด เท่านี้เอง (อันนี้ออกแค่ข้อเล็ก)
อันดับระหว่างแข่งคือ 18xx พอจบรอบตรวจคะแนนจริงก็เด้งกลับมาที่ 1377 เพราะข้อที่ส่งไปถูกหมด (แต่ก็ยังไม่เพียงพอสำหรับผ่านเข้ารอบต่อไปอยู่ดี) ... ไม่เป็นไรรอบหน้าเอาใหม่ เนอะ ^^)v
แต่คิดไปคิดมา คราวก่อนก็วืดเพราะมีแต่ไปคาราโอเกะ เลยคิดว่าควรให้ importance และ energy กับการแข่งให้มากที่สุดจะดีกว่า
รอบนี้เหมือนจะเป็น math จ๋าเลย แค่ข้อแรกที่ถามว่าจะระบายธนูได้กี่วง ก็ต้องใช้ความรู้เรื่องพื้นที่วงกลม + สมการกำลังสอง + อนุกรมเข้ามาช่วย
เราเริ่มจากสังเกตว่าวงกลมแรกจะใช้สีระบายไป
2r + 1 วงกลมถัดๆ มาใช้ 2r + 1 + 4 และ 2r + 1 + 8 ดังนั้นจะตั้งเป็นสมการได้ว่าused_color(n) = (2r+1) + (2r+1 + 4) + (2r+1 + 8) + ... + (2r+1 + 4(n-1))
= summation (2r+1 + 4k) for k in [0 .. n-1]
= n(2r+1) + 4 * summation k for k in [0 .. n-1]
= n(2r+1) + 4n(n-1)/2
= n(2r+1) + 2n(n-1)
แต่เนื่องจากสิ่งที่เรารู้คือ
t = used_color(n) และต้องการคำนวณกลับเพื่อหา n ดังนั้น0 = n(2r+1) + 2n(n-1) - t = 2n^2 - (2r-1)n - t
ก็จะได้ว่า
a = 2 b = 2r - 1 c = -t n = (-b ± sqrt(b^2 - 4ac)) / 2a
ถึงตอนนี้ก็แค่แก้สมการข้างบน ได้คำตอบมา 2 อันก็เลือกเอาคำตอบที่มากกว่า 0 แล้วปัดเศษทิ้งครับ
ข้อสองคิดวิธี optimize ไม่ออก เลยเขียน recursive ไป (loop ใหญ่สุดของแบบเล็กคือ 60 ล้าน ก็ยัง brute-force ออกในเวลาที่รับได้) แต่เสียดายที่คิดผิด debug ไม่ทัน
ส่วนข้อสามแนวคิดคือหาตัวคูณร่วมน้อยของเลขทั้ง set ที่เค้าให้ แล้วก็แยกตัวประกอบมันออกมาเป็น list นึง ทีนี้ถ้า list มันใหญ่กว่าขนาดของการ์ดทั้งหมดก็ merge ตัวเลขใน list นี้ด้วยการคูณจนกว่ามันจะมีขนาดเท่ากับการ์ด เท่านี้เอง (อันนี้ออกแค่ข้อเล็ก)
อันดับระหว่างแข่งคือ 18xx พอจบรอบตรวจคะแนนจริงก็เด้งกลับมาที่ 1377 เพราะข้อที่ส่งไปถูกหมด (แต่ก็ยังไม่เพียงพอสำหรับผ่านเข้ารอบต่อไปอยู่ดี) ... ไม่เป็นไรรอบหน้าเอาใหม่ เนอะ ^^)v
Apr 14, 2013
Code Jam 2013 รอบคัดเลือก
เนื่องจากไม่อยากให้เกิดเหตุการณ์แบบรอบ 1 ของปีที่แล้ว ปีนี้เลยนอนเอาแรงไม่บ้าพลังถ่างตาทำตั้งแต่เช้ามืด ทำให้กว่าจะได้เริ่มอ่านโจทย์ก็บ่าย 2 เข้าไปแล้ว
ปีนี้ความตั้งใจแรกคือจะพยายามเขียนส่งให้ได้หลายๆ ภาษา คือฝึก ML, Lisp, Bash อะไรพวกนี้จนคิดว่าน่าจะคล่องพอเอามาใช้แก้โจทย์ปัญหาจริงๆ ได้แล้ว น่าเสียดายที่รับ input ไม่เป็น เลยกลับมาตายรังด้วย Python เหมือนเดิม (แต่ก็มี Haskell โผล่มาครึ่งข้อ) ไม่แน่ใจว่ารอบต่อๆ ไปจะเขียน C++ ทันหรือเปล่า เพราะโดนจำกัดเวลาเหลือแค่ 2.5 ชั่วโมงแล้ว
ข้อแรกโจทย์ extended เกม OX ให้ใหญ่ขึ้นเป็นตาราง 4x4 แถมยังอนุญาตให้มี wildcard (เป็นได้ทั้ง X และ O) อย่างมาก 1 ที่บนกระดาน ก็ถามว่าเกมตอนนี้ใครชนะ หรือว่าเสมอ หรือว่ายังเล่นไม่จบ
เคยเจอคำถามเกี่ยวกับ grid แบบนี้มาพอสมควร อันที่จริงก็ต้องไล่เช็คทั้งแนวตั้ง แนวนอน และก็แนวทะแยงซ้ายขวาเลย แต่เพิ่งมาสำนึกได้ว่าเขียนแบบนั้นมี code ซ้ำกันเยอะๆ จะเริ่ม maintenance ยากละ เลยสังเกตว่าถ้าหมุน grid ให้ได้เป็นแบบนี้
1 2 3 7 4 1 4 5 6 => 8 5 2 7 8 9 9 6 3
จะสามารถ reuse code ส่วนที่เช็คแนวนอนมาเช็คแนวตั้งได้ด้วย เช่นเดียวกับ code เช็คแนวทะแยง การ implement แค่ส่วนนี้คงมีวิธีเจ๋งๆ ให้เลือกใช้เยอะอยู่ ส่วนผมที่มาจากสาย functional เลือกใช้
transpose . reversed ครับdef transpose(grid):
return [''.join(line) for line in zip(*grid)]
def chk_hori(grid):
for line in grid:
if all(c in 'XT' for c in line):
return 'X won'
if all(c in 'OT' for c in line):
return 'O won'
def chk_diag(grid):
if all(grid[i][i] in 'XT' for i in range(len(grid))):
return 'X won'
if all(grid[i][i] in 'OT' for i in range(len(grid))):
return 'O won'
def chk_won(grid):
for _ in range(2):
for chk in [chk_hori, chk_diag]:
answer = chk(grid)
if answer:
return answer
grid = transpose(reversed(grid))
def chk_full(grid):
return not any('.' in line for line in grid)
for case in range(int(input())):
grid = [input() for _ in range(4)]
input()
answer = chk_won(grid)
if not answer:
answer = 'Draw' if chk_full(grid) else 'Game has not completed'
print('Case #{}: {}'.format(case+1, answer))
ข้อถัดมาถามว่าสามารถใช้เครื่องตัดหญ้าอัตโนมัติ (ที่ดันวิ่งตรงไปข้างหน้าได้อย่างเดียว) ตัดหญ้าให้แต่ละช่องมีความสูงตาม pattern ที่วางไว้ได้หรือเปล่า
พบว่า algorithm ง่ายกว่าที่คิด คือดูว่าแต่ละจุดบนสนามหญ้านั้น ต้องมีความสูงเท่ากับความสูงหญ้าที่สูงที่สุดในแนวนอนหรือแนวตั้งเท่านั้น เพราะถ้าเกิดมีจุดที่สูงกว่าทั้งแนวนอนและแนวตั้งพร้อมกัน จะทำให้ไม่สามารถตัดหญ้าในช่องนั้นให้ต่ำกว่าค่าสูงสุดได้
def transpose(lawn):
return [list(line) for line in zip(*lawn)]
def beautiful_garden(lawn, n, m):
tlawn = transpose(lawn)
def chk(y, x):
return lawn[y][x] in [max(tlawn[x]), max(lawn[y])]
return all(all(chk(y, x) for x in range(m)) for y in range(n))
for case in range(int(input())):
n, m = [int(i) for i in input().split()]
lawn = [[int(i) for i in input().split()] for _ in range(n)]
answer = 'YES' if beautiful_garden(lawn, n, m) else 'NO'
print('Case #{}: {}'.format(case+1, answer))
ข้อที่ 3 ให้ว่ามีเลข palindrome ที่รากที่สองของมันก็ยังเป็น palindrome ด้วยทั้งหมดกี่ตัวในช่วงที่กำหนด ซึ่งมีความรู้สึกว่าถ้าเล่นกับ palindrome แล้ว Haskell จะสวยงามมาก แต่ก็ไปตายที่ test กลางเลยกลับไปใช้ Python แทน
import Data.List.Split (splitOn)
boolAsNum b = if b then 1 else 0
isSquare x = root^2 == x
where root = sqrt x
isPalindrome x = y == reverse y
where y = show x
countFair x y
| x > y = 0
| otherwise = (boolAsNum $ all isPalindrome [x,x^2]) + countFair (x+1) y
eachLoop nosLoop = do
raw <- getLine
let rawSqrtNum = [sqrt $ read x | x <- splitOn " " raw]
[start, stop] = [f x | (f,x) <- zip [ceiling, floor] rawSqrtNum]
putStrLn $ "Case #" ++ (show nosLoop) ++ ": " ++ (show $ countFair start stop)
main = do
allLoop <- getLine
sequence_ [eachLoop n | n <- [1..read allLoop]]
ส่วนนี่คือ Python ที่ optimize ไปนิดหน่อยสำหรับความยากปานกลาง โดยส่วนที่วนสร้างเลข palindrome ตัวถัดไปยังไม่ได้ optimize สำหรับโจทย์นี้โดยเฉพาะเลย (ว่าแล้วก็ต้องเขียนเก็บเข้า lib ตัวเองซะแล้ว)
odd = lambda x: x % 2 == 1
square = lambda n: int(n ** 0.5) ** 2 == n
palindrome = lambda n: str(n) == str(n)[::-1]
def int_sqrt(n):
if n == 0:
return 0
a, b = divmod(n.bit_length(), 2)
x = 2 ** (a + b)
while True:
y = x + n // x
y //= 2
if y >= x:
return x
x = y
def next_palindrome(n):
s = str(n)
size = len(s)
fst = s[:size//2+1] if odd(size) else s[:size//2]
lst = s[-size//2:]
size_old_fst = len(fst)
if fst <= lst[::-1]:
fst = str(int(fst) + 1)
lst = fst[:-1] if len(fst) > size_old_fst else fst
return int(fst[:-1] + lst[::-1]) if odd(size) else int(fst + lst[::-1])
def palindrome_range(start, stop):
while start < stop:
if palindrome(start):
yield start
start = next_palindrome(start)
for case in range(int(input())):
start, stop = [int(n) for n in input().split()]
start = int_sqrt(start) + (0 if square(start) else 1)
stop = int_sqrt(stop)
answer = sum(palindrome(pal**2) for pal in palindrome_range(start, stop+1))
print('Case #{}: {}'.format(case+1, answer))
ส่วนข้อ 4 ไม่ได้ทำ เพราะสังเกตเห็น pattern ของข้อ 3 เลยกะจะแก้ความยากระดับโหดสุด (input ใหญ่ได้ถึง 10^100) แต่ลอง optimize ดูแล้วทำทันแค่ 10^80 เท่านั้น ก็เลยต้องตัดใจไปตามระเบียบ แต่แต้มแค่นี้ก็เพียงพอสำหรับรอบ 1 แล้วครับ ;)
Apr 8, 2013
TCDC เชียงใหม่
tl; dr มันคือห้องสมุดฮายโซวสำหรับ designer นั่นเองครับ

วิธีการเดินทางก็ไม่ยาก ถ้ามาจากแจ่งหมูกะทะ (แจ่งศรีภูมิ) ให้ไปทางริมแม่น้ำปิง (ทางที่จะไปเจดีย์ขาว) พอถึงอีกไฟแดงนึงก็เลี้ยวซ้ายเลย TCDC อยู่ซ้ายมือครับ
ที่น่าทึ่งก็คือใน Google Street View ยังไม่มีอาคารนี้เลย นับว่าสร้างได้เร็วมากๆ (แต่มองจาก satellite mode เห็นหลังคาแล้วนะ)
ตัวอาคารทำจากวัสดุเทียบเคียงไม้สร้างเป็นทรงเรขาคณิตเรียบๆ ออกแนว modern-minimalism มี 3 ชั้น (ผมหาทางขึ้นชั้น 3 ไม่เจอ -- แต่ช่างมันเพราะเป็นชั้นสำหรับเจ้าหน้าที่) เนื่องด้วยความเรียบ (เกินไป) ของมันเลยทำให้ไม่รู้ว่าจะถ่ายรูปมุมไหนดี แถมยังมีบริเวณที่ห้ามถ่ายรูปอีกด้วย - -"
ส่วนนี่เป็น model งานออกแบบอาคาร TCDC แบบอื่นๆ ที่ไม่สามารถนำมาสร้างจริงได้ แต่ก็สวยใช่เล่น


ด้านพื้นที่ใช้สอย ชั้นล่างสุดเป็นส่วนแสดงนิทรรศการ ไปคราวนี้เจองาน "เล่าเรื่อง เมืองใหม่ Chiang Mai Revisited" โดยเน้นเขตเศรฐกิจอย่างย่านนิมมานเหมินทร์ที่เปลี่ยนไปมากในช่วงไม่กี่ปีที่ผ่านมานี้ครับ

ส่วนชั้นสองเป็นห้องสมุด designer ที่ไม่ได้มีแต่หนังสือศิลปะอย่างเดียว แต่ยังจัดบริเวณที่เป็น material lib ไว้ด้วย (ตัวอย่างของ material แบบต่างๆ ที่นิยมใช้ในงานออกแบบเช่น เนื้อผ้า กระเบื้อง กระดาษ กระจก -- ห้ามถ่ายรูปแล้ว) ซึ่งส่วนตัวผมว่ามันยังน้อยไปหน่อย จริงๆ แล้วเอาหนังสือออกให้ไปหมดเพื่อแสดงแต่ material เลยก็น่าจะได้นะ?
จบดื้อๆ แบบนี้แหละครับ สำหรับผมที่ไม่ใช่สาย art คงรู้สึกเฉยๆ แต่ถ้าเป็นเด็กวิจิตร/ถาปัดก็อาจจะถือว่าเป็นแดนศักดิ์สิทธิ์ที่ควรไปสักการะบ่อยๆ ก็ได้นะ

วิธีการเดินทางก็ไม่ยาก ถ้ามาจากแจ่งหมูกะทะ (แจ่งศรีภูมิ) ให้ไปทางริมแม่น้ำปิง (ทางที่จะไปเจดีย์ขาว) พอถึงอีกไฟแดงนึงก็เลี้ยวซ้ายเลย TCDC อยู่ซ้ายมือครับ
ที่น่าทึ่งก็คือใน Google Street View ยังไม่มีอาคารนี้เลย นับว่าสร้างได้เร็วมากๆ (แต่มองจาก satellite mode เห็นหลังคาแล้วนะ)
ตัวอาคารทำจากวัสดุเทียบเคียงไม้สร้างเป็นทรงเรขาคณิตเรียบๆ ออกแนว modern-minimalism มี 3 ชั้น (ผมหาทางขึ้นชั้น 3 ไม่เจอ -- แต่ช่างมันเพราะเป็นชั้นสำหรับเจ้าหน้าที่) เนื่องด้วยความเรียบ (เกินไป) ของมันเลยทำให้ไม่รู้ว่าจะถ่ายรูปมุมไหนดี แถมยังมีบริเวณที่ห้ามถ่ายรูปอีกด้วย - -"
ส่วนนี่เป็น model งานออกแบบอาคาร TCDC แบบอื่นๆ ที่ไม่สามารถนำมาสร้างจริงได้ แต่ก็สวยใช่เล่น


ด้านพื้นที่ใช้สอย ชั้นล่างสุดเป็นส่วนแสดงนิทรรศการ ไปคราวนี้เจองาน "เล่าเรื่อง เมืองใหม่ Chiang Mai Revisited" โดยเน้นเขตเศรฐกิจอย่างย่านนิมมานเหมินทร์ที่เปลี่ยนไปมากในช่วงไม่กี่ปีที่ผ่านมานี้ครับ

ส่วนชั้นสองเป็นห้องสมุด designer ที่ไม่ได้มีแต่หนังสือศิลปะอย่างเดียว แต่ยังจัดบริเวณที่เป็น material lib ไว้ด้วย (ตัวอย่างของ material แบบต่างๆ ที่นิยมใช้ในงานออกแบบเช่น เนื้อผ้า กระเบื้อง กระดาษ กระจก -- ห้ามถ่ายรูปแล้ว) ซึ่งส่วนตัวผมว่ามันยังน้อยไปหน่อย จริงๆ แล้วเอาหนังสือออกให้ไปหมดเพื่อแสดงแต่ material เลยก็น่าจะได้นะ?
จบดื้อๆ แบบนี้แหละครับ สำหรับผมที่ไม่ใช่สาย art คงรู้สึกเฉยๆ แต่ถ้าเป็นเด็กวิจิตร/ถาปัดก็อาจจะถือว่าเป็นแดนศักดิ์สิทธิ์ที่ควรไปสักการะบ่อยๆ ก็ได้นะ
Apr 7, 2013
Bit Flag
ในภาษาสมัยใหม่ เราคงคุ้นเคยกับการเขียนฟังก์ชั่น (และเรียกใช้) แบบนี้
โชคร้ายที่ระบบ keyword argument ไม่ได้เป็นแบบนี้ทุกภาษา อย่างเช่นใน PHP ถ้าจะเปิดตัว flag c เพียงตัวเดียว ก็ยังคงต้องบอกว่า a, b ถูกปิดอยู่ด้วย (ต้องบอกสถานะของ flag ทุกตัวที่อยู่ก่อนหน้า c)
ทางออกง่ายๆ แต่ทำให้ syntax ดูรุงรังหน่อยคือการให้ argument ส่วนที่เป็น flag ใช้ datatype แบบ hash table เช่นนี้
ทางออกที่คลาสสิก (แต่ปวดหัว) กว่าคือการใช้ bit flag แบบนี้
หลายคนอาจบอกว่าการใช้ bit flag นั้นมีข้อดีเหนือกว่า keyword argument ตรงที่สามารถ store สถานะของ flag เก็บไว้ใน data ตัวหนึ่ง (เพื่อที่จะนำไปใช้ซ้ำในที่อื่น) ซึ่งข้อได้เปรียบนี้ไม่เป็นความจริงเลยสำหรับภาษาที่แตก array, hash table ลงไปเป็น argument ได้
ก็เลือกใช้ความสามารถเหล่านี้ตามความสะดวกของแต่ละภาษานะครับ อย่าไปฝืนมันมากถ้าตัวภาษามันไม่ได้ออกแบบให้ทำเรื่องยากๆ บางเรื่องไว้แต่แรก
def foo(n, m, a=False, b=False, c=False):
if a:
n += 42
if b:
n *= 7
if c:
n **= 2
return n % m
...
foo(5, 99)
foo(5, 99, a=True)
foo(5, 99, c=True)
foo(5, 99, c=True, b=True, a=True)
โชคร้ายที่ระบบ keyword argument ไม่ได้เป็นแบบนี้ทุกภาษา อย่างเช่นใน PHP ถ้าจะเปิดตัว flag c เพียงตัวเดียว ก็ยังคงต้องบอกว่า a, b ถูกปิดอยู่ด้วย (ต้องบอกสถานะของ flag ทุกตัวที่อยู่ก่อนหน้า c)
ทางออกง่ายๆ แต่ทำให้ syntax ดูรุงรังหน่อยคือการให้ argument ส่วนที่เป็น flag ใช้ datatype แบบ hash table เช่นนี้
function foo($n, $m, $options=array()) {
if (array_key_exists('a', $options) && $options['a'])
$n += 42;
if (array_key_exists('b', $options) && $options['b'])
$n *= 7;
if (array_key_exists('c', $options) && $options['c'])
$n *= $n;
return $n % $m;
}
...
foo(5, 99);
foo(5, 99, array('a' => true));
foo(5, 99, array('c' => true));
foo(5, 99, array('c' => true, 'b' => true, 'a' => true));
ทางออกที่คลาสสิก (แต่ปวดหัว) กว่าคือการใช้ bit flag แบบนี้
const int A = 0x01;
const int B = 0x02;
const int C = 0x04;
int foo(int n, int m, int options) {
if (options & A)
n += 42;
if (options & B)
n *= 7;
if (options & C)
n *= n;
return n % m;
}
...
foo(5, 99, 0);
foo(5, 99, A);
foo(5, 99, C);
foo(5, 99, C|B|A);
หลายคนอาจบอกว่าการใช้ bit flag นั้นมีข้อดีเหนือกว่า keyword argument ตรงที่สามารถ store สถานะของ flag เก็บไว้ใน data ตัวหนึ่ง (เพื่อที่จะนำไปใช้ซ้ำในที่อื่น) ซึ่งข้อได้เปรียบนี้ไม่เป็นความจริงเลยสำหรับภาษาที่แตก array, hash table ลงไปเป็น argument ได้
args = [5, 99]
flags = {'b': True, 'c': True}
foo(*args, **flags) == foo(5, 99, b=True, c=True)
ก็เลือกใช้ความสามารถเหล่านี้ตามความสะดวกของแต่ละภาษานะครับ อย่าไปฝืนมันมากถ้าตัวภาษามันไม่ได้ออกแบบให้ทำเรื่องยากๆ บางเรื่องไว้แต่แรก
Mar 12, 2013
42
เนื่องจากเมื่อวานเป็นวันคล้ายเกิดของ Douglas Adams ซึ่งถ้าเขามีชีวิตอยู่ก็จะอายุขึ้นปีที่ 61 แล้ว Google เลยทำ Doodle รำลึกถึงนักเขียนนิยายชื่อก้องคนนี้ให้ได้เล่นกันครับ

รายละเอียดเล็กน้อยๆ ที่เก็บได้จากยานหัวใจทอง ยานอวกาศหลักของเรื่องที่สามารถเดินทางทะลุข้ามมิติจักรวาลได้ด้วยหลักการของความไม่น่าจะเป็น
และนี่คือเรื่องราวต่างๆ ที่สามารถอ่านได้จากหนังสือคู่มือนักโบก

รายละเอียดเล็กน้อยๆ ที่เก็บได้จากยานหัวใจทอง ยานอวกาศหลักของเรื่องที่สามารถเดินทางทะลุข้ามมิติจักรวาลได้ด้วยหลักการของความไม่น่าจะเป็น
- ประตูถอนหายใจ ที่เปิดออกมาก็จะเจอกับเจ้าหุ่นมาร์วินผู้แบกโลก (เวอร์ชันหนังมาร์วินหัวโตกว่านี้มาก)
- คอนโซลยานที่คอยพ่นเทปสื่ออารมณ์ ถ้ามัวอ่านแต่ข้อความในเทปนี้คงไม่ได้ทำอะไรพอดี
- ที่เป็นแท่งๆ นั่นคือนิ้วอิเล็กทรอนิกส์สำหรับโบกยาน - เวลาฝรั่งเค้าโบกรถจะเหยียดแขนสุดแล้วชูนิ้วโป้งขึ้น (เวอร์ชันหนังเครื่องนี้กลายเป็นแหวนสวมนิ้วแทน)
- เครื่องซับอีธาเซนโซเมตริก เอาไว้รับสัญญาณของยานอวกาศที่อาจบังเอิญบินผ่านมาให้ได้โบก
- ชาจากเครื่องชงเครื่องดื่มอัตโนมัติ ที่จะพยายามอ่านความคิดของคนสั่งว่าต้องการเครื่องดื่มอะไร แต่ทำไมเครื่องดื่มทุกแก้วที่ผลิตได้ถึงมีรสชาติที่ไม่ต่างกันเลย?
- ตัวหนังสือคู่มือนักโบก หัวใจหลักของเรื่องนี้ พร้อมข้อความอันเป็นมิตรว่า "อย่าได้ตกใจ"
- กระเป๋าเดินทางที่สูญหายของอาเธอร์ แล้วอยู่ๆ ก็โดนพ่นออกมาจากถังขยะห้วงเวลา
- ผ้าเช็ดตัว อุปกรณ์สารพัดประโยชน์ที่นักโบกต้องมีคู่กายเสมอ
และนี่คือเรื่องราวต่างๆ ที่สามารถอ่านได้จากหนังสือคู่มือนักโบก
- ปลาแปลภาษาที่คอยกินคลื่นเสียงเป็นอาหาร แล้วขับถ่ายออกมาเป็นสัญญาณประสาทในภาษาของผู้ที่ใส่ปลานี่ไว้ในหู
- คำจำกัดความของโลกโดยหนังสือเล่มนี้ เนื่องจากไม่ค่อยมีเนื้อหาสาระใดๆ จึงสามารถเขียนอธิบายได้สั้นๆ แค่ว่า "แทบปราศจากภยันอันตราย"
- เคล็ดลับสำหรับการบิน.... ก็เพียงแค่หกล้มให้ไม่โดนพื้นแค่นั้นเอง
- รสชาติของเครื่องดื่มสุดยอดแห่งจักรวาล แพน-กาแลคติค การ์เกิล บลัสเตอร์
- ระบบการเดินทางด้วยหลักการความไม่น่าจะเป็นของยานหัวใจทอง ที่สามารถเดินทางจากปลายจักรวาลด้านหนึ่งไปสู่อีกด้านได้ในพริบตา
- ต้นกำเนิดของจักรวาลที่เราอาศัยอยู่ ที่จริงแล้วก็เป็นเพียงการสั่งน้ำมูกของยักษ์เท่านั้น
- มนุษย์ที่คิดว่าตัวเองฉลาดที่สุดบนโลก แท้จริงแล้วก็ฉลาดน้อยกว่าปลาโลมาและหนูเสียอีก
- ความสำคัญของผ้าเช็ดตัวที่นักโบกทุกคนต้องมีคู่กาย
- จุดจบของโลกใบเล็กๆ จากพวกโวกอนที่ป่าเถื่อน
- คอมพิวเตอร์สุดฉลาดล้ำคิดลึก ที่ตอบคำถามสุดยอดของชีวิต จักรวาล และทุกสรรพสิ่งได้ว่าเท่ากับ 42
Mar 2, 2013
Swap ตัวแปร
โปรแกรมที่เล็กและง่ายรองจาก hello world ที่โปรแกรมเมอร์หลายคนต้องผ่านตามาบ้าง คือโปรแกรม (ฟังก์ชัน) สำหรับสลับค่าตัวแปรนั่นเอง
แต่ก่อนจะลงลึกที่รายละเอียด มาดู simple yet best practice ใน Pyhton กันก่อน :P
อธิบายก่อนว่าการเข้าถึง data ในคอมพิวเตอร์ จะคล้ายๆ กับคนที่มีแขนข้างเดียว คือหยิบของได้ทีละ 1 อย่าง ไม่สามารถหยิบของพร้อมกัน 2 อย่างแล้ววางสลับที่กันทันทีได้เหมือนในชีวิตจริง
วิธีแก้ปัญหาที่ตรงไปตรงมาภายใต้ข้อจำกัดนี้ คือหยิบของชิ้นแรกไปวางไว้ในที่ว่างก่อน หยิบของชิ้นที่สองไปวางแทนที่ๆ ของชิ้นแรกเคยอยู่ แล้วค่อยกลับไปหยิบของชิ้นแรกวางแทนที่ๆ ของชิ้นสองเคยอยู่
จะอธิบายให้คอมพิวเตอร์เข้าใจได้ ก็ต้องบอกด้วยว่าที่ว่างนั้นคือตรงไหน (พูดลอยๆ ไม่ได้ เดี๋ยวกลับไปหาไม่เจอ) เช่นนี้
ปัญหาของการย้ายแบบนี้ คือมันเป็นการมองในเชิง object โลกมนุษย์ ซึ่งไม่ได้ใกล้เคียงกับกิจกรรมที่เกิดขึ้นใน memory เลย มันไม่ใช่การย้ายของด้วยซ้ำ แต่เป็นการทำสำเนาสิ่งของแล้วย้ายที่สลับไปมาต่างหาก
อนึ่ง วิธีนี้ยังมีข้อเสียตรงที่มันใช้พื้นที่ว่างเพิ่มเติมสำหรับเก็บข้อมูลระหว่างทางอีก แล้วมันจะมีทางมั้ยที่จะสลับที่ตัวแปรโดยไม่ต้องอาศัยตัวแปรอื่นเข้ามาทำหน้าที่เป็นที่พักข้อมูล?
ลองนั่งคิดเล่นๆ ซักพักคงพบว่ามันก็ไม่ได้ยากอะไร เริ่มจากเอาค่าของตัวแปรสองไปเก็บรวมกับตัวแปรแรก แล้วเอาตัวแปรแรก (ที่ตอนนี้มีค่าของตัวแปรแรกและตัวแปรสองรวมกัน) กลับไปหักลบกับตัวแปรสอง เท่านี้ตัวแปรที่สองก็จะมีค่าเท่ากับตัวแปรแรกแบบดั้งเดิมแล้ว (ขั้นที่เหลือคงไม่ต้องบอกว่าทำยังไงต่อ)
แบบนี้ก็เกือบดีแล้ว แต่ยังมีข้อควรระวังคือ overflow เนื่องจากมันเป็นวิธีทางคณิตศาสตร์ แถมโปรแกรมแบบนี้ก็ยังไม่ค่อยสวยงามเท่าไหร่ด้วย
ถ้าจะมองให้เป็นไปในทางคอมพิวเตอร์จริงๆ ต้องเปลี่ยนการดำเนินการ +, - ไปใช้ xor แทน เช่นนี้
ซึ่งสามารถลดรูปได้อีกขั้นจนเหลือเพียงบรรทัดเดียวว่า
อย่างไรก็ตาม การมองว่าคอมพิวเตอร์เปรียบเหมือนคนที่มีแขนข้างเดียวนั้น ก็คงไม่ถูกต้องอีกต่อไปแล้ว (เป็นการมองแบบ Turing machine ซึ่งตกยุคไปชาติเศษๆ) เพราะในปัจจุบัน คอมพิวเตอร์มีแขนเหล่านี้เพิ่มมากขึ้น และสามารถเข้าถึงข้อมูลได้หลายตำแหน่งในเวลาเดียวกัน แต่การเขียนโปรแกรมให้ทำงานแบบ parallel ให้ได้ดีนั้น ก็ไม่ใช่เรื่องง่ายซักเท่าไหร่นัก หน้าตาของโปรแกรมอาจจะออกมาเช่นนี้
ส่วนภาษาเชิง functional ที่ไม่ยอมให้มี mutable อย่างการสลับเปลี่ยนค่าตัวแปร ก็ยังสามารถทำท่านี้ได้โดยใช้เทคนิคตั้งชื่อตัวแปรสลับที่กันใน environment ที่ต่างกัน (ภาษาเค้าเรียกว่า Monad) ต่อไปนี้คือตัวอย่างใน Haskell
หรือแบบนี้ใน Lisp (สังเกตการใช้คำสั่ง
สุดท้ายนี้กลับไปดู Python ที่เรียบง่ายอีกรอบ แท้จริงแล้วมันคือการสั่ง
แปลได้ว่า แรกสุดมันจะเก็บค่าตัวแปร b และ a ตามลำดับลง container ชนิดหนึ่ง (ใน Python มันคือ tuple) แล้วหลังจากนั้นจึงดึงตัวแปรออกจาก container นี้มาให้ตัวแปร a และ b ตามลำดับ แนวคิดแบบนี้ค่อนข้าง general มาก และสามารถนำไปใช้กับกรณีที่มีตัวแปรให้สลับเยอะกว่านี้ได้ด้วย เช่น
แต่ก่อนจะลงลึกที่รายละเอียด มาดู simple yet best practice ใน Pyhton กันก่อน :P
a, b = b, a
อธิบายก่อนว่าการเข้าถึง data ในคอมพิวเตอร์ จะคล้ายๆ กับคนที่มีแขนข้างเดียว คือหยิบของได้ทีละ 1 อย่าง ไม่สามารถหยิบของพร้อมกัน 2 อย่างแล้ววางสลับที่กันทันทีได้เหมือนในชีวิตจริง
วิธีแก้ปัญหาที่ตรงไปตรงมาภายใต้ข้อจำกัดนี้ คือหยิบของชิ้นแรกไปวางไว้ในที่ว่างก่อน หยิบของชิ้นที่สองไปวางแทนที่ๆ ของชิ้นแรกเคยอยู่ แล้วค่อยกลับไปหยิบของชิ้นแรกวางแทนที่ๆ ของชิ้นสองเคยอยู่
จะอธิบายให้คอมพิวเตอร์เข้าใจได้ ก็ต้องบอกด้วยว่าที่ว่างนั้นคือตรงไหน (พูดลอยๆ ไม่ได้ เดี๋ยวกลับไปหาไม่เจอ) เช่นนี้
int t; t = a; a = b; b = t;
ปัญหาของการย้ายแบบนี้ คือมันเป็นการมองในเชิง object โลกมนุษย์ ซึ่งไม่ได้ใกล้เคียงกับกิจกรรมที่เกิดขึ้นใน memory เลย มันไม่ใช่การย้ายของด้วยซ้ำ แต่เป็นการทำสำเนาสิ่งของแล้วย้ายที่สลับไปมาต่างหาก
อนึ่ง วิธีนี้ยังมีข้อเสียตรงที่มันใช้พื้นที่ว่างเพิ่มเติมสำหรับเก็บข้อมูลระหว่างทางอีก แล้วมันจะมีทางมั้ยที่จะสลับที่ตัวแปรโดยไม่ต้องอาศัยตัวแปรอื่นเข้ามาทำหน้าที่เป็นที่พักข้อมูล?
ลองนั่งคิดเล่นๆ ซักพักคงพบว่ามันก็ไม่ได้ยากอะไร เริ่มจากเอาค่าของตัวแปรสองไปเก็บรวมกับตัวแปรแรก แล้วเอาตัวแปรแรก (ที่ตอนนี้มีค่าของตัวแปรแรกและตัวแปรสองรวมกัน) กลับไปหักลบกับตัวแปรสอง เท่านี้ตัวแปรที่สองก็จะมีค่าเท่ากับตัวแปรแรกแบบดั้งเดิมแล้ว (ขั้นที่เหลือคงไม่ต้องบอกว่าทำยังไงต่อ)
a = a + b; b = a - b; a = a - b;
แบบนี้ก็เกือบดีแล้ว แต่ยังมีข้อควรระวังคือ overflow เนื่องจากมันเป็นวิธีทางคณิตศาสตร์ แถมโปรแกรมแบบนี้ก็ยังไม่ค่อยสวยงามเท่าไหร่ด้วย
ถ้าจะมองให้เป็นไปในทางคอมพิวเตอร์จริงๆ ต้องเปลี่ยนการดำเนินการ +, - ไปใช้ xor แทน เช่นนี้
a ^= b; b ^= a; a ^= b;
ซึ่งสามารถลดรูปได้อีกขั้นจนเหลือเพียงบรรทัดเดียวว่า
a ^= b ^= a ^= b;
อย่างไรก็ตาม การมองว่าคอมพิวเตอร์เปรียบเหมือนคนที่มีแขนข้างเดียวนั้น ก็คงไม่ถูกต้องอีกต่อไปแล้ว (เป็นการมองแบบ Turing machine ซึ่งตกยุคไปชาติเศษๆ) เพราะในปัจจุบัน คอมพิวเตอร์มีแขนเหล่านี้เพิ่มมากขึ้น และสามารถเข้าถึงข้อมูลได้หลายตำแหน่งในเวลาเดียวกัน แต่การเขียนโปรแกรมให้ทำงานแบบ parallel ให้ได้ดีนั้น ก็ไม่ใช่เรื่องง่ายซักเท่าไหร่นัก หน้าตาของโปรแกรมอาจจะออกมาเช่นนี้
process [1, 2]: goto address [a, b] read into process memory sync with process [2, 1] goto address [b, a] write from process memory
ส่วนภาษาเชิง functional ที่ไม่ยอมให้มี mutable อย่างการสลับเปลี่ยนค่าตัวแปร ก็ยังสามารถทำท่านี้ได้โดยใช้เทคนิคตั้งชื่อตัวแปรสลับที่กันใน environment ที่ต่างกัน (ภาษาเค้าเรียกว่า Monad) ต่อไปนี้คือตัวอย่างใน Haskell
do (a,b) <- return (b,a) someMagic a b ...
หรือแบบนี้ใน Lisp (สังเกตการใช้คำสั่ง
let เพื่อสลับตัวแปร)(let ([a b]
[b a])
(magic-happens a b ...))
สุดท้ายนี้กลับไปดู Python ที่เรียบง่ายอีกรอบ แท้จริงแล้วมันคือการสั่ง
container = b, a a, b = container
แปลได้ว่า แรกสุดมันจะเก็บค่าตัวแปร b และ a ตามลำดับลง container ชนิดหนึ่ง (ใน Python มันคือ tuple) แล้วหลังจากนั้นจึงดึงตัวแปรออกจาก container นี้มาให้ตัวแปร a และ b ตามลำดับ แนวคิดแบบนี้ค่อนข้าง general มาก และสามารถนำไปใช้กับกรณีที่มีตัวแปรให้สลับเยอะกว่านี้ได้ด้วย เช่น
a, b, c, d = d, -b, -c, a
Subscribe to:
Posts (Atom)




