ค้นหารหัสผ่าน


12

รหัสล็อคแบบ N หลักทั่วไปประกอบด้วยดิสก์หมุน N ตัว แผ่นดิสก์แต่ละแผ่นมีตัวเลข 0-9 ตามลำดับและคุณต้องเปลี่ยนเป็นรหัสผ่านที่ถูกต้องเพื่อเปิด แน่นอนถ้าคุณไม่ทราบว่ารหัสผ่านที่คุณจะต้องพยายามที่มากที่สุด 10 Nครั้งก่อนที่จะปลดล็อคมัน นั่นไม่น่าสนใจ

กุญแจรหัส

ลองพิจารณาชุดตัวล็อคที่แตกต่างกันลองตั้งชื่อตัวล็อคการเปิดเผยระยะทาง

ในความพยายามทุกครั้งที่ไม่ประสบความสำเร็จในการเปิดล็อคระยะห่างมันจะตอบสนองจำนวนการเคลื่อนไหวขั้นต่ำเพื่อปลดล็อก

หนึ่งการเคลื่อนไหวถูกกำหนดให้เป็นหมุนโดยตำแหน่งหนึ่งเช่นจะต้องเคลื่อนไหว 1 จาก890ไป899และ 9 การเคลื่อนไหวจากการ137952

ความท้าทาย

เมื่อไม่ทราบรหัสล็อคให้ลองเปิดล็อคด้วยจำนวนครั้งน้อยที่สุด(ไม่ใช่การเคลื่อนไหว) ขณะที่โปรแกรมไม่ให้ยาวเกินไป

กฏและสกอร์

  • คุณควรเขียนโปรแกรมเต็มรูปแบบซึ่งอินพุตจาก 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 testdata สำหรับทุกความยาวดังนั้นจำนวนของ testdata ทั้งหมดคือ 1000 ข้อมูล testdata จะถูกสร้างแบบสุ่ม

  • คะแนนสุดท้ายจะเป็น (จำนวนการเดาทั้งหมดใน testdata ทั้งหมด) * 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คุณได้คะแนนที่ดีของ
Colera 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;
        }

นี่เขียนการเดาเพื่อ 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, -32 ตัวเลือกสำหรับแต่ละคน แต่ละกรณีเหล่านี้ใช้แบบฟอร์มที่คล้ายกัน

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

ตัวเลขบางส่วนเปลี่ยนไป แต่โดยหลักแล้วเราลองหนึ่งในสองวิธีที่เป็นไปได้และตรวจสอบว่าการเปลี่ยนแปลงนั้นเป็นตัวเลขที่ถูกต้องสำหรับหลักนั้นหรือไม่ หากไม่เป็นเช่นนั้นตัวเลขอื่น ๆ จะถูกต้องดังนั้นเราจึงตั้งค่าตัวเลขนั้นจากนั้นปรับความแตกต่างด้วยตนเอง

วิธีนี้หมายความว่าเราควรกำหนดอย่างน้อยที่สุด 1 การคาดเดาสำหรับ 0s เริ่มต้น 2 การเดาต่อหลักและจากนั้น 1 การเดาสุดท้ายเพื่อให้แน่ใจว่าตัวเลขสุดท้ายไม่ผ่าน

มันอาจจะเป็นบั๊กกี้มันทำงานได้ไกลเท่าที่ฉันเคยตรวจสอบด้วยตนเอง แต่ก็ไม่รับประกัน พบข้อผิดพลาดและถูกแบนขอบคุณ Colera Su


37ผมทดสอบแล้วมันไม่ได้ทำงานเมื่อคำตอบคือ ผลลัพธ์คือ: 00, 50, 30, 75, 75(ใช่สอง 75s)
Colera Su

ใส่<กับ>ทุกifในswitchดูเหมือนว่าจะแก้ไขข้อผิดพลาด 182255*ln(617+50)=1185166หากเป็นสิ่งที่คุณต้องการคะแนนของคุณคือ
Colera Su

@ColeraSu แน่นอน! ฉันต้องทำผิดกับการค้นหา / แทนที่เมื่อทำให้รหัสสั้นลง ฉันได้ทำการแก้ไขในรหัส golfed (เวอร์ชัน verbose มีการเปรียบเทียบที่ถูกต้อง)
Kamil Drakari

2

Python 2 และ 3: 175 bytes, ความพยายามทั้งหมด = 1005972, คะแนน = 5448445

โปรแกรมนี้ใช้เวลา ceil (บันทึก (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 Version of Challenge ( แก้ไขโดย 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คลาสผิด ฉันได้ส่งคำขอแก้ไข ประการที่สองฉันคิดว่าคุณเข้าใจผิดเกณฑ์การให้คะแนน คะแนนถูกคำนวณโดย testdata ที่สร้างโดยตัวสร้างไม่ใช่ตัวอย่าง (ฉันดำเนินการโปรแกรมของคุณและจำนวนทั้งหมดคือ 1005972) บันทึกธรรมชาติก็หายไปเช่นกัน ประการที่สามฉันได้ระบุว่าคุณต้องจัดเตรียมโปรแกรมแบบเต็มดังนั้นคุณควรรวมLockIOส่วนในการนับไบต์ด้วย นอกจากนี้คุณต้องแสดงผลลัพธ์สุดท้ายซึ่งจะนับรวมอยู่ในคะแนนด้วย
Colera Su

@ColeraSu "คลาส LockIO" เกี่ยวข้องกับที่นี่ได้อย่างไร นอกจากนี้บล็อก Python ที่สองของรหัสใช้สำหรับอะไร
user202729

@ user202729 LockและmasterLockเป็นเพียงเพื่อความสะดวกในการทดสอบ LockIOคือสิ่งที่คุณต้องส่งจริง ๆ เนื่องจากใช้รูปแบบ I / O ที่ต้องการ
Colera Su

@nfnneil ฉันได้เพิ่มโปรแกรมตัวอย่างในโพสต์หลัก ฉันยังส่งคำขอแก้ไขสำหรับการอ้างอิงของคุณ
Colera Su

@ColeraSu ขณะที่ฉันหลับฉันรู้ว่าคุณหมายถึงอะไรและขอบคุณผู้ชาย มันเป็นความท้าทายที่ดี
Neil

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 ตามที่ร้องขอโดย OP ไม่มีต้นแบบสำเร็จรูป ขอบคุณ 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 ได้รับแรงบันดาลใจจากการส่งของ Kamil Drakari

ส่วนที่เหลือของการส่ง TIO เป็นสำเร็จรูปสำหรับ R การส่ง TIO แสดงเวลาทำงานและจำนวนการดำเนินการทั้งหมดสำหรับ 1,000 การทำงานด้วย L = 1 ... 200, 5 ซ้ำสำหรับแต่ละค่าของ L


ฉันได้รับError in scan(n = 1) : scan() expected 'a real', got 'S=rep(0,L)'เมื่อดำเนินการ
Colera Su

1
ดูเหมือนว่าใช้scan(file=file("stdin"),n=1)งานได้ โปรแกรมนี้ (เช่นเดียวกับคุณเพียงแค่แก้ไข I / O) 202999*ln(277+50)=1175356ได้รับคะแนนของ
Colera Su

@ColeraSu ฉันอาจจะพลาดบางสิ่งบางอย่าง แต่ฉันคิดว่า202999*ln(258+50) != 202999*ln(277+50)
NofP

ดูเหมือนว่า @ user202729 ทำผิดพลาด แก้ไขแล้ว.
Colera Su
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.