마이클 Crichton의 쥐덫


9

1984 년 Michael Crichton은 BASIC에서 Creative Computing 잡지에 출판 된 보안 프로그램을 작성했습니다. 프로그램은 사용자에게 원하는 문구를 입력하고 키 스트로크 사이의 간격을 기록한 다음 문구를 다시 입력하도록 요청합니다. 타이밍이 너무 다른 경우 프로그램은 사용자를 사기꾼으로 식별합니다.

과제 : 선택한 언어로 Crichton의 프로그램 버전을 작성하십시오.

규칙 :

  1. 사용자와의 의사 소통을위한 문구 ( "키 구문을 입력하십시오", "키 구문을 다시 입력하십시오"등)는 실제 길이에 관계없이 각각 1 바이트로 계산됩니다. 이것은 사용자 통신 전용이며 문자열에서 프로그램 코드를 숨기려고 시도하지 마십시오.

  2. 합격 / 불합격 테스트는 원래 구간과의 편차 백분율의 평균 절대 값을 기반으로해야합니다. 문자열이 일치하지 않으면 재량에 따라 리턴에 실패하거나 사용자가 다시 시도하도록 허용하십시오.

  3. 핵심 문구는 null 문자열을 허용하지 않아야합니다. 키 구문이 문자열 데이터 유형에 비해 너무 길면, 임의로 재량으로 자르거나 허용하지 않고 다시 시작할 수 있습니다.

  4. 테스트 감도 (통과 / 실패 테스트의 임계 값)는 소스 코드에서 조정 가능해야합니다.

  5. 소스 코드를 공룡과 비슷하게 형식화 할 수 있다면 원래 총 바이트 수의 20 %를 보너스로 제공했습니다. 이것은 매우 주관적이고 인기 콘테스트에 더 적합하다고 지적 되었으므로이 보너스를 제거했습니다. 그러나 나는 여전히 공룡 서식을 진심으로 권장하며, 코드를 공룡처럼 보이도록 형식을 지정하면 순수하게 주석, 줄 바꿈 또는 공백 문자를 바이트 총계에서 빼낼 수 있습니다.

  6. 문자열 길이 및 공룡 형식 조정에 따라 가장 짧은 바이트 수를 얻습니다.

위의 사양은 Crichton의 코드 작동과 정확히 일치하지 않으며 사본은 온라인에서 찾을 수 있습니다. 사양을 따르고 원본을 복제하지 마십시오.


5
"이것은 Michael Crichton이므로 소스 코드를 공룡과 비슷하게 형식화 할 수 있다면 총 바이트 수에서 20 %를 빼십시오." -음 ... 아니 이 규칙은 너무 주관적입니다. 제거하십시오. 그 외에는 계속 진행하십시오.
John Dvorak

4
@JanDvorak 나는 "너무"주관적이라고 생각하지 않습니다. ASCII 예술을 디노로 부르는 것은 꽤 쉬운 호출입니다.
Optimizer

3
@Optimizer 모든 경우에 해당되는 것은 아닙니다. 그리스 문자 람다는 공룡처럼 보입니까? 나는 그것을 확신합니다.
John Dvorak

3
다른 몇 가지 사소한 설명 : "Please type the key phrase"1 바이트로 계산 됩니까? 아니면 문구 만 계산하고 인용 된 문구는 3 바이트 ( ", phrase, ")로 계산합니까? 더 긴 간격과 훨씬 짧은 간격이 "취소"되어 다시 한 번 더되는 것이 의도적인가? 프로그램은 두 가지 핵심 문구가 일치하는지 확인해야합니까?
Doorknob

답변:


9

루비, 171167 157 바이트

require'io/console';t=Time;f=->a{loop{x=t.now;STDIN.getch==?\r?break: a<<t.now-x};a};p"Please type the key phrase";f[r=[]];p"Please type the key phrase again";p r.zip(f[[]]).map{|x,y|(1-x/y).abs}.reduce(:+)/r.size>0.2

true평균 분산이 20 %를 초과하면 출력 하고, 그렇지 않으면 출력 false합니다.

공룡 ASCII 예술 시도 :

(_=/\
  \ \
   \ \
    \ \              _...---..__
     \ \          .∕` #{t=Time} `\._
      \ \      .∕ #{z='io/console'} `\.
       \ \.__.∕  #{require z;s=STDIN} `\.
        \ #{p'1:';f=->a{loop{x=t.now;#   \.
         s.getch==?\r?break: a<<t.now-x;# `\.
          };a};f[r=[]];p'2:';p r.zip(f[[]])#\  
           .map{|x,y|(1-x/y).abs}.reduce(:+)#|
            .fdiv(r.size)>0.2}###########\   \
            `-._    ,___...----...__,   ,__\  \
                |   |_|           |_|   |    \ \
                |___|               |___|      \\/)

언 골프 드 :

require 'io/console' # so we can read one char at a time

t = Time

f = ->(a) {
  loop {
    x = t.now # record start time
    break if STDIN.getch == ?\r
    a << t.now - x # push (start time - end time) into array
  }
  a
}

puts "Please type the key phrase"
f[r = []] 

puts "Please type the key phrase again"

# interweave timing arrays, compute variances, sum elements
# then divide by array length. Check to see if average
# is greater than threshold (0.2)
p r.zip(f[[]]).map { |x,y| (1-x/y).abs }.reduce(:+) / r.size > 0.2

require 'io/console' 라이브러리가 이미로드되었으므로 일부 Ruby REPL에서 실행될 때 제거 할 수 있습니다.


4

자바 768 바이트

뭐? 자바? 코드 골프를 위해?

이것은 아마도 최악의 일이지만 어쨌든 시도했습니다.

콘솔 창에 모든 메시지가 표시되지만 실제 입력은 JTextField에서 발생합니다. 정확히 좋은 것은 아닙니다. 아, 그리고 5 바이트를 절약하려면 JFrame의 크기를 직접 조정해야합니다. 또한 두 번째로 문자열 정확성을 확인하지 않습니다. 그것이 사양에 위배되는지 확실하지 않습니다.

쓰다:

텍스트 필드에 키를 입력하십시오.

Enter 키를 누르지 말고 콘솔로 이동하여 무언가를 입력하십시오. 다른 메시지가 표시됩니다

텍스트 필드에 같은 것을 입력하십시오 (이제 지워 져야 함).

콘솔로 이동하여 다시 누르십시오. 침입자인지 아닌지를 표시합니다.

언 골프 :

import java.util.*;
import javax.swing.*;
import javax.swing.event.*;

public class CrichtonsMousetrap {
    public static void main(String[]a){
        new CrichtonsMousetrap();
    }
    long start;
    List<Long>elapsed = new ArrayList<>();
    List<Long>e2;
    public CrichtonsMousetrap(){
        JFrame f = new JFrame();
        f.setSize(199,70);
        f.setVisible(true);
        JTextField t = new JTextField();
        System.out.println("please type in the key phrase.");
        f.add(t);
        t.getDocument().addDocumentListener(new DocumentListener(){
            @Override
            public void changedUpdate(DocumentEvent e) {}
            @Override
            public void insertUpdate(DocumentEvent e) {
                long r = System.nanoTime();
                if(start!=0){elapsed.add(r-start);}
                start=r;}
            @Override
            public void removeUpdate(DocumentEvent e) {}            
        });
        Scanner s = new Scanner(System.in);
        s.next();
        System.out.println("please type that again!");
        e2=elapsed;
        elapsed=new ArrayList<>();
        start=0;
        t.setText("");
        s.next();
        double sum=0;
        for(int i=0;i<e2.size();i++){
            sum+=Math.abs(1-elapsed.get(i)/(double)e2.get(i));
        }
        System.out.println("your average percent error was " + sum/e2.size());
        double okLimit = .2;
        System.out.println(sum/e2.size() < okLimit ? "you're ok":"INTRUDER!");
    }
}

골프 :

import java.util.*;import javax.swing.*;import javax.swing.event.*;class q{static long p;static List<Long>y=new ArrayList<>(),o;public static void main(String[]a){JFrame f=new JFrame();f.setSize(0,0);f.setVisible(true);JTextField t=new JTextField();System.out.println("please type in the key phrase.");f.add(t);t.getDocument().addDocumentListener(new DocumentListener(){public void changedUpdate(DocumentEvent e){}public void insertUpdate(DocumentEvent e){long r=System.nanoTime();if(p!=0){y.add(r-p);}p=r;}public void removeUpdate(DocumentEvent e){}});Scanner s = new Scanner(System.in);s.next();System.out.println("please type that again!");o=y;y=new ArrayList<>();p=0;t.setText("");s.next();double b=0;for(int i=0;i<o.size();b+=Math.abs(1-y.get(i)/(double)o.get(i++)));System.out.print(b/o.size() < .25 ? "you're ok":"INTRUDER!");}}

Java에서 원시 모드로 TTY를 설정하는 방법은 없습니다 (JNI를 사용할 준비가되지 않은 경우). 그래서 왜 JFrame이 필요한지 이해합니다. 그러나 실제로 이것은 나이가 들어 본 가장 사용자 친화적 인 프로그램입니다. :-)이 답변을 찬성 또는 하향 표로 할 것인지 확실하지 않습니다.
coredump 2018

나는 사용자가 친근하지 않은 것에 대해 찬성했습니다. 기본적으로 예술입니다.
Ingo Bürk

나는 수업을 확장함으로써 더 많은 골프를 할 수 있다고 생각 JFrame하므로 필요하지 않을 것 f입니다.
PurkkaKoodari

3

HTML, 자바 스크립트 (ES6), 328

코드의 총 바이트 수는 402 바이트이며 사용자와 상호 작용할 메시지는 다음과 같습니다.

"Valid User"
"Imposter alert!!"
"Please Enter the Key again"
Please Enter the Key

총 78 바이트이므로 총 점수 => 402-78 + 4 = 328

최신 Firefox 에서 아래 스 니펫을 실행하고 입력 상자에 키를 입력 한 다음 Enter 키를 입력하십시오.

이 코드는 입력 한 키와 다시 입력 한 키가 동일한 지 확인하고 (그렇지 않은 경우 다시 입력하라는 프롬프트 표시) 평균 절대 차이 백분율을 계산하고 변수 값보다 작은 지 확인합니다. V

<a id=t >Please Enter the Key</a><input id=f /><script>V=.3,a=[],i=0,s=b="",q=0
c=_=>(j=0,_.slice(1).map(v=>j+=Math.abs(v)/i),alert(j<V?"Valid User":"Imposter alert!!"))
r=_=>(a=[],i=0,t.textContent="Please Enter the Key again",f.value="")
f.onkeyup=_=>_.keyCode==13?q++?s==f.value?(A=a,B=b,A=a.map((v,i)=>v-A[i-1]),c(b.map((v,i)=>(v-B[i-1]-A[i])/A[i]))):r():r(b=a,s=f.value):a[i++]=Date.now()</script>


3

C, 154 (플래그의 경우 86 + 68)

d[99],i,a,b;main(x,y){P"Please type the key phrase"W(E-13)U,x=y;U;P"Please type 
the key phrase again"W(a<i)E,b+=abs(Y-Z)*99/Z,++a,x=y;b<a*9||P"No cake for imposters");}

컴파일 -DY=(y=clock())-x, -DZ=a[d], -DE=getch(), -DW=);while, -DU=i++[d]=Y-DP=puts(. 표시 목적으로 개행을 추가하고 제거 할 수 있습니다 (주어진 바이트 수는 없음).

언 골프 + 댓글 :

d[99],i,a,b;
main(x,y,z){
    puts("Please type the key phrase");
    do
        z = getch(),
        i++[d] = (y = clock()) - x, // save amount of time from last key. first value is garbage.
        x = y;
    while((z = getch())-13); // read until carriage return. 
    for(;a < i && getch(); ++a) // don't check for validity, just get a char
        b += abs((y = clock())- x - d[a])*99/d[a], // (y=clock())-x is time from last key.
                                                     // subtract from original time, *99, divide by new
                                                     // then get sum of these
        x = y;
    b < i*9  // check that the average difference is less than 9/99
    || puts("No cake for imposters"); // identify as imposter if greater/equal
    // don't output anything if not an imposter
}

이렇게하면 다시 입력 한 구문이 동일한 지 확인하지 않으며 사용자가 사기꾼으로 식별되지 않은 경우 아무 것도 출력하지 않습니다.

또한 첫 번째 키 입력 전에 프롬프트 한 후 소요 된 시간도 고려하지 않습니다.


getch내기 getcgetchar? `getch '에 대한 정의되지 않은 참조가 있는데, 올바르게 리콜하면 더 이상 사용되지 않습니까?
coredump 2015

또한 "file.c : 1 : 1 : warning : data definition에 유형 또는 스토리지 클래스가 없습니다"(gcc)가있었습니다. char전역 선언 전에 추가 했으며 이제 런타임에 세그먼트 오류가 발생합니다. 빌드 방법에 대한 세부 정보를 줄 수 있습니까? 어떤 컴파일러를 사용하고 있습니까? 감사.
coredump 2015

@coredump 경고는 무해합니다. 경고를 제거하려면을 입력 int하고로 초기화해야 0합니다. Windows에서 gcc를 사용하여 이것을 테스트했습니다 (Window 사용 getch). getch대신에 getc또는 문자를 처리하기 전에 리턴 키를 누를 필요가 getchar없기 때문에 사용됩니다 getch( getch더 이상 사용되지 않는 기능을 사용하는 데 아무런 문제가 없지만 Windows에서는 실제로 사용되지 않습니다).
es1024

Linux에서 테스트 중이며 작동하도록 stackoverflow.com/questions/7469139/… 에 의지 했습니다. 감사.
coredump

2

스칼라 REPL 233

def l:Stream[(Int,Long)]=(Console.in.read,System.nanoTime)#::l    
def m={
    println("Enter");     
    l.takeWhile(_._1!=13).map(_._2).toList.sliding(2).map(a=>a(1)-a(0))
}
val k=m.zip(m)     
k.map(a=>Math.abs(a._2-a._1)/(a._1.toDouble*k.length)).sum<0.2

모든 간격이 제거되면 다음이 있습니다.

def l:Stream[(Int,Long)]=(Console.in.read,System.nanoTime)#::l;def m={println("Enter");l.takeWhile(_._1!=13).map(_._2).toList.sliding(2).map(a=>a(1)-a(0))};val k=m.zip(m);k.map(a=>Math.abs(a._2-a._1)/(a._1.toDouble*k.length)).sum<0.2

나는 내가 누구보다 더 재능있는 사람이 공룡으로 만들 수 있다고 확신합니다!

간단한 설명 :

l메소드는 문자를 읽고 nanoTime각 문자를 입력했을 때 의 위치 를 유지합니다 .

m메소드는를 인쇄 "Enter"하고 lEnter 키 (문자 13)를 눌렀을 때 메소드를 중단 한 다음에만 맵핑 nanoTimes한 다음 각 문자 사이의 시간 간격을 가져옵니다.

다음 두 줄은 두 개의 문자열을 읽고 압축 한 다음 두 번째 간격과 첫 번째 간격의 백분율 차이의 평균 절대 값을 찾아서이 평균이보다 작은 지 여부를 인쇄합니다 0.2.


1

공통 리스프 : 660

(ql:quickload'(cl-charms alexandria))(defun m(&key(ok 0.2))(labels((^(s)(fresh-line)(princ s)(return-from m))(d(a b)(abs(/ (- b a) b)))($(x)(princ x)(force-output))(?(m)(charms:with-curses()($ m)(clear-input)(charms:enable-raw-input)(loop for c = (read-char)for n = (get-internal-real-time)for x = nil then (/(- n b)internal-time-units-per-second)for b = n when (eql c #\Esc)do (^"QUIT")when x collect x into % until (eql c #\Newline) collect c into ! finally(progn(terpri)(return(cons(coerce !'string)%)))))))(let*((ip(?"INIT PASSWORD: "))(ps(car ip))(sp(if(equal""ps)(^"NO EMPTY PASSWORD ALLOWED")(?"ENTER PASSWORD: ")))(r(if(equal ps(car sp))(alexandria:mean(mapcar #'d(cdr sp)(cdr ip)))(^"YOU DIDN'T SAY THE MAGIC WORD!"))))(if(> r ok)($"YOU ARE A FAKE!")($"IDENTITY CONFIRMED")))))(m)

언 골프

(ql:quickload'(cl-charms alexandria))
(defun m(&key(ok 0.2))
  (labels
      ((^(s)(fresh-line)(princ s)(return-from m))
       (d(a b)(abs(/ (- b a) b)))
       ($(x)(princ x)(force-output))
       (?(m)(charms:with-curses()
              (clear-input)
              ($ m)
              (charms:enable-raw-input)
              (loop for c = (read-char)
                    for n = (get-internal-real-time)
                    for x = nil then (/ (- n b)
                                        internal-time-units-per-second)
                    for b = n
                    when (eql c #\Esc)
                      do (^"QUIT")
                    when x
                      collect x into %
                    until (eql c #\Newline)
                    collect c into !
                    finally (progn
                              (terpri)
                              (return
                                (cons (coerce !'string) %)))))))
    (let* ((ip (?"INIT PASSWORD: "))
           (ps (car ip))
           (sp (if (equal "" ps)
                 (^"NO EMPTY PASSWORD ALLOWED")
                 (?"ENTER PASSWORD: ")))
           (r (if (equal ps (car sp))
                (alexandria:mean(mapcar #'d(cdr sp)(cdr ip)))
                (^"YOU DIDN'T SAY THE MAGIC WORD!"))))
      (if (> r ok)
        ($"YOU ARE A FAKE!")
        ($"IDENTITY CONFIRMED")))))

(m) ;; call function

추가 비고

  • 모든 규칙을 준수
  • 사용자가 처음 빈 암호를 제공하면 프로그램이 깨끗하게 중단됩니다
  • 을 입력 Escape하면 프로그램이 완전히 중단됩니다.
  • 최근 SBCL 및 CCL 구현에서 테스트
  • Ncurses를 감싸는 cl-charms가 필요합니다. 이는 원시 입력을 캡처하는 가장 쉬운 방법입니다.
  • 이것은 squeamish-ossifrage가 찾은 원본 버전 에서 영감을 얻었지만 복사되지 않았습니다.

공룡 보너스

" Common Lisp은 moribund dinosaur " 라는 것을 모두가 알고 있기 때문에 보너스를 받아야합니다 .


따옴표 블록 대신 코드 블록으로 전환 할 수 있습니까? (코드 용)
Optimizer

@Optimizer 완료
코어 덤프
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.