May 25, 2015

ลองใช้ Lamy ครั้งแรก

ชีวิตนี้ไม่เคยคิดว่าจะใช้ปากกาด้ามแพงเกินร้อยบาทครับ แต่ก็ได้ Lamy มาฟรีด้ามนึงเป็นของขวัญวันรับปริญญา

ดองไว้เป็นปีแล้วเพราะไม่รู้ว่าใช้ยังไง จนกระทั่งไม่กี่วันก่อนที่ปากกาทุกด้ามจงใจหมึกตัน เลยได้ฤกษ์เอาออกมาลองใช้ซะเลย

ด้ามที่ได้มานี้หัวเป็นขนาด M ครับ โดยรวมแล้วเอาไปเขียนลื่นสนุกดี แม้มีสะดุดบางจังหวะ

แต่ตอนเอามาวาดรูปนี่รู้สึกควบคุมน้ำหนักเส้นไม่ได้เลย (ไม่เหมือนหัวลูกลื่นที่สามารถฝนบางๆ น้อยกว่าขนาดที่บอกไว้ได้) ...





สรุปแล้วไม่ค่อยชอบเท่าไหร่แฮะ นี่ผมแปลกไปเองหรือเปล่าเนี่ย?

May 22, 2015

Voronoi จากภาพ

วันก่อนไปเจอคำถามใน Code Golf มา เค้าให้สร้าง Voronoi เพื่อเลียนแบบภาพต้นฉบับครับ

อ่านแล้วสนุกดี ผลงานของคนอื่นที่ได้ๆ ก็ดูเหมือนงานศิลป์พวก Divisionism/Pointillism ด้วย เลยลองกลับมาเขียนเองแบบมั่วๆ บ้าง 555

import random
from PIL import Image
from PIL.ImageFilter import FIND_EDGES, GaussianBlur, SHARPEN

def coordinate(width, height):
    yield from ((x, y) for y in range(height) for x in range(width))

def normalized(choices):
    lower = min(weight for _, weight in choices)
    upper = max(weight for _, weight in choices)
    norm = lambda weight: (weight-lower) + (upper-lower)//4
    return [((x, y), norm(weight)) for (x, y), weight in choices]

def random_by_weight(choices):
    rand_val = random.uniform(0, sum(weight for _, weight in choices))
    index = 0
    count = 0
    while count < rand_val:
        count += choices[index][1]
        index += 1
    return choices.pop(index-1)[0]

def init_centroids(image, cells):
    width, height = image.size
    edge_img = image.filter(FIND_EDGES).filter(GaussianBlur).filter(SHARPEN)
    weight = lambda x, y: 256 - max(edge_img.getpixel((x, y)))
    choices = [((x, y), weight(x, y)) for x, y in coordinate(width, height)]
    return [random_by_weight(normalized(choices)) for _ in range(cells)]

def init_rgbs(image, centroids):
    rgb_im = image.convert('RGB')
    return [rgb_im.getpixel((x, y)) for x, y in centroids]

def simulate_voronoi(image_path, cells=25, scale=None):
    image = Image.open(image_path)
    if scale is not None:
        image.thumbnail((scale, scale), Image.ANTIALIAS)
    centroids = init_centroids(image, cells)
    rgbs = init_rgbs(image, centroids)
    return image.size, list(zip(centroids, rgbs))
ผลลัพธ์ที่ออกมาก็ประมาณนี้ครับ (ที่ 500 เซลล์ Voronoi)

เอาไปสู้เขาไม่ได้หรอก เพราะเขียนไปมั่วแบบคนไม่มีพื้นฐาน image processing อะไรเลย แต่ก็สนุกดีได้ลองใช้ PIL เป็นครั้งแรกด้วย

May 14, 2015

Sexy Love



ช่วงนี้ทำงานแรงงานครับ ไม่ค่อยได้ใช้สมองเท่าไหร่ เลยต้องเปิดเพลงวนไปเรื่อยๆ ให้มันรู้สึกสดชื่นตลอดเวลา

แล้ว YouTube ก็วนเพลง Sexy Love มาให้

รู้ตัวอีกที 2 ชั่วโมงถัดมา ก็ยังกดเล่นซ้ำ ฟังเพลงนี้ซ้ำๆ อยู่ครับ

ท่าเต้นโรบอทนี่มันแจ่มจริงๆ ให้ดิ้นตายสิ :3

May 7, 2015

Entertainment



เพลงนี้เป็นเพลงประกอบเครดิตหนัง Now You See Me (2013) ครับ คือทั้งเรื่องไม่ได้ใช้เพลงนี้มาประกอบเลยนั่นแหละ ถ้าไม่นั่งดูเครดิตหนังก็ไม่รู้ว่ามี

ฟังแล้วสนุกดี ได้กลิ่นหนังจีนสมัยก่อนลอยมาแต่ไกลเลย (ทั้งๆ ที่เป็นวงจากฝรั่งเศส) สงสัยเพราะว่าเมโลดี้อยู่ในกุญแจไดอาโทนิคด้วย แต่มันก็ไม่ได้ออกบลูแจ๊สแม้แต่น้อย กลับเป็นร๊อคมันส์ๆ ให้โยกหัวตามได้

ก็ถือว่าเป็นการผสมผสานที่น่าสนใจดี นั่งฟังได้ทั้งวัน

May 6, 2015

Noah


ไม่กี่วันก่อนช่อง HBO เอาเรื่องนี้มาฉายครับ ดูจบแล้วคำพูดนี้พุ่งเข้ามาในหัวเลย

God is dead
-- Friedrich Nietzsche

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

เวลาผ่านไปหลายชั่วอายุคน พระเจ้าเห็นว่าโลกเสื่อมโทรมลงมาก จึงต้องการชำระล้างโลกด้วยพลังแห่งน้ำ ก่อนลงมือก็ไปกระซิบบอกโนอาห์ (โคตรเหลนของอดัม-อีฟ) ให้เตรียมตัวรับมือก่อน โดยอย่าลืมพาพวกสรรพสัตว์ไปด้วย โนอาห์เลยต่อเรือยักษ์ตามที่พระเจ้าว่า

จุดแตกต่างจากไบเบิลที่เด่นชัดจุดแรกในเวอร์ชันหนัง คือพระเจ้าไม่ได้พูดตรงๆ กับโนอาห์แต่ใช้วิธีฉายภาพภัยพิบัติที่จะเกิดขึ้นให้ดูในฝันแทน (ถ้าเคยดู Prince of Egypt ปี 1998 จะเห็นว่าพระเจ้าอวตารร่างลงมาเป็นลูกไฟเพื่อพูดคุยกับโมเสสตรงๆ เลย) อันที่จริง หนังเรื่องนี้ทั้งเรื่องไม่ได้แสดงตัวตนหรือคำพูดของพระเจ้าเลย

จุดต่อมาคือมนุษย์ที่โนอาห์พาขึ้นเรือไปนั้น ไม่สามารถมีลูกหลานต่อไปได้ ซึ่งก็กลายเป็นดราม่าหลักของเรื่องเมื่ออิล่า แฟนสาวกับลูกคนหนึ่งโนอาห์ (นำแสดงโดยเฮอร์ไมโอนี่ :P) ที่เป็นหมันมาตั้งแต่เด็ก ดันตั้งท้องบนเรือซะงั้น โนอาห์ซึ่งคิดว่าความเสื่อมใดๆ ในโลกล้วนเกิดจากน้ำมือของมนุษย์ จึงต้องการฆ่าลูกของอิล่าเสียเมื่อเธอคลอด

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

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

การที่พระเจ้าไม่เคยปรากฎตัวขึ้นมาแม้แต่ครั้งเดียว เราอาจตีความได้ว่าโนอาห์ดันฝันเห็นแฟนตาซีที่น่ากลัวมากๆ แล้วหมกมุ่นกับมันจนต้องสร้างเรือขึ้นมา ไม่จำเป็นต้องมีพระเจ้ามาเกี่ยวข้องเลย (ใครไม่เคยฝันแฟนตาซีน่าตื่นเต้นแบบนี้บ้าง?) พอฝนตกหนักน้ำท่วมก็โป๊ะเชะกับที่โนอาห์กลัวพอดี

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

The choice was put in your hands because he put it there.
-- Ila, Noah (2014)

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

พระเจ้าที่ไร้อำนาจเช่นนี้ ก็คงไม่ต่างจากพระเจ้าที่ตายแล้วอย่างที่นิทเช่บอกไว้

Apr 16, 2015

Code Jam 2015 รอบคัดเลือก


ปีนี้ประมาทไปเยอะครับ คือตอนแรกตั้งใจว่าจะถ่างตามาเริ่มเล่นตั้งแต่ปล่อยโจทย์ตอน 6 โมงเช้าเลย แต่สุดท้ายก็เผลอหลับไปตอนตี 4 ตื่นมารู้ตัวอีกทีก็บ่ายแล้ว เลยพักสมองออกเล่นบอร์ดเกมกะ @tamwb และ @aibig ตามนัดปาร์ตี้สงกรานต์ แถมกลับมาก็ยังไม่มีสมาธิแก้โจทย์มัวแต่ดู MV เกาหลีอีก กว่าได้เริ่มทำแข่งจริงจังก็เหลือเวลาไม่กี่ชั่วโมงแล้ว

ตอนอ่านโจทย์ผ่านๆ ทุกข้อนี่คิดว่าง่าย ปีนี้ได้แก้มือเก็บคะแนนเต็มแน่ๆ ... ที่ไหนได้ bug ซ่อนเร้น 1 ข้อ แล้วก็ตีความโจทย์อีก 1 ข้อ สุดท้ายแก้ไม่ทัน ได้ส่งแค่ 2 ข้อ ดีแค่ไหนแล้วที่ยังไม่ตกรอบ 555



ข้อแรกง่ายฮะ แต่ถ้ายังอ่านโจทย์แล้วไม่อินขอให้ดูคลิปนี้ตอนนาทีที่ 7:05 และ 7:23 (เรียบร้อยแล้วก็กลับไปดูตั้งแต่ต้นด้วยจะดีมาก) :P



ส่วน code ก็ประมาณ
import Text.Printf (printf)
import Data.List.Split (splitOn)

invites audience =
    let aux []     _   _   inv = inv
        aux (p:ps) shy acc inv = aux ps (shy+1) (acc+p+more) (inv+more)
            where more = max 0 (shy-acc)
    in  aux audience 0 0 0

test t = do
    it <- getLine
    let [_, ps] = splitOn " " it
    printf "Case #%d: %d\n" t $ invites [read [p] :: Integer | p <- ps]

main = do
    loop <- getLine
    sequence_ [test t | t <- [1..read loop :: Integer]]
(อย่างไรก็ตาม เท่าที่เคยไปคอนเสิร์ตหลายครั้ง รู้สึกว่าคนไทยจะมีค่าความอายเป็น infinity นะ)


ข้อสองข้ามไปนะฮะ ทำไม่ได้ (ข้อสี่ด้วย)

ส่วนข้อสามนี่สนุกดี ถ้ายังจำเนื้อหาม.ปลายได้ เราจะมีเลขมหัศจรรย์ตัวนึงเรียกว่า i ซึ่งมีนิยามที่สวยงามเรียบง่าย คือ
i^2 = -1
สังเกตเพิ่มอีกหน่อยก็จะเห็นว่า
i^4 = 1    (multiplicative identity)
โจทย์เพิ่มความสนุกโดยให้ตัวเลขมหัศจรรย์ j และ k มาด้วย ทั้งสองตัวที่เพิ่มเข้ามานี้ มีนิยามแบบเดียวกันกะ i เด๊ะๆ เลย เพียงแต่มันไม่ใช่ i เพราะเรานิยามการคูณระหว่างตัวเลขเหล่านี้ว่า
ij = k
jk = i
ki = j
ความซับซ้อนของตัวเลขชุดนี้ยังเพิ่มขึ้นไปอีก เมื่อเรานิยามให้มันไม่มีสมบัติสลับที่ด้วย ซึ่งในที่นี้คือ
ji = -k
kj = -i
ik = -j
เพื่อความสะดวก สมมติชื่อให้เลขชุดนี้ว่า ℍu ละกันครับ โชคดีที่อย่างน้อยในเซ็ต ℍu = {1, i, j, k} มันยังมี
  • สมบัติปิดบนการคูณ คือ ถ้าใช้การคูณอย่างเดียวบนสมาชิกของเซ็ต ℍu ผลลัพธ์ที่ได้ก็จะเป็นสมาชิกของเซ็ต ℍu ด้วย
  • สมบัติจัดกลุ่มการคูณ คือ a(bc) = (ab)c สำหรับทุก a, b, c ∈ ℍu
สรุปง่ายๆ ถ้าใครถนัดเรื่องการคูณไขว้เวกเตอร์ ก็นึกถึงกฎมือขวาได้เลย

จาก X, LS ที่โจทย์ให้ การแก้ปัญหาแบบตรงๆ ก็คือวิ่งผ่านชุดตัวเลข LS เป็นจำนวน X ครั้ง โดยเลขแต่ละตัวเลข s ∈ LS ที่วิ่งผ่าน ก็จัดการคูณเก็บไว้ในใจไปเรื่อยๆ ถ้าเจอตัวเลขครบทั้ง i, j, k และหางที่เหลือคูณกันออกมาเป็น 1 ก็ตอบว่าถูกได้เลย

ถ้าอ่านมาจนถึงตรงนี้แล้วยังงงไม่หาย ลองดูการทำงานตามขั้นตอนวิธีด้วยตัวอย่างนี้
X  = 10
LS = ji

sequence: ji ji ji ji ji ji ji ji ji ji
running:  --->--->-------->----------->
found:       i   j        k           1
โจทย์ข้อนี้ฉลาดตรงที่เอาตัวเลข Xขนาดใหญ่มากๆ มาขู่ ทั้งที่เราสามารถ modulo มันทิ้งให้เหลือแค่หลักสิบได้ (ซึ่งก็คือ คำถามชุดใหญ่จะมีความยากแทบไม่ต่างกับคำถามชุดเล็กเลย)

การลดขนาด X ทำได้โดยใช้ข้อสังเกตที่ว่า i^4 = j^4 = k^4 = 1 ซึ่งบอกเป็นนัยอยู่ 2 อย่างคือ
  • ถ้าวิ่งคูณหา i, j, k แต่ละตัวเกิน 4 รอบแล้วยังไม่เจอ ไม่ต้องวิ่งต่อ เพราะแต่ละรอบที่วิ่งเพิ่ม จะไม่ได้ผลลัพธ์ใหม่แล้ว
  • หลังจากหา i, j, k ได้ครบแล้ว หางที่เหลือสามารถ mod 4 ได้
ดังนั้น เราจะวิ่งผ่านชุดตัวเลขนี้ 3 ครั้ง (เพื่อหา i, j, k) โดยแต่ละครั้งวิ่งไม่เกิน 4 รอบ ซึ่งก็เท่ากับวิ่ง 12 รอบ แล้วรอบที่เหลือก็จับ mod 4 ได้เลย

หรือพูดจาภาษา code ก็คือ
def correct_misspelling(ijks, x):
    x = min(x, 12+(x%4))
    accumulate = Quaternion('+1')
    searching = [Quaternion(it) for it in 'kji']
    for _ in range(x):
        for it in ijks:
            accumulate *= Quaternion(it)
            if searching and searching[-1] == accumulate:
                accumulate = Quaternion('+1')
                searching.pop()
    return not searching and accumulate == Quaternion('+1')

for case in range(int(input())):
    _, x = [int(n) for n in input().split()]
    ijks = input().strip()
    ans = 'YES' if correct_misspelling(ijks, x) else 'NO'
    print('Case #{}: {}'.format(case+1, ans))
ข้อนี้ถ้าจะ optimize เพิ่มก็ยังทำได้อีก (code จริงที่เอาไปส่งก็เขียนสวยน้อยกว่านี้เพราะมัวแต่ optimize มากเกินไป) โดยเรามีข้อสังเกตดังนี้
  • aba = b สำหรับทุก a, b ∈ ℍu
  • เราสามารถทดเก็บค่าสุดท้ายที่ได้จากการวิ่งผ่านเพื่อหาผลคูณของทุกตัวใน LS ไว้ได้ แล้วพอจะวิ่งผ่าน LS อีกรอบก็ใช้ค่าที่ทดไว้ได้เลย
  • ในการทดลองจริง จำนวน X ที่จำเป็นต่อการคำนวณไม่เคยมีค่าเกิน 8 เลย ซึ่งก็คือ x = min(x, 4+(x%4))
ถ้ายังอยากรู้ว่าข้อสังเกตเหล่านี้จริงหรือไม่ ถ้าจริงแล้วจะช่วยการคำนวณอย่างไร proof เพิ่มดูเองได้เลยครับ

Mar 8, 2015

คำถาม

ญ. - ไม่ง่วงเหรอ

ช. - ไม่จ้า

ญ. - ไม่หิวเหรอ

ช. - ยังอิ่มอยู่เลยจ้า

ญ. - แล้วไม่คิดถึงเราเหรอ

Nov 18, 2014

แอพ Calendar ตัวใหม่ของ Android Lollipop มาพร้อมกับภาพพาดหัว

ตอนนี้เวลาจดเหตุการณ์ใหม่ในแอพ calendar มันจะโชว์รูปด้วยถ้ามี keyword ไปตรงกับคำเตรียมไว้

ดูแล้วน่ารักดีครับ ลองหาคร่าวๆ เจอเท่านี้ ใครเจออะไรอีกสะกิดบอกกันได้ :D

Nov 3, 2014

Code Mania 01 และทำไมถึงควรเลิกเขียน JavaScript

เสาร์ที่ผ่านมาไปพูดเรื่อง "เลิกเขียน JavaScript กันดีกว่า" ในงาน Code Mania ที่จุฬาฯ มาครับ

คุณ @KaizerWing ให้เวลาเตรียมตัวล่วงหน้ามาเป็นเดือนแล้ว ตอนนั้นหัวโล่งๆ ยังมองภาพไม่ออกว่างานจะออกมาหน้าตายังไง เลยเลือกเรื่องที่คุ้นมือมากที่สุดในตอนนี้อย่าง CoffeeScript ไปพูด

แต่ครั้นจะพูด CoffeeScript เพียวๆ เลยเดี๋ยวคนจะตามไม่ทัน เลยหาจุดเชื่อมโยงเป็น JavaScript ที่มีจุดประหลาดน่าสนใจและคนเขียนเยอะมาปูเรื่องครับ

เสียดายว่าแอบขี้เกียจไปหน่อย ตอนช่วงท้ายๆ เลยปิดไม่ค่อยดีเท่าไหร่ ถ้าเพิ่มสไลด์สำคัญๆ ไปอีกซัก 2 แผ่นน่าจะเรียกเสียงฮือฮาได้มากกว่านี้นะ

สไลด์อยู่นี่ครับ ส่วนทีมงานบอกมาว่ากำลังตัดต่อวิดีโออยู่ เรียบร้อยเมื่อไหร่เดี๋ยวผมมา update อีกที



งานนี้สนุกมากครับ รู้สึกว่าสนุกกว่า BarCamp ที่ช่วงหลังๆ เริ่มแผ่วแล้วด้วย ก็หวังว่าจะมีงานทำนองนี้ออกมาอีกเรื่อยๆ อาจจะจัดหลายวันเป็นแคมป์กิน-นอน-เต้นรอบกองไฟก็น่าสนนะครับ :D

Oct 29, 2014

City2048

เป็นเกมแบบเดียวกะ 2048 แหละครับ แค่เปลี่ยนจากตัวเลข ไปเป็นตึกแบบต่างๆ ไล่ลำดับแค่นั้นเอง


สนุกใช้ได้ครับ ภาพสวยไอเดียแจ่มด้วย แต่ช่วงแรกๆ ต้องจำรูปแบบตึกกันหน่อย ซึ่งเอาจริงๆ ก็ไม่ได้ยากอะไรมาก เพราะจะเล่นให้ถึง 2048 ก็จำตึกไป 10 แบบเอง (แบบแรกสุดที่เป็นฐานใช้รูปป่า -- ไม่นับนะ)

ส่วนวิธีคิดคะแนนจะต่างไปพอสมควร คือไม่ใช่คะแนนคูณสองไปเรื่อยๆ แล้ว แต่จะเพิ่มเป็นเส้นตรงครั้งละ 5 แทน