Just algorithm!
แก้โจทย์ Knight's Tour ด้วย C#

ช่วงนี้ไม่ค่อยมีเวลามาเขียนโปรแกรมแก้โจทย์ Algorithm เล่นนานละ
แต่ไปเจอโจทย์นึงที่ Web TwoGuru ชื่อว่า Knight's Tour
น่าสนใจเลยลองเขียนดูบ้าง



Knight's Tour คือ การเดินม้าในตารางหมากรุก 8x8
โดยเริ่มที่ช่องใดก็ได้ เดินไปเรื่อย ๆ ห้ามทับจุดเดิม และเดินให้ครบทุกช่อง
เห็นโจทย์ก็รู้เลยน่าสนใจ
ซึ่งดูผิวเผินน่าจะยาก จากการคำนวนของ Web TwoGuru เห็นว่ามีรูปแบบเป็น สี่แสนล้านล้านล้านล้านล้านล้านรูปแบบ !!! Smiley
แต่คิดว่าหลักการของ Functional Programming น่าจะแก้ปัญหานี้ได้ไม่ยาก Smiley

ไม่พูดพร่ำทำเพลง เขียนรูปแบบการเดินของม้าก่อนเลย

int[][] moves = new[] {
                    new[] {+1, -2},
                    new[] {+2, -1},
                    new[] {+2, +1},
                    new[] {+1, +2},
                    new[] {-1, +2},
                    new[] {-2, +1},
                    new[] {-2, -1},
                    new[] {-1, -2},
};


ต่อด้วยหากระดาน กระดาน 8x8 ซึ่งใช้ 64 ช่อง
ตอนแรกคิดว่าจะใช้ BitArray ขนาด 64 ช่อง แต่คิดไปคิดมา
ulong ก็เป็น Type ที่มี 64bit นี่หว่า เลยตัดสินใจใช้ ulong
ก็เลยต้องเขียนสูตรการแปลงจากตำแหน่งบนกระดานเป็น ulong และก็แปลงกลับ

Func<int[], ulong> positionToULong = pos => 1UL << (pos[1] * 8 + pos[0]);
Func<ulong, int[]> ulongToPosition = u => {
    int log2 = 0, x, y;
    while (u != 1) {
        log2++;
        u >>= 1;
    }
    y = Math.DivRem(log2, 8, out x);
    return new[] { x, y };
};


ต่อมาก็เขียนสูตรการเดินของม้าซะ
ในแต่ละช่องม้าสามารถเดินไปจุดไหนบ้างใช้สูตรนี้

Func<ulong, ulong[]> nextPoint = u => {
    var pos = ulongToPosition(u);
    return (from move in moves
            select new[] { pos[0] + move[0], pos[1] + move[1] } into nextPos
            where nextPos[0] >= 0 && nextPos[0] < 8 &&
                  nextPos[1] >= 0 && nextPos[1] < 8
            select positionToULong(nextPos)).ToArray();
};
nextPoint = nextPoint.Memoize();


ในสูตรถ้าม้าตัวไหนเดินออกนอกตารางก็ตัดทิ้งไป
แล้วก็จะเห็นคำสั่ง Memoize ในบรรทัดสุดท้าย
เป็นการทำให้ Function จำคำตอบได้ไม่ต้องคำนวณใหม่
อ่าน Article เก่า เพิ่มเติมครับ

และก็มาถึง Function สุดท้าย
เป็น Algorithm การเดินม้าให้ครบ 64 ตาแล้วครับ

Func<ulong, ulong, IEnumerable<IEnumerable<ulong>>> func = null;
func = (board, u) => {
    //ถ้าเดินทับจุดเดิม ก็ไม่มีผลลัพธ์
    if ((board & u) > 0)
        return Enumerable.Empty<IEnumerable<ulong>>();

    //ถ้าเดินครบ 64 ตา ก็คืนค่าตำแหน่งสุดท้าย
    var newBoard = board | u;
    if (newBoard == ulong.MaxValue)
        return u.ToEnumerable().ToEnumerable();

    //เอาตาเดินม้าถัดไป มาวนใส่ Function นี้
    //ได้ผลลัพธ์ ก็เอาตำแหน่งปัจจุบันมารวมกับคำตอบที่ได้
    return from px in nextPoint(u)
           from sol in func(newBoard, px)
           select new[] { u }.Concat(sol);
};


ป๊าด!!! จบแล้วครับ เริ่มรันได้เลย Smiley

var result = (from pos in func(0, 1).First().Select(ulongToPosition).WithIndex()
              group pos by pos.B[1] into g
              orderby g.Key
              select (from pos2 in g
                      orderby pos2.B[0]
                      select pos2.A.ToString("00")).Join(" ")).Join("rn");
Console.WriteLine(result);

//00 37 54 33 02 35 18 21
//53 46 01 36 19 22 03 16
//38 55 32 45 34 17 20 09
//47 52 39 56 23 10 15 04
//58 31 44 51 40 25 08 11
//43 48 57 24 61 14 05 26
//30 59 50 41 28 07 12 63
//49 42 29 60 13 62 27 06


ใช้เวลาไป 2 วินาทีกว่า ๆ!! Smiley
โค๊ดแปลงเป็นตารางมี Function แปลก ๆ ไม่ต้องงงว่ามาจากไหน
เป็น Function ที่ผมเขียนใช้เอง
สนใจไปหาดาวน์โหลดใน Framework ของผมนะครับ Smiley

เพื่อนผมมันบอกว่า Functional Programming อ่านยาก
เอาไปใช้ใน Production ไม่ได้
ผมก็ว่าจริงครับ ถ้าเขียนแล้วคนอื่นอ่านไม่เข้าใจ ก็เป็นโค๊ดที่ Maintain ไม่ได้
แต่มันก็เขียนสนุกครับ ตอนนี้เลยได้แต่เขียนคนเดียว มันส์คนเดียว Smiley
คนไหนเขียน Functional Programming บ้าง ยกมือขึ้นครับ !!! (จะมีมั้ยเนี่ย หายากจริง ๆ)




Create Date : 04 สิงหาคม 2552
Last Update : 4 สิงหาคม 2552 0:45:26 น. 4 comments
Counter : 2871 Pageviews.

 
สุดยอดคร้าบบบ


โดย: Executive Toilet วันที่: 4 สิงหาคม 2552 เวลา:15:05:39 น.  

 
เก่งมากครับ


โดย: zkaru วันที่: 5 สิงหาคม 2552 เวลา:7:41:18 น.  

 
ถ้าใช้ plinq เวลาจะเหลือแค่ 2 ใน 3 คับ


โดย: plinq IP: 124.120.88.207 วันที่: 16 ตุลาคม 2552 เวลา:16:38:52 น.  

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


โดย: milk IP: 58.10.84.108 วันที่: 30 เมษายน 2556 เวลา:11:47:22 น.  

ชื่อ :
Comment :
  *ใช้ code html ตกแต่งข้อความได้เฉพาะสมาชิก
 

chaowman
Location :
กรุงเทพฯ Thailand

[Profile ทั้งหมด]

ให้ทิปเจ้าของ Blog [?]
ฝากข้อความหลังไมค์
Rss Feed
Smember
ผู้ติดตามบล็อก : 8 คน [?]





New Comments
Group Blog
 
All Blogs
 
Friends' blogs
[Add chaowman's blog to your web]
Links
 

 Pantip.com | PantipMarket.com | Pantown.com | © 2004 BlogGang.com allrights reserved.