Şifreyi bulun


12

Sıradan bir N basamaklı şifreli kilit, N döner diskten oluşur. Her disk sırayla 0-9 arası rakamlara sahiptir ve açmak için doğru şifreye çevirmeniz gerekir. Açıkçası, şifreyi bilmiyorsanız, kilidini açmadan önce en fazla 10 N kez denemeniz gerekir. Bu ilginç değil.

şifreli kilit

Öyleyse kombinasyon kilidinin bir varyantını düşünelim, mesafeyi ortaya çıkaran kilit olarak adlandırın.

Mesafeyi açığa çıkaran bir kilidi açmaya yönelik her başarısız girişimde, kilidini açmak için minimum hareket sayısına yanıt verir.

Bu 1 hareket ihtiyacı örneğin, bir hareket, bir konum bir dönme hareketi olarak tanımlanır 890için 899ve 9 hareketleri 137için 952.

Meydan okuma

Şifresi bilinmeyen bir mesafeyi ortaya çıkaran bir kilit verildiğinde , programı çok uzun süre engellemekten korurken , kilidi minimum sayıda denemeyle (hareketlerle değil) açmaya çalışın .

Kurallar ve Puanlamalar

  • Stdin'den çıkışlara ve stdout'a çıkış yapan tam bir program yazmalısınız. Program giriş / çıkışı aşağıdaki gibi yapmalıdır:
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
  • Programınız N = 200 değerine kadar işlem görmeli ve herhangi bir girişte 5 saniyeden daha kısa sürede çalışmalıdır.

  • Çıktıda önde gelen sıfırlar atlanmamalıdır.

  • Her uzunluk için 5 test verisi olduğundan toplam test verisi sayısı 1000'dir. Test verileri rastgele oluşturulur.

  • Nihai puan (tüm test verilerindeki toplam tahmin sayısı) * ln (bayt cinsinden kod uzunluğu + 50) olacaktır. En düşük puan kazanır. (ln doğal kütüktür)

  • Programı senin için puanlayacağım. Programınızı nasıl puanlayacağımı bilmek istiyorsanız veya kendiniz puanlamak istiyorsanız , bu yayındaki önceki düzenlemelere göz atın .

  • Bu mücadele 2017/12/07 14:00 UTC de sona erecek. O zaman çözümümü göndereceğim.

Koşu Örneği

İle başlayan satırlar >girişi, diğerleri ise program çıktısını temsil eder.

Aklınızda bir şifre olabilir ve test etmek için programınızla etkileşimde bulunabilirsiniz.

> 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

Örnek Program

EDIT: Belki yukarıdaki giriş / çıkış biçimi net değildi. İşte Python'da örnek bir program.

Python, 369 bayt, toplam deneme sayısı = 1005973, puan = 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'a mücadeleyi basitleştirdiği için teşekkürler .

Yanıtlar:


3

Cı, 388 374 368 bayt, toplam girişimler = 162.751, = 982.280 skor

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'ye Hoşgeldiniz! Güzel bir puan aldınız 162751*ln(388+50)=989887.
Colera Su

3

C # (.NET Core) , 617 bayt, toplam deneme = 182255, skor = 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;}}}

Umarım bu formattaki C # sizin için çalışır. Tam bir program biçimindedir, bu nedenle yürütülebilir bir dosyayı derlemenin bir yolu olmalıdır. Bunu kolaylaştırmak için yapabileceğim bir şey varsa bana bildirin. Code Golf etiketi kaldırılsa bile baytlar puanlamanın bir parçası, bu yüzden resmi gönderimim tüm gereksiz boşlukları ve kullanışlı adları kaldırıyor. Aşağıdaki açıklamamda, kodlanmamış kodun parçaları kullanılacak:

açıklama

Bu program yalnızca tek bir yardımcı yöntem kullanır:

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

Bu tahmin stdout'a yazar, sonra stdin ile olan mesafeyi okur. Bir tahminin tam kombinasyon olması durumunda programı hemen sonlandırır. Ben buna çok diyorum. Sonra ilk kurulum:

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

Bu, kombinasyonun uzunluğunu alır, ardından 0'ların tümü ile tahmin etmeye başlar. Daha sonra, bir fordöngüdeki her basamaktan tekrarlar.

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

Her basamak için 5'i tahmin eder, ardından bir önceki tahminden bu yana mesafenin nasıl değiştiğine bağlı olarak bir sonraki adıma karar verir (bu rakamın 0 olduğu yer).

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

Mesafe 5 artarsa, o mesafe için 0 doğrudur. Bu rakamı 0'a geri ayarlayın. Kaydedilen mesafeyi manuel olarak değiştirmek fazladan bir tahminde bulunmayı önler.

case -5:
    break;

Mesafe 5 azalırsa, 5 doğru rakamdır ve hemen bir sonraki basamağa geçiyoruz.

Bundan sonra işler zor. İlk tahminlerimi kullanmak 5ve 0benim için, kalan fark olasılıklarının 3, 1, -1, -3her biri için 2 olasılık olduğu, ayırt etmek için 1 ek tahmine ihtiyaç duyduğu anlamına gelir . Bu vakaların her biri benzer bir form alır

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

Sayılardan bazıları değişir, ancak aslında iki olasılıktan birini deneriz ve değişikliğin bu rakam için doğru olup olmadığını kontrol ederiz. Değilse, diğer rakam doğrudur, bu yüzden bu rakamı ayarlayıp farkı manuel olarak ayarladık.

Bu yöntem, ilk 0'lar için en fazla 1 tahminde, her basamak için 2 tahminde ve son rakamın düşmediğinden emin olmak için 1 son tahminde bulunmamız gerektiği anlamına gelir.

Ama buggy olabilir, ben elle kontrol kadar çalışır ama bu bir garanti. Colera Su sayesinde hata bulundu ve ezildi


Test ettim ve cevap geldiğinde işe yaramadı 37. Çıktı: 00, 50, 30, 75, 75(evet, iki 75s).
Colera Su

Değiştirme <ile >her ifin switchhatayı düzeltmek gibi görünüyor. Eğer istediğin buysa, puanın 182255*ln(617+50)=1185166.
Colera Su

@ColeraSu Gerçekten! Kodu kısaltırken bul / değiştir ile bir hata yapmış olmalıyım. Golfçü kodda düzeltmeyi yaptım (ayrıntılı sürüm doğru karşılaştırmaları vardı).
Kamil Drakari

2

Python 2 ve 3: 175 bayt, toplam deneme = 1005972, skor = 5448445

Bu program tavan (log (n)) * Her kombinasyon için 10 deneme veya her basamak 10 deneme (yani 33330 deneme) alır.

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)

Giriş / çıkış işlevselliği konusunda bana yardımcı olduğu için Colera Su'ya çok teşekkürler.

Mücadelenin Python Sürümü ( OP tarafından değiştirildi ).

Python'un içine kilit kodunun bir versiyonunu yazdım. Devam edip bunu Python'da (benim gibi) çözmeye çalışıyorsanız kullanabilirsiniz. Aşağıdaki Python 2 ve 3'te çalışır. Kilidi, test edebileceğiniz bir sınıf olarak uygulamak çok daha mantıklıydı ve girişleri tahmin etmek için bir jeneratör işlevi oluşturmaya karar verdim.

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

İlk olarak, LockIOsınıfı yanlış yazdığım için üzgünüm . Bir düzenleme isteği gönderdim. İkincisi, sanırım puanlama kriterini yanlış okudunuz. Skor, jeneratör tarafından oluşturulan test verileri tarafından hesaplanır, örnek değil (Programınızı yürüttüm ve toplam sayı 1005972'dir). Doğal kütük de eksik. Üçüncü olarak, tam bir program sağlamanız gerektiğini belirttim, bu yüzden LockIOparçayı bayt sayınıza da eklemelisiniz . Ayrıca, nihai sonucu çıkarmanız gerekir ve bu da puanda sayılır.
Colera Su

@ColeraSu "Sınıf LockIO" burada nasıl ilişkilidir? Ayrıca Python kodunun ikinci bloğu ne için kullanılır?
user202729

@ user202729 Lockve masterLocksadece test kolaylığı içindir. LockIOgerekli G / Ç biçimini kullandığından göndermeniz gereken şeydir.
Colera Su

@nfnneil Ana yayına örnek bir program ekledim. Ayrıca referansınız için bir düzenleme isteği gönderdim.
Colera Su

@ColeraSu Uykuya daldığımda ne demek istediğini anladım ve teşekkürler adamım. İyi bir mücadeleydi.
Neil

2

R , 277 bayt (skor = 1175356) 258 bayt, toplam deneme = 202999, skor = 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)

Çevrimiçi deneyin!

Stdin-stdout versiyonu, OP tarafından talep edildiği gibi, ısıtıcı plaka yok. İlk hatayı düzelttiği için Colera Su'ya teşekkürler. Bu, yorumdakinden daha kısa bir versiyon.


Burada TIO içinde bir grup test yapmak için TIO gönderiminin altında

R , 189 bayt

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}

Çevrimiçi deneyin!

İlk tahmin olarak sıfırlardan oluşan bir vektör düşünelim. V'ye mevcut tahmin ve çözüm arasındaki mesafeyi söyleyelim. Her pozisyon için, sadece 0'ı 5 ve 4 ile değiştirdiğinizde V'deki değişiklikleri kontrol etmeniz gerekir. Aslında, 0 ile 5 arasındaki farklar vektörüm s1'de listelenir. 0 ile 4 arasında değişen farklar vektörüm s2'de listelenmiştir. Gördüğünüz gibi bu iki vektör, çözeltinin rakamlarını benzersiz şekilde eşler.

Böylece toplam test sayısı 3 * L 2 * L + 1'dir, burada L kodun uzunluğudur: tüm sıfırlara karşı bir ilk kontrol, daha sonra her basamak için iki kontrol, bir 5'e karşı ve bir 4'e karşı.

Bir faktör 3'ten bir faktör 2'ye yapılan iyileştirme, Kamil Drakari'nin sunumundan esinlenmiştir.

TIO gönderisinin geri kalanı R için kazan plakasıdır. TIO gönderimi, L = 1 ... 200 ile 1000 çalışma için toplam işlem sayısını, her bir L değeri için 5 tekrar gösterir.


Error in scan(n = 1) : scan() expected 'a real', got 'S=rep(0,L)'Yürütürken anladım .
Colera Su

1
Öyle görünüyor scan(file=file("stdin"),n=1). Bu program (sizinkiyle aynı, sadece düzeltilmiş I / O) puanı alır 202999*ln(277+50)=1175356.
Colera Su

@ColeraSu, bir şeyleri kaçırmış olabilirim, ama bunu düşündüm202999*ln(258+50) != 202999*ln(277+50)
NofP

@ User202729 bir yazım hatası yaptı gibi görünüyor. Sabit.
Colera Su
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.