ไม่ได้เขียน blog มานานมาก
แต่ว่าตอนนี้มีองค์ประกอบดีๆ 3 อย่างคือ
1. เพิ่งพลาดไม่ได้ join
codejam เลยต้องฝึกฝีมือเผื่อปีหน้า
2. กำลังหัดเขียน
f# 3. ช่วงนี้งานค่อนข้างโอเค ไม่ยุ่งมาก
เลยตั้งเป้าว่า solve codejam ไปเรื่อย ๆ ด้วย f# และเขียน blog ไปด้วย
เริ่มที่ข้อแรก
Alien Numbers โจทย์คือ จะมีตัวเลขภาษาต่างดาวมา 2 ชุด ให้แปลจากตัวเลขภาษานึงไปอีกภาษานึง
สมมติมนุษย์ใช้เลข
อารบิก 0123456789 มนุษย์ต่างดาวใช้เลข
hex 0123456789abcdef
ดังนั้นเลข 10 จะเท่ากับ a
มนุษย์ต่างดาวไม่ได้ใช้ภาษาเหมือนเรา 0-9 ของเขาอาจจะเป็น )!@#$%^&*(
แต่หลักการนับเหมือนเลขของมนุษย์ทุกอย่าง
อ่านรายละเอียดเพิ่ม
ที่นี่ครับ
โจทย์ข้อนี้ถือว่าง่ายมาก ถ้ารู้จัก
เลขฐานก็สบายเลย
วิธีคิดคือให้แปลจากภาษาแรกเป็น int ก่อน แล้วจาก int ค่อยแปลเป็นภาษาที่สอง
เริ่มจาก function หลัก
let solve value txt1 txt2 =
function ชื่อ solve
value คือ เลขที่ต้องแปล เช่น foo
txt1 คือ ชุดตัวเลขของเลขที่ต้องแปล เช่น of8
txt2 คือ ชุดตัวเลขอีกภาษานึง ที่เราต้องการแปลเป็นภาษานี้ เช่น 0123456789
value type เป็น string ส่วน txt1 กับ txt2 เป็น char[]
function การแปลจาก txt1 เป็น int คือ
let txtToNum txt v =
let baseN = Array.length txt
let foldFn a b = a * baseN + Array.IndexOf(txt, b)
Seq.fold foldFn 0 v
baseN คือ จำนวนเลขฐาน เช่น of8 เป็นเลขฐาน 3
foldFn คือ สูตรการคำนวนเลขฐานอื่นๆ เป็น int
โดยเอาเลขก่อนหน้า (a) x เลขฐาน (baseN) + ค่าของตัวอักษรนั้น
เช่นเลข foo จาก of8
โดยถ้านับตามตำแหน่ง f เท่ากับ 1 ส่วน o เท่ากับ 0
f = 1
fo = 1 * 3 + 0 = 3
foo = 3 * 3 + 0 = 9
ดังนั้น foo = 9
function การแปลจาก int เป็น txt2 คือ
let numToTxt txt v =
let baseN = Array.length txt
let unfoldFn = function
| -1 -> None
| n -> match Math.DivRem(n, baseN) with
| 0, r -> Some(r, -1)
| d, r -> Some(r, d)
v |> Seq.unfold unfoldFn
|> Enumerable.Reverse
|> Seq.map (Array.get txt)
|> Seq.map string
|> String.Concat
unfoldFn คือ function แปลเลข int เป็นเลขฐานใด ๆ
สมมติเป็นเลข 454 และต้องการแปลเป็นเลขฐาน 6
454 / 6 ได้ 75 เศษ 4
75 / 6 ได้ 12 เศษ 3
12 / 6 ได้ 2 เศษ 0
2 / 6 ได้ 0 เศษ 2
เราจะได้ 4,3,0,2 ผลลัพธ์ที่ได้ต้องอ่านย้อนหลัง
เราเลยต้อง call Enumerable.Reverse เป็น 2,0,3,4
Seq.map (Array.get txt) คือการ map กับอีกชุดอักษร
เช่น 2,0,3,4 map กับ A?JM!. ก็จะกลายเป็น J,A,M,!
แล้ว Seq.map string กับ String.Concat คือ แปลงเป็น string
จาก J,A,M,! เป็น JAM!
เวลาเรียก function ก็ง่าย
value |> txtToNum txt1
|> numToTxt txt2
โยน value เข้าไป txtToNum และเอาผลลัพธ์ไป numToTxt
จบ