Monday, December 08, 2008

random เรียกชื่อคน

เมื่อสุดสัปดาห์ที่ผ่านมาผมมีภาระกิจต้องไปสัมมนากับบริษัทฯ โดยในสัมมนาผมต้องนำคุยทำความรู้จักกับนิยามของ Knowledge แต่เนื่องจากเรื่องนี้มันคลุมเครือและออกนามธรรมมาก การที่น้องๆจะสมัครใจแสดงความคิดเห็น คงจะยากมาก ประกอบกับพึ่งอ่าน blog ของอาจารย์ cholwich ซึ่งเขียนโปรแกรม random ชื่อนักเรียนด้วย java ก็เลยลอกวิธีการมาใช้บ้าง แต่เนื่องจากช่วงนี้กำลังอินกับ clojure ก็เลย implement ด้วย clisp

ลองมาดูตัวโปรแกรมกัน
เริ่มจากการกำหนด global variable สำหรับเก็บชื่อคน
(defvar *names*)

ตามด้วยการกำหนดชื่อคน
(setq *names* '(pok bunny pann pune))

Note: global variable ใน clisp มี scope แบบ dynamic, การตั้งชื่อนิยมตั้งด้วย * นำหน้า เพื่อให้แยกความแตกต่างจาก local variable เพราะถ้าตั้งชื่อตรงกันอาจจะเจอปัญหาการ binding ได้

จากนั้นก็สร้าง function ที่ random ชื่อออกมา
(defun next ()
(nth (random (length *names*)) *names*))

nth คือ function ที่ใช้ access list ที่ตำแหน่ง index ที่ต้องการ
ส่วน (random N) จะได้ค่า integer ระหว่าง 0 ถึง (N-1)

โปรแกรมก็ทำงานได้ดี แต่ใช้ไปนานๆ มัน random คนออกมาซ้ำๆกันมากไปหน่อย
กลับมาจากสัมมนาแล้ว ก็เลยมานั่งปรับปรุงให้มันเอาชื่อคนที่เคยเรียกแล้วออกไปจาก list ให้ด้วย (จะได้ไม่เรียกซ้ำ)
(defun next ()
(let ((name (nth (random (length *names*)) *names*)))
(setq *names* (remove name *names*))
name))

สุดท้ายก็ปรับปรุงว่า ถ้าเอาชื่อออกจนหมดแล้ว ก็ให้ reset รายชื่อใหม่
(defun next ()
(if (null *names*)
(setq *names* '(pok bunny pann pune)))
(let ((name (nth (random (length *names*)) *names*)))
(setq *names* (remove name *names*))
name))

Related link from Roti