N-rainha-e-eqüino

21

Existe uma variante do conhecido problema das rainhas N que envolve rainhas e cavaleiros e é considerado "consideravelmente mais difícil" 1 . A declaração do problema é a seguinte:

Você deve colocar um número igual de cavaleiros e rainhas em um tabuleiro de xadrez, de modo que nenhuma peça ataque outra peça. Qual é o número máximo de peças que você pode colocar no quadro e quantas maneiras diferentes você pode fazer isso?

Neste desafio do , você receberá uma entrada n entre 3 e 32 (da maneira mais adequada para o seu idioma). Para um dado n , pode haver zero ou mais soluções para o problema acima. Caso não exista solução, você não deve produzir / devolver nada ( nulo , string vazia , false , ...). Caso contrário, você deve fornecer dois resultados:

  1. Uma placa de solução (veja abaixo) para o tamanho n, em que não é possível adicionar uma peça de xadrez da rainha ou do cavaleiro sem que nenhuma peça esteja sendo atacada. Deve haver um número igual de rainhas e cavaleiros .
  2. A fonte de um programa a ser executado que não aceita entrada e fornece (i) outra solução (ou nada ) para o mesmo tamanho n , no mesmo formato, bem como (ii) outro programa para a próxima solução (e assim por diante) ...)

Observe que:

  • A sequência de programas nunca deve retornar a mesma placa duas vezes, deve cobrir todas as soluções possíveis para o problema de tamanho n e, eventualmente, deve terminar (não produzindo saída).
  • Você pode retornar dois valores, retornar um e imprimir o outro ou imprimir os dois valores de retorno.
  • No entanto , se você imprimir a placa e o próximo programa, a placa não deve ser considerada parte do próximo programa (eu recomendo imprimir a placa em comentário ou usar os fluxos de saída e erro padrão).
  • O valor do programa como um retorno deve ser uma sequência, não um encerramento.

Formato da placa

  • Uma placa é um quadrado de tamanho n .
  • Uma célula do tabuleiro pode estar vazia, uma rainha ou um cavaleiro.
  • Você deve escolher valores distintos para cada tipo de célula (ou seja, você pode usar outros símbolos além de Q, N ao imprimir o quadro).
  • Se você retornar um quadro não-string, ele deverá ser uma coleção ordenada dos n 2 valores do quadro (por exemplo, matriz, vetor ou lista na ordem principal de linha / coluna, ...).
  • Se você imprimir o quadro, poderá imprimi-lo ao quadrado ou como uma linha. Por exemplo, uma placa de solução do tamanho 4 pode ser impressa da seguinte maneira (espaços não necessários; símbolos a seu critério):

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

    Se você sente isso, também pode gerar:

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

    ... mas isso é suficiente:

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

    Não importa se você itera pelas células em uma ordem principal ou de coluna, porque existem soluções simétricas. Por exemplo, as soluções para n = 4 são:

    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
    

Você também pode olhar para as soluções para n = 5 como matrizes ; as placas contém #, qe nsímbolos, que são células vazias de diferentes tipos (ver minha resposta abaixo). Eu conto 2836 placas para n = 6 , como na resposta de Sleafar (eu introduzi um bug ao reduzir a contagem de bytes, mas está corrigido agora).

Muito obrigado a Sleafar por encontrar não um, mas dois bugs no meu código.

Ponto

O código mais curto em bytes vence.

Medimos o tamanho do primeiro programa, o que aceita n .


1 . Queens and Knights , de Roger KW Hui (cuidado! Contém uma solução)

coredump
fonte
4
Talvez você deva dar uma recompensa por isso. Honestamente, o problema já é difícil sem a parte correta.
mbomb007
Podemos usar outros símbolos além de Q, N e - para denotar Rainhas e Cavaleiros e vazios, desde que sejam distintos?
Fatalize 01/04
@Fatalize Sim, claro
coredump
11
@ Coredump eu quis dizer lendo o conteúdo da função. E considerarei isso como um "sim, você tem permissão para ler seu próprio código-fonte e / ou conteúdo da função". (Minha solução depende dele, então ...)
wizzwizz4
11
@coredump Se eu entendi o desafio corretamente, sua solução de referência para n = 6 contém entradas inválidas (por exemplo, -------------------------N--------Q-é inválida porque mais peças podem ser adicionadas :) Q--------N---------------N--------Q-.
Sleafar 06/04

Respostas:

2

Groovy, 515 bytes

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

Teste

Forneça n como um argumento de linha de comando:

groovy qak.groovy 4

A primeira linha da saída é sempre uma solução como comentário (0 = vazio, 1 = rainha, 2 = cavaleiro), seguido pelo código na segunda linha:

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

O script a seguir pode ser usado para teste automatizado (forneça n como argumento novamente):

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

Como tentei tornar a solução a menor possível, ela é muito lenta (veja os detalhes abaixo). Testei apenas n = 4 com esta versão para ver se a quineificação funciona.

Resultados

n = soluções 4: 40 ( formato convertido )
n = soluções 5: 172 ( formato convertido )
n = soluções 6: 2836 ( formato convertido )

Algoritmo

Esta é uma versão não quine da solução, levemente não destruída:

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

Quineificação

Eu usei uma abordagem muito simples aqui para manter o tamanho do código baixo.

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

A variável X mantém o índice da solução para imprimir a seguir. Y mantém uma cópia modificada do algoritmo acima, usada para calcular todas as soluções e, em seguida, selecionar apenas uma delas, razão pela qual é tão lenta. A vantagem desta solução é que ela não requer muito código adicional. O código armazenado em Y é executado com a ajuda da classe Eval (um quine verdadeiro não é necessário).

O código modificado imprime a solução apontada por X , aumenta X e anexa uma cópia de si mesma:

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

Também tentei produzir todas as soluções como código para o segundo passo, mas para n = 6 estava produzindo muito código para o Groovy lidar.

Sleafar
fonte
Boa resposta, bom trabalho.
Coredump #
6

Lisp comum, 737

auto-resposta

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

Exemplo

Cole o acima no REPL, que retorna um objeto de função:

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

Chame-o (a estrela está vinculada ao último valor retornado):

QN> (funcall * 4)

Isso imprime o seguinte na saída padrão:

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

Além disso, o valor retornado por esta função é:

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

... que é uma matriz literal. O número 5 representa rainhas, 6 é para cavaleiros e qualquer outra coisa representa uma célula vazia, exceto que há mais informações armazenadas internamente. Se copiarmos e colarmos a função retornada para a repl, obteremos uma nova função.

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

E podemos chamá-lo, sem argumentos:

QN> (funcall * )

Essa chamada retorna uma nova solução #(5 0 0 0 0 0 0 2 0 0 0 6 0 0 2 0)e a fonte de outra função (não mostrada aqui). Caso a função original ou a última gerada não encontre uma solução, nada será impresso e nada será retornado.

Valores internos

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

Eu costumava gerar poucas soluções. Agora, propago qual célula é segura para uma rainha e para um cavaleiro, independentemente. Por exemplo, aqui está uma saída para n = 5 com impressão bonita:

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

Quando colocamos a rainha Q, as posições afastadas por um cavaleiro desta rainha ainda são seguras para rainhas e são indicadasq . Da mesma forma, cavaleiros que são alcançáveis ​​apenas por rainhas são seguros para outros cavaleiros. Os valores são bit a bit e -ed para representar os movimentos possíveis e algumas células são alcançáveis ​​por nenhum tipo de peça.

Mais precisamente, aqui está a sequência de placas que levam à seguinte solução (da esquerda para a direita), onde as células livres são gradualmente restringidas com valores diferentes:

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

Abordagem não quine

Versão comentada e não-gasta

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

Duplicatas e erros

Minha primeira solução gerou soluções duplicadas. Para resolvê-lo, apresentei dois contadores para rainhas e cavaleiros. O contador para rainhas (respectivamente cavaleiros) mantém o controle da primeira posição no tabuleiro onde existe uma rainha (resp. Cavaleiro): eu adiciono uma rainha (resp. Cavaleiro) apenas nas posições que seguem essa posição mínima.

Esse método me impede de revisar soluções que já foram encontradas em iterações anteriores, porque eu itero com uma posição crescente de rainha (resp. Cavaleiro).

No entanto, Sleafar notou que havia soluções para as quais havia espaço para rainhas e cavaleiros, o que é contrário às regras. Por um tempo, tive que voltar a uma pesquisa normal e armazenar todas as soluções conhecidas para evitar duplicatas, que pareciam muito caras (tanto em termos de bytes quanto de uso de memória).

Em vez disso, eis o que faço agora: quando um quadro de soluções em potencial é encontrado, tento adicionar exatamente uma rainha e uma cavaleiro, sem levar em conta os contadores (ou seja, para todas as células do quadro). Se isso for possível, a placa atual é uma duplicata da anterior e eu rejeito a solução.

Testes

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

Tive idéias diferentes para fazer sucessivos cálculos. O mais fácil é provavelmente gerar todas as soluções primeiro como uma lista de strings e escrever quines seqüenciais que saem dessa lista a cada geração. No entanto, isso não parecia ser mais curto do que a abordagem atual. Como alternativa, tentei reescrever o código recursivo com uma pilha personalizada e despejar todas as variáveis ​​de estado toda vez que encontro uma solução; o objetivo é que a próxima etapa possa ser processada como uma continuação da etapa atual. Talvez isso seja mais adequado para uma linguagem baseada em pilha. O atual é bastante simples e depende das variáveis ​​do leitor Common Lisp, que são sempre divertidas de usar.

coredump
fonte