コンビネーションバイクロック


46

シナリオ

長い一日の仕事でオフィスで時間を過ごしstackexchange.comを閲覧した、私はようやく16:58にドアを出ました。私はまだインターンであるため、現在の交通手段は自転車です。信頼できるプジョーレイノルズ501に向かいますが、航海する前にロックを解除する必要があります。ロックは、フレームと前輪を通る標準の4桁のコンビネーションロック(0〜9)です。目を覚まそうとするとき、手を組んで組み合わせに入る。 コンビネーションバイクロック

挑戦

私の指はとても疲れているので、最小限の動きで正しい組み合わせにロックを回したいと思います。1つの動きは、1つの位置(36度)による回転として定義されます。たとえば、から5737への1つの動きがあり5738ます。ただし、連続する3つのリングを同時に把握し、1つとして回転させることができます。これは、1つの動きとしてカウントされます。たとえば、からまたはへの移動1つだけです。桁番号1、2、および4は桁番号3とは無関係に同じ方向に移動したため、からに移動することは1つの動きではありません。57376837562657376838

したがって、特定の組み合わせについては、自転車のロック(4桁の整数)で見ることができ、ロックを解除するためにできる最小の動きは何ですか、そして、はい、いつでもどちらの方向にも回転できます。これにより、ある方向にいくつかの数字を、別の方向に他の数字を回せることを意味します。ロックを解除するたびに、すべての動きが反時計回りまたは時計回りになるわけではありません。

私は怠け者なので、ロック解除コードは0000です。

これはコードゴルフです。多くのコードを書くのは面倒なので、バイト数の最も短いプログラムが勝ちます。

入力は標準入力からであり、コードは、各移動後に各ステップで表示できる組み合わせを出力する必要があります(末尾の0000を含む)。各組み合わせの出力は、スペース/改行/コンマ/ピリオド/アンパサンドで区切る必要があります。

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

私はこれをhttp://bicycles.stackexchange.comに投稿しようとしましたが、彼らはそれを好きではありませんでした...

免責事項:最初のゴルフですので、壊れている情報や不足している情報はお知らせください!また、すべての例を手作業で行ったので、動きが少ないソリューションがあるかもしれません!

編集:等しい数の動き(実際にはすべて)を持つ複数のソリューションパスがある回答の場合、推奨されるソリューションはありません。


18
PPCGへようこそ。とてもいい最初の挑戦!
ドアノブ

4
これは私にはしっかり見えます!PPCGへようこそ!
メゴ

1
ナイスチャレンジ。7478と3737の場合の出力はどうすればいいですか?
-noisyass2

1
@ noisyass2ありがとう。flawrの答えは次のとおりです:7478 8588 9698 0708 0808 0908 0008 0000および3737 2627 1517 0407 0307 0207 0107 0007 0008 0009 0000最初の3回は同時に、数字1と3で3回、数字2でさらに4回、合計7回動きます。一方、私がそれぞれ個別に動かすと、それぞれ3回の動き、したがって9回の動きがかかります。
ルイ

1
タイトル「Combination Lock」(または「Bike Lock」)がより多くの視聴者を引き付けるのではないかと思っています。
DavidC

回答:


10

Matlab、412 327バイト

ゴルフ(ゴルフをしてくれた@AndrasDeakに感謝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)

このコードは、指定された番号から0000可能なステップのみを使用する最短の「パス」を見つけるために、いくつかの動的プログラミングを使用します。課題は基本的に最短パスの問題です(あるいは、ステップを通勤グループと見なすこともできます)が、効率的な実装を実現することは困難でした。基本構造は2つの10000要素配列で、1つはそのインデックスに到達するためのステップ数を格納し、もう1つはグラフの前の「ノード」へのポインタを格納します。他のすべての可能な番号への「パス」を同時に計算します。

例:

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    

完全なコード(コメントを含む):

%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,''])

いいね!ほとんど自分でMatlabユーザーであるため、私はそれがどれだけうまくいくのか疑問に思っていました。
ルイ

1
入力6444すると、コードは6444 7554 8664 9774 0884 0994 0004 0003 0002 0001 0000になりますが、答えは6444 6333 6222 6111 6000 7000 8000 9000 0000であることがわかります。私の答えは8ステップで、あなたは10です。問題、それはゴルフバージョンと非ゴルフバージョンの両方にあるようです。これは、最新の編集で修正されています。
ルイ

1
コードの小さなエラーを修正しました。でs最後の行であるべきです[0,1,1,1]。その後、8ステップのソリューションも手に入ります!ご不便をおかけして申し訳ありません=)
flawr

1
@Lui matlab / octaveチャットルームがあります。他のものの中には、Matlabから派生したゴルフラングアンゲMATLのベースのようなものがあります。
-flawr

1
4826の場合、11のムーブソリューションが見つかりました:4826 3716 2606 1506 0406 0306 0206 0106 0007 0008 0009 0000
noisyass2

4

バッチ-288バイト

あなたがそれらが連続的でなければならない(リング)と言ったとしても、私はロジックによって(例に従って)、toのように真ん中のものをスキップできると仮定12340224ます。

set / px =
セットa =%x:〜0,1%&set b =%x:〜1,1%&set c =%x:〜2,1%&set d =%x:〜3,1%
:l
@echo%x%&if%a%== 0(if%d%NEQ 0 set / ad = d-1)else set / 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

これが私のバッチソリューションです:236バイト。


編集:修正されたソリューション

set / px =
セットa =%x:〜0,1%&set b =%x:〜1,1%&set c =%x:〜2,1%&set d =%x:〜3,1%
:l
@echo%x%&set k = 1&if%a%== 0(if%d%NEQ 0 set / ad = d-1&set k = 0)else set / aa = a-1&set k = 1
@if%b%NEQ 0%k%== 1 set / ab = b-1&set k = 0の場合
@if%c%NEQ 0%k%== 0 set / ac = c-1の場合
@if%x%NEQ 0000 set x =%a %% b %% c %% d%&goto l

新しいソリューション(基になるコメントに従って修正された)は288バイト重いです。


私はあなたの答えを深く掘り下げていませんが、最初の段落のあなたの論理に従うのに苦労しています。具体的にどの例を挙げていますか?から1234に移動する例0224 1つの動きではありません。アイデアは、2本の指だけを使用して、1つのグリップで最大3つの連続したリングを握ることができるということです。
ルイ

つまり、3つの連続したリングを移動できる場合、2番目のリングを避けて、1番目と3番目のリングも移動できると考えるのが合理的です。または、コードを変更する必要がありますか?
ノイズ

あなたの仮定は間違っています。コードを変更する必要があります。上記のコメントで説明されているロジックが表示されますか?
ルイ

コードが修正されました。私はいくつかの異なるタイプの組み合わせで確認しましたが、いつもより短い道を辿っているように見えます。
ノイズ

これは下向きにしかカウントされないため、大きな数字の組み合わせ(たとえば、9999で18の動き)に必要以上に時間がかかります
-faubi

2

Haskell-310バイト

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

これは、組み合わせの1つが適切な組み合わせになるまで、既に到達した各組み合わせに各ターンを適用することにより、組み合わせの新しいリストを繰り返し作成することで機能します。メモリの使用量が指数関数的に増加しないように、各反復で重複がリストから削除されます。

ブルートフォースソリューションとして、これは非常に非効率的であり、実行に数分かかることがあります。

私はHaskellの経験があまりないので、おそらくもっとうまくやれるかもしれません。


あなたのアプローチの強固な基盤のようです。私はHaskellを使った経験はなく、(知っている限り)Haskellをコンパイル/実行する方法もありません。簡単なグーグルでも、どこでも試すことができません。試用できるリンクを提供できますか?ありがとう。
ルイ

@Lui Glasgow Haskell Compilerを使用してコンパイルできますが、ダウンロードして使用する以外は、実行する方法がわかりません。
faubi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.