Just algorithm!
แก้ปัญหา 8 Queens Puzzle ด้วย Linq

รู้จัก 8 queens puzzle มั้ยครับ?
กฎของ 8 queens puzzle มีอยู่ว่า
ให้วาง queen 8 ตัว บนตาราง 8x8
โดยที่ queen แต่ละตัว ไม่กินกันเอง



เอาล่ะครับ คุณลองเขียน Code ของคุณดู ภาษาอะไรก็ได้ เขียนยังไงครับ
นี่เป็นตัวอย่าง Code 8 queens ของ Python นะครับ

def n_queens(n, width):
     if n == 0:
        return [[]] # one solution, the empty list
    else:
        return add_queen(n-1, width, n_queens(n-1, width))

def add_queen(new_row, width, previous_solutions):
    solutions = []
    for sol in previous_solutions:
        # Try to place a queen on each column on row new_row.
        for new_col in range(width):
            # print 'trying', new_col, 'on row', new_row
            if safe_queen(new_row, new_col, sol):
                # No interference, so add this solution to the list.
                solutions.append(sol + [new_col])
    return solutions

def safe_queen(new_row, new_col, sol):
    # Check against each piece on each of the new_row existing rows.
    for row in range(new_row):
        if (sol[row] == new_col or                  # same column clash
            abs(sol[row] - new_col) == abs(row - new_row)):   # diagonal clash
                return 0
    return 1

for sol in n_queens(8, 8):
   print sol

Code Python ผมคัดลอกมาจาก wiki นะครับ

Code Python ที่ว่าสั้น ลองเปรียบเทียบกับ C# ดูกัน
โดยใช้หลักของ Functional Programming และ Linq

//ประกาศ function สำหรับทำ NQueens
Func<IEnumerable<int>, IEnumerable<IEnumerable<int>>> nQueens = null;

                    //queen ตัวปัจจุบัน
nQueens = queens => from q in queens

                    //join กับ NQueens จาก queens ตัวที่เหลือ, ตัวที่เหลือต้องมีค่าไม่เท่ากับตัวปัจจุบัน
                    from qs in nQueens(queens.Where(t => t != q))

                    //queen ตัวปัจจุบัน ต้องมีเส้นทะแยงมุม ไม่เท่ากับ NQueens ตัวใดเลย
                    where !qs.Where((t, i) => i + 1 == Math.Abs(q - t)).Any()
                   
                    //เชื่อม queen ตัวปัจจุบันกับ NQueens
                    select new[] { q }.Concat(qs);

//ถ้า queen เหลือตัวเดียว, NQueens ก็มีแค่ solution เดียว
nQueens = nQueens.When(queens => queens.Count() == 1, queens => new[] { queens });


จบแล้วครับ Smiley
ใช้แค่ 3 statements สำหรับเขียน Function
Method ชื่อ When เอามาจาก Post นี้ นะครับ

ลอง Output ออกมาเป็นแบบ Console ดู

Console.WriteLine("  A B C D E F G H");
nQueens(0.To(7)).First().ForEach((q, i) =>
    Console.WriteLine("{0} " + "_ ".Repeat(q) + "Q " + "_ ".Repeat(7 - q), i + 1)
);
//  A B C D E F G H
//1 Q _ _ _ _ _ _ _
//2 _ _ _ _ Q _ _ _
//3 _ _ _ _ _ _ _ Q
//4 _ _ _ _ _ Q _ _
//5 _ _ Q _ _ _ _ _
//6 _ _ _ _ _ _ Q _
//7 _ Q _ _ _ _ _ _
//8 _ _ _ Q _ _ _ _


คำตอบถูกต้อง Smiley

เมื่อเปรียบเทียบกับ Code ของ Python ด้านบน
จะพบว่าประหยัดบรรทัดไปเยอะ แถมอ่านง่าย
อ่านแล้วเข้าใจการทำงานของ Function ได้ทันที

อีกสักตัวอย่างจาก โจทย์ในห้องหว้ากอ ของ คุณศล
"จากรูปด้านล่าง ใส่เลข 2-8 ลงในวงกลมที่ว่าง
โดยใช้เลขละหนึ่งครั้ง มีเงื่อนไขคือเลขแต่ละตัวจะต้อง
อยู่ระหว่าง (มีเพื่อนบ้านเป็น) เลขที่ใหญ่กว่ามัน หรือเล็กกว่ามันทั้งซ้าย-ขวา
ถามว่า เราสามารถใส่เลขได้กี่แบบ?

(ตัวอย่างเช่น 4-2-1 เลข 2 ตรงกลางผิดเงื่อนไข หรือ 4-2-3 เลข 2 ไม่ผิดเงื่อนไข)"



ใช้ for-loop คงดูซับซ้อน
แต่ถ้าเราใช้หลักการเดียวกับ N-Queens ด้านบน
รับรองง่ายนิดเดียว

Func<IEnumerable<int>, IEnumerable<IEnumerable<int>>> func = null;
func = set => from x in set
              from xs in func(set.Where(t => t != x))
              where (xs.Count() % 2 == 1) ? x > xs.First() : x < xs.First()
              select new[] { x }.Concat(xs);
func = func.When(set => !set.Any(), set => new[] { new[] { 1 } });

Console.WriteLine(func(2.To(8)).Count());
//272


เขียนเสร็จแล้ว Smiley
จะเห็นว่า Code ส่วนใหญ่จะคล้ายกับ N-Queens
แต่ต่างกันแค่ส่วนของ Where
ซึ่งบอกว่า ถ้าจำนวนเลขในวงแหวนเป็นเลขคี่ เลขปัจจุบันต้องมากกว่าเลขล่าสุด
แต่ถ้าจำนวนเลขในวงแหวนเป็นเลขคู่ เลขปัจจุบันต้องน้อยกว่าเลขล่าสุด

จบแล้วครับ Smiley
Post หน้ามาทำ Extension Methods กันดีกว่าครับ

* อ่านจบแล้ว กรุณา Comment ด้วยครับ เพื่อเป็น Feedback และเป็นกำลังใจ
* บทความนี้คัดลอกได้ แต่ต้องมี Link หรือ Url กลับมาที่หน้านี้ และเมื่อคัดลอกแล้วกรุณา Comment แจ้งด้วยครับ





Create Date : 31 สิงหาคม 2551
Last Update : 31 สิงหาคม 2551 1:34:00 น. 5 comments
Counter : 2220 Pageviews.

 
แจ่มครับ... ต้องแวะเวียนมาจับตาดูบล็อกนี้บ่อย ๆ ซะแล้ว


โดย: ศล วันที่: 31 สิงหาคม 2551 เวลา:17:14:52 น.  

 
ว้าว คุณศล ขอบคุณที่มาเจิมครับ


โดย: chaowman วันที่: 31 สิงหาคม 2551 เวลา:20:24:56 น.  

 
สุดยอดครับ ผมกำลังหัดใช้ linq อยู่เลย


โดย: rsquare IP: 58.64.51.190 วันที่: 16 มกราคม 2552 เวลา:16:17:38 น.  

 
ของผมมันได้ผลลัพธ์แบบนี้อ่ะคับ

A B C D E F G H
1 _8QueenGame.Program+Repeatd_1f ' 1[System.Char]Q _8QueenGame.Program+Repeatd__1f ' 1[System.Char]
2 _8QueenGame.Program+Repeatd_1f ' 1[System.Char]Q _8QueenGame.Program+Repeatd__1f ' 1[System.Char]
3 _8QueenGame.Program+Repeatd_1f ' 1[System.Char]Q _8QueenGame.Program+Repeatd__1f ' 1[System.Char]
4 _8QueenGame.Program+Repeatd_1f ' 1[System.Char]Q _8QueenGame.Program+Repeatd__1f ' 1[System.Char]
5 _8QueenGame.Program+Repeatd_1f ' 1[System.Char]Q _8QueenGame.Program+Repeatd__1f ' 1[System.Char]
6 _8QueenGame.Program+Repeatd_1f ' 1[System.Char]Q _8QueenGame.Program+Repeatd__1f ' 1[System.Char]
7 _8QueenGame.Program+Repeatd_1f ' 1[System.Char]Q _8QueenGame.Program+Repeatd__1f ' 1[System.Char]
8 _8QueenGame.Program+Repeatd_1f ' 1[System.Char]Q _8QueenGame.Program+Repeatd__1f ' 1[System.Char]


โดย: karpomman IP: 10.182.255.60, 203.144.240.232 วันที่: 2 กรกฎาคม 2553 เวลา:15:20:22 น.  

 
K.karpomman
คิดว่า Copy Method ผิดไปนะครับ
ลอง Download code ใน chaow.codeplex.com
หา Method ชื่อ Repeat ใน Class ชื่อ StringExt แล้วลองใช้ดูครับ


โดย: chaowman วันที่: 12 กรกฎาคม 2553 เวลา:1:20:07 น.  

ชื่อ :
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.