ดักหนูของ Michael Crichton


9

ในปี 1984 Michael Crichton เขียนโปรแกรมความปลอดภัยใน BASIC ที่ตีพิมพ์ในนิตยสาร Creative Computing โปรแกรมจะขอให้ผู้ใช้พิมพ์วลีที่ต้องการบันทึกช่วงเวลาระหว่างการกดแป้นจากนั้นขอให้เธอพิมพ์วลีอีกครั้ง หากการกำหนดเวลาแตกต่างกันมากเกินไปโปรแกรมจะระบุผู้ใช้ว่าเป็นผู้แอบอ้าง

การมอบหมายของคุณ: สร้างโปรแกรมของ Crichton ในภาษาที่คุณเลือก

กฎ:

  1. วลีสำหรับการสื่อสารกับผู้ใช้ ("โปรดพิมพ์วลีสำคัญ" "โปรดพิมพ์วลีสำคัญอีกครั้ง" ฯลฯ ) นับเป็นหนึ่งไบต์โดยไม่คำนึงถึงความยาวจริง นี่ใช้สำหรับการสื่อสารของผู้ใช้เท่านั้นอย่าพยายามซ่อนรหัสโปรแกรมในสตริง

  2. การทดสอบผ่าน / ไม่ผ่านควรขึ้นอยู่กับค่าสัมบูรณ์โดยเฉลี่ยของผลต่างเปอร์เซ็นต์จากช่วงเวลาเดิม หากสตริงไม่ตรงกันให้ส่งคืนข้อผิดพลาดหรืออนุญาตให้ผู้ใช้ลองอีกครั้งตามดุลยพินิจของคุณ

  3. วลีที่สำคัญไม่ควรอนุญาตให้มีสตริงที่เป็นโมฆะ ในกรณีที่วลีสำคัญยาวเกินไปสำหรับประเภทข้อมูลสตริงของคุณให้ตัดหรือไม่อนุญาตและเริ่มต้นใหม่ตามดุลยพินิจของคุณ

  4. ความไวของการทดสอบ (เกณฑ์สำหรับการทดสอบผ่าน / ไม่ผ่าน) ควรปรับได้ในซอร์สโค้ด

  5. เดิมฉันได้ให้โบนัส 20% ของจำนวนไบต์ทั้งหมดหากซอร์สโค้ดของคุณสามารถจัดรูปแบบให้คล้ายไดโนเสาร์ได้ มีการชี้ให้เห็นว่านี่เป็นเรื่องส่วนตัวและอาจเหมาะสมกว่าสำหรับการประกวดความนิยมดังนั้นฉันจึงลบโบนัสนี้ออกไป อย่างไรก็ตามฉันยังคงสนับสนุนการจัดรูปแบบไดโนเสาร์อย่างเต็มที่และหากคุณจัดรูปแบบรหัสของคุณให้ดูเหมือนไดโนเสาร์คุณสามารถหักความคิดเห็นเกี่ยวกับความงามเครื่องสำอางค์ตัวละคร Linebreak หรือ Whitespace จากจำนวนไบต์ทั้งหมดของคุณได้

  6. การนับจำนวนไบต์ที่สั้นที่สุดขึ้นอยู่กับการปรับการจัดรูปแบบความยาวสตริงและไดโนเสาร์

โปรดทราบว่าข้อกำหนดของฉันข้างต้นไม่ตรงกับการทำงานของรหัสของ Crichton สำเนาซึ่งอาจพบได้ทางออนไลน์ ทำตามสเป็คอย่าพยายามโคลนต้นฉบับ


5
"มันคือ Michael Crichton ดังนั้นลบ 20% จากจำนวนไบต์ทั้งหมดหากซอร์สโค้ดของคุณสามารถจัดรูปแบบให้คล้ายไดโนเสาร์ได้" - อืมม ... ไม่ กฎนี้เป็นอัตนัยเกินไป กรุณาลบ นอกจากนั้นโปรดไปข้างหน้า
John Dvorak

4
@JanDvorak ฉันไม่คิดว่ามันเป็นอัตนัย "เกินไป" มันเป็นเรื่องง่ายที่จะโทรหา ASCII art ในรูป dino หรือไม่
Optimizer

3
@Optimizer ไม่ใช่ในทุกกรณี ตัวอักษรกรีกแลมบ์ดาดูเหมือนไดโนเสาร์หรือไม่? ฉันค่อนข้างแน่ใจว่ามันทำ
John Dvorak

3
ความคิดเห็นเล็กน้อยอื่น ๆ : "Please type the key phrase"นับเป็น 1 ไบต์หรือนับเฉพาะวลีและวลีที่อ้างถึงจะนับเป็น 3 ไบต์ ( "วลี") มันเป็นความตั้งใจหรือไม่ที่ช่วงเวลาที่ยาวนานกว่าและช่วงเวลาที่สั้นกว่าจะ "ยกเลิก" และกลับมาเป็นอีกครั้งได้หรือไม่? โปรแกรมต้องตรวจสอบว่าวลีสำคัญสองคำตรงกันหรือไม่
ลูกบิดประตู

3
มันเป็นในเดือนมิถุนายน 1984 คุณสามารถดูโปรแกรมต้นฉบับได้ที่นี่
r3mainer

คำตอบ:


9

ทับทิม, 171 167 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}###########\   \
            `-._    ,___...----...__,   ,__\  \
                |   |_|           |_|   |    \ \
                |___|               |___|      \\/)

Ungolfed:

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 REPLs บางตัวเนื่องจากโหลดไลบรารีแล้ว


4

Java 768 ไบต์

อะไร? Java? สำหรับรหัสกอล์ฟ?

นี่อาจเป็นสิ่งที่แย่ที่สุดที่ต้องทำ แต่ฉันก็ลองทำดู

มันแสดงข้อความใด ๆ ในหน้าต่างคอนโซล แต่การพิมพ์จริงเกิดขึ้นใน JTextField ดูไม่ดีอย่างแน่นอน โอ้และเพื่อประหยัด 5 ไบต์คุณต้องปรับขนาด JFrame ด้วยตัวเอง นอกจากนี้มันจะไม่ตรวจสอบความถูกต้องของสตริงในครั้งที่สอง ไม่แน่ใจว่ามันผิดหรือเปล่า

ใช้:

พิมพ์รหัสของคุณในฟิลด์ข้อความ

อย่ากด Enter ไปที่คอนโซลและพิมพ์บางอย่าง มันจะแสดงข้อความอื่น

พิมพ์สิ่งเดียวกันในฟิลด์ข้อความ (ซึ่งควรจะถูกลบทิ้ง)

ไปที่คอนโซลแล้วกดบางสิ่งอีกครั้ง มันจะแสดงว่าคุณเป็นผู้บุกรุกหรือไม่

ungolfed:

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

ไม่มีวิธีตั้งค่า TTY ในโหมด raw จาก java (เว้นแต่คุณพร้อมที่จะใช้ JNI) ดังนั้นฉันเข้าใจว่าทำไมคุณต้องมี JFrame แต่จริงๆแล้วนี่เป็นโปรแกรมที่เป็นมิตรกับผู้ใช้น้อยที่สุดที่ฉันเคยเห็นมานาน :-) ฉันไม่แน่ใจว่าฉันต้องการ upvote หรือ downvote คำตอบนี้หรือไม่
coredump

ฉัน upvote สำหรับจำนวนที่ไม่เป็นมิตรของผู้ใช้ (นั่นคือแม้แต่คำ?) มันเป็นงานศิลปะโดยทั่วไป
Ingo Bürk

ผมเชื่อว่านี่อาจจะแข็งแรงเล่นกอล์ฟมากขึ้นโดยการทำชั้นขยายดังนั้นคุณจะไม่จำเป็นต้องJFrame f
PurkkaKoodari

3

HTML, JavaScript (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(เพิ่มบรรทัดใหม่เพื่อวัตถุประสงค์ในการนำเสนอและอาจถูกลบออก (นับเป็นจำนวนไบต์ที่ให้ไว้)

ความคิดเห็น + Ungolfed:

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วางเดิมพันgetcหรือgetchar? ฉันมีการอ้างอิงที่ไม่ได้กำหนดกับ `getch 'ซึ่งหากฉันจำได้ว่าเลิกใช้อย่างถูกต้อง
coredump

ฉันยังมี "file.c: 1: 1: คำเตือน: คำจำกัดความของข้อมูลไม่มีประเภทหรือคลาสหน่วยเก็บข้อมูล" (gcc) ฉันเพิ่มcharก่อนที่จะประกาศทั่วโลกและตอนนี้สิ่งนี้ให้ข้อผิดพลาดการแบ่งส่วนที่รันไทม์ คุณให้รายละเอียดเกี่ยวกับวิธีสร้างมันได้หรือไม่ คุณใช้คอมไพเลอร์อะไร? ขอบคุณ
coredump

@coredump คำเตือนไม่เป็นอันตราย แม้ว่าถ้าคุณต้องการที่จะลบคำเตือนมันควรจะเป็นประเภทintและเริ่มต้น0ได้ที่ ฉันทดสอบโดยใช้ gcc บน Windows (โดยใช้ Window's 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", แบ่งlวิธีการเมื่อกดปุ่มใส่ (ตัวละครที่ 13) จากนั้นแมปมันเพียงnanoTimesและจากนั้นได้รับช่วงเวลาระหว่างตัวละครแต่ละตัว

2 บรรทัดถัดไปอ่านใน 2 สตริงซิปแล้วหาค่าสัมบูรณ์เฉลี่ยของความแตกต่างของเปอร์เซ็นต์ระหว่างช่วงที่สองและที่หนึ่งและสุดท้ายพิมพ์ว่าค่าเฉลี่ยนี้น้อยกว่าหรือไม่ 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)

Ungolfed

(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 ล่าสุด
  • ต้องการ cl-Charms ซึ่งเป็นเสื้อคลุมรอบ ๆ ncurses นี่เป็นวิธีที่ง่ายที่สุดในการจับภาพข้อมูลดิบ
  • นี่คือแรงบันดาลใจจาก (แต่ไม่ได้คัดลอกมาจาก) ฉบับดั้งเดิมที่พบโดยsqueamish-ossifrage

โบนัสไดโนเสาร์

ฉันควรได้รับโบนัสเพราะทุกคนรู้ว่า " Common LISP เป็นสัตว์ที่มีรูปร่างผิดปกติ "


คุณสามารถเปลี่ยนเป็นรหัสบล็อคแทนบล็อกคำพูดได้หรือไม่? (สำหรับรหัสของคุณ)
เครื่องมือเพิ่มประสิทธิภาพ

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