Tìm mật khẩu


12

Một khóa kết hợp chữ số N thông thường bao gồm N đĩa quay. Mỗi đĩa có các chữ số 0-9 được ghi theo thứ tự và bạn cần chuyển chúng sang mật khẩu chính xác để mở. Rõ ràng, nếu bạn không biết mật khẩu, bạn sẽ cần thử tối đa 10 N lần trước khi mở khóa. Điều đó không thú vị.

khóa kết hợp

Vì vậy, hãy xem xét một biến thể của khóa kết hợp, đặt tên là khóa tiết lộ khoảng cách.

Trong mọi nỗ lực không thành công để mở khóa tiết lộ khoảng cách, nó sẽ đáp ứng số lượng chuyển động tối thiểu để mở khóa.

Một chuyển động được định nghĩa là xoay theo một vị trí, ví dụ: nó cần 1 chuyển động từ 890đến 899và 9 chuyển động từ 137đến 952.

Các thách thức

Đưa ra một khóa tiết lộ khoảng cách với mật khẩu không xác định, hãy thử mở khóa với số lần thử tối thiểu (không phải chuyển động), trong khi giữ cho chương trình không bị quá lâu.

Nội quy & Điểm

  • Bạn nên viết một chương trình đầy đủ mà đầu vào từ stdin và đầu ra đến thiết bị xuất chuẩn. Chương trình nên thực hiện đầu vào / đầu ra như sau:
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
  • Chương trình của bạn sẽ xử lý tối đa N = 200 và chỉ chạy dưới 5 giây cho bất kỳ đầu vào nào.

  • Số không hàng đầu trong đầu ra không nên được bỏ qua.

  • Có 5 testdata cho mỗi độ dài, vì vậy tổng số testdata là 1000. Testdata được tạo ngẫu nhiên.

  • Điểm cuối cùng sẽ là (tổng số lần đoán trong tất cả các bài kiểm tra) * ln (độ dài mã tính bằng byte + 50). Điểm số thấp nhất chiến thắng. (ln là nhật ký tự nhiên)

  • Tôi sẽ chấm điểm chương trình cho bạn. Nếu bạn muốn biết làm thế nào tôi sẽ chấm điểm chương trình của bạn, hoặc bạn muốn tự chấm điểm chương trình đó, hãy xem các chỉnh sửa trước đây trên bài đăng này .

  • Thử thách này sẽ kết thúc vào 2017/12/07 14:00 UTC. Tôi sẽ đăng giải pháp của tôi sau đó.

Chạy ví dụ

Các dòng bắt đầu bằng >đại diện cho đầu vào và các dòng khác đại diện cho đầu ra chương trình.

Bạn có thể có một mật khẩu trong tâm trí của bạn và tương tác với chương trình của bạn để kiểm tra nó.

> 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

Chương trình mẫu

EDIT: Có thể định dạng đầu vào / đầu ra ở trên không rõ ràng. Đây là một chương trình mẫu trong Python.

Python, 369 byte, tổng số lần thử = 1005973, điểm = 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

Cảm ơn Jonah vì đã đơn giản hóa thử thách.

Câu trả lời:


3

C, 388 374 368 byte, tổng số lần thử = 162751, điểm = 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);}

Chào mừng đến với PPCG! Bạn có một số điểm tốt đẹp của 162751*ln(388+50)=989887.
Colera Su

3

C # (.NET Core) , 617 byte, tổng số lần thử = 182255, điểm = 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;}}}

Hy vọng rằng C # trong định dạng này làm việc cho bạn. Nó ở dạng một chương trình hoàn chỉnh, vì vậy cần có một cách để biên dịch thành một tệp thực thi. Hãy cho tôi biết nếu có bất cứ điều gì tôi có thể làm để làm cho nó dễ dàng hơn. Byte là một phần của tính điểm ngay cả khi thẻ Code Golf bị xóa để việc gửi chính thức của tôi xóa tất cả các khoảng trắng không cần thiết và các tên hữu ích. Giải thích của tôi dưới đây sẽ sử dụng các đoạn mã không được mã hóa:

Giải trình

Chương trình này chỉ sử dụng một phương thức trợ giúp duy nhất:

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

Điều này viết dự đoán vào thiết bị xuất chuẩn, sau đó đọc khoảng cách từ stdin. Nó cũng ngay lập tức kết thúc chương trình nếu một dự đoán là sự kết hợp chính xác. Tôi gọi nó là rất nhiều. Tiếp theo thiết lập ban đầu:

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

Điều này nhận được độ dài của sự kết hợp, sau đó bắt đầu đoán với tất cả 0. Sau đó, nó lặp lại qua từng chữ số trong một forvòng lặp.

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

Đối với mỗi chữ số, nó đoán 5, sau đó quyết định bước tiếp theo dựa trên khoảng cách thay đổi kể từ lần đoán trước (trong đó chữ số đó là 0).

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

Nếu khoảng cách tăng thêm 5, thì 0 là chính xác cho khoảng cách đó. Điều chỉnh chữ số đó trở về 0. Thay đổi khoảng cách đã ghi bằng tay sẽ tránh việc đoán thêm.

case -5:
    break;

Nếu khoảng cách giảm 5, thì 5 là chữ số chính xác và chúng tôi chuyển sang chữ số tiếp theo ngay lập tức.

Sau đó mọi thứ thật khó khăn. Sử dụng 50cho những dự đoán ban đầu của tôi có nghĩa là các khả năng khác biệt còn lại là 3, 1, -1, -3với 2 khả năng cho mỗi khả năng, mỗi lần cần thêm 1 lần đoán để phân biệt. Mỗi trường hợp này có một hình thức tương tự

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

Một số con số thay đổi, nhưng về cơ bản chúng tôi thử một trong hai khả năng và kiểm tra xem sự thay đổi đó có đúng với con số đó không. Nếu không, thì chữ số kia là chính xác nên chúng tôi đặt chữ số đó sau đó điều chỉnh chênh lệch bằng tay.

Phương pháp này có nghĩa là chúng ta nên yêu cầu, nhiều nhất là 1 lần đoán cho 0 số ban đầu, 2 lần đoán cho mỗi chữ số và sau đó là 1 lần đoán cuối cùng để đảm bảo chữ số cuối cùng không rơi vào.

Mặc dù nó có thể có lỗi, nó hoạt động theo như tôi đã kiểm tra thủ công nhưng điều đó không đảm bảo. Lỗi được tìm thấy và đè bẹp nhờ Colera Su


Tôi đã thử nó và nó không hoạt động khi câu trả lời là 37. Đầu ra là: 00, 50, 30, 75, 75(có, hai 75 giây).
Colera Su

Thay thế <bằng >trong mỗi iftrong switchdường như để sửa chữa lỗi. Nếu đó là những gì bạn muốn, điểm số của bạn là 182255*ln(617+50)=1185166.
Colera Su

@ColeraSu Thật vậy! Tôi đã có một lỗi với việc tìm / thay thế khi rút ngắn mã. Tôi đã thực hiện sửa lỗi trong mã đánh gôn (phiên bản dài dòng có so sánh chính xác).
Kamil Drakari

2

Python 2 và 3: 175 byte, tổng số lần thử = 1005972, điểm = 5448445

Chương trình này mất ceil (log (n)) * 10 lần thử cho mỗi kết hợp hoặc mỗi chữ số duy nhất mất 10 lần thử (vì vậy, 333mất 30 lần thử).

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)

Rất cảm ơn Colera Su đã giúp tôi với chức năng đầu vào / đầu ra.

Phiên bản thử thách Python ( Được sửa đổi bởi OP ).

Tôi đã viết một phiên bản mã khóa bên trong Python. Bạn có thể tiếp tục và sử dụng nếu bạn đang cố gắng giải quyết vấn đề này bằng Python (như tôi). Các công việc sau đây trong Python 2 và 3. Nó có ý nghĩa hơn rất nhiều khi thực hiện khóa như một lớp bạn có thể kiểm tra và tôi quyết định tạo một hàm tạo để đoán các đầu vào.

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

Đầu tiên, xin lỗi về điều đó tôi đã viết LockIOsai lớp. Tôi đã gửi một yêu cầu chỉnh sửa. Thứ hai, tôi nghĩ bạn đã đọc sai tiêu chí chấm điểm. Điểm số được tính bằng testdata được tạo bởi trình tạo chứ không phải ví dụ (Tôi đã thực hiện chương trình của bạn và tổng số là 1005972). Nhật ký tự nhiên cũng bị thiếu. Thứ ba, tôi đã xác định rằng bạn cần cung cấp một chương trình đầy đủ, vì vậy bạn cũng nên bao gồm cả LockIOphần trong số byte của mình. Ngoài ra, bạn cần xuất kết quả cuối cùng và điều đó cũng được tính vào điểm số.
Colera Su

@ColeraSu "Lớp LockIO" có liên quan như thế nào ở đây? Ngoài ra, khối thứ hai của mã Python được sử dụng để làm gì?
dùng202729

@ user202729 LockmasterLockchỉ để thuận tiện cho việc thử nghiệm. LockIOlà những gì bạn thực sự cần gửi, vì nó sử dụng định dạng I / O cần thiết.
Colera Su

@nfnneil Tôi đã thêm một chương trình mẫu trong bài chính. Tôi cũng đã gửi một yêu cầu chỉnh sửa để bạn tham khảo.
Colera Su

@ColeraSu Khi tôi đang ngủ, tôi nhận ra ý của bạn và cảm ơn người đàn ông. Đó là một thử thách tốt.
Neil

2

R , 277 byte (điểm = 1175356) 258 byte, tổng số lần thử = 202999, điểm = 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)

Hãy thử trực tuyến!

Phiên bản Stdin-stdout, theo yêu cầu của OP, không có bản mẫu. Cảm ơn Colera Su đã sửa một lỗi ban đầu. Đây là một phiên bản ngắn hơn một chút so với phiên bản trong các bình luận.


Dưới đây là bài nộp TIO để chạy một loạt các bài kiểm tra trong TIO

R , 189 byte

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}

Hãy thử trực tuyến!

Chúng ta hãy xem xét một vectơ số không như dự đoán ban đầu. Hãy gọi V khoảng cách giữa dự đoán hiện tại và giải pháp. Đối với mỗi vị trí, bạn chỉ cần kiểm tra các thay đổi trong V khi thay 0 bằng 5 và bằng 4. Trên thực tế, sự khác biệt giữa thay đổi 0 bằng 5 được liệt kê trong vectơ s1 của tôi. Sự khác biệt giữa thay đổi 0 với 4 được liệt kê trong vector s2 của tôi. Như bạn thấy hai vectơ này ánh xạ duy nhất các chữ số của giải pháp.

Do đó, tổng số kiểm tra là 3 * L 2 * L + 1, trong đó L là độ dài của mã: kiểm tra ban đầu đối với tất cả các số không, sau đó hai kiểm tra cho mỗi chữ số, một kiểm tra so với 5 và một so với 4.

Sự cải thiện từ yếu tố 3 lên yếu tố 2 được lấy cảm hứng từ sự phục tùng của Kamil Drakari.

Phần còn lại của đệ trình TIO được soạn sẵn cho R. Trình TIO hiển thị thời gian chạy và tổng số thao tác cho 1000 lần chạy với L = 1 ... 200, 5 lần lặp cho mỗi giá trị của L.


Tôi nhận được Error in scan(n = 1) : scan() expected 'a real', got 'S=rep(0,L)'khi thực hiện.
Colera Su

1
Có vẻ như scan(file=file("stdin"),n=1)hoạt động. Chương trình này (giống như của bạn, chỉ cần sửa I / O) được điểm 202999*ln(277+50)=1175356.
Colera Su

@ColeraSu, tôi có thể đã bỏ lỡ điều gì đó, nhưng tôi nghĩ rằng202999*ln(258+50) != 202999*ln(277+50)
NofP

Có vẻ như @ user202729 đã mắc lỗi đánh máy. Đã sửa.
Colera Su
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.