Dec 13 2009

ดึงราคาหุ้นใน SET

Category: Generalm3rLinEz @ 18:14

ไปอ่านเอกสารพวก Chart Patterns มา ซึ่งมันคือ Pattern ของกราฟราคาหุ้นที่คนเขียนเอกสารพวกนี้เค้าสังเกตมาว่า เป็นสัญญาณอะไรบางอย่างที่ทำให้หุ้นจะเปลี่ยนราคา (ขึ้น หรือ ลง) ไปอย่างรวดเร็วทำให้สามารถใช้ trade ทำกำไร (หรือขาดทุนยับ) ได้ ส่วนใหญ่คนเขียนเอกสารเค้าก็จะออกตัวไว้ก่อนเลยว่า มันไม่ถูก 100% นะ แต่ก็ไม่เคยมีใครบอกว่ามันถูกกี่ % ดังนั้นก่อนอื่นต้องหาวิธีดึงราคามาเอาไว้ทำการทดลองก่อน

จริงๆแล้ว API ที่ บ.เหมาะกับงานนี้มากเลย แต่ถ้าเอา Data ตรงนั้นมาใช้กลัวว่าอาจจะได้เตะฝุ่นก่อนทำงานครบปี :[ เหอะๆ

class DayData:
    date = None
    open = None
    close = None
    max = None
    min = None
    volume = None
    value = None
    set_index = None

    def __init__(self):
        pass

    @staticmethod
    def to_datetime(str):
        from datetime import datetime
        ds = [int(x) for x in str.split('/')]
        ds[2] = ds[2] + 2000
        return datetime(ds[2], ds[1], ds[0])
                
    @staticmethod
    def to_decimal(str):
        from decimal import Decimal
        return Decimal(str.replace(',',''))

class SETFetch:
    @staticmethod
    def fetch(symbol):
        import urllib2
        from decimal import Decimal
        from BeautifulSoup import BeautifulSoup
        
        set_url_format = "http://www.settrade.com/C04_02_stock_historical_p1.jsp?txtSymbol=%s&from=%d";
        cur_pos = 1
        all_data = []

        while True:
            page = urllib2.urlopen(set_url_format % (symbol, cur_pos))
            soup = BeautifulSoup(page)
            read_data = soup.findAll('tr','tdbg_gray20') + soup.findAll('tr','tdbg_white20')
            if len(read_data) == 0:
                # no more data to read
                break
            cur_pos = cur_pos + len(read_data)
            all_data = all_data + read_data

        daily = []
        for day in all_data:
            flds = day.findAll('td')
            current = DayData()
            current.date =  DayData.to_datetime(flds[0].text)
            current.open = DayData.to_decimal(flds[1].text)
            current.max = DayData.to_decimal(flds[2].text)
            current.min = DayData.to_decimal(flds[3].text)
            current.close = DayData.to_decimal(flds[5].text)
            current.volume = DayData.to_decimal(flds[8].text) * 1000
            current.value = DayData.to_decimal(flds[9].text)
            current.set_index = DayData.to_decimal(flds[10].text)
            daily.append(current)    
        daily.sort(key=lambda x: x.date, reverse=True)
        return daily

if __name__ == '__main__':
    daily = SETFetch.fetch('PTT')
    for day in daily:
        print day.date
    #pdb.set_trace()
ตัวอย่างการใช้งาน
Python 2.6.3 (r263rc1:75186, Oct  2 2009, 20:40:30) [MSC v.1500 32 bit (Intel)]
on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from setfetch import SETFetch
>>> data = SETFetch.fetch('CPF')
>>> dir(data[0])
['__doc__', '__init__', '__module__', 'close', 'date', 'max', 'min', 'open', 's
t_index', 'to_datetime', 'to_decimal', 'value', 'volume']
>>> for sample in data[0:10]:
...     print sample.date, sample.close
...
2009-12-11 00:00:00 10.90
2009-12-09 00:00:00 10.70
2009-12-08 00:00:00 10.80
2009-12-04 00:00:00 11.00
2009-12-03 00:00:00 10.70
2009-12-02 00:00:00 10.60
2009-12-01 00:00:00 10.90
2009-11-30 00:00:00 10.70
2009-11-27 00:00:00 10.20
2009-11-26 00:00:00 10.40
>>>

เท่าที่รู้ SET จะไม่ยอมให้ใครมาเผยแพร่ Historical Prices พวกนี้ ยกเว้นคนที่จ่ายตังค์ให้ SET และถ้าจะเผยแพร่ก็ต้องเผยแพร่แบบเก็บเงินเท่านั้นด้วย! (แจกฟรีไม่ได้) แต่ทุกวันนี้ก็จะเห็นมีการแอบแจกกันบ่อยๆ :} เป็นเหตุผลว่าทำไมถึงดูราคาหุ้นไทยในเว็บดีๆอย่าง Google Finance ไม่ได้ (แต่ทำไม Bloomberg ดูได้ไม่รู้ ขี้โกงๆ)

ช่วงนี้นอกจากจะเขียนโค้ดช้าลงแล้ว เวลาว่างยาวๆติดๆกันก็ไม่ค่อยจะมี ความสนใจก็เยอะเหลือเกิน >_< เลยต้องพยายามทำให้เสร็จไปเป็นชิ้นเล็กๆ ครั้งหน้าค่อยมาต่อกันเรื่อง Bar Pattern ที่ไปดูมา ว่าพอมาทดสอบกับข้อมูล 6 เดือนที่ดึงมาแล้วมันจะเวิร์คแค่ไหน

Tags: , , ,

Nov 10 2009

Data Visualization

Category: Toolsm3rLinEz @ 00:17

gant_so 

ทุกวันนี้พวกเราทำงานกับข้อมูลจำนวนมาก มันเป็นศาสตร์ใหญ่ๆอย่างนึงเลยทีเดียวในเรื่องของวิธีการเอาข้อมูลมาแสดง ว่าการแสดงในรูปแบบไหนถึงจะทำให้ผู้ชมเข้าใจข้อมูลได้ง่ายที่สุด และสามารถ reveal feature บางอย่างที่ถ้าสังเกตจาก representation อย่างอื่นแล้วอาจจะมองไม่เห็น!

รูปด้านบนเกิดจากการเอาโพสต์จากบลอกภาษาอังกฤษของผมมาตัดคำแล้วเอามาทำเป็นต้นไม้ จะเห็นได้ขึ้นมาชัดระดับนึงว่า เวลาเราเขียนคำๆนึงแล้ว เรามักจะเอาคำอะไรมาต่อ (อื้มมมม น่าจับพวกเนื้อเพลงมาทำ คงฮาระดับนึง :P) อันนี้มีคนใจดีทำไว้ให้เล่น ที่ Many Eyes

อันนี้เป็นอีกรูปนึงที่ความถี่ของคำเยอะกว่ารูปแรกมาก (ใช้คำว่า I)

gant_i

จริงๆแล้วตัวเว็บมันยังมีรูปแบบในการ Visualize ให้เล่นอีกหลายแบบมาก รวมถึงรูปแบบข้อมูลที่เอา input ให้ระบบไปก็ยังมี 2 รูปแบบ ตัวอย่างข้อมูลที่เป็นโพสต์จากบลอกของผมเรียกว่า Free Text แต่ยังมีอีกแบบนึงที่เป็น Table ซึ่งทำให้สามารถนำเสนอข้อมูลที่มันสัมพันธ์กันซับซ้อนมากกว่า 1 มิติได้

ส่วนอันนี้เป็นอีกรูปแบบนึงที่เรียกว่า Phrase Net อันนี้จะเน้นการแสดงความสัมพันธ์ในระดับคำแทน เราสามารถเลือกได้ว่าให้ระบบแสดงความสัมพันธ์แบบไหน ตัวอย่างเช่น สัมพันธ์แบบเป็นวลีในรูปแบบ “A and B” หรือ “A’s B” หรือ “A of B” หรือ “A[space]B” อันที่เอามาให้ดูนี่เป็นแบบ “A[space]B” รู้สึกว่ารูปสวยดี (อันนี้เหมาะจะเอามาทำกับเนื้อเพลงมากกว่าอันข้างบนอีก ฮ่าๆ)

gant_pn

ส่วนอันนี้ชอบมาก! สวยกว่านั่งทำ Typography เองอีก โอ้ว!!! ใครโดนสั่งทำปกสมุดแล้วคิดอะไรไม่ออก เอาไอนี่ไปวางแก้ขัดได้เลย ~

gant_typo

สาขา ป.โท ที่ใกล้เคียงเรื่องพวกนี้ที่สุดน่าจะเป็นเรื่อง Human Computer Interaction (HCI) เคยอยากเรียนเหมือนกัน แต่จน .. เอ้ย! แต่โง่ …. เย้ยย! รู้สึกว่าถ้าไปเรียนก็คงสนุกดี (เข้าทาง) ชอบเรื่องพวกนี้มากๆเลย ถ้าไปเรียนก็อยากไปเรียน ”เพื่อความบันเทิง” อ่ะ (แต่คงยากจะเกิดเหตุการณ์แบบนั้นขึ้น –_-‘ ถ้ายังคงมีภาระชีวิตที่ต้องรับผิดชอบอยู่)

ใครสนใจก็ลองไปเล่นกันดู :)

Tags: , , ,

Nov 7 2009

2 เดือนในตลาด

Category: Generalm3rLinEz @ 13:06

เผลอๆผ่านมาจะครบสองเดือนแล้วตั้งแต่เริ่มเข้าไปซื้อขายหุ้นใน SET ~

ผมสารภาพว่าก่อนหน้านี้ เวลาดูข่าวทีวี (เอ๊ะ .. ดูทีวีด้วยเหรอ) ช่วงที่เค้าบอกว่าวันนี้ดัชนีตกไปกี่จุดๆ จะเป็นช่วงเวลาที่น่าเบื่อสำหรับผมมากก (พูดเรื่องอะไรกันวะ) แต่หลังจากเริ่มทำงานที่บริษัทก็เลยรู้ว่า product ของ Thomson Reuters มันเกี่ยวกับ Financial Market ล้วนๆเลยนี่หว่า (ก่อนสัมภาษณ์เข้าทีไม่กี่วันยังคิดอยู่เลย ว่านี่จะเข้ามาเป็นลูกจ้างนักข่าว เขียนโปรแกรมตามสั่งให้รึเปล่าวะ 555+) ก็เลยเริ่มสนใจขึ้นมามาก ประกอบกับวัยเพิ่งเริ่มทำงาน ภาระอะไรก็ไม่มี ยังรับความเสี่ยงสูงๆได้อยู่ น่าจะใช้โอกาสนี้ให้คุ้มค่าหน่อย

เคยคุยกับพี่ที่ทีม เค้าบอกว่าเค้าเริ่มซื้อๆขายๆตั้งแต่ ปี 2 … จะไม่น่าแปลกใจเท่าไหร่ถ้าพี่เค้าไม่ได้อายุมากกว่าผมประมาณ 6 ปี = =’ ผมก็แอบรู้สึกว่าตัวเองเริ่มช้าไปนิดนึง จริงๆเรื่องนี้อาจจะแล้วแต่คน แต่ผมคิดว่าวันนึงเราคงหลีกเลี่ยงการรู้จัก “ตลาด” ไม่ได้ เริ่มรู้จักตลาดเร็วๆก็น่าจะดีกว่า ถ้าย้อนเวลากลับไปได้อยากเริ่มซะตั้งแต่เรียนมหาลัยนี่หละ เหมาะที่สุดแล้ว

โชคดีอีกอย่างคือที่บ้านก็ไม่ได้ไม่เห็นด้วยกับการเอาเงินไปโยนไว้ใน Market แต่อย่างใด และยังให้คำแนะนำที่ดีได้ ผมคุยกับเพื่อนหลายๆคน บางบ้านจะไม่สนับสนุนให้ “เล่นหุ้น” มาก ช่วงสองเดือนนี้ก็ได้คำแนะนำจากป๊าตลอด และก็จากพี่ๆที่ทีมบ้าง เจอเหตุการณ์สำคัญไปสองครั้ง

  1. อย่างแรก ซื้อหุ้นน้ำผลไม้ของ TIPCO แล้ว (มารู้ตอนหลังว่ามันบังเอิญมากก) ราคามันขึ้นสูงอย่างมีนัยสำคัญ ก็ขายทิ้ง ถือเป็น impression ที่สุดยอดมากสำหรับมือใหม่ ทำให้ view ผมตอนนั้นโคด optimistic เลย (ถ้าเงินมันหาง่ายขนาดนั้น คงมีคนนอนจิ้มๆคีย์บอร์ดอยู่บ้านมากมาย =_=’)
  2. อย่างที่สอง ตอนมีข่าวทุบตลาด แล้วดัชนีร่วงติดกัน 2-3 วัน ช่วงนั้นหุ้นที่ซื้อมาแทบทุกตัวราคาตกระนาว ก็ได้เรียนรู้กันไปหลายอย่าง ทำลายความ optimistic ลงไปอย่างสิ้นเชิง และทำให้รู้สึกว่าต้องระมัดระวังขึ้นมาก

 

Technical Analysis และ Value Investing

วิธีการทำเงินในตลาดมันเข้าใจง่ายมากครับ ก็คือซื้อมาแล้วก็ขายออกไปให้แพงกว่า! แต่ปัญหาคือ แล้วจะซื้อตอนไหนและขายตอนไหนน่ะสิ ???

มี “แนวคิด” สองอย่างที่ใครๆในตลาดก็รู้จัก คือเรื่องของ Technical Analysis และ Value Investing (VI)

อย่างแรกมีความหมายตามชื่อ คือ Technical Analysis นั้น จะสนใจข้อมูลที่อยู่ตรงหน้าเป็นหลัก คือ ราคา ปริมาณการซื้อขาย แล้วพยายามทำนายอนาคต มีเครื่องมือที่สำคัญคือ indicator ซึ่งจริงๆแล้วมันคือการเอาข้อมูลที่เห็นตรงหน้า (ราคา เปิด ปิด สูงสุด ต่ำสุด ซื้อขายล่าสุด ปริมาณ) ไปผ่านการคำนวณอะไรบางอย่าง แล้วเอามาแสดงอีกรอบ เท่านั้นเอง หลังจากเราเห็นข้อมูลพวกนี้ก็สามารถมองหา Signal (สัญญาณ) ได้ สัญญาณที่บอกว่าราคากำลังจะขึ้นเรียกว่า Bullish Signal (กระทิง) ในขณะที่สัญญาณที่บอกว่าราคาจะตกเรียกว่า Bearish Signal (หมี)

Indicator ก็แบ่งเป็นประเภทต่างๆ ที่เห็นพูดถึงกันบ่อยก็คือ MACD ที่เป็น indicator ประเภท trend following นั่นคือมันจะทำงานได้ดีเวลา “แนวโน้ม” ราคามัน “ขึ้น” หรือว่า “ลง” อย่างชัดเจน และจะทำงานได้แย่มากถ้าราคามันแกว่งไปมาแบบไม่มี trend หรือรูปแบบ Whipsaw ส่วนอีกตัวที่พูดถึงบ่อยเช่นกันคือ Relative Strength Index (RSI) เป็น Indicator ประเภท momentum คือบอกว่าตอนนี้มีการซื้อหรือขายมากเกินไปรึยัง (over-bought, over-sold) ถ้ามากเกินไปแล้วก็อาจจะถึงเวลาที่ราคาจะกลับตัว

อย่างที่สอง คือ Value Investing เป็นแนวคิดที่ริเริ่มสอนโดย Benjamin Graham ซึ่งปรากฎว่า ศิษย์เอกของอาจารย์คนนี้ “รวยแหลก” แทบทุกคน หนึ่งในนั้นรวมถึงนักลงทุนที่ขึ้นชื่อว่าประสบความสำเร็จที่สุดในโลก คือ Warren Buffett ด้วย เนื่องจากว่ามือใหม่อย่างผมเป็นพวกที่ incline ไปทาง TA มากกว่า เลยรู้แนวคิดของ VI แค่นิดหน่อย คือการเลือกหุ้นเพื่อลงทุนของ VI นั้นมักจะใช้ข้อมูลที่เป็น Reference Data คือเป็นประวัติการจ่ายปันผลของบริษัท ทรัพย์สินของบริษัทเป็นยังไงบ้าง ราคานี้เหมาะสมแล้วหรือเปล่า? คำพูดที่จะได้ยินบ่อยๆจาก VI คือ “ราคาต่ำกว่าที่ควรจะเป็นมาก ควรซื้อ” หรือ “ราคาสูงกว่าที่ควรจะเป็นมากแล้ว ควรขาย” ตัวอย่างหุ้นที่ “น่าซื้อ” สำหรับคนกลุ่มนี้ เช่น หุ้นที่ราคาหุ้นนั้น ต่ำกว่าทรัพย์สินที่บริษัทมีทั้งหมดเสียอีก แบบนี้ก็จะถือว่าราคามันต่ำกว่าความเป็นจริง และเชื่อว่าวันนึงราคาก็จะ (ขึ้นมา) reflect เรื่องนี้ในที่สุด พวกนี้ส่วนใหญ่จะถือยาว คือ buy-and-hold ซื้อไว้แล้วก็เฝ้าดูห่างๆก็พอ ไม่ต้องเฝ้าหน้าจอรอดูจุดกลับตัวเหมือนพวก TA

เรื่องแปลกๆที่ผมสังเกตเห็น คือ VI กับ TA จะแบ่งก๊กกันชัดเจน และมักจะมี argument ให้เห็นบ่อยๆว่าแบบไหนทำเงินได้ดีกว่า ข้ออ้างอย่างนึงที่มักจะเห็นบ่อยๆคือ VI ดีกว่าเพราะว่านักลงทุนที่รวยที่สุดเป็น VI พันธุ์แท้! .. อันนี้ก็เหมือนกับการอ้างว่า ถ้าอยากรวยไม่ต้องเรียนมหาวิทยาลัยก็ได้ เพราะ Bill Gates ก็ไม่ได้จบมหาวิทยาลัย

การแบ่งก๊กระหว่าง VI กับ TA ทำให้ผมคิดถึงตัวเอง รวมถึงพวก “C++ หัวแข็ง” “Microsoft หัวแข็ง” “Linux หัวแข็ง” หลายๆคน ผมว่าการมี “ศาสนา” พวกนี้ทำให้เราพลาดอะไรดีๆไปหลายอย่าง

คำแนะนำสำหรับคนอยากเริ่ม

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

หลังจากนั้นก็ต้องเปิดบัญชีซื้อกับโบรคเกอร์ เนื่องจากว่าเราเข้าไปซื้อๆขายๆในตลาดเองไม่ได้ ต้องมี middle-man หรือนายหน้าพวกนี้จัดการให้ โดยเค้าก็จะมีการคิดค่าดำเนินการนิดหน่อย (Commission) เช่น ถ้าซื้อหุ้นราคา 1 บาท จำนวน 1000 หุ้น แบบนี้เราจะต้องจ่ายค่าดำเนินการเพิ่ม 1.5 บาท เป็นต้น รวมเงินที่ต้องจ่ายเป็น 1001.5 บาท

มือใหม่รายย่อยอย่างเราๆก็น่าจะเปิดเป็นแบบ internet trading (อีกแบบคือใช้โทรศัพท์โทรไปหาเจ้าหน้าที่การตลาด หรือเรียกสั้นๆว่า “มาร์” มาจาก marketing) แล้วก็เปิดเป็นบัญชีแบบ Cash Balance คือต้องโอนเงินเข้าไปก่อนจึงจะซื้อหุ้นได้ (เหมือนโทรศัพท์มือถือ Pre-paid) ซึ่งน่าจะปลอดภัยมากกว่า ส่วนบัญชีอีกแบบจะให้ซื้อได้ก่อน แล้วค่อยเช็คบิลทีหลัง

ตอนนี้ก็มีโบรคอยู่หลายๆที่ วิธีเลือกง่ายๆสำหรับมือใหม่คือเลือกโบรคที่ “ไม่คิดค่า commission ขั้นต่ำ” ณ เวลาที่ผมเขียนนี่ค่า commission อยู่ที่ 0.15% หมายถึงถ้าซื้อขาย 100 บาท จะเป็นค่าคอม 0.15 บาท แต่ถ้าหากมีค่าคอมขั้นต่ำ 50 บาท (สมมติ) หลังคำนวณค่าคอมแล้วได้แค่ 0.15 บาทก็จะต้องจ่าย 50 บาทเต็มๆ

อีกอย่างที่ต้องดูคือโปรแกรมสำหรับดูราคาแบบ Real-time ของโบรคมันใช้ได้กับคอมพิวเตอร์ของเรารึเปล่า หลายๆที่ใช้ technology พวก ActiveX นั่นหมายถึงต้องใช้ Windows และ IE เท่านั้นจึงจะใช้ได้ บางที่เช่นที่ผมใช้อยู่ก็จะมีส่วนที่เป็น HTML ธรรมดาให้ใช้เหมือนกัน (สำหรับ Firefox และพวก PDA) ใช้ดูราคา ส่งคำสั่งซื้อขายได้ แต่มันจะไม่ real-time เท่านั้นเอง

ตอนที่ผมเลือกโบรคที่เจ้าที่สนใจอยู่สองที่ คือ KTZmico และ Kim Eng (ไม่ได้ค่าโฆษณานะ) สุดท้ายผมเลือก Kim Eng ด้วยเหตุผลหลายอย่าง หนึ่งในนั้นคือชื่อโดเมนมันพิมพ์ง่ายกว่ามาก! สนนค่าเปิดพอร์ตอยู่ที่ 30 บาทถ้วน ถ้าใครอยากเริ่มผมแนะนำให้เริ่มเตรียมเอกสารเปิดไว้เลย เพราะหลังเปิดแล้วจะช่วยให้ Active ขึ้นมาก

Hope this helps

Tags: , ,

Oct 20 2009

ประชาธิปไตย ต้องถ่วงน้ำหนัก

Category: Generalm3rLinEz @ 23:58

200px-Election_MG_3455

ตอนแรกผม “โยนหินถามทาง” ไปใน Facebook ด้วยหัวข้อ “ประชาธิปไตย ต้องถ่วงน้ำหนัก” ปรากฎว่ามีคนมาคอมเม็นต์สองคน คือทีระพาบ (เป็นไปตามแผน) แล้วก็พี่บอย ในเชิงไม่เห็นด้วย

ผมไม่ค่อยแปลกใจเท่าไหร่ถ้าจะมีคนไม่เห็นด้วยมากมายกับเรื่องนี้ จริงๆแล้วเรื่องนี้ผมก็เคยถกเถียงกับเพื่อนๆด้วยกันมาบ้างก่อนหน้านี้แล้ว ถ้าใครยังเข้าใจคำว่า “ถ่วงน้ำหนัก” ไม่ถูก ผมขอธิบายให้เห็นภาพคร่าวๆดังนี้

  • คะแนน Vote ของกลุ่ม A คิดเป็นคนละ 10 คะแนน
  • คะแนน Vote ของกลุ่ม B คิดเป็นคนละ 1 คะแนน
  • คะแนน Vote ของกลุ่ม C ไม่คิดคะแนน

ประเด็นสำคัญคือ แล้วเราจะเอาหลักเกณฑ์ที่ไหนมาจัด “มนุษย์” ผู้มีสติปัญญาในการตรึกตรองตัดสินใจแต่ละคน มาอยู่ในกลุ่ม A B หรือ C ???

ลองมาดูตัวอย่างง่ายๆพวกนี้ดู

  • ถ่วงน้ำหนักตามการศึกษา - เรียนมาสูง น้ำหนักมากกว่า
  • ถ่วงน้ำหนักตามอายุ อายุ - อายุมาก น้ำหนักมากกว่า
  • ถ่วงน้ำหนักตามประวัติการช่วยเหลือสังคม - ยังไง ???

อย่าแปลกใจถ้าจะไม่เห็นด้วยกับอะไรข้างบนเลย เพราะว่ามันมีปัญหามากมายในการจะนิยามอะไรแต่ละอย่างออกมา -- การศึกษาไม่ได้บอกว่าการตัดสินใจของบุคคลนั้นจะดีกว่า (และไม่ bias) อายุก็เช่นเดียวกัน

ประชาธิปไตยในสังคมอินเทอร์เน็ต ที่ใช้งานอยู่

แนวคิดที่ว่านี้ ผมเห็นที่ StackOverflow.com ซึ่งมันเป็นกระดานถามตอบสำหรับพวกโปรแกรมเมอร์

จุดเด่นที่น่าสนใจสรุปเป็นข้อๆคือ

  • สมาชิกใหม่ที่เข้าไป จะตั้งคำถาม และคำตอบได้เท่านั้น
  • ทุกครั้งที่มีคน “โหวต” ให้ เจ้าของคำถามหรือคำตอบจะได้ “คะแนนความน่าเชื่อถือ” เพิ่ม
  • สมาชิกที่มีคะแนนความน่าเชื่อถือเกิน N1 จะมีสิทธิ์ในการ “โหวต”
  • ความน่าเชื่อถือเกิน N2 มีสิทธิ์ในการแก้ไขข้อความที่คนอื่นเขียน
  • ความน่าเชื่อถือเกิน N3 สามารถ “แจ้งปิด” คำถามได้
  • แจ้งปิดเกิน M1 คน คำถามจะปิดโดยอัตโนมัติ

ผมว่ามันเป็น Model ที่วิเศษมาก เพราะมันสามารถป้องกันสังคมแห่งนี้จาก “สแปม” บนอินเทอร์เน็ตมากมายได้ รวมถึงคำตอบและคำถามดีๆ ก็จะได้รับการ “โหวต” จาก “สังคม” ให้มองเห็นและเข้าถึงได้โดยง่ายอยู่เสมอ

จริงๆแล้วหลักการประเภทโหวตนี่ก็มีใช้กันในเว็บในประเทศเหมือนกัน อย่างเช่นการโหวตความคิดเห็นใน manager, การสั่งปิดกระทู้ / ให้ gift ใน Pantip เป็นต้น

การถ่วงน้ำหนัก กับ ประชาธิปไตยในประเทศไทย

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

"มาตรา 105 บุคคลผู้มีคุณสมบัติดังต่อไปนี้ เป็นผู้มีสิทธิเลือกตั้ง

         (1) มีสัญชาติไทย แต่บุคคลผู้มีสัญชาติไทยโดยการแปลงสัญชาติต้องได้สัญชาติไทยมาแล้วไม่น้อยกว่าห้าปี

         (2) มีอายุไม่ต่ำกว่าสิบแปดปีบริบูรณ์ในวันที่ 1 มกราคมของปีที่มีการเลือกตั้ง และ

         (3) มีชื่ออยู่ในทะเบียนบ้านในเขตเลือกตั้งมาแล้วเป็นเวลาไม่น้อยกว่าเก้าสิบวันนับถึงวันเลือกตั้ง

 

"มาตรา 106 บุคคลผู้มีลักษณะดังต่อไปนี้ในวันเลือกตั้งเป็นบุคคลต้องห้าม มิให้ใช้สิทธิเลือกตั้ง คือ

         (1) วิกลจริต หรือจิตฟั่นเฟือนไม่สมประกอบ

         (2) เป็นภิกษุ สามเณร นักพรต หรือนักบวช

         (3) ต้องคุมขังอยู่โดยหมายของศาลหรือโดยคำสั่งที่ชอบด้วยกฎหมาย

         (4) อยู่ในระหว่างถูกเพิกถอนสิทธิเลือกตั้ง"

 

สงสัยว่าในตอนเริ่มแรก ใครเป็นคนนิยามการ “ถ่วงน้ำหนัก” เหล่านี้ --  ทำไมต้องเป็นคนไทยมาอย่างน้อย 5 ปี -- ทำไมต้อง 18 ปี -- ถูกคุมขังแล้วทำไมถึงเลือกตั้งไม่ได้ – แล้วทำไมพระสงฆ์ต้อง Neutral …

จากที่ผมคุยกับเพื่อนๆ ผมรู้สึกว่า พอพูดเรื่อง “การถ่วงน้ำหนัก” ขึ้นมาทีนึง จุดโฟกัสเราจะพุ่งไปที่ “การไม่เคารพความคิดเห็นผู้อื่น” หรือ “ไม่เท่าเทียมกัน” “ดูถูกชาวนา” จริงๆแล้วเราน่าจะโฟกัสผลประโยชน์ที่จะเกิดขึ้นด้วยว่ามันมีอะไรบ้าง -- การ ซื้อสิทธิ์ ขายเสียง มันก็คือการ “สแปม” ประเทศไทยดีๆนี่เอง

ทิ้งคำถามไว้ให้คิดกันเล่นๆ แล้วถ้าจะตั้งเกณฑ์ให้การ “ถ่วง” เพิ่ม จะตั้งยังไงดี ???

ปล. หลังจากเขียนเสร็จ เพิ่งจะเอะใจ ไปหาคำแนวๆ “Weighted Vote Democracy” ปรากฎว่าเจอหน้านี้ Voting System อ่านคร่าวๆแล้วรู้สึกมีเรื่องน่าสนใจหลายอย่าง ไว้จะไปอ่านต่อ

ปล2. คนที่เค้าเรียนรัฐศาสตร์ หรืออะไรทำนองนี้มา จะมีวิธีอธิบายเรื่องพวกนี้ หรือเข้าใจปัญหาแนวนี้มากกว่ารึเปล่าหว่า

ปล3. ขอขอบคุณบลอกชื่อคล้ายๆกัน “ประชาธิปไตย ต้องเรียนรู้” – แต่ไม่ใช่ว่ะ มันต้องปรับปรุง

ปล4. ผมสนใจการเมืองน้อยมาก ถ้ามี View อะไรอยากเสริม ช่วยคอมเม็นต์มาด้วย :)

Tags: ,

Oct 14 2009

Phantom IFrames

Category: Generalm3rLinEz @ 04:25

ปัญหาคือ อยู่ๆโปรแกรม php ที่ใช้อยู่มันก็มีโค้ด iframe มาแทรกได้ยังไงก็ไม่รู้ ??? เท่าที่ผมเคยอ่านผ่านๆจากเรื่อง ประกาศเลิกใช้ FileZilla ของคุณ Ford Antitrust ก็พอจะทราบความเป็นไปได้อย่างนึงคือว่าการเซฟ password ไว้บนเครื่องก็อาจจะโดนโปรแกรมไม่ถึงประสงค์มาดูด usr/password ไปใช้ในการเอาโค้ดไม่พึงประสงค์พวกนี้มาแทรกไว้ในโค้ดของเราได้

แต่เนื่องจากว่า password ของ account ภาค ตั้งแต่โดนเปลี่ยนมาก็แทบจะไม่มีใครรู้เลย –*- (จริงๆนะ) แล้วเท่าที่ผมทราบคนเดียวที่มี password มันก็ aware เรื่อง security มากจนไม่น่าจะเกิดเรื่องแบบนี้ขึ้นได้

อย่างไรก็ตาม หลังจากไปบ่นๆไว้ใน Facebook เรื่องย้ายบอร์ด แล้วสุดท้ายก็เงียบไป (ยุ่งจัด T-T) ในที่สุดก็มีคนยื่นมือมาแก้ให้ครับ ขอบคุณกอล์ฟไม่เกมไว้ ณ ที่นี่ด้วย เรื่องนี้ ดูเหมือนผมจะลบโค้ด iframe ออกไม่เกลี้ยง =_=’ เพราะตอนลบจะเลือกลบเฉพาะไฟล์ที่ “น่าจะ” โดนโหลด อันนี้เป็นนิสัยเสียของผมเองที่เวลาจะลองอะไรจะลองแบบ minimal เสมอ พอแก้เพิ่มแล้วไม่เห็นว่าผลมันดีขึ้นก็จะเลิกทำซะงั้น ..

ของแบบนี้ต้องยกให้คนมีกระสบการณ์จริงๆ :)

GolfB

Tags: , ,

Sep 27 2009

ปัญหาภาษาไทยกับ iTunes และ Windows

Category: .NETm3rLinEz @ 12:58

เป็นปัญหาเดียวกับเรื่องภาษาไทยเป็นตัวยึกยือ มันเกิดจากข้อมูลใน ID3 Tag (เป็นส่วนของไฟล์ที่ไว้บอกข้อมูลเกี่ยวกับเพลง) มันเก็บภาษาไทยโดยใช้ Encoding แบบนึง (มักจะเป็น Windows-874 / TIS620 ซัมติง …)

MP3TagProblem

อ่านหาวิธีแก้ตามเว็บบอร์ดชุมชนคนไทยก็พบวิธีแก้ง่ายๆอย่างนึงคือต้องไปเปลี่ยน Regional Settings ให้เป็นไทยหลายๆอัน แล้วจะดิสเพลย์ได้ถูกต้อง o__O! แล้วค่อยใช้ iTunes convert ID3 ให้กลายเป็นเวอร์ชันใหม่ๆ (ที่จะเป็น unicode รองรับหลายภาษา)

การทำแบบนี้มันก็มีปัญหาอยู่บ้าง เพราะพอเปลี่ยน Regional แล้วก็จะทำให้ไม่รู้ว่าอัลบั้มไหน convert ID3 ไปเรียบร้อยแล้วรึยัง (เพราะมันแสดงได้ถูกต้องทั้งหมด) อย่างตอนนี้ผมลง OS ใหม่เป็น Windows 7 อัลบั้มเก่าๆเน่าไปหลายอันอยู่ … ก็เลยเขียนโปรแกรม convert ดีกว่า! (นั่น …. หาเรื่องเขียนบลอกอะดิ๊ๆๆๆๆ)

ประเด็นสำคัญ

  • Tool สำหรับแปลง ID3 ที่เป็น encoding หนึ่งไปอีกอันนึงก็มีอยู่แล้วบ้าง แต่ส่วนใหญ่มักจะเป็นบน Linux กับ Mac หาของ Windows ไม่เจอ (หรือผมอาจจะตาถั่วเอง)
  • ใช้ Lib สำหรับอ่าน ID3 คือ TabLig Sharp
  • ใช้ Reflection ในการวนรอบ property ทุกอันที่เป็น string และ string[] เป็นครั้งแรกที่เริ่มเห็นคุณค่าของ relfection!
  • พอมันมี Library ภายนอกก็เลยมี DLL หลายอัน รวมให้เป็น EXE อันเดียวโดยใช้ ILMerge จะทำให้ ship ง่ายกว่า (แต่ยังไม่คิดจะ ship รอให้มี demand ก่อน ฮ่าๆ)
  • อันตรายมาก: ยังไม่มีวิธีเช็คเลยว่าไฟล์ไหนถูกแปลงไปแล้วบ้าง เพราะถ้าแปลงซ้ำกันสองครั้งมันจะทำให้เนื้อหาไฟล์พังไปเลย >_< โดนไปหนึ่งดอกเรียบร้อย
  • ตอนนี้ใช้ iTunes โดยให้มัน Consolidate Library แล้ว รู้สึกทำให้ย้ายของง่ายกว่า
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;

namespace ID3ConvertToUnicode
{
class Program
{
public static string FixThaiCodePage(string str)
{
if (str == null) return null;
byte[] raw = Encoding.Default.GetBytes(str);
string res = Encoding.GetEncoding("windows-874").GetString(raw);
return res;
}

public static string[] FixThaiCodePage(string[] strings)
{
string[] res = new string[strings.Length];
for (int i = 0; i < strings.Length; i++)
{
res[i] = FixThaiCodePage(strings[i]);
}
return res;
}

static void Main(string[] args)
{
string[] files = Directory.GetFiles(".");
foreach (string file in files)
{
if (!file.EndsWith(".mp3"))
continue;

Console.WriteLine("Converting: " + file);
TagLib.File music = TagLib.File.Create(file);

foreach (PropertyInfo pinfo in music.Tag.GetType().GetProperties())
{
if (!pinfo.CanRead || !pinfo.CanWrite)
continue;

if (pinfo.PropertyType == typeof(string))
{
string s = pinfo.GetValue(music.Tag, null) as string;
s = FixThaiCodePage(s);
pinfo.SetValue(music.Tag, s, null);
}

if (pinfo.PropertyType == typeof(string[]))
{
string[] s = pinfo.GetValue(music.Tag, null) as string[];
s = FixThaiCodePage(s);
pinfo.SetValue(music.Tag, s, null);
}
}
music.Save();
Console.WriteLine();
}

}
}
}

ilmerge /target:winexe  /out:ID3Retag.exe 
ID3ConvertToUnicode.exe policy.2.0.taglib-sharp.dll taglib-sharp.dll

iTunesThaiFixed

ยอดเยี่ยม!

Tags: , , ,

Sep 20 2009

Remote Debugging J2EE Application

Category: Java | Toolsm3rLinEz @ 12:04

ตั้งชื่อบลอกไม่ถูก คำศัพท์ Java มันเยอะจัด (J2EE, Web Container, Servlet, ...)

ฐานโค้ดที่ผมดูอยู่ที่ทำงานมันค่อนข้างใหญ่มาก เป็นไฟล์ Text ขนาดรวมกันเกือบ 20 MB ซึ่งจริงๆแล้วส่วนที่เราจะเข้าไปมองจริงๆมันก็ไม่ได้เยอะอะไรหรอกครับ แต่ปัญหาก็คือว่า เราจะหาส่วนที่เราต้องการมาได้ยังไงจากข้อมูลที่เยอะขนาดนั้น ??? คำตอบหนึ่งคือใช้โปรแกรมพวก Cross Referencing เช่น OpenGrok จะช่วยให้ค้นหาส่วนของโค้ดที่ต้องการได้ง่ายขึ้นเยอะเลย นอกจากนี้ OpenGrok ยังสนับสนุนการทำ index บน repository ของพวก SCM Tools ต่างๆเช่น SVN, Git และ Mercurial อีกด้วย

เข้าเรื่อง … ปัญหาที่ผมเจอคือ OpenGrok มันดันไม่โชว์ History ให้ ซึ่งหลังจากถามไปใน mailing-list ก็พบว่ามันเกิดจากการหาโปรแกรม hg (Mercurial) ไม่เจอใน PATH ผมลองมา reproduce ที่บ้านบน environment ที่เป็น Windows ก็ยังเจอปัญหาเดียวกันอยู่ เลยต้องหาวิธี Debug OpenGrok ตอนนั้นคิดๆไว้หลายวิธี

  • Build เฉพาะ Class ที่ทำหน้าที่ส่วนนั้นขึ้นมาใหม่ แล้วใส่ให้มันโหลดขึ้นก่อนใน CLASSPATH  .. อันนี้สุดท้ายก็ทำไม่ได้เพราะผม build เป็นไฟล์ๆไม่ได้มันติดพวก dependency เลยไม่รู้ว่าสรุปแล้วใช้วิธีนี้ได้ป่าว
  • อ่านวิธี Build OpenGrok จากเว็บมันแล้วลองตั้ง breakpoint ตรงส่วนที่เป็นปัญหา อ่านแล้ววิธีนี้น่าจะง่าย แต่เนื่องจากว่าตัว Container ที่ใช้มันเป็น Tomcat แต่ปกติ Netbeans มันจะติดมากับ Glassfish เลยเกิดความขี้เกียด config ขึ้นมาในบัดดล
  • ทำ Remote Debugging คือ start Tomcat ใหม่ให้มันรันแบบ Debug และเปิด port 7001 รอไว้ แล้วเอา Debugger เข้าไป attach … อันนี้ได้ผลครับ และง่ายมากด้วย แต่ต้อง build OpenGrok ได้น่ะ หลังจากตั้ง breakpoint ไว้แล้วปรากฎว่ามัน break จริงๆด้วยว่ะ! Watch + Evaluate ได้แทบทุกอย่างเลย

จริงๆ ASP.NET ก็มีของแบบนี้เหมือนกัน มันเหมาะมากเวลาเกิดปัญหากับ Application ใหญ่ๆที่การ Setup ให้เกิดปัญหาเดียวกันมันยาก ใช้แล้วก็รู้สึกว่า Java ก็ไม่เลวครับ : )

Java Options สำหรับ Start Tomcat

-Xdebug
-Djava.compiler=NONE
-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7001

แล้วใช้ Netbeans attach เข้าไปที่ port 7001 ของ localhost

Tags: , , , , ,

Sep 13 2009

จบโค้ดแยม 2009

Category: Generalm3rLinEz @ 02:25

สรุปว่า Round 1 ปีนี้ทำถูกจริงๆและได้คะแนนแค่ 1 ข้อครับ =_=’  แล้วก็มีอีกข้อที่ถ้าส่งทันน่าจะผ่าน 1B ไปแล้ว ต้องยอมรับว่ายังอ่อนซ้อม Python อยู่มาก ไปหาวิธีดีบักที่ไหนมาก็เจอแต่เรื่อง pdb   จริงๆผมอยากได้หน้าต่าง immediate, watch แบบ Visual Studio อ่ะ ตอนแข่งนี่ก็เลยใช้ VIM + printf debugging กว่าจะหาสาเหตุแต่ละอย่างเจอก็เหนื่อย แถมเจอแล้วเป็นเรื่องผิดแบบโง่ๆอีก +_+ อาทิเช่นลืมหารตอนสุดท้าย หรือว่า copy input file มาไม่ครบ

สิ่งที่ได้มามากที่สุดก็คงเป็นเรื่อง Python ที่รู้จักเยอะขึ้นในหลายแง่มุม ภาษามันเหมาะกับการเอามาเขียนอัลกอซับซ้อนมากเลยนะ เพราะเขียนแล้วอ่านง่าย บางคนถึงกับยกให้เป็น Executable pseudo code เลยทีเดียว จนบางทีผมรู้สึกว่าพอเอามาใช้เขียนพวก Web App ง่ายๆแล้วมันจะได้ใช้ “ข้อดี” ของภาษานี้อย่างเต็มที่รึเปล่า ??

พรุ่งนี้รอบ 4 โมงเย็นคงไม่ได้เล่นเพราะต้องไปเที่ยว โอกาสผ่านเข้ารอบนี้น่าจะสูงเพราะพวกเคี่ยวๆก็ผ่านไปใน 1A กับ 1B หมดแล้ว ปีหน้าเจอกันใหม่ฮะ สวัสดีคุณโค้ดแยม =)

ปล. รอบ Qualify นี่สนุกสุดแล้ว

Tags: , , ,

Sep 4 2009

เฉลยกูเกิ้ลโค้ดแยม : รอบคัดเลือก 2009

Category: Generalm3rLinEz @ 09:19

ยังคงคอนเซ็ปต์เดิม ว่าต้อง “แยม” ไม่ใช่ “แจม” (ผมอยากกวนตรีนราชบัณฑิตอ่ะ ไม่มีไรหรอก - -‘’)

ปีก่อนลุยด้วย C# ปีนี้ลุยด้วย Python แทนครับ ผมชอบความเรียบง่ายของภาษานะ แต่ตอนนี้ติดอยู่ที่ไม่รู้จะ Debug ยังไงให้มันง่ายๆ อยากให้เหมือน C# แบบที่พอ Break แล้วจะพิมพ์โค้ดอะไรเข้าไปทดสอบ (ในหน้าต่าง Immediate) ก็ได้ ใครรู้บอกที

Alien Language

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

Edit: แอบไปดูโค้ดรุจมา ใช้วิธีเปลี่ยน ( กับ ) เป็น [ กับ ] แล้ว treat as regex เลย … อึ้ง

import re

if __name__ == '__main__':
#in_filename = "A-small.in"
#in_filename = "A-dummy.in"
in_filename = "A-large.in"
#out_filename = "A-small.out"
out_filename = "A-large.out"

in_file = open(in_filename, 'r')
out_file = open(out_filename, 'w')

L,D,num_cases = [int(x) for x in in_file.readline().split(' ')]

# Read the dictionary
words = []
for i in range(0,D):
words.append(in_file.readline())


for c in range(0,num_cases):
# Clone a list
ws = words[:]
s = in_file.readline()
clues = re.findall('(\([a-z]+\)|[a-z])',s)
#print clues
for k in range(0,len(clues)):
ws = filter(lambda x: clues[k].find(x[k]) != -1, ws)
out_file.write("Case #%d: %d\n" % (c+1, len(ws)))

out_file.close()


Watersheds

ผมคิดว่าข้อนี้ยากที่สุดสำหรับปีนี้แล้ว โจทย์มันคล้ายๆกับการเทสีใน Paint คือจะใช้ floodfill ทำก็ได้ (มีตัวอย่างโค้ด Floodfill ภาษา Java ที่บลอกภาษาอังกฤษ)  หรือใช้วิธีอื่นก็ได้ อย่างที่ทำครั้งนี้เป็นการแสกนดูก่อนว่าจุดไหนบนแผนที่เป็นกลุ่มเดียวกันบ้าง (คล้ายๆเรื่อง Disjoint Set) แล้วค่อยทำการ Assign ตัวอักษรให้ใหม่ โปรแกรมนี้เขียนเละๆ และดีบักนานมากกก อาจจะเพราะไม่ได้เขียนนานแล้วแล้วก็ยังไม่ค่อยคุ้นกับวิธี Debug ใน Python ด้วย ใช้ “Printf Debugging” ตลอด ฮะๆ

import re
import sys

if __name__ == '__main__':
#in_filename = "B-small.in"
#in_filename = "B-dummy.in"
in_filename = "B-large.in"
#out_filename = "B-small.out"
out_filename = "B-large.out"

in_file = open(in_filename, 'r')
out_file = open(out_filename, 'w')

num_cases = int(in_file.readline())
for c in range(0,num_cases):
H,W = [int(x) for x in in_file.readline().split(' ')]
map = []
for h in range(0,H):
map = map + [int(x) for x in in_file.readline().split(' ')]
label = range(0,H*W)
assoc = [-1]*H*W

for h in range(0,H):
for w in range(0,W):
cursor = h*W + w
min = sys.maxint
way = -1

pos1 = (h-1)*W + w
if h != 0 and map[pos1] < min:
min = map[pos1]
way = 1

pos2 = h*W + w - 1
if w != 0 and map[pos2] < min:
min = map[pos2]
way = 2

pos3 = h*W + w + 1
if (w + 1) < W and map[pos3] < min:
min = map[pos3]
way = 3

pos4 = (h + 1)*W + w
if (h + 1) < H and map[pos4] < min:
min = map[pos4]
way = 4

# If is Sink
if min < map[cursor]:
if way == 1:
assoc[label[cursor]] = label[pos1]
elif way == 2:
assoc[label[cursor]] = label[pos2]
elif way == 3:
assoc[label[cursor]] = label[pos3]
elif way == 4:
assoc[label[cursor]] = label[pos4]

# Do paths compression
#print "Before", assoc
for ind in range(0,len(assoc)):
next = assoc[ind]
last = next
while next != -1:
last = next
next = assoc[next]
assoc[ind] = last
#print "Compress", assoc

# Final relabel
out_file.write("Case #%d:\n" % (c+1))
char_map = {}
running = ord('a')
for h in range(0,H):
for w in range(0,W):
cursor = h*W + w
if assoc[label[cursor]] != -1:
label[cursor] = assoc[label[cursor]]
if label[cursor] not in char_map:
char_map[label[cursor]] = running
running = running + 1

#print label[h*W:h*W + W]
out_file.write(' '.join([chr(char_map[x]) for x in label[h*W:h*W + W]]))
out_file.write('\n')


out_file.close()


Welcome to Code Jam

ดูเหมือนอันนี้จะง่ายกว่าข้อสอง ใช้ Dynamic Programming แก้ เป็นตารางขนาด len(‘welcome to code jam’) x len({text}) แต่ละแถวคือจำนวนคำตอบที่จบด้วยตัวอักษรที่คู่กับแถวนั้น  ปกติพวกโค้ด DP จะอ่านไม่ค่อยรู้เรื่องอยู่แล้วเพราะมันเป็นการเอาความสัมพันธ์เวียนเกิด (Recursion) ใน math มาเปลี่ยนเป็นโค้ด o__o’’

เข้าใจว่าข้อนี้ถ้าแก้ด้วย Brute force ก็น่าจะทันเวลา (ล่ะมั้ง) วิเคราะห์ไม่เป็นแล้ว :-o

Edit: คะแนนออกแล้วปรากฎว่า ลืมไปบรรทัดนึง ตรง answer = reduce( …. ต้องเปลี่ยนเป็น answer = reduce(..) % 10000 สะเพร่าเสมอต้นเสมอปลาย - -‘’

w, e, l, c, o, m, e,  , c, o, d, e,  , t, o,  , c, o, d, e,  , j, a, m,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 6, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0


import re
import sys

if __name__ == '__main__':
#in_filename = "C-small.in"
#in_filename = "C-dummy.in"
in_filename = "C-large.in"
#out_filename = "C-small.out"
out_filename = "C-large.out"

in_file = open(in_filename, 'r')
out_file = open(out_filename, 'w')

num_cases = int(in_file.readline())
for case in range(0,num_cases):
text = in_file.readline()
sen = "welcome to code jam"
W = len(text)
H = len(sen)
tab = [0]*W*H
for r in range(0,H):
sum = 0
for c in range(0,W):
cursor = r*W + c
if r == 0 and text[c] == sen[0]:
tab[cursor] = 1
else:
sum = (sum + tab[(r-1)*W + c]) % 10000
if text[c] == sen[r]:
tab[cursor] = sum
#print tab[r*W:r*W+W]

# Sum last row
answer = reduce(lambda x,y: x + y, tab[(H-1)*W:H*W])
print "Case #%d ..." % (case + 1)
out_file.write("Case #%d: %04d\n" % ((case+1), answer))
#print '-'*80
out_file.close()


เมื่อคืนนอนเร็วมากด้วยความอ่อนเพลีย เลยได้ตื่นมาเล่นตั้งแต่ 6 โมงเช้าครับ เขียนไปเรื่อยๆจน 9 โมง ติดข้อสองนานมากกกก

ปีนี้รู้สึกไม่ค่อยมีคน Active มาเล่นด้วยเท่าไหร่ คนรุ่นเดียวกันสงสัยจะทำงานไม่มีเวลาว่างกลับมาก็เหนื่อยแล้วล่ะมั้ง วันนี้ระหว่างวันก็ไม่ได้ยุ่งกับ Code Jam ได้แต่เปิด Score board มามองตาปริบๆ แล้วก็แอบๆทดเลขลงกระดาษไปพลางๆ พอดีวันนี้งานเข้าซะด้วย ฮือๆ รู้สึกนายแท็ปก็จะคล้ายๆกัน

ครั้งนี้ได้ใช้ Python คล่องมือขึ้นเยอะ (แต่ยังไม่รู้จะเอาไปทำอะไรดี .. อ้ะ) มีอะไรแนะนำผมคอมเม็นต์มาได้เลยนะครับ ^ ^ ยังเป็นมือใหม่อยู่ เพื่อนๆที่ทำด้วยกันลองเอาโค้ดขึ้นบลอกมาแบ่งกันดูด้วยก็ดี อยากเห็นวิธีของคนรอบตัวมากกว่าอยากเห็นวิธีของฝรั่ง/คนจีนในเน็ต : )

Edit: มีคนทักเรื่อง DP มาเยอะ (สองคนถ้วน o__o) จริงๆแล้วส่วนใหญ่โจทย์ที่เป็น DP ส่วนใหญ่มันจะ

  • เป็นโจทย์พวก Optimization เช่นหาน้อยที่สุด แพงที่สุด จำนวนมากที่สุด ระยะทางสั้นสุด
  • เป็นโจทย์ที่คำตอบของปัญหาใหญ่ๆมักจะคำนวณได้จากปัญหาเล็กๆ เช่น factorial, fibonacci, …
  • เวลาไม่รู้จะทำยังไงแล้ว (ฮ่าๆ)

อย่างข้อ 3 นี่ สมมติว่าให้ text มาเป็นคำว่า “d d o o o g d d” และให้หาคำว่า “d o g”

  • แถวแรก (คู่กับตัว d) จะแทนจำนวน seq ที่เป็นไปได้ที่ลงท้ายด้วยตัว d นั่นก็คือตำแหน่งที่เป็นตัว d จะเป็น 1 ส่วนที่อื่นเป็น 0
    ได้ 1 1 0 0 0 0 1 1
  • แถวที่สอง (คู่กับตัว o) เป็นจำนวน seq ที่ลงท้ายด้วย o คือ “d o” ช่องที่จะเป็นไปได้ก็คือช่องที่เป็นตัว o เท่านั้น แต่จะมีจำนวนเท่าไหร่ก็ขึ้นกับว่าก่อนหน้าตัวมันเองมี seq “d” ให้ใช้ทั้งหมดกี่อัน ทำได้โดยการเอาแถวข้างบนบวกกันจนถึงตัวมันเอง
    ได้ 0 0 2 2 2 0 0 0
  • แถวที่สาม (คู่กับตัว g) ทำแบบเดียวกับแถวสอง คือเติมเฉพาะช่องที่เป็น g และนับจำนวน seq ก่อนหน้าที่เป็น “d o”
    ได้ 0 0 0 0 0 6 0 0
  • เอาแถวสุดท้าย sum ทั้งแถว ได้จำนวนรูปแบบทั้งหมดที่เป็นไปได้

Tags: , , ,

Aug 30 2009

เขียนโค้ดละลายแม่น้ำ

Category: Directionm3rLinEz @ 10:19

ตั้งแต่เริ่มทำงานมา ตามลักษณะงานที่มันเป็นการเขียนโปรแกรมสั้นๆอยู่แล้วซึ่งส่วนใหญ่ก็เป็นการดัดแปลงโปรแกรมตัวอย่าง ทำให้ผมเขียนโค้ดน้อยลงอย่างมากเทียบกับสมัยเรียน (เลยต้องมาระบายอารมณ์ตามบลอกตามที่ท่านเห็น ฮะๆ)

ปัญหาที่ผมสังเกตเกี่ยวกับตัวเองคือ โปรแกรมจำนวนมากที่เคยเขียนในสมัยเรียนมันหายไปไหนหมดก็ไม่รู้! ตัวอย่างโปรเจคที่ “ละลายโค้ด” จำนวนมากลงไป เช่น

  • โค้ดสมัยเรียนค่ายโอลิมปิก
  • โปรแกรมรายรับรายจ่ายง่ายๆบน Windows Mobile และโปรแกรมอื่นๆที่เคยส่ง บ.สามารถ
  • โปรแกรม ChemLive! ที่ส่ง MS Imagine Cup
  • โปรเจควิชา Database + Software Engineering ที่คณะ
  • โปรเจคที่เคยส่งงาน RFID ของ NECTEC
  • โปรเจคย่อยๆมากมายในวิชาเรียนอื่นๆ เช่น Fund Dist, Computer Security, Operating System, Computer Graphics, Image Processing, ..

ถ้าถามถึงโปรเจคทั้งหมดที่ยกมา ผมแทบ “จำไม่ได้” เลยว่าทำอะไรไปบ้างและได้อะไรมาบ้าง งานที่ทำไปบางชิ้นเอาไปวางไว้ที่ไหนก็ไม่รู้เหมือนกัน

มานั่งคิดๆดู มันก็มีหลายปัจจัยที่ทำให้งานที่เคยใช้เวลาทำมาไม่มีประโยชน์อะไรในตอนนี้ เช่น

  • ผมไม่มั่นใจในงาน งานบางอันที่ต้อง “รีบปั่นรีบส่ง” หลังงานเสร็จ ผมจะคิดในใจ (ดังๆ) ว่า “ของมันไม่ดีจริง” แล้วหลังจากนั้นถ้ามีโอกาสอะไรที่จะเอาไป “ต่อยอด” งานได้ ผมจะรู้สึกหวั่นๆ เหมือนกำลังโดนจับผิด หลายครั้งมีโอกาสดีๆเช่น บ.ข้างนอก อยากให้เอาโปรแกรม ChemLive! ไปทำต่อ ผมก็ (น่าจะ) เป็นคนเดียวในทีมที่ไม่สบายใจเอาซะมากๆ ผมไม่อยากแบกรับภาระจากการซ่อมบำรุงงานที่ผมไม่มั่นใจ งานบางชิ้นในลักษณะนี้ก็เลยหายไปจากสารบบโดยปริยาย –..-‘’ เป็นนิสัยเสียที่น่าจะโดนเพื่อนๆร่วมทีมว่าอยู่เยอะเหมือนกัน
  • งานไม่มั่นใจในผม หลายครั้งการเอางานที่เราคิดว่า “นี่ทำมาดีมากแล้วนะ” ไปส่งประกวด แล้ว Feedback จากกรรมการมันไม่เป็นไปอย่างที่คิด มันก็ทำให้เสียกำลังใจและพาลไม่อยากทำต่อได้ครับ ตัวอย่างที่เข้าเคสนี้คือโปรแกรม RFID ที่ค่อนข้างจะทุ่ม effort กันสูงมากทั้งทีม แต่มีปัญหาเรื่องการนำเสนอ (อ่านต่อที่ “การนำเสนอสำคัญกว่าโค้ด”)
  • ผมกำลังทำการบ้านส่ง ผมไม่ได้เขียนโค้ด อันนี้เป็นพวกโปรเจคในคณะ ที่ส่วนใหญ่จะมีเดดไลน์และ scope ชัดเจน มันต่างจาก “ปั่นส่ง” ในข้อแรกตรงที่ งานในลักษณะนี้ มันเป็น “ปั่นส่ง” จากเริ่ม คือก็ทำให้เสร็จๆไปงั้น แต่ในเคสแรกตอนแรกอาจจะทำด้วยความสนุก แต่ตอนหลังโดนบีบให้ปั่น พอส่งเสร็จก็ลืมไปเลยว่าเคยทำ เช่นพวก Database หรือ Software Engineering

จวบจนสองโปรเจคสุดท้ายก่อนเรียนจบ คือ Game Programming กับ Senior Project  ผมก็รู้สึกว่าได้สร้าง “คุณค่า” ไว้พอสมควร

อย่างแรกคือ Game Programming ผมไม่รู้สึกว่าโค้ดตัวเองที่เขียนร่วมกับเพื่อนๆอีก 2 คนมัน “เละ” ถ้ามีโอกาสให้กลับไปทำโปรเจค Ogre อีกรอบนี่จะเป็นที่แรกที่ผมกลับไปดู :) 

ส่วน Senior Project ถึงแม้ผลลัพธ์มันจะออกมาไม่ดีเท่าไหร่และได้ชมเชยใน NSC แต่ผมก็รู้สึกว่าได้ตั้งใจทำเต็มที่แล้ว และทุกอย่างที่ทำทุกวันนี้ก็เข้าถึงได้โดยง่ายเพราะเอาไปวางไว้บน Project Hosting หลายครั้งยังต้องเข้าไปดู Code C++ ที่ตัวเองเขียนอยู่เลย (เพราะบางทีจำไม่ได้ว่าเขียนยังไง - -‘’)

ผมมีแนวทาง (ที่ตอนนี้ใช้อยู่เอง) ในการเพิ่ม “คุณค่า” ให้โปรแกรมที่เขียนดังต่อไปนี้

    1. พยายามทำให้ Source Code ที่เขียนและงานที่ทำเข้าถึงง่ายที่สุด สมัยนี้มีเว็บประเภท Project Hosting ให้ใช้เยอะแยะ ทั้ง Git Hub, Google Code, Code Plex, Source Forge (แต่ก่อนประเทศไทยมี Code Bank ด้วย แต่ไม่รู้เจ๊งไปรึยัง)
    2. จดบันทึกสิ่งที่ทำอยู่ ไม่ต้องละเอียดมาก (แต่ก็อย่าแย่ถึงขั้น “โอ้ววว ไพธอนหล่อแสรดดด” –..-‘a) เอาแบบไว้อ่านคนเดียวก็ได้ จะ Tweet หรือจะ Blog ก็น่าจะเวิร์คเหมือนกัน อันนี้จะเหมือนการ Document ตลอดเวลา แล้วตอนหลังเวลาติดปัญหาเดียวกันจะได้กลับมาดูได้ นอกจากนั้นอาจจะได้วิธีการที่ดีกว่าเดิมจากเพื่อนๆที่มาอ่านอีก (แนะนำวิธีจด)
    3. วิ่งเข้าหาสิ่งใหม่ๆให้บ่อยๆ ในงานที่ทำเล่นๆหรือที่เดดไลน์มันไม่บีบคั้นมาก ลอง “เลือก” อะไรที่มันแตกต่างจากเดิม (และดูดีมีอนาคต :P) มาลองบ้างดีมั้ย?? สมัยนี้มีพวก Framework, Libraries, ภาษาใหม่ๆ ให้ลองใช้เยอะแยะ
    4. อย่าปั่นงาน ..ทำยากโคดว่ะ

ขอให้สนุกกับการเป็นนักเขียนโค้ด “เชิงคุณค่า”

Tags: , ,