Quine N ราชินีและม้า


21

มีตัวแปรของปัญหา N-queens ที่รู้จักกันดีซึ่งเกี่ยวข้องกับราชินีและอัศวินและถูกกล่าวว่าเป็น"ยากมากขึ้น" 1 คำชี้แจงปัญหามีดังนี้:

คุณต้องวางอัศวิน kn และควีนส์จำนวนเท่ากันบนกระดานหมากรุกเพื่อไม่ให้ชิ้นส่วนใดโจมตีอีกชิ้นหนึ่ง จำนวนชิ้นส่วนสูงสุดที่คุณสามารถวางบนกระดานคืออะไรและคุณสามารถทำมันได้หลายวิธี

ในคุณจะได้รับอินพุตnระหว่าง 3 ถึง 32 (ในแบบที่เหมาะสมที่สุดสำหรับภาษาของคุณ) สำหรับn ที่ระบุอาจมีวิธีแก้ปัญหาศูนย์หรือมากกว่านั้น ในกรณีที่ไม่มีวิธีแก้ปัญหาคุณต้องเอาท์พุท / คืนค่าอะไร ( ไม่มี , สตริงว่าง , เท็จ , ... ) มิฉะนั้นคุณต้องให้ผลลัพธ์สองรายการ:

  1. บอร์ดแก้ปัญหา (ดูด้านล่าง) สำหรับขนาดnที่ไม่สามารถเพิ่มราชินีหรืออัศวินหมากรุกได้โดยไม่ต้องถูกโจมตี จะต้องมีจำนวนควีนและอัศวินเท่ากัน
  2. แหล่งที่มาของโปรแกรมที่จะรันซึ่งไม่รับอินพุตและให้ (i) โซลูชันอื่น (หรือไม่มีอะไร ) สำหรับขนาดเดียวกันnในรูปแบบเดียวกันและ (ii) โปรแกรมอื่นสำหรับโซลูชันถัดไป (และอื่น ๆ ... )

โปรดทราบว่า:

  • ลำดับของโปรแกรมจะต้องไม่ส่งคืนบอร์ดเดิมสองครั้งต้องครอบคลุมการแก้ปัญหาที่เป็นไปได้ทั้งหมดสำหรับปัญหาของขนาดnและในที่สุดก็ต้องยุติ (ไม่มีการแสดงผล)
  • คุณสามารถคืนค่าสองค่าคืนค่าหนึ่งแล้วพิมพ์ค่าอื่นหรือพิมพ์ค่าคืนสองค่า
  • อย่างไรก็ตามหากคุณพิมพ์ทั้งบอร์ดและโปรแกรมถัดไปบอร์ดจะต้องไม่ถูกพิจารณาว่าเป็นส่วนหนึ่งของโปรแกรมถัดไป (ฉันขอแนะนำให้พิมพ์บอร์ดเป็นข้อคิดเห็นหรือใช้ทั้งเอาต์พุตมาตรฐานและสตรีมข้อผิดพลาด)
  • program-as-a-return-value ต้องเป็นสตริงไม่ใช่การปิด

รูปแบบคณะกรรมการ

  • คณะกรรมการเป็นตารางที่มีขนาดn
  • บอร์ดเซลล์สามารถว่างเปล่าราชินีหรืออัศวิน
  • คุณต้องเลือกค่าที่แตกต่างสำหรับเซลล์แต่ละประเภท (เช่นคุณสามารถใช้สัญลักษณ์อื่นนอกเหนือจาก Q, N เมื่อพิมพ์บอร์ด)
  • หากคุณส่งคืนบอร์ดที่ไม่ใช่สตริงจะต้องเป็นคอลเล็กชันที่ได้รับคำสั่งของn 2ของบอร์ด (เช่นเมทริกซ์เวกเตอร์หรือรายการในลำดับแถว / คอลัมน์หลัก, ... )
  • หากคุณพิมพ์บอร์ดคุณสามารถพิมพ์มันยกกำลังสองหรือเป็นบรรทัด ตัวอย่างเช่นบอร์ดโซลูชันขนาด 4 สามารถพิมพ์ได้ดังต่อไปนี้ (ไม่จำเป็นต้องใช้ช่องว่างสัญลักษณ์ตามดุลยพินิจของคุณ):

    Q - - -
    - - - -
    - - - -
    - - N -
    

    หากคุณรู้สึกเช่นนั้นคุณสามารถส่งออก:

    ♛ · · ·
    · · · ·
    · · · ·
    · · ♞ ·
    

    ... แต่นี่ก็เพียงพอแล้ว:

    Q-------------N-
    

    ไม่สำคัญว่าคุณจะวนซ้ำในเซลล์ตามลำดับแถวหลักหรือคอลัมน์หลักเนื่องจากมีวิธีแก้ปัญหาแบบสมมาตร ตัวอย่างเช่นโซลูชันสำหรับ n = 4 คือ:

    Q------N--------
    Q----------N----
    Q------------N--
    Q-------------N-
    -Q----------N---
    -Q------------N-
    -Q-------------N
    --Q---------N---
    --Q----------N--
    --Q------------N
    ---QN-----------
    ---Q----N-------
    ---Q---------N--
    ---Q----------N-
    ---NQ-----------
    ----Q------N----
    ----Q----------N
    N------Q--------
    -------QN-------
    -------Q----N---
    ---N----Q-------
    -------NQ-------
    --------Q------N
    N----------Q----
    ----N------Q----
    -----------QN---
    -N----------Q---
    --N---------Q---
    -------N----Q---
    -----------NQ---
    N------------Q--
    --N----------Q--
    ---N---------Q--
    N-------------Q-
    -N------------Q-
    ---N----------Q-
    -N-------------Q
    --N------------Q
    ----N----------Q
    --------N------Q
    

นอกจากนี้คุณยังสามารถดูการแก้ปัญหาสำหรับ n = 5 เป็นเมทริกซ์ ; บอร์ดมี#, qและnสัญลักษณ์ซึ่งเป็นเซลล์ที่ว่างเปล่าของชนิดที่แตกต่างกัน (ดูคำตอบของฉันด้านล่าง) ฉันนับ2836 บอร์ดสำหรับn = 6เหมือนในคำตอบของ Sleafar (ฉันแนะนำข้อบกพร่องเมื่อลดจำนวนไบต์ แต่ตอนนี้ได้รับการแก้ไขแล้ว)

ขอบคุณมากสำหรับ Sleafar ที่ค้นหาไม่ใช่หนึ่งข้อยกเว้นสองข้อในรหัสของฉัน

คะแนน

รหัสที่สั้นที่สุดในหน่วยไบต์ชนะ

เราวัดขนาดของโปรแกรมแรกหนึ่งซึ่งยอมรับn


1 . ราชินีและอัศวินโดย Roger KW Hui (ระวัง! มีคำตอบ)


4
บางทีคุณควรวางรางวัลนี้ สุจริตปัญหาคือยากพอโดยไม่มีส่วนควิน
mbomb007

เราสามารถใช้สัญลักษณ์อื่นนอกเหนือจาก Q, N และ - เพื่อแสดงถึงราชินีและอัศวินและว่างเปล่าตราบใดที่มันแตกต่างกัน?
ทำให้เสียชีวิต

@ ทำให้ใช่แน่นอน
coredump

1
@coredump ฉันหมายถึงการอ่านเนื้อหาของฟังก์ชั่น และฉันจะถือว่าเป็น "ใช่คุณได้รับอนุญาตให้อ่านซอร์สโค้ดและ / หรือเนื้อหาของฟังก์ชันของคุณเอง" (วิธีการแก้ปัญหาของฉันขึ้นอยู่กับมันดังนั้น ... )
wizzwizz4

1
@coredump ถ้าผมเข้าใจความท้าทายอย่างถูกต้องแล้วการแก้ปัญหาการอ้างอิงของคุณสำหรับ n = 6 มีรายการไม่ถูกต้อง (เช่น-------------------------N--------Q-ไม่ถูกต้องเพราะชิ้นส่วนต่าง ๆ สามารถเข้ามา: Q--------N---------------N--------Q-)
Sleafar

คำตอบ:


2

Groovy 515 ไบต์

X=0;Y="N="+args[0]+";M=N*N;S=[];def f(b,i,j,v){(i..<j).findAll{k->!(0..<M).any{l->w=b[l];r=(k.intdiv(N)-l.intdiv(N)).abs();c=(k%N-l%N).abs();s=v+w;w>0&&(k==l||(r==0||c==0||r==c?s<4:r<3&&c<3&&s>2))}}.collect{a=b.clone();a[it]=v;[it,a]}};def r(b,q,n){f(b,q,M,1).each{i->f(i[1],n,M,2).each{j->if(f(j[1],0,M,1).any{f(it[1],0,M,2)}){r(j[1],i[0],j[0])}else{S.add(j[1])}}}};r(new int[M],0,0);if(x<S.size()){sprintf('//%s%cX=%d;Y=%c%s%c;print(Eval.xy(X,Y,Y))',S[x].toString(),10,x+1,34,y,34)}else{''}";print(Eval.xy(X,Y,Y))

การทดสอบ

ระบุnเป็นอาร์กิวเมนต์บรรทัดคำสั่ง:

groovy qak.groovy 4

บรรทัดแรกของเอาต์พุตเป็นคำตอบเสมอ (0 = ว่าง, 1 = ราชินี, 2 = อัศวิน), ตามด้วยรหัสในบรรทัดที่สอง:

//[1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]
X=1;Y="N=4;M=N*N;S=[];def f(b,i,j,v){(i..<j).findAll{k->!(0..<M).any{l->w=b[l];r=(k.intdiv(N)-l.intdiv(N)).abs();c=(k%N-l%N).abs();s=v+w;w>0&&(k==l||(r==0||c==0||r==c?s<4:r<3&&c<3&&s>2))}}.collect{a=b.clone();a[it]=v;[it,a]}};def r(b,q,n){f(b,q,M,1).each{i->f(i[1],n,M,2).each{j->if(f(j[1],0,M,1).any{f(it[1],0,M,2)}){r(j[1],i[0],j[0])}else{S.add(j[1])}}}};r(new int[M],0,0);if(x<S.size()){sprintf('//%s%cX=%d;Y=%c%s%c;print(Eval.xy(X,Y,Y))',S[x].toString(),10,x+1,34,y,34)}else{''}";print(Eval.xy(X,Y,Y))

สคริปต์ต่อไปนี้สามารถใช้สำหรับการทดสอบอัตโนมัติ (ระบุnเป็นอาร์กิวเมนต์อีกครั้ง):

#!/bin/bash
set -e
test -n "$1"
groovy qak.groovy "$1" > t
while test -s t; do
    head -n1 t
    groovy t > t2
    mv t2 t
done

เนื่องจากฉันพยายามทำให้โซลูชันมีขนาดเล็กที่สุดเท่าที่จะทำได้ช้ามาก (ดูรายละเอียดด้านล่าง) ฉันทดสอบเฉพาะ n = 4 กับรุ่นนี้เพื่อดูว่าการเลิกใช้งานนั้นใช้งานได้หรือไม่

ผล

n = 4: 40 โซลูชั่น ( รูปแบบที่แปลงแล้ว )
n = 5: 172 โซลูชั่น ( รูปแบบที่แปลงแล้ว )
n = 6: 2836 โซลูชั่น ( รูปแบบที่แปลงแล้ว )

ขั้นตอนวิธี

นี่เป็นโซลูชันที่ไม่ใช่รุ่นควินินเล็กน้อย:

N=args[0] as int
M=N*N
S=[]

/**
 * Generate a list of valid posibilities to place a new piece.
 * @param b Starting board.
 * @param i Start of the index range to check (inclusive).
 * @param j End of the index range to check (exclusive).
 * @param v Value of the new piece (1=queen, 2=knight).
 * @return A pair with the index of the new piece and a corresponding board for each possibility.
 */
def f(b,i,j,v){
    (i..<j).findAll{k->
        !(0..<M).any{l->
            w=b[l]
            r=(k.intdiv(N)-l.intdiv(N)).abs()
            c=(k%N-l%N).abs()
            s=v+w
            w>0&&(k==l||(r==0||c==0||r==c?s<4:r<3&&c<3&&s>2))
        }
    }.collect{
        a=b.clone();a[it]=v;[it,a]
    }
}

/**
 * Recursively look for solutions.
 * @param b Starting board.
 * @param q Start of the index range to check for queens.
 * @param n Start of the index range to check for knights.
 */
def r(b,q,n){
    f(b,q,M,1).each{i->
        f(i[1],n,M,2).each{j->
            if(f(j[1],0,M,1).any{f(it[1],0,M,2)}){
                r(j[1],i[0],j[0])
            }else{
                S.add(j[1])
            }
        }
    }
}

r(new int[M],0,0)
S.each{println(it)}

Quineification

ฉันใช้วิธีการง่ายๆที่นี่เพื่อรักษาขนาดรหัสให้ต่ำ

X=0;Y="...";print(Eval.xy(X,Y,Y))

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

รหัสที่แก้ไขจะพิมพ์วิธีแก้ปัญหาที่ชี้ไปXเพิ่มXและผนวกสำเนาของตัวเอง:

//[...]
X=1;Y="...";print(Eval.xy(X,Y,Y))

ฉันพยายามเอาท์พุทโซลูชันทั้งหมดเป็นรหัสสำหรับขั้นตอนที่สอง แต่สำหรับ n = 6 มันผลิตโค้ดมากเกินไปสำหรับ Groovy ที่จะจัดการ


คำตอบที่ดีงานที่ดี
coredump

6

เสียงกระเพื่อมสามัญ, 737

คำตอบด้วยตนเอง

(lambda(n &aux(d 1))#2=(catch'$(let((s(* n n))(c d))(labels((R(w % @ b ! &aux r h v a)(loop for u from % below s do(setf h(mod u n)v(floor u n)a #4=(aref b u))(when(< 0(logand a w)4)(and(= 6 w)!(throw'! t))(let((b(copy-seq b))(o 5))(loop for(K D)on'(-1 -2 -1 2 1 -2 1 2)for y =(+ K v)for x =(+(or D -1)h)for u =(and(< -1 y n)(< -1 x n)(+(* y n)x))if u do #1=(if(< #4#4)(setf #4#(logand #4#o(if(= w o)3 0)))))(#8=dotimes(y N)(#8#(x N)(let((u(+(* y n)x))(o 6))(if(or(= x h)(= y v)(=(abs(- h x))(abs(- v y))))#1#))))(setf #4#w r(or(cond((= w 5)(R 6 @ U b !))((R 5 @ U b())t)((catch'!(R 5 0 0 b t))t)(t(and(=(decf c)0)(incf d)(or(format t"~%(lambda(&aux(n ~A)(d ~A))~%~S)"n d'#2#)(throw'$ B)))t))r)))))r))(R 5 0 0(fill(make-array s)3)())))))

ตัวอย่าง

วางด้านบนใน REPL ซึ่งส่งคืนวัตถุฟังก์ชัน:

#<FUNCTION (LAMBDA (N &AUX (D 1))) {1006D1010B}>

เรียกมันว่า (ดาวถูกผูกไว้กับค่าที่ส่งคืนล่าสุด):

QN> (funcall * 4)

พิมพ์สิ่งต่อไปนี้ไปยังเอาต์พุตมาตรฐาน:

(lambda(&aux(n 4)(d 2))
#1=(CATCH '$
 (LET ((S (* N N)) (C D))
   (LABELS ((R (W % @ B ! &AUX R H V A)
              (LOOP FOR U FROM % BELOW S
                    DO (SETF H (MOD U N)
                             V (FLOOR U N)
                             A #2=(AREF B U)) (WHEN (< 0 (LOGAND A W) 4)
                                                (AND (= 6 W) !
                                                     (THROW '! T))
                                                (LET ((B (COPY-SEQ B))
                                                      (O 5))
                                                  (LOOP FOR (K D) ON '(-1
                                                                       -2
                                                                       -1 2
                                                                       1 -2
                                                                       1 2)
                                                        FOR Y = (+ K V)
                                                        FOR X = (+
                                                                 (OR D -1)
                                                                 H)
                                                        FOR U = (AND
                                                                 (< -1 Y N)
                                                                 (< -1 X N)
                                                                 (+ (* Y N)
                                                                    X))
                                                        IF U
                                                        DO #3=(IF (< #2# 4)
                                                                  (SETF #2#
                                                                          (LOGAND
                                                                           #2#
                                                                           O
                                                                           (IF (=
                                                                                W
                                                                                O)
                                                                               3
                                                                               0)))))
                                                  (DOTIMES (Y N)
                                                    (DOTIMES (X N)
                                                      (LET ((U
                                                             (+ (* Y N) X))
                                                            (O 6))
                                                        (IF (OR (= X H)
                                                                (= Y V)
                                                                (=
                                                                 (ABS
                                                                  (- H X))
                                                                 (ABS
                                                                  (- V
                                                                     Y))))
                                                            #3#))))
                                                  (SETF #2# W
                                                        R
                                                          (OR
                                                           (COND
                                                            ((= W 5)
                                                             (R 6 @ U B !))
                                                            ((R 5 @ U B
                                                                NIL)
                                                             T)
                                                            ((CATCH '!
                                                               (R 5 0 0 B
                                                                  T))
                                                             T)
                                                            (T
                                                             (AND
                                                              (= (DECF C)
                                                                 0)
                                                              (INCF D)
                                                              (OR
                                                               (FORMAT T
                                                                       "~%(lambda(&aux(n ~A)(d ~A))~%~S)"
                                                                       N D
                                                                       '#1#)
                                                               (THROW '$
                                                                 B)))
                                                             T))
                                                           R)))))
              R))
     (R 5 0 0 (FILL (MAKE-ARRAY S) 3) NIL)))))

นอกจากนี้ค่าที่ส่งคืนโดยฟังก์ชันนี้คือ:

#(5 0 0 0 0 0 0 6 0 0 0 2 0 2 0 0)

... ซึ่งเป็นตัวอักษรอาร์เรย์ หมายเลข 5 หมายถึงราชินี 6 สำหรับอัศวินและสิ่งอื่น ๆ หมายถึงเซลล์ว่างยกเว้นมีข้อมูลเพิ่มเติมที่เก็บไว้ภายใน ถ้าเราคัดลอก - วางฟังก์ชั่นที่ส่งคืนไปยังแบบจำลองเราได้รับฟังก์ชั่นใหม่

#<FUNCTION (LAMBDA (&AUX (N 4) (D 2))) {100819148B}>

และเราสามารถเรียกมันได้โดยไม่มีข้อโต้แย้ง:

QN> (funcall * )

การเรียกนี้ส่งคืนโซลูชันใหม่#(5 0 0 0 0 0 0 2 0 0 0 6 0 0 2 0)และแหล่งที่มาของฟังก์ชันอื่น (ไม่แสดงที่นี่) ในกรณีที่ฟังก์ชั่นดั้งเดิมหรือฟังก์ชั่นที่สร้างขึ้นล่าสุดไม่พบวิธีแก้ไขจะไม่มีการพิมพ์อะไรเลย

ค่าภายใน

|----------+--------+---------+--------+-----------------|
|          | Binary | Decimal | Symbol | Meaning         |
|----------+--------+---------+--------+-----------------|
| Empty    |    000 |       0 | -      | safe for none   |
|          |    001 |       1 | q      | safe for queen  |
|          |    010 |       2 | n      | safe for knight |
|          |    011 |       3 | #      | safe for both   |
|----------+--------+---------+--------+-----------------|
| Occupied |    101 |       5 | Q      | a queen         |
|          |    110 |       6 | K      | a knight        |
|----------+--------+---------+--------+-----------------|

ฉันเคยสร้างวิธีแก้ปัญหาน้อยเกินไป ตอนนี้ฉันเผยแพร่สิ่งที่เซลล์มีความปลอดภัยสำหรับราชินีและอัศวินอิสระ ตัวอย่างเช่นนี่คือผลลัพธ์สำหรับ n = 5 ที่มีการพิมพ์แบบสวย:

Q - - - - 
- - - n N 
- q - n n 
- # n - n 
- n # # - 

เมื่อเราวางราชินีQตำแหน่งที่เป็นอัศวินย้ายออกจากราชินีนี้ยังคงปลอดภัยสำหรับราชินีและแสดงqว่า ในทำนองเดียวกันอัศวินที่เข้าถึงได้โดยราชินีเท่านั้นจะปลอดภัยต่ออัศวินคนอื่น ๆ ค่าเป็นบิตและ -ed เพื่อแสดงถึงการเคลื่อนไหวที่เป็นไปได้และบางเซลล์สามารถเข้าถึงได้โดยไม่ต้องใช้ชิ้นส่วน

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

# # # # # #     q - - - q #     - - - - - #     - - - - - #     - - - - - n
# # # # # #     - - Q - - -     - - Q - - -     - - Q - - -     - - Q - - -
# # # # # #     q - - - q #     q - - - - -     Q - - - - -     Q - - - - -
# # # # # #     - q - q - #     - q - - - n     - - - - - n     - - - - - n
# # # # # #     # # - # # -     n n - n N -     - - - n N -     - - - - N -
# # # # # #     # # - # # #     # # - n n n     - # - - n n     - n - - n N

วิธีการที่ไม่ใช่ควิน

Ungolfed รุ่นที่แสดงความคิดเห็น

(defun queens-and-knights
    (n    ; size of problem
     fn   ; function called for each solution

     ;; AUX parameters are like LET* bindings but shorter.
     &aux
       ;; total number of cells in a board
       (s (* n n)))

  (labels
      ;; Define recursive function R
      ((R (w      ; what piece to place: 5=queen, 6=knight 
           %      ; min position for piece of type W
           @      ; min position for the other kind of piece
           b      ; current board
           !      ; T iff we are in "check" mode (see below)
           &aux  
           r      ; result of this function: will be "true" iff we can
                  ; place at least one piece of type W on the board b
           h      ; current horizontal position 
           v      ; current vertical position
           a      ; current piece at position (h,v)
           )

         (loop
            ;; only consider position U starting from position %,
            ;; because any other position below % was already visited
            ;; at a higher level of recursion (e.g. the second queen
            ;; we place is being placed in a recursive call, and we
            ;; don't visit position before the first queen).
            for u from % below s

            do
              (setf h (mod u n)         ; Intialize H, V and A
                    v (floor u n)       ; 
                    a (aref b u))       ; 

            ;; Apply an AND mask to current value A in the board
            ;; with the type of chess piece W. In order to consider
            ;; position U as "safe", the result of the bitwise AND
            ;; must be below 4 (empty cell) and non-null.
              (when (< 0 (logand a w) 4)

                ;; WE FOUND A SAFE PLACE TO PUT PIECE W

                (when (and ! (= 6 w))
                  ;; In "check" mode, when we place a knight, we knwo
                  ;; that the check is successful. In other words, it
                  ;; is possible to place an additional queen and
                  ;; knight in some board up the call stack. Instead
                  ;; of updating the board we can directly exit from
                  ;; here (that gave a major speed improvement since
                  ;; we do this a lot). Here we do a non-local exit to
                  ;; the catch named "!".
                  (throw '! t))

                ;; We make a copy of current board b and bind it to the
                ;; same symbol b. This allocates a lot of memory
                ;; compared to the previous approach where I used a
                ;; single board and an "undo" list, but it is shorter
                ;; both in code size and in runtime.
                (let ((b (copy-seq b)))

                  ;; Propagate knights' constraints
                  (loop
                     ;; O is the other kind of piece, i.e. queen here
                     ;; because be propagate knights. This is used as
                     ;; a mask to remove knights pieces as possible
                     ;; choices.
                     with o = 5

                     ;; The list below is arranged so that two
                     ;; consecutive numbers form a knight-move. The ON
                     ;; iteration keyword descend sublist by sublist,
                     ;; i.e. (-1 -2), (-2 -1), (-1 2), ..., (2 NIL). We
                     ;; destructure each list being iterated as (K D),
                     ;; and when D is NIL, we use value -1.
                     for (K D) on '(-1 -2 -1 2 1 -2 1 2)

                     ;; Compute position X, Y and index U in board,
                     ;; while checking that the position is inside the
                     ;; board.
                     for y = (+ K v)
                     for x = (+ (or D -1) h)
                     for u = (and (< -1 y n)
                                  (< -1 x n)
                                  (+(* y n)x))

                     ;; if U is a valid position...
                     if u
                     do
                     ;; The reader variable #1# is affected to the
                     ;; following expression and reused below for
                     ;; queens. That's why the expression is not
                     ;; specific to knights. The trick here is to
                     ;; use the symbols with different lexical
                     ;; bindings.
                       #1=(when (< (aref b u) 4) ; empty?
                            (setf (aref b u)

                                  (logand
                                   ;; Bitwise AND of current value ...
                                   (aref b u)

                                   ;; ... with o: position U is not a
                                   ;; safe place for W (inverse of O)
                                   ;; anymore, because if we put a W
                                   ;; there, it would attack our
                                   ;; current cell (H,V).
                                   o

                                   ;; ... and with zero (unsafe for
                                   ;; all) if our piece W is also a
                                   ;; knight (resp. queen). Indeed, we
                                   ;; cannot put anything at position
                                   ;; U because we are attacking it.
                                   (if (= w o) 3 0)))))

                  ;; Propagate queens' constraints
                  (dotimes (y N)
                    (dotimes (x N)
                      (let ((u(+(* y n)x))(o 6))
                        (if (or (= x h)
                                (= y v)
                                (= (abs(- h x)) (abs(- v y))))

                            ;; Same code as above #1=(if ...)
                            #1#))))

                  (setf
                   ;; Place piece
                   (aref b u) w

                   ;; Set result value
                   r (or (cond
                           ;; Queen? Try to place a Knight and maybe
                           ;; other queens. The result is true only if
                           ;; the recursive call is.
                           ((= w 5) (R 6 @ U b !))

                           ;; Not a queen, so all below concern   
                           ;; knights: we always return T because
                           ;; we found a safe position.
                           ;; But we still need to know if
                           ;; board B is an actual solution and 
                           ;; call FN if it is.
                           ;; ------------------------------------

                           ;; Can be place a queen too? then current
                           ;; board is not a solution.
                           ((R 5 @ U b()) t)

                           ;; Try to place a queen and a knight
                           ;; without constraining the min positions
                           ;; (% and @); this is the "check" mode that
                           ;; is represented by the last argument to
                           ;; R, set to T here. If it throws true,
                           ;; then board B is a duplicate of a
                           ;; previous one, except that it is missing
                           ;; pieces due to constraints % and @. The
                           ;; "check" mode is a fix to a bug where we
                           ;; reported as solutions boards where there
                           ;; was still room for other pieces.
                           ((catch'!(R 5 0 0 b t)) t)

                           ;; Default case: we could not add one more
                           ;; layer of pieces, and so current board B
                           ;; is a solution. Call function FN.
                           (t (funcall fn b) t))

                         ;; R keeps being true if it already was for
                         ;; another position.
                         r)))))

         ;; Return result R
         r))

    ;; Start search with a queen and an empty board.
    (R 5 0 0 (fill (make-array s) 3)  nil)))

รายการซ้ำและข้อบกพร่อง

ทางออกแรกของฉันแสดงผลลัพธ์ที่ซ้ำกัน เพื่อที่จะแก้ปัญหานี้ฉันได้แนะนำตัวนับสองตัวสำหรับราชินีและอัศวิน ตัวนับสำหรับราชินี (resp. knights) คอยติดตามตำแหน่งแรกในกระดานที่มีราชินี (resp. knight) อยู่: ฉันเพิ่มราชินี (resp. a knight) ในตำแหน่งที่ตามตำแหน่งที่น้อยที่สุดนั้นเท่านั้น

วิธีการดังกล่าวทำให้ฉันไม่สามารถกลับมาแก้ปัญหาที่พบในการทำซ้ำก่อนหน้านี้เพราะฉันทำซ้ำกับตำแหน่งของราชินี (resp. knight) ที่เพิ่มขึ้น

อย่างไรก็ตาม Sleafar สังเกตเห็นว่ามีวิธีแก้ปัญหาที่อาจมีที่ว่างสำหรับราชินีและอัศวินซึ่งขัดกับกฎ ในขณะที่ฉันต้องกลับไปใช้การค้นหาปกติและเก็บโซลูชันที่รู้จักทั้งหมดเพื่อป้องกันการซ้ำซ้อนซึ่งรู้สึกว่าแพงเกินไป (ทั้งในแง่ของไบต์และการใช้หน่วยความจำ)

แต่นี่คือสิ่งที่ฉันทำตอนนี้: เมื่อพบวิธีแก้ปัญหาคณะกรรมการที่มีศักยภาพฉันพยายามที่จะเพิ่มหนึ่งควีนและอัศวินอย่างใดอย่างหนึ่งโดยไม่คำนึงถึงเคาน์เตอร์ (เช่นสำหรับเซลล์ทั้งหมดบนกระดาน) หากเป็นไปได้บอร์ดปัจจุบันจะซ้ำกับบอร์ดก่อนหน้าและฉันปฏิเสธวิธีแก้ปัญหา

การทดสอบ

|---+---------+------------+--------------|
| N |  boards |    seconds |        bytes |
|---+---------+------------+--------------|
| 3 |       0 |          0 |        32768 |
| 4 |      40 |          0 |       360416 |
| 5 |     172 |          0 |      3440016 |
| 6 |    2836 |   0.085907 |     61251584 |
| 7 |   23876 |   1.265178 |    869666288 |
| 8 |  383586 |  24.991300 |  17235142848 |
| 9 | 6064506 | 524.982987 | 359952648832 |
|---+---------+------------+--------------|

ควิน-ification

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.