N-królowa koni i koni

21

Istnieje wariant dobrze znanego problemu N-królowych, który dotyczy królowych i rycerzy i jest uważany za „znacznie trudniejszy” 1 . Opis problemu jest następujący:

Musisz umieścić taką samą liczbę rycerzy ♞ i królowych ♛ na szachownicy, aby żaden pionek nie atakował żadnego innego pionka. Jaką maksymalną liczbę elementów możesz umieścić na planszy i ile różnych sposobów możesz to zrobić?

W tym wyzwaniu otrzymasz n od 3 do 32 (w sposób najbardziej odpowiedni dla twojego języka). Dla danego n może istnieć zero lub więcej rozwiązań powyższego problemu. Jeśli nie ma rozwiązania, musisz nic nie wyświetlać / zwracać ( zero , pusty ciąg , fałsz , ...). W przeciwnym razie musisz podać dwa wyniki:

  1. Plansza rozwiązania (patrz poniżej) dla rozmiaru n, gdzie nie jest możliwe dodanie szachowej królowej lub rycerza bez atakowania żadnego pionka. Musi być równa liczba królowych i rycerzy .
  2. Źródło programu do uruchomienia, który nie przyjmuje danych wejściowych i daje (i) inne rozwiązanie (lub nic ) dla tego samego rozmiaru n , w tym samym formacie, a także (ii) inny program dla następnego rozwiązania (i tak dalej) ...)

Uwaga:

  • Sekwencja programów nigdy nie może zwrócić tej samej płyty dwukrotnie, musi obejmować wszystkie możliwe rozwiązania problemu rozmiaru n i ostatecznie musi się zakończyć (nie generując żadnych danych wyjściowych).
  • Możesz zwrócić dwie wartości, zwrócić jedną i wydrukować drugą lub wydrukować dwie zwracane wartości.
  • jednak , jeśli drukować zarówno płytę i następny program, zarząd nie może być uważany za część następnego programu (polecam drukowania płytę w komentarzu, lub użyć zarówno standardowe strumienie wyjścia i błędów).
  • Program jako wartość zwrotna musi być łańcuchem, a nie zamknięciem.

Format planszy

  • Tablica ma kwadratowy rozmiar n .
  • Komórka planszowa może być pusta, królowa lub rycerz.
  • Musisz wybrać odrębne wartości dla każdego rodzaju komórek (tzn. Możesz użyć innych symboli niż Q, N podczas drukowania płytki).
  • Jeśli zwrócisz tablicę niesznurkową, musi to być uporządkowany zbiór n 2 wartości planszy (np. Macierz, wektor lub lista w kolejności rzędów / kolumn, ...).
  • Jeśli wydrukujesz tablicę, możesz wydrukować ją w kwadracie lub w linii. Na przykład tablicę rozwiązań wielkości 4 można wydrukować w następujący sposób (spacje nie są wymagane; symbole według własnego uznania):

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

    Jeśli tak uważasz, możesz także wygenerować:

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

    ... ale to wystarczy:

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

    Nie ma znaczenia, czy iterujesz przez komórki w kolejności rzędów lub kolumn, ponieważ istnieją rozwiązania symetryczne. Na przykład rozwiązania dla n = 4 to:

    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
    

Możesz także spojrzeć na rozwiązania dla n = 5 jako macierzy ; deski zawiera #, qoraz nsymbole, które są puste komórki różnego rodzaju (patrz moją odpowiedź poniżej). Liczę 2836 plansz dla n = 6 , jak w odpowiedzi Sleafara (wprowadziłem błąd przy zmniejszaniu liczby bajtów, ale teraz jest naprawiony).

Wielkie podziękowania dla Sleafar za znalezienie nie jednego, ale dwóch błędów w moim kodzie.

Wynik

Najkrótszy kod w bajtach wygrywa.

Mierzymy rozmiar pierwszego programu, który akceptuje n .


1 . Queens and Knights , autor: Roger KW Hui (uwaga! Zawiera rozwiązanie)

rdzeń rdzeniowy
źródło
4
Może powinieneś za to wynagrodzić. Szczerze mówiąc, problem jest wystarczająco trudny bez części quine.
mbomb007
Czy możemy użyć symboli innych niż Q, N i - do oznaczenia Królowych i Rycerzy i opróżnienia, o ile są one odrębne?
Fatalize
@Fatalize Tak, jasne
rdzeń
1
@coredump Miałem na myśli czytanie zawartości funkcji. Przyjmuję to jako „tak, możesz czytać własny kod źródłowy i / lub zawartość funkcji”. (Moje rozwiązanie na tym polega, więc ...)
wizzwizz4
1
@coredump Jeśli poprawnie rozumiem wyzwanie, to rozwiązanie referencyjne dla n = 6 zawiera nieprawidłowe wpisy (np. -------------------------N--------Q-jest nieprawidłowe, ponieważ można dodać więcej elementów :) Q--------N---------------N--------Q-.
Sleafar,

Odpowiedzi:

2

Groovy, 515 bajtów

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))

Testowanie

Podaj n jako argument wiersza poleceń:

groovy qak.groovy 4

Pierwszy wiersz wyniku jest zawsze rozwiązaniem jako komentarz (0 = pusty, 1 = królowa, 2 = rycerz), po którym następuje kod w drugim wierszu:

//[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))

Do automatycznego testowania można użyć następującego skryptu (ponownie wprowadź n jako argument):

#!/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

Ponieważ starałem się, aby rozwiązanie było jak najmniejsze, jest bardzo wolne (szczegóły poniżej). Testowałem tylko n = 4 z tą wersją, aby sprawdzić, czy quineification działa.

Wyniki

n = 4: 40 rozwiązań ( przekonwertowany format )
n = 5: 172 rozwiązań ( przekonwertowany format )
n = 6: 2836 rozwiązań ( przekonwertowany format )

Algorytm

To jest nieco nieprzyzwyczajenia nie-quine wersja rozwiązania:

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

Zastosowałem tutaj bardzo proste podejście, aby utrzymać niski rozmiar kodu.

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

Zmienna X przechowuje indeks rozwiązania do wydrukowania w następnej kolejności. Y przechowuje zmodyfikowaną kopię powyższego algorytmu, która służy do obliczenia wszystkich rozwiązań, a następnie wybrania tylko jednego z nich, co jest przyczyną tak powolnego działania. Zaletą tego rozwiązania jest to, że nie wymaga dużo dodatkowego kodu. Kod przechowywany w Y jest wykonywany za pomocą klasy Eval (prawda quine nie jest wymagana).

Zmodyfikowany kod drukuje rozwiązanie wskazane przez X , zwiększa X i dołącza swoją kopię:

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

Próbowałem też wypisać wszystkie rozwiązania jako kod dla drugiego kroku, ale dla n = 6 produkowało zbyt dużo kodu, aby Groovy mógł sobie z tym poradzić.

Sleafar
źródło
Dobra odpowiedź, dobra robota.
rdzeń rdzeniowy
6

Common Lisp, 737

odpowiedź własna

(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)())))))

Przykład

Wklej powyższe w REPL, która zwraca obiekt funkcji:

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

Zadzwoń (gwiazda jest przypisana do ostatniej zwróconej wartości):

QN> (funcall * 4)

Spowoduje to wydrukowanie na standardowym wyjściu:

(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)))))

Ponadto wartość zwracana przez tę funkcję to:

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

... który jest dosłownie tablicą. Liczba 5 reprezentuje królowe, 6 oznacza rycerzy, a wszystko inne oznacza pustą komórkę, z wyjątkiem tego, że więcej informacji jest przechowywanych wewnętrznie. Jeśli skopiujemy i wkleimy zwróconą funkcję do repliki, otrzymamy nową funkcję.

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

I możemy to nazwać bez argumentów:

QN> (funcall * )

To wywołanie zwraca nowe rozwiązanie #(5 0 0 0 0 0 0 2 0 0 0 6 0 0 2 0)i źródło innej funkcji (nie pokazano tutaj). W przypadku gdy funkcja oryginalna lub ostatnio wygenerowana nie znajdzie rozwiązania, nic nie jest drukowane i nic nie jest zwracane.

Wartości wewnętrzne

|----------+--------+---------+--------+-----------------|
|          | 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        |
|----------+--------+---------+--------+-----------------|

Wygenerowałem zbyt mało rozwiązań. Teraz propaguję niezależnie, która komórka jest bezpieczna dla królowej i rycerza. Na przykład, oto wynik dla n = 5 z ładnym drukowaniem:

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

Kiedy umieściliśmy królową Q, pozycje, które są ruchem rycerza od tej królowej, są nadal bezpieczne dla królowych i oznaczone q. Podobnie rycerze, do których dostęp mają tylko królowe, są bezpieczni dla innych rycerzy. Wartości są bitowe i -ed reprezentują możliwe ruchy, a niektóre komórki są osiągalne bez żadnego elementu.

Dokładniej, oto sekwencja tablic prowadząca do następującego rozwiązania (od lewej do prawej), w którym wolne komórki są stopniowo ograniczane różnymi wartościami:

# # # # # #     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

Podejście inne niż quine

Wersja bez komentarza

(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)))

Duplikaty i błędy

Moje pierwsze rozwiązanie wygenerowało zduplikowane rozwiązania. Aby to rozwiązać, wprowadziłem dwa liczniki dla królowych i rycerzy. Licznik królowych (lub rycerzy) śledzi pierwszą pozycję na planszy, na której istnieje królowa (lub rycerz): Dodaję królową (lub rycerza) tylko na pozycjach następujących po tej minimalnej pozycji.

Te metody uniemożliwiają mi ponowne przyjrzenie się rozwiązaniom, które zostały już znalezione w poprzednich iteracjach, ponieważ iteruję z rosnącą pozycją królowej (lub rycerza).

Sleafar zauważył jednak, że istnieją rozwiązania, w których może być miejsce dla królowych i rycerzy, co jest niezgodne z zasadami. Przez chwilę myślałem, że muszę wrócić do normalnego wyszukiwania i przechowywać wszystkie znane rozwiązania, aby zapobiec duplikatom, co wydawało się zbyt kosztowne (zarówno pod względem bajtów, jak i użycia pamięci).

Zamiast tego oto, co robię teraz: kiedy zostanie znaleziona potencjalna plansza rozwiązania, próbuję dodać dokładnie jedną królową i jednego rycerza, nie biorąc pod uwagę liczników (tj. Dla wszystkich komórek na planszy). Jeśli to możliwe, obecna tablica jest duplikatem poprzedniej i odrzucam rozwiązanie.

Testy

|---+---------+------------+--------------|
| 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 |
|---+---------+------------+--------------|

Quine-ification

Miałem różne pomysły, aby tworzyć kolejne quiny. Najłatwiej jest prawdopodobnie wygenerować najpierw wszystkie rozwiązania jako listę ciągów znaków i napisać sekwencyjne quiny, które wyskakują z tej listy przy każdym pokoleniu. Nie wydawało się to jednak krótsze niż obecne podejście. Alternatywnie próbowałem przepisać kod rekurencyjny za pomocą niestandardowego stosu i zrzucić wszystkie zmienne stanu za każdym razem, gdy znajdę rozwiązanie; celem jest, aby następny krok mógł być przetwarzany jako kontynuacja bieżącego kroku. Być może byłoby to lepiej dostosowane do języka opartego na stosie. Obecna jest dość prosta i opiera się na zmiennych czytnika Common Lisp, które zawsze są przyjemne w użyciu.

rdzeń rdzeniowy
źródło