Aug 14, 2011

สวัสดีวันแม่ (ย้อนหลัง)

ขอบคุณ และขอโทษครับ

รักแม่นะครับ

Aug 3, 2011

พายุ น้ำท่วม เซ็ง

ยังอยู่ที่เดิม เหมือนเมื่อหลาย ปีที่แล้วนั่นแหละ
แปลกจริง บันทึกถึงมันเป็นครั้งที่ 3 อารมณ์คนละอย่างเลยวู้ย

"5:58"

นี่ถ้าเป็นสมัยก่อนคงนึกว่าตื่นได้โดยไม่ต้องพึ่งนาฬิกาปลุก
แต่จริงๆ แล้วคือนั่งเว่นเว้อทั้งๆ ที่เป็นช่วงสอบมาตลอดคืนต่างหาก

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

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

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

อะไรทำให้เราเป็นคนอย่างนี้ไปได้เนี่ย???

ยอมรับตรงๆ เลยละกัน ว่าเพราะแม่เป็นหลัก
ตอนเด็กๆ ก็โกหกเก่งพอตัวอยู่ละ (ไม่งั้นก็เจอไม้เรียวไม่เว้นวัน)
พอมาเจอกับเหตุการณ์บ้าบอนั่น โกหกเก่งขึ้นอีก 10 เท่าเลย - -"
เบื่อแล้วโว้ย ไม่เอาแล้วโว้ย
อยากเลิกโกหกให้ได้ซักที
T^T

ยิ่งช่วงนี้เศร้าบ้าบอเป็นพิเศษด้วย
ยิ่งคิดมาก ยิ่งเศร้ามากกว่าเดิมอีก
โอ้ ไอ่ความสงบ สุขุม เยือกเย็นหายไปไหนหมดเนี่ย

ไม่อยากทำตัวเองให้ไร้สาระมากไปกว่านี้อีกแล้ว
เริ่มต้นตั้งแต่นี้เลย! ปั่นจักรยานออกไปหน้าหมู้บ้าน
แล้วก็ถ่ายรูปน้ำท่วมไปฝากพ่อ (ขอมาตั้งแต่เมื่อวานละ)

"9:46"

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

ตั้งสติ แล้วก็ทำวันนี้ให้ดีที่สุดละกัน
อย่างน้อย จะได้ไม่เสียใจถ้าหันกลับมามอง!

Jul 26, 2011

เฉลยโจทย์ HLP Hackathon ด้วย Python


สืบเนื่องจากงาน HLP Hackathon อันสุดเมามันส์ได้จบไป ทางทีมงานหัวลำโพงก็ได้ปล่อยโจทย์ออกมาให้ชาว geek ที่ไม่ได้ร่วมแข่งขันมาประลองฝีมือแล้ว

เนื่องจากผมเป็นหนึ่งในผู้เข้าแข่งขันงานนี้ จึงขอนำ code ทีเขียนอย่างมึนเมาด้วย Python 3 ในวันแข่งมา review อีกรอบให้สวยงามขึ้น และคิดว่าคงมีประโยชน์อยู่บ้างสำหรับผู้ที่ยังมีพลัง code ไม่แก่กล้าพอจะได้นำไปศึกษาต่อครับ ^^

โดยผมขอเฉลยเฉพาะข้อที่ใช้ programming จริงจังนะครับ ข้อฮาๆ อย่าง sudoku ถ้าคุณหาคำตอบไม่ได้ภายใน 30 วินาทีแปลว่ายัง geek ไม่พอครับ!!! ;P (คำใบ้)

โอเค ร่ายยาวไปมันไม่ geek ถ้าพร้อมแล้วก็ลุยกันเลย!!!
{ ไปยังข้อ 6, 7, 9, 10, 11, 12, 13 }

ข้อ 6: ข้อนี้ง่ายๆ ครับ กดเครื่องคิดเลขทำมือยังได้เลย
def sixtythree(n):
    if n == 0:
        return '0'
    m = []
    while n > 0:
        m.append(n%63)
        n = n //63
    m.reverse()
    return m

map = [i for i in range(10)]
map.extend([chr(i+97) for i in range(26)])
map.extend([chr(i+65) for i in range(26)])
map.append('_')

num = 9124569914

##########

print("http://molo.me/p/", end='')
out = sixtythree(num)
for i in range(len(out)):
    print(map[out[i]], end='')

ข้อ 7: ปวดหัวหน่อยนึงกับการที่ Python เป็น dynamic type เวลาลงไปยุ่งกับ bit เลยยากกว่า static type ดังนั้นการ define ฟังก์ชันสำหรับ circular shift ต้องระวังดีๆ ครับ
import re

def cshift(a, n):
    n %= 8
    l = a >> n
    r = a << (8-n)%8
    r %= 2**8
    return l | r

map = [chr(96+26-i) for i in range(26)]

word = []
while True:
    try:
        raw = input()
    except EOFError:
        break
    
    raw = re.sub('0x', '', raw)
    raw = re.split(' ', raw)

    for i in range(len(raw)):
        raw[i] = int(raw[i], 16)
    word.extend(raw)

###############

for i in range(len(word)):
    word[i] = cshift(word[i], i)
    word[i] -= 65
    word[i] = map[word[i]]
    print(word[i], end='')
ปล. ข้อนี้รับ input ทาง stdio นะครับ เขียน input เก็บเป็นไฟล์แล้วจาก terminal/command line ก็ใช้คำสั่ง python script.py < input.txt จะสะดวกขึ้นมากครับ
ข้อ 9: มาเป็นไฟล์ raw อย่างนี้ ไม่ยากเลยครับ (โดยส่วนตัวผมขี้เกียจ output เป็นรูป งานนี้ใช้ notepad เปิดไฟล์ text เอาแล้ว pan หาดีๆ นะครับ!)
p = open('input.raw', 'rb')

out = ''
for i in range(640*480):
    rch = p.read(1)
    if ord(rch) == 1:
        out += '0'
    else:
        out += ' '
    och = p.read(3)
    if i%640 == 0:
        out += '\n'
p.close()

f = open('out.txt', 'w')
f.write(out)
f.close()

ข้อ 10: ปัญหาเดียวของข้อนี้คือ อย่าทำตอนเมาเป็นอันขาด! เพราะวันแข่งไม่มี test case แบบไฟล์มาให้ ได้คีย์มือเองแล้วจะพบว่ามันนรกแตกมาก!!! (รับทาง stdio เช่นกันครับ)
import re

def gcd(a, b):
    if b == 0:
        return a
    else:
        return gcd(b, a%b)

def mgcd(nlist):
    a = nlist[0]
    for i in range(1, len(nlist)):
        a = gcd(a, nlist[i])
    return a

tc = []
while True:
    try:
        raw = input()
    except EOFError:
        break
    
    raw = re.split(', ', raw)
    for i in range(len(raw)):
        raw[i] = int(raw[i])

    tc.append(mgcd(raw))

########

out = 0
for i in tc:
    out = out ^ i
print(out)

ข้อ 11: เหมือนจะยากแต่ก็ไม่มากไปกว่าข้อ 9 เลยครับ ^_____^
p = []
for i in range(1, 5):
    p.append(open('input' + str(i) + '.raw', 'rb'))

out = ''
for i in range(640*480):
    same = True
    chk = p[0].read(4)
    for j in range(1, 4):
        tmp = p[j].read(4)
        if chk != tmp:
            same = False

    if same:
        out += '0'
    else:
        out += ' '
    if i%640 == 0:
        out += '\n'

for i in range(4):
    p[i].close()

f = open('out.txt', 'w')
f.write(out)
f.close()

ข้อ 12: ใช้ recursive technique แล้วชีวิตง่ายขึ้นจมครับ ใครไม่แม่นไปเทรนมาดีๆ นะครับ ^^b
ways = 0
z = 1
#        0,      4,        9,        e,
map = [ [0,0,0,0,0,0,0,0,z,0,0,0,0,z,0,0,0], # 0
        [0,0,0,0,z,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,0,0,z,0],
        [0,0,0,0,0,0,0,0,0,z,0,0,0,0,0,0,0],
        [0,0,z,0,0,0,z,0,z,0,z,0,0,0,0,0,0], # 4
        [0,0,0,0,0,0,0,0,z,z,0,z,0,0,0,0,0],
        [z,0,0,z,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,z,0,z,0,0,0,z,0,0,0,0,z,0],
        [0,0,0,0,0,0,0,z,z,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,z,0,0,0], # 9
        [0,0,0,0,0,0,0,0,0,0,0,0,z,0,0,0,0],
        [0,0,0,z,0,0,0,0,0,0,0,z,0,0,0,0,0],
        [0,0,0,0,0,0,0,z,0,z,z,0,0,0,0,0,0],
        [0,0,0,0,0,z,0,0,z,0,0,z,0,0,0,0,0],
        [z,0,0,z,0,0,z,0,0,0,0,0,0,0,0,z,0], # e
        [0,0,0,z,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,z,0,0,0,0,0,0,0,0,0,0,0,0,0,z,0] ]        

def rerun(x, y):
    global ways
    if map[y][x] == 1:
        return
    if x != 16 and y != 16:
        rerun(x+1, y)
        rerun(x, y+1)
    elif x == 16 and y != 16:
        rerun(x, y+1)
    elif x != 16 and y == 16:
        rerun(x+1, y)
    else:
        ways += 1
        return

#########

rerun(0, 0)
print(ways - 41604)
ปล. สำหรับผู้สนใจ Dynamic Programming สามารถดูตัวอย่างข้อนี้ได้จากบล๊อกคุณ Tanin ครับ
ข้อ 13: ข้อนี้ยากสมชื่อจริงๆ ครับ! ด้วย recursive technique บน Python ผมพบว่าสามารถหาคำตอบได้แค่ภาพที่ 1 และ 5 เท่านั้น T^T ใครมีไอเดียเด็ดๆ ไม่ให้เกิด stack overflow มาคุยกันครับ edited: แก้ไขตามคำแนะนำของคุณ Tanin โดยการเอาบรรทัดที่ 13 ออกก็แก้โจทย์ได้เลยครับ! เจ๋งจริงๆ
import re
import sys
import math

def refill(x, y, color):
    if not 0 <= x < 200 or not 0 <= y < 200:
        return
    if color == map[y][x]:
        map[y][x] = ''
        refill(x+1, y, color)
        refill(x, y+1, color)
        refill(x-1, y, color)
        # refill(x, y-1, color) # remove by @tanin47 suggestion
    else:
        return

if len(sys.argv) > 1:
    name = sys.argv[1]
else:
    name = input()
if '.bmp' not in name:
    name += '.bmp'
p = open(name, 'rb')
p.read(54)

map = []
for i in range(200):
    map.append([])
    for j in range(200):
        map[i].append(p.read(3))
p.close()

obj = 0
for y in range(200):
    for x in range(200):
        if map[y][x] != '':
            refill(x, y, map[y][x])
            obj += 1
print(math.floor(math.sqrt(obj)))
ปล. ข้อนี้ผมคิดไม่ออกในเวลานะ แต่พอกลับมาบ้านแล้วทำได้เฉยแฮะ ^^" และด้วยความที่ผมใช้ Python 3 ทำให้ยังไม่มี lib สำหรับอ่านไฟล์รูปภาพแบบ .png ดังนั้นผมจึงใช้ Paint เซฟภาพให้เป็น .bmp เอาครับ
สุดท้ายนี้ก็ May the Code be with You นะครับ สวัสดีครับ ^^

11th โชว์รูม - อวกาศ

หลายเดือนที่ผ่านมาไม่มีไรทำ
ก็วาดรูปเล่นตามประสาอินดี้อะนะ


เพราะว่าพึ่งได้เจ้าตัวนี้มา เลยมีนายแบบให้มองทุกซอกมุม


เลยเกิดความคิดว่า เอาตัวเก่ามาออกแบบท่าทางในหัวดีกว่าแฮะ


แล้วก็ไปลากเอายานจาก Star Wars มาวาดด้วย ^^


พูดถึงยานอวกาศ ก็ต้องนึกถึง Enterprise ใน Star Trek หละ


ส่วนตัวนี้เป็นหุ่น concept สร้างจาก LEGO


ปิดท้าย ระหว่างวาดก็ฟังเพลงเหล่านี้ประกอบ ^^

Feb 1, 2011

รำลึกความหลังอันสุดเซ็ง

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

Jan 26, 2011

รถชนรับปีใหม่...

... 2 ปีติด

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

Jan 16, 2011

Cryptography ตอนที่ 6 การเข้ารหัสลับแบบฮิลล์

สวัสดีครับ หายหน้าหายตาไปหลายตอนเลย
พอดีวันนี้ไปยืม SyntaxHighlighter มาแปะเว็บเล่น
เลยถือโอกาสอัพอะไรที่มันต้องใช้ขมองหน่อยละกัน ;)

แล้วเราก็มาต่อกันที่ การเข้ารหัสลับแบบฮิลล์ (Hill Cipher)
ซึ่งได้ชื่อมาจาก Lester S. Hill นักคณิตศาสตร์ชาวอเมริกัน
โดยวิธีการนี้ได้ถูกคิดค้นและตีพิมพ์ในปี 1929 ครับ

วิธีการนี้จะกำหนดเมทริกซ์ 1 ตัวขึ้นมาเป็นกุญแจ
แล้วเอาคำที่ต้องการเข้ารหัสมาคูณกับเมทริกซ์นี้ครับ
ฟังดูไม่ยาก แต่ก็มีรายละเอียดเยอะมากทีเดียว
ไปดูกันเลยครับ

ให้ m >= 2 เป็นจำนวนนับ ให้ P = C = (Z26)m
K = {m x m เมทริกซ์ที่มีอินเวอร์สบน Z26}
สำหรับ K นี้ จะกล่าวว่า
eK(x) = xK และ dK(y) = yK-1
เมื่อโอเปอเรชันทุกตัวทำงานบน Z26

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

เมทริกซ์ในโลกคอมพิวเตอร์นั้น สร้างได้ง่ายๆ โดย array 2 มิติ
ในภาษา python ก็คือการใช้ลิสต์ซ้อนลิสต์ เช่น [[1, 2], [3, 4]] ครับ
แต่เนื่องจากตัวเลขทั้งหลายของเราดันไปอยู่บน Z26 ซะหนิ
การเขียนฟังก์ชันสำหรับการคูณ/หาอินเวอร์สจึงต้องดัดแปลงเยอะอยู่
ดังนั้น ในที่นี้เราเล่นกับเมทริกซ์ขนาด 2x2 เท่านั้นครับ

def matrix(a00 = 0, a01 = 0, a10 = 0, a11 = 0):
return([[a00%26, a01%26], [a10%26, a11%26]])


ในเมื่อเราต้องการเมทริกซ์ขนาดแค่ 2x2 เท่านั้น
การนั่งเขียน [[1, 2], [3, 4]] ทุกครั้งก็มีโอกาสพลาดได้ง่ายๆ
ดังนั้น การกำหนดฟังก์ชันขึ้นมาใช้งานเฉพาะเลยจึงเข้าท่ากว่า

def matrix_multiple(matrix_1, matrix_2):
result_matrix = matrix()
for i in range(len(matrix_1)):
for j in range(len(matrix_2[0])):
for k in range(len(matrix_1[0])):
result_matrix[i][j] += matrix_1[i][k] * matrix_2[k][j]
result_matrix[i][j] %= 26
return(result_matrix)


แล้วเราก็มาเขียนการคูณเมทริกซ์กันครับ
อันนี้เป็นการเขียนสำหรับเผื่อการใช้คูณเมทริกซ์ธรรมดาด้วย
แต่ต้องตัดบรรทัดที่เอาผลลัพท์ไป modulo 26 ทิ้งไป
แล้วเช็คตอนแรกว่า มิติของเมทริกซ์เป็นไปตามกฏการคูณหรือเปล่า?

def determinant_inv(m):
determinant = m[0][0]*m[1][1] - m[0][1]*m[1][0]
if determinant != 0:
return(multiple_inv(26, determinant%26))


อันนี้เป็นการหา determinant ที่อินเวอร์สเรียบร้อยแล้วครับ
เพราะเราไม่มีความจำเป็นที่ต้องใช้ค่า det เปล่าๆ
แถมการได้ det ที่มีค่าเป็น 0 ก็ไม่มีประโยชน์ในที่นี้อีกครับ

def matrix_inv(m):
det_inv = determinant_inv(m)
if det_inv != None:
inverse = matrix(m[1][1], -m[0][1], -m[1][0], m[0][0])
for i in range(2):
for j in range(2):
inverse[i][j] *= det_inv
inverse[i][j] %= 26
return(inverse)


อินเวอร์สเมทริกซ์ซึ่งสามรถประยุกต์กับเมทริกซ์ 2x2 ทั่วไปได้เหมือนด้านบน

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

def hill(pain_text, matrix):
if len(pain_text)%2 != 0:
return("text lenght must be even number")
if matrix_inv(matrix) == None:
return("matrix must have inverse in order to decrypt")
else:
cipher_text = ""
char_num = [[0, 0]]
for i in range(int(len(pain_text)/2)):
char_num[0][0] = lower_to_number(pain_text[2*i])
char_num[0][1] = lower_to_number(pain_text[2*i + 1])
char_num = matrix_multiple(char_num, matrix)
cipher_text += number_to_upper(char_num[0][0])
cipher_text += number_to_upper(char_num[0][1])
return(cipher_text)


ทีนี้เวลาเรียกใช้งาน ถ้าจะให้ง่ายก็ทำการเก็บตัวแปรที่เป็นเมทริกซ์ไว้ก่อนครับ เช่น

>>> a = encrypt.matrix(1, 5, 3, 4)
>>> encrypt.hill("testhill", a)
'FHXKFPSV'


ส่วนการถอดรหัสก็ง่ายเหมือนเดิมครับ
เลยฝากไว้เป็นการบ้านละกัน :P

HJIFLQSEKGZQ

Jan 10, 2011

ความเปลี่ยนแปลง???

เวลาเปลี่ยน ใจคนเปลี่ยน
เพราะใจเปลี่ยน ความคิดเลยเปลี่ยน
เมื่อความคิดเปลี่ยน การกระทำก็เปลี่ยนด้วย

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

Jan 7, 2011

เริ่มปีใหม่อย่างงงๆ

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

Dec 3, 2010

Cryptography ตอนที่ 5 การเข้ารหัสลับวิจเญอแนร์

เราจะเห็นว่าการเข้ารหัสลับในสามตอนที่ผ่านมานั้น จะจับคู่จากอักษรไปยังอักษรตัวเดิมเสมอ
ซึ่งนั่นส่งผลให้เราใช้วิธีง่ายๆ คือไล่แทนอักษรไปเรื่อยๆ (brute force) ได้ แม้ว่ามันจะกินเวลาก็ตาม
เราเรียกวิธีเข้ารหัสจากทั้งสามตอนนั้นว่าเป็นแบบ monoalphabetic หรือแบบอักษรตายตัวครับ

ในปี 1553 จึงได้มีการคิดค้นวิธีเข้ารหัสลับแบบ polyalphabetic หรือแบบอักษรไม่ตายตัวขึ้น
ผู้คิดค้นคือ Giovan Battista Bellaso แต่เนื่องด้วยเหตุผลทางประวัติศาสตร์ในช่วงศตวรรษที่ 19
ทำให้ผู้ที่ได้รับเครดิทกลายเป็น Blaise de Vigen?re แทน เราจึงรู้จักวิธีนี้ในชื่อ Vigen?re Cipher

ข้อดีของการเข้ารหัสลับด้วยวิธีนี้คือ เข้ารหัสง่าย แต่โจมตีรหัสยาก (อย่างน้อยถ้าไม่มีคอมฯ)
ขั้นตอนการเข้ารหัสก็ง่ายเหลือหลายอย่างที่ว่ามา แค่เลือกชุดตัวเลขที่จะใช้เป็นกุญแจมาชุดหนึ่ง
แล้วก็เอาอักษรตัวแรกบวกกับเลขในกุญแจอันแรก อักษรตัวที่สองบวกเลขตัวที่สองไปเรื่อยๆ
จนเมื่อชุดตัวเลขในกุญแจที่ใช้หมด ก็กลับไปเริ่มเลขตัวแรกในกุญแจใหม่อีกครั้ง
ง่ายจริงๆ ให้ดินตายเลย (งั้นไปดูคณิตศาสตร์ก่อนที่จะดิ้นตายดีกว่า 555+)

ให้ P = C = Z26 และให้ K = {(a1, a2, a3, ... , ai) ใน Z26 สำหรับ i ใน N}
สำหรับ K = (a1, a2, a3, ... , ai) สร้าง K* = (a1, a2, a3, ... , ai, a1, ...) และกล่าวว่า
eK(x) = (xj + aj) mod 26 และ dK(y) = (yj - aj) mod 26
สำหรับ x, y ที่เป็นสมาชิกของ Z26 และ aj ที่เป็นสมาชิกของ K*

สำหรับนักคณิตศาสตร์แล้ว จะแปลงกุญแจจากสั้นๆ ให้เป็นอนันต์ก่อน แล้วจึงค่อยนำกุญแจไปใช้
จะเห็นว่าวิธีนี้ key space ใหญ่ขึ้นอย่างรวดเร็ว เพียงแค่เพิ่มตัวเลขในกุญแจ ซึ่งคือ 26i นั่นเอง
เลขในกุญแจเพียงแค่ 5 ตัวจะสร้าง key space ที่ใหญ่ถึง 255 = 11.8 x 106 เลยครับ

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

บรรทัด 1 เปลี่ยนชื่อ และเปลี่ยนเงื่อนไขการใช้กุญแจจากแบบเลขตัวเดียว เป็นลิสต์เลขหลายตัว
บรรทัด 5 เปลี่ยน logic ของการคำนวน คือให้ใช้เลขในกุญแจตามลำดับที่เปลี่ยนไปเรื่อยๆ

def vigenere(pain_text, key_list):
cipher_text = ""
for i in range(len(pain_text)):
char_num = lower_to_number(pain_text[i])
char_num += key_list[i%len(key_list)]
char_num %= 26
cipher_text += number_to_upper(char_num)
return(cipher_text)


จะเห็นว่า ทางคอมพิวเตอร์นั้น เราไม่จำเป็นต้องสร้าง K* เหมือนทางคณิตศาสตร์ก็ได้
แต่จะใช้ modulo เพื่อวนเรียกใช้เลขที่เราต้องการเมื่อเราใช้เลขในลิสต์หมดครับ
อ๋อ เวลาเรียกฟังก์ชันนี้ขึ้นมาใช้ ตัวแปรด้านหลังต้องพิมพ์เป็นตัวแปรแบบลิสต์อย่างนี้นะครับ

>>> encrypt.vigenere("testvigenerecipher", [4, 25, 7, 12, 0]) 


ส่วนผลลัพท์จะออกมาเป็นอย่างไร ต้องฝากเป็นการบ้านไว้พร้อมกับการเขียน decrypt ครับ
เจอกันคราวหน้าครับ ^__^