Feb 21 2010

ทำไมคนเราถึงเกลียดภาษาอื่นๆ

Category: Generalm3rLinEz @ 09:02

แน่นอน ภาษา Programming นะครับ ไม่ใช่ จีน ญี่ปุ่น อังกฤษ :P

ไปเจอคำถามนี้และคำตอบที่น่าสนใจมาก ว่าการเกลียดภาษาอื่นๆมักจะแบ่งเป็น 3 แบบ

เกลียด เพราะได้ยินข่าวลือแย่ๆมา เช่น

  • “Ruby ช้า เขียนแล้วโค้ดสวยก็จริงแต่ทำงานช้าโคดๆ”
  • “เขียน VB, C#, .NET แล้วโง่ เอะอะอะไรก็ลากแปะ”
  • “Java ช้า”
  • “C++ มีแต่ไดโนเสาร์เขียน”

พวกนี้ส่วนใหญ่พอได้ยินข่าวลือพวกนี้มาจาก forums หรือเว็บข่าว ก็มักจะฝังใจแล้วบอกต่อๆกัน แต่ก็ไม่เคยลองเอง และก็ไม่รู้ว่ามันไม่ดีตามที่บอกรึเปล่า

เกลียด เพราะใช้แล้วไม่พอใจ

พวกนี้เคยใช้จริง แล้วไม่พอใจจริง ซึ่งอาจเกิดจากสาเหตุ เช่น

  • โดนหัวหน้า อาจารย์ เจ้านาย บังคับให้ทำ ซึ่งทำแล้วปรากฎว่าใช้แล้วได้ผลไม่ดี (อาจจะแบบว่าใช้อย่างอื่นแล้วเหมาะกว่า เช่น เคยเอา C++ ไปเขียน Web App) ก็เลยไม่ชอบ
  • ใช้แล้วมัน “ไม่ใช่ว่ะ”
  • ไม่ค่อยมีข้อมูลในการใช้เรียนรู้ หรือ learning curve ชันไป

เกลียด โดยหลักการ

ไม่ชอบลักษณะ / คุณสมบัติ บางอย่างของภาษา โดยอาจจะรู้สึกว่าภาษาหนึ่งดีกว่าอีกภาษา ตรงที่ … เช่น

  • “ไม่ชอบ Java เพราะต้องทำงานบน JVM  … มันไม่ถูกต้องนะ! เขียน C++ แล้วให้ compile เป็น native สิ!” -- คลั่ง C++
  • “ไม่ชอบ C++ เพราะต้องมารับผิดชอบการเขียนให้มัน cross platform เอง ต้องมาเช็ค #ifdef เบื้อกอะไรตั้งมากมาย แล้วต้องมาเรียนรู้ platform-specific system calls เอง เฮ้อ” -- ผมเขียน Java
  • “ไม่ชอบ Java เพราะ syntax มันช่างบุโรคั่งและยืดเยื้อ รวมถึงแคร์เรื่อง backward compatibility เหลือเกิน ไม่ Elegant เหมือนภาษาผมเอาซะเลย” -- ผมเขียน C#

ส่วนตัวผมมีประสบการณ์กับการไม่ชอบทั้ง 3 แบบ

แบบ 1 สมัยเด็กๆผมรู้สึกว่า VB 6 ดูดีมีอนาคตกว่า VC++ มากๆ เพราะแค่ new project ใหม่ก็ได้ Window เปล่าๆมาอันนึงแล้ว ส่วน VC++ ต้องเขียนโค้ดเองกว่า 80 บรรทัดกว่าจะได้หน้าต่างว่างๆมา ผมก็เลยไม่เข้าใจอย่างยิ่งว่าทำไมคนถึงยังชอบไปเขียน C++ กัน ประกอบกับเจอพวก C++ หัวแข็งมากมายใน forum ดังสมัยนั้น (thaidev.com) ซึ่งบางที task VC++ บางอย่างที่มาถามๆกันในเว็บบอร์ด ผม “Thinking in VB 6” พรืดเดียวก็ออกแล้ว ผมจึงไม่ชอบ C++ และเป็นผู้ ไม่สนับสนุน อย่างเป็นทางการ ตั้งแต่นั้น

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

แบบ 2 ผมเกลียด C บน Microcontroller มากๆครับ! เนื่องจากว่ามันเป็นภาษาที่ค่อนข้างพิกา… เอ้ย จำกัด ไม่สามารถใช้ประโยชน์ของ C ได้อย่างเต็มที่, call stack ก็มีขนาดจำกัด แล้วยังมี bahavior ที่คาดเดาไม่ได้อีกหลายอย่าง (ขนาดผมเขียน C แบบพื้นฐานมากๆแล้วนะ) ประกอบกับผมขาด resource (เวลา + ฮาร์ดแวร์ที่ใช้เบิร์นโปรแกรมลงบอร์ด) ทำให้สุดท้ายผลมันออกมาไม่ดี แล้วก็มีเรื่องไม่ดีมากตามมาอีกหลายอย่าง (เพื่อนสนิทรู้กัน - -‘’) ผมเลย “พาล” เกลียด C บน Micro แบบฝังใจไปเลยจนทุกวันนี้

เปรียบเทียบกับประสบการณ์เดียวกันบน Verilog (มันใช้งานละแบบกันน่ะ แค่เป็น hardware เหมือนกันเลยเอามาเทียบ) ผมประทับใจมากกก

แบบ 3 ถ้าจะมีคงเป็น PHP ซึ่งตอนนั้นผมขยับจาก ASP ไปเป็น ASP.NET พอดี สมัยนั้น ผมดูภาษามันแล้วรู้สึกว่าวิธีการ extends ภาษาด้วยการลง mod เพิ่มมันดูพิลึกๆ (มาก) แล้วก็ยังมีเรื่องต้อง compile คู่กับ MySQL lib ให้ตรงเวอร์ชันอีกไม่งั้นจะใช้ด้วยกันไม่ได้ ก็เลยไม่คิดจะศึกษาเพิ่มเติมนอกจากเขียนอะไรง่ายๆที่สมัยนั้นคนชอบเขียนกัน (Counter, Webboard, GuestBook) ซึ่งการไม่ศึกษา PHP ทำผมเสียโอกาสไปเยอะพอควร

เอาจริงๆผมไม่ค่อยเกลียดอะไรในระดับนี้เท่าไหร่นะ ด้วยเหตุผลที่ว่า ภาษาไหนที่มันไม่ดังผมก็จะไม่ค่อยสนใจ แล้วภาษาที่ดังขึ้นมาได้ก็แปลว่ามันผ่านกระบวนการ natural selection และมันโดนทดสอบด้วย “เวลา” มาระดับนึงแล้ว มันก็คงมีข้อดีของมันแหละ

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

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

Tags:

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 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 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 29 2009

เฉลยกูเกิ้ลโค้ดแยม : Fly Swatter

Category: Generalm3rLinEz @ 00:41

ในบรรดาโจทย์ปี 2008 คิดว่าข้อนี้น่าจะยากที่สุดครับ แอบเถื่อนนิดหน่อยตรงที่มันใช้ Math พอสมควร ใจความหลักของโจทย์ข้อนี้คือ “จะหาพื้นที่ที่ตัดกันระหว่างวงกลมกับสี่เหลี่ยมได้ยังไง” ซึ่งมันก็มีหลายวิธี

  • ทำ Computer Integration วิธีนี้ผมใช้ตอนปีก่อน อารมณ์ประมาณซอยเป็นสี่เหลี่ยมคางหมูหลายๆอันให้ถี่ๆ ก็จะใช้ประมาณพื้นที่ได้ โจทย์บอกว่าคำตอบต้องละเอียดถึง 1e-6 ก็ต้องแบ่งให้ถี่ๆแบบสัมพันธ์หน่อย เหมือนวิธีนี้จะเรียกผลรวมรีมันด์อะไรซักอย่าง จำไม่ได้ล่ะ (ได้แคลคูลัส C)
  • ทำ Integrate รูปปิด ประมาณว่าหาสูตรคำนวณพื้นที่นั่นเอง หลังจากนั้นก็เอาขอบเขตมาแทนค่าพร้อมกับตัดเติมลบอีกนิดหน่อย ก็จะได้พื้นที่ออกมาเลย การ Integrate สมการวงกลม (x^2 + y^2 = r^2) มันทำยาก ใช้ Tool พวกที่ช่วยทำ Integrate ให้ได้ แล้วค่อยมาเอาแทนค่า (รายละเอียดเต็มๆเชิญกระมู้นี้)

  • อีกวิธีใช้เรขาคณิตวิเคราะห์ธรรมดา! คำนวณพื้นที่ส่วนที่รู้แล้วด้วยวิธีปกติก่อน ส่วนที่มันเป็นโค้งๆก็ใช้วิธีการหาพื้นที่ของ segment แล้วลบออกด้วยพื้นที่สามเปลี่ยม ก็จะได้เฉพาะพื้นที่ส่วนที่เป็นโค้งๆสีเหลือง เอามาคำนวณต่อได้ ครั้งนี้ใช้วิธีนี้

Circular ไปที่โค้ด Python  ขอสารภาพว่าดีบั๊กอยู่นานพอควร ไม่รู้ตอนสอบปีก่อนรอด Large test case ข้อนี้มาได้ไง ><’’
โค้ดน่าเกลียดไปหน่อย ซ้อนกันหลายบล็อคเกิน

import math

def calculate_segment(R,x1,y1,x2,y2):
ang1 = math.atan(y1/x1)
ang2 = math.atan(y2/x2)
ang = math.fabs(ang1 - ang2)
area = (ang/math.pi/2)*math.pi*R**2
cord = math.sqrt((x1-x2)**2 + (y1-y2)**2)
pie = math.cos(ang/2)*R*cord/2
return area - pie

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

in_file = open(in_filename, 'r')
num_cases = int(in_file.readline())
out_file = open(out_filename, 'w')

for c in range(0,num_cases):
f, R, t, r, g = [float(x) for x in in_file.readline().split(' ')]
r = r + f
g = g - 2*f
t = t + f
x1 = r
y1 = r

# Is the interested point inside the circle
is_inside = lambda x,y : (x**2 + y**2) <= (R-t)**2

# Get y from x, or get x from y
get_pair = lambda x : math.sqrt((R-t)**2 - x**2)

if g > 0.0:
area = 0.0
while x1 <= R-t:
while y1 <= R-t:
x2 = x1 + g
y2 = y1 + g
if is_inside(x1,y1):
if is_inside(x2,y2):
# Full rectangle is inside
area = area + (x2-x1)*(y2-y1)
else:
x1_y2_in = is_inside(x1,y2)
x2_y1_in = is_inside(x2,y1)
if x1_y2_in and x2_y1_in:
xt = get_pair(y2)
yt = get_pair(x2)
area = area + (x2-x1)*(y2-y1)
area = area - (x2-xt)*(y2-yt)/2
area = area + calculate_segment(R-t,xt,y2,x2,yt)
elif x1_y2_in and not x2_y1_in:
xt2 = get_pair(y2)
xt1 = get_pair(y1)
area = area + (xt2 + xt1 - 2*x1)*(y2-y1)/2
area = area + calculate_segment(R-t,xt2,y2,xt1,y1)
elif not x1_y2_in and x2_y1_in:
yt1 = get_pair(x1)
yt2 = get_pair(x2)
area = area + (yt1 + yt2 - 2*y1)*(x2-x1)/2
area = area + calculate_segment(R-t,x1,yt1,x2,yt2)
else:
yt = get_pair(x1)
xt = get_pair(y1)
area = area + (yt-y1)*(xt-x1)/2
area = area + calculate_segment(R-t,x1,yt,xt,y1)
y1 = y1 + g + 2*r
x1 = x1 + g + 2*r
y1 = r
all_area = math.pi*R*R/4
prob = (all_area - area)/all_area
else:
prob = 1.0
out_file.write("Case #%d: %f\n" % (c+1, prob))

out_file.close()





Tags: , , ,

Aug 12 2009

เฉลยกูเกิ้ลโค้ดแยม : Train Timetable

Category: Generalm3rLinEz @ 18:41

ครั้งก่อน Feedback ไม่ค่อยดี (จริงๆแล้วไม่มี feedback - -‘’) เลยตัดสินใจเลิกเขียนอธิบายดีกว่า เมื่อยตุ้ม 55+

โจทย์ที่นี่ (Qualification Round 2008)

จุดเน้น : ข้อนี้มันออกแนวๆ Simulation มากกว่านะ คือจำลองเหตุการณ์ตามที่กำหนดให้ไปเรื่อยๆ แล้วบันทึกค่าไว้เป็นคำตอบ โค้ดไม่ยาวเท่าไหร่ แต่ดีบักอยู่หลายชม. ไม่เคยเขียนนี่หว่า - -‘ จบข้อนี้ได้ความรู้ Python ใหม่ๆ ได้แก่

  • ลองใช้ List Comprehension เพิ่มเติม
  • ลองใช้ Lambda กับ map, filter, reduce และ list.sort
class Event(object):
def __init__(self):
# Time in seconds
self.time = 0
# Offset to apply to train count
self.offset = (0,0)

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

in_file = open(in_filename, 'r')
num_cases = int(in_file.readline())
out_file = open(out_filename, 'w')

for c in range(0,num_cases):
turnaround = int(in_file.readline())
from_a, from_b = [int(x) for x in in_file.readline().split(' ')]
actions = []

for a in range(0,from_a):
# Get departure/arrival time in minutes
depart, arrive = [reduce(lambda h,m : h*60 + m,[ int(y) for y in x.split(':') ]) for x in in_file.readline().split(' ')]
# Departure event : A--
ev = Event()
ev.time = depart
ev.offset = -1,0
actions.append(ev)

# Ready for next departure : B++
ev = Event()
ev.time = arrive + turnaround
ev.offset = 0,1
actions.append(ev)

for b in range(0,from_b):
# Get departure/arrival time in minutes
depart, arrive = [reduce(lambda h,m : h*60 + m,[ int(y) for y in x.split(':') ]) for x in in_file.readline().split(' ')]

# Departure event : B--
ev = Event()
ev.time = depart
ev.offset = 0,-1
actions.append(ev)

# Ready for next departure : A++
ev = Event()
ev.time = arrive + turnaround
ev.offset = 1,0
actions.append(ev)

# Sort the events by their times
actions.sort(cmp=lambda x,y : cmp(x.time,y.time))

train_count_a, train_count_b = 0,0
lowest_a, lowest_b = 0,0
last_time = None

for act in actions:
if last_time != act.time:
# Only track the lowest values when all events
# at the same time are all processed
lowest_a = min(lowest_a, train_count_a)
lowest_b = min(lowest_b, train_count_b)
last_time = act.time

#print act.time,act.offset

train_count_a = train_count_a + act.offset[0]
train_count_b = train_count_b + act.offset[1]

#l = raw_input("pause ..")

out_file.write("Case #%d: %d %d\n" % (c+1,lowest_a*-1, lowest_b*-1))

out_file.close()





Tags: , ,

Aug 11 2009

เฉลยกูเกิ้ลโค้ดแยม : Saving the Universe

Category: Generalm3rLinEz @ 22:26

ช่วงนี้กำลังคลั่งไคล้ Python ครับ แต่ถ้าคลั่งไคล้อย่างเดียวแต่ไม่ได้ทำแลบเปียกเลยก็คงเขียนไม่คล่องซักที เลยลองเอา Python ไปทำโจทย์เก่าที่เคยทำด้วย C# ของ Google Code Jam ปีที่แล้วดู ทำเสร็จแล้วดองไว้ที่บ้านก็ไม่ดี เอามาเฉลยดีกว่า เผื่อใครอยากลองแข่งปีนี้ (รอบ QR วันที่ 2 กันยายน 2009)

โจทย์ข้อนี้มาจาก Qualification Round 2008 โดยย่อ โจทย์จะให้รายชื่อ Search Engine มาทั้งหมด S อัน และคำค้นหาอีก Q อัน คำค้นหาจะถูกประมวลผลเรียงตามลำดับที่ได้รับเข้ามา โดยในเวลาใดเวลาหนึ่งจะมี Search Engine ทำงานอยู่ได้เพียงตัวเดียว

ถ้าคำค้นหาตรงกับชื่อ Search Engine จะทำให้ Search Engine ระเบิด! ดังนั้นจึงอนุญาตให้ “สลับ” Search Engine จากตัวหนึ่งไปอีกตัวหนึ่งได้ คำถามคือ จากรายชื่อ SE และคำค้นหาที่ให้มา จำเป็นจะต้องใช้การสลับอย่างน้อยสุดกี่ครั้ง จึงจะประมวลผลการค้นหาทั้งหมดได้

ตัวอย่าง

มี SE

  • Googol Vietnam
  • Googol Jersey
  • Googol Ethiopi

มีคำค้นหา

  • Googol Jersey
  • Googol Vietnam
  • Googol Jersey
  • Googol Jersey
  • Googol Jersey
  • Googol Jersey
  • Googol Ethiopia
  • Googol Ethiopia
  • Googol Ethiopia
  • Googol Ethiopia
  • Googol Vietnam
  • Googol Ethiopi

ตอบ 1 ครั้ง

เฉลย

ข้อนี้แก้ได้ด้วยวิธีแบบ Greedy ครับ คำอธิบายยาวๆลองไปดู E-learning ของอาจารย์สมชาย แล้วกัน :)

แต่สั้นๆคือ “ทำอะไรที่เห็นตรงหน้าให้ดีที่สุดไว้ก่อน”

ข้อนี้ก็เริ่มจากการหา Search Engine ที่จะ process query ได้เยอะที่สุดโดยไม่ต้องสลับ ซึ่งก็หาได้โดยดู query จากต้นไปเรื่อยๆ จนกว่าจะพบ query ที่เป็นชื่อ Search Engine ครบหมดทุกตัว ตัวสุดท้ายที่พบ (ตัวที่ทำให้บรรลุเงื่อนไข “พบหมดทุกตัว”) จะเป็น Search Engine ตัวที่ทำให้ process query ได้เยอะที่สุดตัวแรก ซึ่งก่อนที่จะ process query อันสุดท้ายนี้ เราจำเป็นอย่างหลีกเลี่ยงไมได้ ต้องทำการ “สลับ” เสียก่อน หลังจากสลับแล้ว query อันสุดท้ายนี้ก็จะนับเป็น Search Engine ที่เราได้ “พบ” แล้วอีกตัวหนึ่ง ก่อนที่จะทำการมอง query ต่อไปเรื่อยๆจนจบ

ประเด็นที่น่าจะยากสำหรับมือใหม่คือการเช็คว่า “พบ Search Engine ครบทุกตัว” แล้วหรือยัง ??

วิธีที่ผมใช้คือเอาชื่อ Search Engine ใส่พวก Map/Dictionary แล้วตอนได้รับ Query มาก็ตรวจดูว่ามี key อันนี้แล้วหรือยัง ถ้ามี และยังไม่เคยพบ ก็จะเซ็ตให้เป็น True (แปลว่าพบ) แล้วก็ใช้ counter อีกตัวนึงคอยนับว่าเจอครบทุกตัวแล้วหรือยัง

โค้ดใน Python ตามนี้


if __name__ == '__main__':
filename = "A-small-practice.in"
filename = "A-large-practice.in"
out_filename = "A-small.out"
out_filename = "A-large.out"
file = open(filename, 'r')
num_cases = int(file.readline())
out_file = open(out_filename, 'w')
for c in range(0,num_cases):

# For each case
num_switch = 0

# To check for dupplicate search engine names
dict = {}

num_engine = int(file.readline())
found_engine = 0
for e in range(0,num_engine):
engine = file.readline()
dict[engine] = False

num_q = int(file.readline())
for q in range(0,num_q):
query = file.readline()
if dict.has_key(query):
if dict[query] == False:
found_engine = found_engine + 1
dict[query] = True

# Check if there is no possibility of not switching
# all search engines are used up
if found_engine == num_engine:
num_switch = num_switch + 1
found_engine = 1
for (k,v) in dict.items():
if query != k:
dict[k] = False

out_file.write("Case #%d: %d\n" % (c+1, num_switch))

out_file.close()





ครั้งนี้เหมือนโยนหินถามทางครับ~

ถ้า Feed back ดีอาจมีตอนต่อ :)

Tags: , , ,