パスワードを見つける


12

通常のN桁のコンビネーションロックは、N個の回転ディスクで構成されています。各ディスクには数字の0から9が順番に刻まれており、それらを開くには正しいパスワードに変える必要があります。明らかに、パスワードがわからない場合は、ロックを解除する前に最大10 N回試行する必要があります。それは面白くない。

コンビネーションロック

それでは、コンビネーションロックの変形を考えてみましょう。距離を明らかにするロックと名付けてください。

距離を明らかにするロックを開く試みが失敗するたびに、ロックを解除するための最小数の動きに応答します。

1つの動きは、1つの位置による回転として定義されます。たとえば、890〜の1つの動き899と〜の9つの動きが137必要952です。

チャレンジ

パスワードが不明な距離を明らかにするロックがある場合は、プログラムが長くなりすぎないようにしながら、最小限の試行回数(移動ではない)でロックを開こうとします。

ルールとスコアリング

  • stdinから入力し、stdoutに出力する完全なプログラムを作成する必要があります。プログラムは次のように入出力を行う必要があります。
Start
    Input an integer N (number of digits) from stdin
    Do
        Output a line containing decimal string of length N (your attempt) to stdout
        Input an integer K (response of the lock) from stdin
    While K not equal 0
End
  • プログラムは最大N = 200を処理し、どの入力でも5秒未満で実行する必要があります。

  • 出力の先行ゼロは省略しないでください。

  • 長さごとに5つのテストデータがあるため、テストデータの総数は1000です。テストデータはランダムに生成されます。

  • 最終スコアは(すべてのテストデータの推測の合計数)* ln(バイト単位のコード長+ 50)になります。最低スコアが勝ちます。(lnは自然対数)

  • プログラムを採点します。プログラムの採点方法を知りたい場合、または自分でプログラムを採点する場合は、この投稿の以前の編集をご覧ください。

  • このチャレンジは2017/12/07 14:00 UTCに終了します。その後、ソリューションを投稿します。

実行例

で始まる行>は入力を表し、他の行はプログラム出力を表します。

パスワードを頭の中に入れて、プログラムと対話してテストすることができます。

> 3   # 3-digit lock. The hidden password is 746
000   # 1st guess (by program)
> 11  # response to the 1st guess
555   # 2nd guess
> 4   # ...
755
> 2
735
> 2
744
> 2
746   # finally the correct answer! The program attempts 6 times.
> 0   # this is not necessary

サンプルプログラム

編集:たぶん、上記の入力/出力形式は明確ではありませんでした。Pythonのサンプルプログラムを次に示します。

Python、369バイト、試行の合計数= 1005973、スコア= 6073935

import sys

N = int(input()) # get the lock size

ans = ''
for i in range(N): # for each digit
    lst = []
    for j in range(10): # try all numbers
        print('0' * i + str(j) + '0' * (N - i - 1)) # make a guess
        result = int(input()) # receive the response
        lst.append(result)
    ans += str(lst.index(min(lst)))
print(ans) # output the final answer

課題を簡素化してくれたJonahに感謝します。

回答:


3

C、388 374 368バイト、合計試行数= 162751、スコア= 982280

char s[999];i;G;H;t;n;h;e;R(x){scanf("%d",x);}W(i,x,a){printf((i-n?0:4)+"%0*d%0*d\n",i,x,n-i,0);R(a);}S(k,i){if(!(t=e=k>4?s[i]=48:k<1?s[i]=53:!G?H=k,G=i:0)){for(;t++<n;)putchar(48|t==i|t==G);puts("");R(&t);t==h?W(G,e=1,&t):0;s[G]=t>h?53+H:53-H,s[i]=t>h^e?53+k:53-k;G=0;}}main(){R(&n);for(W(n,0,&h);i++<n;S(t-h+5>>1,i))W(i,5,&t);s[G]=53+H,puts(s+1),s[G]=53-H,puts(s+1);}

PPCGへようこそ!あなたはいいスコアを獲得しました162751*ln(388+50)=989887
コレラSu

3

C#(.NET Core)、617バイト、合計試行数= 182255、スコア= 1185166

using System;namespace p{class C{static void Main(){var l=Console.ReadLine();int L=int.Parse(l);var g=new int[L];var p=n(g);for(int i=0;i<L;i++){g[i]=5;var d=n(g);var f=d-p;var s=f;switch(s){case 5:g[i]=0;d-=5;break;case-5:break;case 3:g[i]=1;d=n(g);f=d-p;if(f>0){g[i]=9;d-=2;}break;case 1:g[i]=2;d=n(g);f=d-p;if(f>0){g[i]=8;d-=4;}break;case-1:g[i]=3;d=n(g);f=d-p;if(f>0){g[i]=7;d-=4;}break;case-3:g[i]=4;d=n(g);f=d-p;if(f>-3){g[i]=6;d-=2;}break;}p=d;}n(g);}static int n(int[] g){foreach(var i in g){Console.Write(i);}Console.WriteLine();var s=Console.ReadLine();var d=int.Parse(s);if(d<1) Environment.Exit(0);return d;}}}

この形式のC#がうまく機能することを願っています。完全なプログラムの形式であるため、実行可能ファイルにコンパイルする方法が必要です。簡単にするためにできることはありますか。Code Golfタグが削除されていても、バイトはスコアリングの一部であるため、公式に提出すると、不要な空白と便利な名前がすべて削除されます。以下の説明では、改変されていないコードの断片を使用します。

説明

このプログラムは、単一のヘルパーメソッドのみを使用します。

static int newGuess(IEnumerable<int> guess)
        {
            foreach (var item in guess)
            {
                Console.Write(item);
            }
            Console.WriteLine();
            var distanceString = Console.ReadLine();
            var distance = int.Parse(distanceString);
            if (distance < 1) System.Environment.Exit(0);
            return distance;
        }

これにより、推測が標準出力に書き込まれ、標準入力からの距離が読み取られます。また、推測が正確な組み合わせである場合、プログラムを即座に終了します。私はそれをたくさん呼びます。次に初期設定:

var lengthString = Console.ReadLine();
int length = int.Parse(l);
var guess = new int[length];
var prevDistance = newGuess(guess);

これにより、組み合わせの長さが取得され、すべて0で推測が開始されます。その後、forループ内の各数字を反復処理します。

guess[i] = 5;
var distance = newGuess(guess);
var difference = distance - prevDistance;
var switchVar = difference;
switch (switchVar)

数字ごとに5を推測し、前の推測(その数字は0)からの距離の変化に基づいて次のステップを決定します。

case 5:
    guess[i] = 0;
    distance -= 5;
    break;

距離が5増加した場合、その距離は0でした。その桁を0に戻します。記録された距離を手動で変更すると、余分な推測を防ぐことができます。

case -5:
    break;

距離が5減少した場合、5が正しい数字であり、次の数字にすぐに移動します。

その後、物事はトリッキーです。使用する50、残りの違いの可能性があるというのが私の最初の推測のための手段3, 1, -1, -3を区別するために1つの追加の推測を必要とするごとに、2つの可能性、と。これらの各ケースは同様の形式を取ります

case 3:
    guess[i] = 1;
    distance = newGuess(guess);
    difference = distance - prevDistance;
    if (difference > 0)
    {
        guess[i] = 9;
        distance -= 2;
    }

数値の一部は変更されますが、基本的には2つの可能性のいずれかを試し、変更がその数字に対して正しいかどうかを確認します。そうでない場合は、他の数字が正しいため、その数字を設定してから手動で差を調整します。

この方法では、最初の0に対して最大で1つの推測、1桁あたり2つの推測、最後の1桁が失敗しないように1つの最終的な推測が必要です。

バグがあるかもしれませんが、私が手動でチェックした限り機能しますが、それは保証ではありません。 コレラ・スのおかげでバグが発見されつぶされた


私はそれをテストしましたが、答えがのときはうまくいきませんでした37。出力は次のとおりです00, 50, 30, 75, 75(はい、2つの75)。
コレラSu

<>inに置き換えると、バグが修正ifswitchれるようです。それがあなたが望むものである場合、あなたのスコアは182255*ln(617+50)=1185166です。
コレラSu

@ColeraSu確かに!コードを短縮するときに、検索/置換を間違えたに違いありません。私はゴルフのコードを修正しました(詳細バージョンでは正しい比較が行われました)。
カミルドラカリ

2

Python 2および3:175バイト、合計試行数= 1005972、スコア= 5448445

このプログラムは、組み合わせごとにceil(log(n))* 10回試行するか、1桁ごとに10回試行します(したがって、33330回試行します)。

N=int(input());o=0
def c(a):
 print("0"*(N-len(str(a)))+str(a))
 return int(input())
for j in range(N):m={c(i):i for i in reversed(range(0,10**(j+1),10**j))};o+=m[min(m)]
c(o)

入出力機能をサポートしてくれたColera Suに感謝します。

Pythonバージョンのチャレンジ(OPにより変更)。

Python内でロックコードのバージョンを作成しました。Python(私のように)でこれを解決しようとしている場合は、先に進んで使用できます。以下はPython 2と3で動作します。ロックをテストできるクラスとして実装するだけの方がずっと意味があり、入力を推測するジェネレーター関数を作成することにしました。

import sys

class Lock:
    def __init__(self, number):
        self.lock = str(number)
    def l(self): #lengthOfNumber
        return len(self.lock)
    def c(self, guess): #check a guess
        guess = str(guess)
        guess = "0" * (len(self.lock) - len(guess)) + guess
        difference = 0
        for i in range(len(self.lock)):
            d1 = abs(int(self.lock[i]) - int(guess[i]))
            d2 = 10 - d1
            difference += d1 if d1 < d2 else d2
        return difference

def masterLock():
    testdata = ["000","555","755","735","744","746"]
    for answer in testdata:
        yield Lock(answer)

class LockIO:
    def __init__(self):
        self.lock = int(input())
    def l(self):
        return self.lock
    def c(self, guess):
        guess = str(guess)
        guess = "0" * (self.lock - len(guess)) + guess
        print(guess)
        sys.stdout.flush()
        return int(input())

for l in masterLock():
    # Write your code here that tries to guess it
    #   When you're done testing you can unindent your code,
    #   replace "for l in masterLock():" with "l = LockIO()"
    #   and submit the code.
    # 
    # Examples:
    #  l.l()      # returns the length of the lock
    #  l.c("952") # returns the distance to the lock
    #  l.c(952)   #  number also works
    pass

最初に、LockIOクラスを間違って書いたことを申し訳ありません。編集リクエストを送信しました。第二に、採点基準を誤って読んだと思います。スコアは、例ではなく、ジェネレーターによって生成されたテストデータによって計算されます(プログラムを実行しましたが、総数は1005972です)。自然対数もありません。3番目に、完全なプログラムを提供する必要があることを指定したため、LockIOバイトカウントにもその部分を含める必要があります。さらに、最終結果を出力する必要があり、それもスコアにカウントされます。
コレラSu

@ColeraSuここで「クラスLockIO」はどのように関連していますか?また、Pythonコードの2番目のブロックは何に使用されますか?
user202729

@ user202729 LockmasterLockは、単にテストの便宜上のものです。LockIO必要なI / O形式を使用するため、実際に送信する必要があるものです。
コレラSu

@nfnneilメインポストにサンプルプログラムを追加しました。また、参照用の編集リクエストも送信しました。
コレラSu

@ColeraSu眠りに落ちたとき、私はあなたが何を意味するのかを理解し、男に感謝します。良い挑戦でした。
ニール

2

R277バイト(スコア= 1175356) 258バイト、合計試行= 202999、スコア= 1163205

f=file("stdin","r")
w=function(b=1,A=X){cat(A,"\n",sep="");if(b){b=scan(f,n=1)};b}
M=0:9
s1=c(-5,-3,-1,1,3,5,3,1,-1,-3)
s2=s1+rep(c(1,-1),,,5)
L=w(1,"")
X=S=rep(0,L)
v0=w()
for(i in 1:L){X[i]=5
v1=v0-w()
X[i]=4
v2=v0-w()
S[i]=M[s1==v1&s2==v2]
X=0*S}
b=w(0,S)

オンラインでお試しください!

OPから要求されたStdin-stdoutバージョン、定型文なし。初期のバグを修正してくれたColera Suに感謝します。これは、コメントにあるものよりわずかに短いバージョンです。


以下は、TIO内でテストのバッチを実行するためのTIO送信です

R、189バイト

M=0:9
s1=c(-5,-3,-1,1,3,5,3,1,-1,-3)
s2=c(-4,-2,0,2,4,4,2,0,-2,-4)
f=function(L){S=rep(0,L)
v0=v(S)
X=S
for(i in c(1:L)){X[i]=5
v1=v0-v(X)
X[i]=4
v2=v0-v(X)
S[i]=M[s1==v1&s2==v2]
X[i]=0}
S}

オンラインでお試しください!

最初の推測としてゼロのベクトルを考えてみましょう。Vを現在の推測と解の間の距離と呼びましょう。各位置について、0を5と4に置き換えたときのVの変化のみをチェックする必要があります。実際、0と5の変化の違いはベクトルs1にリストされています。0と4の変更の違いは、ベクトルs2にリストされています。ご覧のとおり、これらの2つのベクトルは、ソリューションの数字を一意にマップします。

したがって、テストの合計数は3 * L 2 * L + 1です。ここで、Lはコードの長さです。すべてのゼロに対する初期チェック、次に各数字に対する2つのチェック、5に対して1つ、4に対して1つです。

要因3から要因2への改善は、Kamil Drakariの提案に触発されました。

TIOの提出の残りはRの定型です。TIOの提出は、L = 1 ... 200での1000回の実行の実行時間と操作の合計数を示し、Lの各値ごとに5回繰り返します。


Error in scan(n = 1) : scan() expected 'a real', got 'S=rep(0,L)'実行時に取得します。
コレラSu

1
scan(file=file("stdin"),n=1)うまくいくようです。このプログラム(お使いのプログラムと同じ、I / Oを修正したばかり)のスコアを取得し202999*ln(277+50)=1175356ます。
コレラSu

@ColeraSu、私は何かを見逃したかもしれませんが、私はそれを考えていた202999*ln(258+50) != 202999*ln(277+50)
-NofP

@ user202729がタイプミスをしたようです。修繕。
コレラSu
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.