Знайдіть пароль


12

Звичайний N-розрядний комбінований замок складається з N обертових дисків. На кожному диску є цифри 0-9, вписані по порядку, і вам потрібно повернути їх до правильного пароля, щоб відкрити його. Очевидно, якщо ви не знаєте пароль, вам потрібно буде спробувати щонайбільше 10 N разів, перш ніж розблокувати його. Це не цікаво.

комбінований замок

Тому давайте розглянемо варіант блокування комбінацій, назвіть його замком, що розкриває відстань.

У кожній невдалій спробі відкрити замок, що виявляє відстань, він відповість мінімальною кількістю рухів, щоб розблокувати.

Один рух визначається як обертання на одну позицію, наприклад, йому потрібно 1 рух від 890до 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

Зразок програми

EDIT: Можливо, формат вводу / виводу вище не був зрозумілий. Ось зразок програми в 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

Дякую Джоні за спрощення виклику.

Відповіді:


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.
Колера Су

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

Це записує здогад до stdout, потім читає відстань від stdin. Він також негайно закінчує програму, якщо здогадка є точною комбінацією. Я це багато називаю. Наступна початкова настройка:

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 - це правильна цифра, і ми переходимо до наступної цифри негайно.

Після цього справи хитрі. Використання 5та 0для моїх початкових здогадок означає, що інші можливості для різниці складаються 3, 1, -1, -3з 2 можливостей для кожної, для чого потрібно 1 додатковий здогад. Кожен із цих випадків приймає подібну форму

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

Деякі числа змінюються, але по суті ми спробуємо одну з двох можливостей і перевіряємо, чи зміна була правильною для цієї цифри. Якщо це не так, то інша цифра правильна, тому ми встановлюємо цю цифру, а потім регулюємо різницю вручну.

Цей метод означає, що нам потрібно мати щонайменше 1 здогадку для початкових 0, 2 здогадки на цифру, а потім 1 остаточну здогадку, щоб остання цифра не проникла.

Це може бути баггі, хоча воно працює, наскільки я перевірив вручну, але це не є гарантією. Помилка знайдена та розбита завдяки Colera Su


Я перевірив це, і він не спрацював, коли відповідь є 37. Вихід: 00, 50, 30, 75, 75(так, два 75s).
Colera Su

Заміна <з >в кожному ifдюймі , switchздається , щоб виправити помилку. Якщо ви цього хочете, ваш рахунок 182255*ln(617+50)=1185166.
Колера Су

@ColeraSu Дійсно! Я, мабуть, помилився з знаходженням / заміною при скороченні коду. Я вніс виправлення в код golfed (у багатослівній версії були правильні порівняння).
Каміль Дракарі

2

Python 2 і 3: 175 байт, загальна кількість спроб = 1005972, оцінка = 5448445

Ця програма бере ceil (log (n)) * 10 спроб за комбінацію або кожна цифра займає 10 спроб (значить, 333займає 30 спроб).

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 ( модифікована ОП ).

Я написав версію коду блокування всередині 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). Природний журнал також відсутній. По-третє, я уточнив, що вам потрібно надати повну програму, тому ви також повинні включити її LockIOчастину в свій байт. Крім того, потрібно вивести кінцевий результат, який також враховується в балі.
Colera Su

@ColeraSu Як тут пов'язаний "клас LockIO"? Також для чого використовується другий блок коду Python?
користувач202729

@ user202729 Lockі masterLockпросто для зручності тестування. LockIOце те, що вам потрібно надіслати, оскільки він використовує необхідний формат вводу / виводу.
Colera Su

@nfnneil Я додав зразок програми в основний пост. Я також надіслав запит на редагування для вашої довідки.
Colera Su

@ColeraSu Коли я засинав, я зрозумів, що ти маєш на увазі, і дякую людині. Це було гарним викликом.
Ніл

2

R , 277 байт (бал = 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)

Спробуйте в Інтернеті!

Версія 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 відстань між поточною здогадкою та рішенням. Для кожної позиції вам потрібно лише перевірити зміни V, коли ви заміните 0 на 5 і на 4. Насправді відмінності між зміною 0 на 5 перераховані в моєму векторі s1. Різниці між зміною 0 на 4 наведені в моєму векторі s2. Як бачите, ці два вектори унікально відображають цифри рішення.

Таким чином, загальна кількість тестів 3 * L 2 * L + 1, де L - довжина коду: початкова перевірка на всі нулі, потім два перевірки на кожну цифру, один проти 5 і один проти 4.

Покращення від коефіцієнта 3 до коефіцієнта 2 надихнуло подання Каміля Дракарі.

Решта подання TIO - це котловарна таблиця для R. У поданні TIO відображається час роботи та загальна кількість операцій за 1000 прогонів з L = 1 ... 200, 5 повторів для кожного значення L.


Я отримую Error in scan(n = 1) : scan() expected 'a real', got 'S=rep(0,L)'при виконанні.
Колера Су

1
Здається, що scan(file=file("stdin"),n=1)працює. Ця програма (така ж, як і ваша, щойно виправлена ​​введення-виведення) отримує бал 202999*ln(277+50)=1175356.
Колера Су

@ColeraSu, можливо, я щось пропустив, але я подумав, що це202999*ln(258+50) != 202999*ln(277+50)
NofP

Здається, що @ user202729 написав помилку. Виправлено.
Колера Су
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.