Permutazioni del Quindici Puzzle


13

La sfida

Considera il seguente diagramma del Quindici Puzzle nel suo stato risolto:

_____________________
|    |    |    |    |
| 1  | 2  | 3  | 4  |
|____|____|____|____|
|    |    |    |    |
| 5  | 6  | 7  | 8  |
|____|____|____|____|
|    |    |    |    |
| 9  | 10 | 11 | 12 |
|____|____|____|____|
|    |    |    |    |
| 13 | 14 | 15 |    |
|____|____|____|____|

Ad ogni mossa, un rompicapo eccitato ha l'opportunità di spostare un pezzo adiacente allo spazio vuoto nello spazio vuoto. Ad esempio, dopo lo 1spostamento, abbiamo 2possibili scenari (lasciamo 0uno spazio vuoto):

1   2   3   4          1   2   3   4
5   6   7   8          5   6   7   8
9   10  11  12   and   9   10  11  0
13  14  0   15         13  14  15  12

Dopo le 2mosse, il puzzle ha 5esiti diversi (nota che i due casi precedenti sono esclusi, poiché non possono essere raggiunti in 2 mosse). Una di queste situazioni è lo stato risolto originale e può essere raggiunta in due modi diversi.

Il tuo compito in questa sfida è quello di produrre il numero di risultati diversi che un determinato numero di mosse può portare. Come input, prendi un numero N >= 0e visualizza il numero di situazioni uniche che possono apparire dopo le Nmosse.

Regole

  • Questo è code-golf. Il codice più corto vince!
  • Le scappatoie standard non sono ammesse.
  • Il tuo codice dovrebbe essere in grado di calcolare il caso N = 10entro pochi minuti. Probabilmente non testerò questa regola a meno che non esista un evidente abuso di tempo in una risposta.

Casi test

(Risultati generati dalle somme di OEIS A089484 (come descritto da Geobits nella chat ), automatizzato dalla sceneggiatura di Martin Büttner . Grazie per tutto l'aiuto!)

0 moves: 1
1 moves: 2
2 moves: 5
3 moves: 12
4 moves: 29
5 moves: 66
6 moves: 136
7 moves: 278
8 moves: 582
9 moves: 1224
10 moves: 2530
11 moves: 5162
12 moves: 10338
13 moves: 20706
14 moves: 41159
15 moves: 81548
16 moves: 160159
17 moves: 313392
18 moves: 607501
19 moves: 1173136
20 moves: 2244884
21 moves: 4271406
22 moves: 8047295
23 moves: 15055186
24 moves: 27873613
25 moves: 51197332
26 moves: 93009236
27 moves: 167435388
28 moves: 297909255
29 moves: 524507316
30 moves: 911835416
31 moves: 1566529356

Risposte:


5

Pyth, 36 byte

lu{smmXd,0@dk)fq1.a.DR4,Txd0UdGQ]U16

Dimostrazione . Collaudare l'imbragatura.

lu{smmXd,0@dk)fq1.a.DR4,Txd0UdGQ]U16

                 .a.DR4,Txd0            Find the Euclidean distance between the
                                        present location of 0 and a given location.
              fq1           Ud          Filter over all locations on that distance
                                        equaling 1.
     mXd,0@dk)                          Map each such location to the grid with 0
                                        and the value at that location swapped.
  {sm                         G         Map all unique grids possible after n-1
                                        steps to all unique grids after n steps.
 u                             Q]U16    Repeat <input> times, starting with the
                                        initial grid.
l                                       Print the length of the resulting set.

3

CJam, 54 52 51 50 49 47 45 byte

G,ari{{:S0#S{4md2$4md@-@@-mh1=},f{Se\}}%:|}*,

Provalo online nell'interprete CJam (dovrebbe richiedere meno di 10 secondi).

Come funziona

G,a       e# Push R := [[0 1 ... 15]].
ri{       e# Do int(input()) times:
  {:S     e#   For each S in R:
    0#    e#     Push the index of 0 in S (I).
    S{    e#     Filter S; for each J in in S:
      4md e#       Push J/4 and J%4.
      2$  e#       Copy I.
      4md e#       Push I/4 and I%4.
      @-  e#       Compute (I%4)-(J%4).
      @@- e#       Compute (J%4)-(I%4).
      mh  e#       2-norm distance: a b -> sqrt(aa + bb)
      1=  e#       Check if the distance is 1.
    },    e#     Keep all values of J with distance 1 from I.
    f{    e#     For each J:
      S   e#       Push S. 
      e\  e#       Swap S at indexes I and J.
    }     e#     This pushes an array of all valid modifications of S.
  }%      e#   Collect the results for all S in R in an array.
  :|      e#   Reduce the outmost array using set union (removes duplicates).
}*        e#

3

Retina , 289 276 byte

^
,abcd%efgh%ijkl%mnox,
(`(,[^,]*)x([^,%])([^,y]*),
$0$1$2x$3y,
(,[^,]*)([^,%])x([^,y]*),
$0$1x$2$3y,
(,[^,]*)x([^,]{4})([^,])([^,y]*),
$0$1$3$2x$4y,
(,[^,]*)([^,])([^,]{4})x([^,y]*),
$0$1x$3$2$4y,
,.{19},(?=.*1)|,[^,]{20},(?=[^1]*$)|y|1$

+)`([^,]{19})(.*),\1,
$1$2
[^a]

a
1

Accetta input e stampa output in modo unario.

È possibile inserire ogni riga in un singolo file o eseguire il codice come con il -sflag. Per esempio:

> echo -n 111|retina -s fifteen_puzzle
111111111111

Il nucleo del metodo è che teniamo traccia di tutte le posizioni possibili (senza ripetizione) che possono verificarsi dopo esatte kfasi. Iniziamo il modulo k = 0e ripetiamo i passaggi di sostituzione (utilizzando il (` and )` modifiers) fino a raggiungere il numero di passaggi di input.

Durante questo calcolo la nostra stringa ha sempre la forma di

(,[puzzle_state]y?,)+1*

dove puzzle_stateè abcd%efgh%ijkl%mnoxcon qualche permutazione delle lettere. xindica il posto vuoto, il resto delle lettere sono le tessere. %sono delimitatori di riga.

yindica che lo stato viene generato nel passaggio corrente ( k), quindi non deve essere utilizzato per generare altri stati in questo passaggio.

1segna il numero di passi rimanenti.

Il meccanico di base del codice Retina è che ogni corrispondenza di una riga dispari viene cambiata nella riga successiva (pari).

Il codice con spiegazione aggiunta:

initialize string
^
,abcd%efgh%ijkl%mnox,

while string changes
(`

for every old (y-less) state concatenate a new state with moving the empty tile to r/l/d/u if possible
right
(,[^,]*)x([^,%])([^,y]*),
$0$1$2x$3y,
left
(,[^,]*)([^,%])x([^,y]*),
$0$1x$2$3y,
down
(,[^,]*)x([^,]{4})([^,])([^,y]*),
$0$1$3$2x$4y,
up
(,[^,]*)([^,])([^,]{4})x([^,y]*),
$0$1x$3$2$4y,

if we should have made this step (there are 1's left) remove old states
,.{19},(?=.*1)

if we should not have made this step (no more 1's left) remove new states
,[^,]{20},(?=[^1]*$)

remove y markers
y

remove one 1 (decrease remaining step count)
1$


remove duplicates until string changes (with + modifier)
+`([^,]{19})(.*),\1,
$1$2    

end while
)`

remove non-a's, 1 a stays from each state
[^a]

change a's to 1's
a
1

10 byte salvati grazie a @MartinButtner.


2

Pitone, 310 253 243 229 byte

Ultima versione con miglioramento suggerito da @randomra:

s=set()
s.add(tuple(range(16)))
def e(a,b):s.add(t[:a]+(t[b],)+t[a+1:b]+(t[a],)+t[b+1:])
for k in range(input()):
 p,s=s,set()
 for t in p:j=t.index(0);j%4and e(j-1,j);j%4>2or e(j,j+1);j<4or e(j-4,j);j>11or e(j,j+4)
print len(s)

La mia versione, che era più lunga (243 byte), ma più facile da leggere:

s=set()
s.add(tuple(range(16)))
def e(a,b):s.add(t[:a]+(t[b],)+t[a+1:b]+(t[a],)+t[b+1:])
for k in range(input()):
 p,s=s,set()
 for t in p:
  j=t.index(0)
  if j%4:e(j-1,j)
  if j%4<3:e(j,j+1)
  if j>3:e(j-4,j)
  if j<12:e(j,j+4)
print len(s)

Semplice prima ricerca della larghezza, codificando gli stati come tuple e memorizzandoli in un set per mantenerli unici.

Richiede circa 0,03 secondi sul mio laptop per N = 10. Il tempo di esecuzione aumenta sostanzialmente per numeri più grandi, ad esempio circa 12 secondi per N = 20.


L'aliasing s.addprobabilmente salverebbe alcuni personaggi.
isaacg,

@isaacg Ho salvato parecchio spostando il codice simile in una funzione. Guardando questo ora, probabilmente non devo passare tcome argomento. Oltre a ciò, immagino che molto probabilmente ci sarà più spazio per migliorare se avessi abilità Python migliori.
Reto Koradi,

3
È possibile convertire le ifdichiarazioni in espressioni cortocircuitando con effetto collaterale, come j%4and e(j-1,j)in modo da poterli mettere in una linea come una tupla booleano: j%4and e(j-1,j),j%4>2or e(j,j+1),j<4or e(j-4,j),j>11or e(j,j+4).
randomra,

@randomra Sembra buono, lo proverò domani. Ho pensato che ci fosse probabilmente un modo intelligente di usare espressioni condizionali invece della serie di ifdichiarazioni. Mi chiedo anche se c'è un modo più breve di costruire una tupla con due elementi scambiati.
Reto Koradi,

1
Conversione in lista, lo scambio e la riconversione tupla è un po 'più breve: def e(a,b):*l,=t;l[a],l[b]=l[b],l[a];s.add(tuple(l)).
randomra,

1

Perl, 148

#!perl -p
$s{"abcd.efgh.ijkl.mno#"}=1;for(1..$_){$x=$_,map{$r{$_}=1if
s/($x)/$3$2$1/}keys%s for
qw!\w)(# #)(\w \w)(.{4})(# #)(.{4})(\w!;%s=%r;%r=()}$_=keys%s

Esempio:

$ time perl 15.pl <<<20
2244884
real    0m39.660s
user    0m38.822s
sys 0m0.336s
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.