Lucchetto a combinazione per bici


46

Lo scenario

Dopo una lunga giornata di lavoro in ufficio e navigando su stackexchange.com , finalmente esco dalla porta alle 16:58, già stanco della giornata. Poiché sono ancora solo uno stagista, la mia attuale modalità di trasporto è in bicicletta. Mi dirigo verso la mia fidata Peugeot Reynolds 501 , ma prima di poter salpare su di essa, devo sbloccarla. Il blocco è un blocco a combinazione standard a quattro cifre (0-9), attraverso il telaio e la ruota anteriore. Mentre provo a rimanere sveglio, alzo la mano per entrare nella combinazione. Lucchetto a combinazione per bici

La sfida

Poiché le mie dita sono così stanche, voglio ruotare la serratura sulla combinazione corretta con il minor numero di movimenti. Un movimento è definito come una rotazione di una posizione (36 gradi), ad esempio c'è un movimento da 5737a 5738. Tuttavia, sono in grado di afferrare fino a tre squilli consecutivi contemporaneamente e di ruotarli come uno , che conta solo come un singolo movimento. Ad esempio v'è anche solo movimento da 5737a 6837o 5626. Passare da 5737a 6838non è un movimento, poiché le cifre numero 1,2 e 4 si sono spostate nella stessa direzione, ma indipendentemente dalla cifra numero 3.

Pertanto, per una data combinazione che posso vedere sul blocco bici (qualsiasi numero intero a 4 cifre), qual è il numero più basso di movimenti che posso fare per sbloccarlo, e sì, posso ruotare in entrambe le direzioni in qualsiasi momento. Con questo intendo dire che posso girare alcune cifre in una direzione e altre nell'altra direzione: non tutti i miei movimenti saranno in senso antiorario o orario per ogni sblocco.

Poiché sono pigro, il mio codice di sblocco è 0000.

Questo è il golf del codice, non posso preoccuparmi di scrivere molto codice, quindi vince il programma più breve in numero di byte.

L'input proviene da stdin e il tuo codice dovrebbe generare le combinazioni che posso vedere ad ogni passo dopo ogni movimento, incluso lo 0000 alla fine. Ciascuna delle combinazioni di output deve essere separata da uno spazio / newline / virgola / punto / e commerciale.

Esempi

Input: 1210
0100
0000

Input: 9871
9870
0980
0090
0000

Input: 5555
4445&3335&2225&1115&0005&0006&0007&0008&0009&0000

Input: 1234
0124 0013 0002 0001 0000

Ho provato a pubblicarlo su http://bicycles.stackexchange.com , ma a loro non è piaciuto ...

Disclaimer: prima golf, quindi tutto ciò che è rotto / qualsiasi informazione mancante fammi sapere! Inoltre ho fatto tutti gli esempi a mano, quindi potrebbero esserci soluzioni che comportano meno movimenti!

EDIT: per le risposte che hanno più percorsi di soluzione con uguale numero di movimenti (praticamente tutti), non esiste una soluzione preferita.


18
Benvenuti in PPCG; molto bella prima sfida!
Maniglia della porta

4
Questo mi sembra solido! Benvenuti in PPCG!
Mego

1
Bella sfida. Posso chiedere quale dovrebbe essere l'output per i casi: 7478 e 3737?
Noisyass2,

1
@ noisyass2 Grazie; La risposta di Flawr dà quanto segue: 7478 8588 9698 0708 0808 0908 0008 0009 0000 e 3737 2627 1517 0407 0307 0207 0107 0007 0008 0009 0000 Solo guardando il 3737, questo ha senso: guardando solo le prime 3 cifre: se muovo tutto i primi tre contemporaneamente, sono necessari 3 movimenti per le cifre 1 e 3, quindi altri 4 movimenti per la cifra 2, quindi un totale di sette. Considerando che se mi muovo ciascuno individualmente, ognuno prende 3 mosse, quindi 9 movimenti.
Lui,

1
Mi chiedo se il titolo "Combination Lock" (o "Bike Lock") possa attrarre più spettatori.
DavidC,

Risposte:


10

Matlab, 412 327 byte

Golf (grazie a @AndrasDeak per il golf s!):

s=dec2bin('iecbmgdoh'.'-97)-48;s=[s;-s];T=1e4;D=Inf(1,T);P=D;I=NaN(T,4);for i=1:T;I(i,:)=sprintf('%04d',i-1)-'0';end;G=input('');D(G+1)=0;for k=0:12;for n=find(D==k);for i=1:18;m=1+mod(I(n,:)+s(i,:),10)*10.^(3:-1:0)';if D(m)==Inf;D(m)=k+1;P(m)=n-1;end;end;end;end;n=0;X='0000';while n-G;n=P(n+1);X=[I(n+1,:)+48;X];end;disp(X)

Questo codice utilizza una programmazione dinamica per trovare il "percorso" più breve da un determinato numero 0000all'utilizzo dei soli passaggi possibili. La sfida è fondamentalmente un prioblema del percorso più breve (in alternativa potresti forse considerare i passaggi come un gruppo commutatuve.) Ma la difficoltà stava arrivando con un'implementazione efficiente . Le strutture di base sono due matrici di 10000 elementi, una per memorizzare il numero di passaggi per arrivare a quell'indice, l'altra per memorizzare un puntatore al 'nodo' precedente nel nostro grafico. Calcola simultaneamente i "percorsi" verso tutti gli altri numeri possibili.

Esempi:

9871
0981
0091
0001
0000

1210
0100
0000

Examples by @noisyass:

7478
8578
9678
0788
0899
0900
0000

3737
2627
1517
0407
0307
0207
0107
0007
0008
0009
0000

Own Example (longest sequence, shared with 6284)

4826
3826
2826
1826
0826
0926
0026
0015
0004
0003
0002
0001
0000    

Codice completo (inclusi alcuni commenti):

%steps
s=[eye(4);1,1,0,0;0,1,1,0;0,0,1,1;1,1,1,0;0,1,1,1];
s=[s;-s];


D=NaN(1,10000);%D(n+1) = number of steps to get to n
P=NaN(1,10000);%P(n+1) was last one before n

I=NaN(10000,4);%integer representation as array
for i=0:9999; 
    I(i+1,:)=sprintf('%04d',i)-'0';
end

G=9871; % define the current number (for the golfed version replaced with input('');
D(G+1)=0;
B=10.^(3:-1:0); %base for each digit

for k=0:100; %upper bound on number of steps;
    L=find(D==k)-1;
    for n=L; %iterate all new steps
        for i=1:18; %search all new steps
            m=sum(mod(I(n+1,:)+s(i,:),10) .* [1000,100,10,1]);
            if isnan(D(m+1))
                D(m+1) = k+1;
                P(m+1)=n;
            end
        end
    end
end
n=0;%we start here
X=[];
while n~=G
    X=[I(n+1,:)+'0';X];
    n=P(n+1);
end
disp([I(G+1,:)+'0';X,''])

Bello! Essendo un utente per lo più Matlab, mi chiedevo come sarebbe andata bene.
Lui,

1
Per inserire 6444il codice, inserisci 6444 7554 8664 9774 0884 0994 0004 0003 0002 0001 0000, mentre trovo la risposta 6444 6333 6222 6111 6000 7000 8000 9000 0000. La mia risposta è 8 passaggi, la tua è 10. Non riesco a vedere il problema, e sembra essere lì sia nella versione golfizzata che non. Questo problema è stato risolto nella tua ultima modifica.
Lui,

1
Ho appena corretto un piccolo errore nel codice. In sultima fila dovrebbe essere [0,1,1,1]. Quindi ottieni anche una soluzione in 8 passaggi! Mi dispiace per l'inconveniente =)
flawr

1
@Lui Esiste una chat room matlab / ottava , tra le altre cose è una sorta di Base per il linguaggio linguistico MATL derivato da Matlab.
flawr

1
per 4826, ho trovato una soluzione di 11 mosse: 4826 3716 2606 1506 0406 0306 0206 0106 0007 0008 0009 0000
noisyass2

4

Lotto - 288 byte

Anche se hai detto che devono essere consecutivi (gli anelli), presumo per logica (seguendo l'esempio) che posso saltare quello di mezzo, da 1234a a 0224.

set / px =
imposta a =% x: ~ 0,1% e imposta b =% x: ~ 1,1% e imposta c =% x: ~ 2,1% e imposta d =% x: ~ 3,1%
: l
@echo% x% e se% a% == 0 (se% d% NEQ 0 impostato / ad = d-1) altrimenti impostato / aa = a-1
@if% b% NEQ 0 set / ab = b-1
@if% c% NEQ 0 set / ac = c-1
@if% x% NEQ 0000 set x =% a %% b %% c %% d% & goto l

Questa è la mia soluzione Batch: 236 byte.


Modifica: soluzione corretta

set / px =
imposta a =% x: ~ 0,1% e imposta b =% x: ~ 1,1% e imposta c =% x: ~ 2,1% e imposta d =% x: ~ 3,1%
: l
@echo% x% e imposta k = 1 e se% a% == 0 (se% d% NEQ 0 imposta / ad = d-1 e imposta k = 0) altrimenti imposta / aa = a-1 e imposta k = 1
@if% b% NEQ 0 se% k% == 1 set / ab = b-1 e set k = 0
@if% c% NEQ 0 se% k% == 0 set / ac = c-1
@if% x% NEQ 0000 set x =% a %% b %% c %% d% & goto l

La nuova soluzione (risolta in base ai commenti sottostanti) è pesante 288 byte.


Non ho esaminato la tua risposta in modo approfondito, ma faccio fatica a seguire la tua logica nel primo paragrafo. A quale esempio ti riferisci in particolare? E il tuo esempio di andare da 1234a non0224 è un movimento. L'idea è che con solo due dita posso afferrare fino a tre squilli consecutivi con una sola presa.
Lui

Volevo dire, se puoi spostare 3 squilli consecutivi, è ragionevole pensare che puoi anche spostare il primo e il terzo, evitando il secondo. O dovrei cambiare il mio codice?
rumore

Il tuo presupposto è sbagliato; dovresti cambiare il tuo codice. Vedi la logica come spiegato nel commento sopra?
Lui

Codice fisso Ho controllato con diversi tipi di combinazioni e mi sembra che prenda sempre la strada più breve.
rumore

Questo sembra contare solo verso il basso, quindi impiega più tempo del necessario per combinazioni con numeri alti (es. 18 mosse per 9999)
faubi

2

Haskell - 310 byte

import Data.Char
import Data.List
r=replicate
h=head
a x=map(:x)[map(`mod`10)$zipWith(+)(h x)((r n 0)++(r(4-j)q)++(r(j-n)0))|j<-[1..3],n<-[0..j],q<-[1,-1]]
x!y=h x==h y
x#[]=(nubBy(!)$x>>=a)#(filter(![(r 4 0)])x)
x#y=unlines.tail.reverse.map(intToDigit<$>)$h y
main=do x<-getLine;putStrLn$[[digitToInt<$>x]]#[]

Funziona creando ripetutamente un nuovo elenco di combinazioni applicando ogni possibile svolta a ciascuna combinazione già raggiunta fino a quando una di esse è la combinazione giusta. I duplicati vengono rimossi dall'elenco su ogni iterazione per impedire che l'utilizzo della memoria cresca in modo esponenziale.

Come soluzione a forza bruta, questo è molto inefficiente e può richiedere diversi minuti per l'esecuzione.

Non ho molta esperienza con Haskell, quindi probabilmente qualcosa potrebbe essere fatto meglio.


Sembra una solida base per il tuo approccio. Non ho esperienza con Haskell, né (che conosco) alcun mezzo per compilarlo / eseguirlo. Un google veloce non mi dà da nessuna parte dove posso provarlo, neanche. Sei in grado di fornire un link che mi permette di provarlo? Grazie.
Lui

@Lui Può essere compilato con il compilatore Haskell di Glasgow , ma a parte il download e l'utilizzo che non conosco alcun modo per eseguirlo.
Faubi,
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.