Mousetrap của Michael Crichton


9

Năm 1984, Michael Crichton đã viết một chương trình bảo mật bằng BASIC được xuất bản trên tạp chí Creative Computing. Chương trình sẽ yêu cầu người dùng nhập một cụm từ theo lựa chọn của cô ấy, ghi lại các khoảng thời gian giữa các lần nhấn phím, sau đó yêu cầu cô ấy gõ lại cụm từ đó. Nếu thời gian khác nhau quá nhiều, chương trình sẽ xác định người dùng là kẻ mạo danh.

Nhiệm vụ của bạn: tạo một phiên bản chương trình của Crichton bằng ngôn ngữ bạn chọn.

Quy tắc:

  1. Các cụm từ để giao tiếp với người dùng ("Vui lòng nhập cụm từ khóa", "Vui lòng nhập lại cụm từ khóa", v.v.) được tính là một byte mỗi lần bất kể độ dài thực tế. Điều này chỉ dành cho giao tiếp người dùng, đừng cố ẩn mã chương trình trong chuỗi.

  2. Kiểm tra đạt / không nên dựa trên giá trị tuyệt đối trung bình của phương sai phần trăm từ các khoảng ban đầu. Nếu các chuỗi không khớp, trả về thất bại hoặc cho phép người dùng thử lại, theo quyết định của bạn.

  3. Các cụm từ chính không nên cho phép một chuỗi null. Trong trường hợp cụm từ khóa quá dài cho kiểu dữ liệu chuỗi của bạn, có thể cắt bớt hoặc không cho phép và bắt đầu lại, theo ý của bạn.

  4. Độ nhạy của kiểm tra (ngưỡng cho kiểm tra đạt / không đạt) phải được điều chỉnh trong mã nguồn.

  5. Ban đầu tôi đã cung cấp phần thưởng 20% ​​tổng số byte nếu mã nguồn của bạn có thể được định dạng để giống với một con khủng long. Nó đã được chỉ ra rằng điều này rất chủ quan và có lẽ phù hợp hơn cho một cuộc thi phổ biến, vì vậy tôi đã loại bỏ phần thưởng này. Tuy nhiên tôi vẫn chân thành khuyến khích định dạng khủng long và nếu bạn định dạng mã của mình trông giống khủng long, bạn có thể khấu trừ mọi nhận xét hoàn toàn về mỹ phẩm, ngắt dòng hoặc ký tự khoảng trắng trong tổng số byte của bạn.

  6. Số byte ngắn nhất sẽ thắng, tùy thuộc vào các điều chỉnh định dạng khủng long và chuỗi.

Lưu ý rằng đặc điểm kỹ thuật của tôi ở trên không khớp chính xác với hoạt động của mã Crichton, các bản sao có thể được tìm thấy trực tuyến. Thực hiện theo thông số kỹ thuật, đừng cố gắng sao chép bản gốc.


5
"Đó là Michael Crichton, vì vậy hãy trừ 20% tổng số byte nếu mã nguồn của bạn có thể được định dạng để giống với một con khủng long." - Ừm ... không. Quy định này quá chủ quan. Hãy loại bỏ. Ngoài ra, xin vui lòng đi trước.
John Dvorak

4
@JanDvorak Tôi không nghĩ nó "quá" chủ quan. Đây là một cuộc gọi khá dễ dàng để gọi một số nghệ thuật ASCII là dino hay không
Trình tối ưu hóa

3
@Optimizer Không phải trong mọi trường hợp. Có phải chữ Hy Lạp lambda trông giống như một con khủng long? Tôi khá chắc chắn rằng nó làm.
John Dvorak

3
Một vài nhận xét nhỏ khác: Có "Please type the key phrase"tính là 1 byte hay chỉ đếm cụm từ và cụm từ được trích dẫn được tính là 3 byte ( ", cụm từ, ")? Có phải là cố ý rằng một khoảng thời gian dài hơn và một khoảng thời gian ngắn hơn nhiều sẽ "hủy bỏ" và trở lại thậm chí một lần nữa? Chương trình có phải xác minh rằng hai cụm từ chính khớp với nhau không?
Doorknob

Câu trả lời:


9

Hồng ngọc 171 167 157 byte

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

Đầu ra truenếu phương sai trung bình là trên 20%, nếu không thì đầu ra false.

Nỗ lực nghệ thuật khủng long 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}###########\   \
            `-._    ,___...----...__,   ,__\  \
                |   |_|           |_|   |    \ \
                |___|               |___|      \\/)

Ung dung:

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' có thể bị xóa khi chạy trong một số REPL của Ruby, vì thư viện đã được tải.


4

Java 768 byte

gì? Java? cho mã golf?

Đây có lẽ là điều tồi tệ nhất để làm, nhưng dù sao tôi cũng đã thử nó.

Nó hiển thị bất kỳ thông báo nào trong cửa sổ giao diện điều khiển, nhưng việc gõ thực tế xảy ra trong JTextField. Không chính xác tìm kiếm tốt đẹp. Ồ, và để tiết kiệm 5 byte, bạn phải tự thay đổi kích thước JFrame. Ngoài ra, nó không kiểm tra tính chính xác của chuỗi lần thứ hai. Không chắc chắn nếu điều đó là trái với thông số kỹ thuật.

Để sử dụng:

Nhập khóa của bạn vào trường văn bản.

Đừng nhấn enter, vào bảng điều khiển và gõ một cái gì đó. Nó sẽ hiển thị một thông báo khác

Nhập điều tương tự trong trường văn bản (hiện sẽ bị xóa).

Đi đến bàn điều khiển và nhấn một cái gì đó một lần nữa. Nó sẽ hiển thị cho dù bạn là kẻ xâm nhập hay không.

vô dụng:

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!");
    }
}

đánh gôn

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!");}}

Không có cách nào để đặt TTY ở chế độ thô từ java (trừ khi bạn sẵn sàng sử dụng JNI). Vì vậy, tôi hiểu tại sao bạn cần một JFrame. Nhưng thực sự, đây là chương trình ít thân thiện với người dùng nhất mà tôi từng thấy trong các thời đại :-) Tôi không chắc mình muốn nâng cấp hay hạ thấp câu trả lời này.
coredump

Tôi nâng cao mức độ không thân thiện của người dùng (đó có phải là một từ không?). Về cơ bản là nghệ thuật.
Ingo Bürk

Tôi tin rằng điều này có thể được đánh gôn nhiều hơn bằng cách mở rộng lớp học JFrame, vì vậy bạn sẽ không cần f.
PurkkaKoodari

3

HTML, JavaScript (ES6), 328

Tổng số byte của mã là 402 byte và các thông báo tương tác với người dùng:

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

là tổng số 78 byte, vì vậy tổng số điểm => 402 - 78 + 4 = 328

Chạy đoạn mã dưới đây trong Firefox mới nhất và nhập khóa vào hộp nhập theo sau là phím Enter.

Mã kiểm tra xem cả khóa nhập và nhập lại có giống nhau không (nhắc nhở nhập lại nếu không), tính toán tỷ lệ phần trăm chênh lệch tuyệt đối trung bình và kiểm tra xem nó có nhỏ hơn giá trị của biến không 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 cho cờ)

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

Biên dịch với -DY=(y=clock())-x, -DZ=a[d], -DE=getch(), -DW=);while, -DU=i++[d]=Y-DP=puts(. Các dòng mới được thêm vào cho mục đích trình bày và có thể bị xóa (số byte đã cho là không có).

Ungolfed + bình luận:

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
}

Điều này không kiểm tra xem cụm từ được gõ lại có giống hệt nhau không và cũng không xuất ra bất cứ điều gì nếu người dùng không được xác định là kẻ mạo danh.

Điều này cũng không xem xét thời gian thực hiện sau khi nhắc trước khi gõ phím đầu tiên.


Không nên getchđặt cược getchay getchar? Tôi có một tham chiếu không xác định đến 'getch', mà nếu tôi nhớ lại một cách chính xác thì không được chấp nhận?
coredump

Tôi cũng đã có "file.c: 1: 1: warning: định nghĩa dữ liệu không có loại hoặc lớp lưu trữ" (gcc). Tôi đã thêm chartrước khi khai báo toàn cầu, và bây giờ, điều này đưa ra lỗi phân đoạn khi chạy. Bạn có thể cho biết chi tiết về cách xây dựng nó? Trình biên dịch nào bạn đang sử dụng? Cảm ơn.
coredump

@coredump Các cảnh báo là vô hại; mặc dù nếu bạn muốn loại bỏ các cảnh báo, thì nó phải là kiểu intvà được khởi tạo 0. Tôi đã thử nghiệm điều này bằng gcc trên Windows (sử dụng Window's getch). getchđược sử dụng thay vì getchoặc getchargetchkhông yêu cầu nhấn phím quay lại trước khi xử lý bất kỳ ký tự nào ( getchthực sự không dùng nữa trên Windows, mặc dù không có gì sai khi sử dụng các hàm không dùng ở đây).
es1024

Tôi đang thử nghiệm trên Linux và đã sử dụng stackoverflow.com/questions/7469139/ trên để làm cho nó hoạt động. Cảm ơn.
coredump

2

Scala 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

Với tất cả các khoảng cách được loại bỏ, bạn có:

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

Mà tôi chắc rằng ai đó tài năng hơn tôi có thể biến thành một con khủng long!

Giải thích ngắn gọn:

Các lphương pháp đọc ký tự và giữ đường của nanoTimekhi mỗi nhân vật được gõ.

Các mbản in phương pháp "Enter", phá vỡ các lphương pháp sau khi nảy nhập (nhân vật 13), sau đó bản đồ nó chỉ là nanoTimes, và sau đó được các khoảng thời gian giữa mỗi nhân vật.

2 dòng tiếp theo đọc thành 2 chuỗi, nén chúng, sau đó tìm giá trị tuyệt đối trung bình của chênh lệch tỷ lệ phần trăm giữa các khoảng thứ hai và đầu tiên, và cuối cùng in xem mức trung bình này có nhỏ hơn hay không 0.2.


1

Lisp thường gặp: 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)

Ung dung

(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

Nhận xét bổ sung

  • Tuân thủ tất cả các quy tắc
  • Khi người dùng lần đầu tiên cung cấp mật khẩu trống, chương trình sẽ hủy bỏ hoàn toàn
  • Khi gõ Escape, chương trình hủy bỏ sạch sẽ.
  • Đã thử nghiệm trên các triển khai SBCL và CCL gần đây
  • Yêu cầu cl-charm, đó là một gói bao quanh Ncurses. Đây là cách dễ nhất để nắm bắt đầu vào thô.
  • Điều này được lấy cảm hứng từ (nhưng không được sao chép từ) phiên bản gốc được tìm thấy bởi squeamish-ossifrage

Phần thưởng khủng long

Tôi nên có một phần thưởng vì mọi người đều biết rằng " Common Lisp là một con khủng long moribund ".


Bạn có thể chuyển sang khối mã thay vì khối trích dẫn? (cho mã của bạn)
Trình tối ưu hóa

@Optimizer đã hoàn tất
coredump
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.