Perangkap Tikus Michael Crichton

9

Pada 1984, Michael Crichton menulis program keamanan di BASIC yang diterbitkan di majalah Creative Computing. Program akan meminta pengguna untuk mengetik frasa pilihannya, mencatat interval antara penekanan tombol, lalu memintanya mengetik ulang frasa. Jika waktunya berbeda terlalu banyak, program akan mengidentifikasi pengguna sebagai penipu.

Tugas Anda: buat versi program Crichton dalam bahasa pilihan Anda.

Aturan:

  1. Frasa untuk berkomunikasi dengan pengguna ("Silakan ketikkan frasa kunci," "Silakan ketik frasa kunci lagi," dll.) Dihitung setiap satu byte, berapa pun panjang sebenarnya. Ini hanya untuk komunikasi pengguna, jangan mencoba menyembunyikan kode program di dalam string.

  2. Tes lulus / gagal harus didasarkan pada nilai absolut rata-rata dari persentase persentase dari interval asli. Jika string tidak cocok, kembalikan gagal atau izinkan pengguna untuk mencoba lagi, atas kebijakan Anda.

  3. Frasa kunci seharusnya tidak mengizinkan string nol. Jika frasa kunci terlalu panjang untuk tipe data string Anda, terpotong atau tidak diizinkan dan mulai lagi, sesuai kebijakan Anda.

  4. Sensitivitas tes (ambang batas untuk lulus / gagal tes) harus disesuaikan dalam kode sumber.

  5. Saya awalnya memberikan bonus 20% dari jumlah byte total jika kode sumber Anda dapat diformat agar menyerupai dinosaurus. Telah ditunjukkan bahwa ini sangat subjektif dan mungkin lebih tepat untuk kontes popularitas, jadi saya telah menghapus bonus ini. Namun saya masih dengan sungguh-sungguh mendorong pemformatan dinosaurus, dan jika Anda memformat kode Anda agar terlihat seperti dinosaurus, Anda dapat mengurangi komentar kosmetik murni, linebreak, atau karakter spasi putih dari total byte Anda.

  6. Kemenangan byte terpendek, tergantung pada panjang string dan penyesuaian format dinosaurus.

Perhatikan bahwa spesifikasi saya di atas tidak sama persis dengan operasi kode Crichton, salinannya dapat ditemukan online. Ikuti spek, jangan coba mengkloning yang asli.

Michael Stern
sumber
5
"Ini Michael Crichton, jadi kurangi 20% dari jumlah byte total jika kode sumbermu bisa diformat agar menyerupai dinosaurus." - umm ... tidak. Aturan ini terlalu subyektif. Tolong di hapus. Selain itu, silakan lanjutkan.
John Dvorak
4
@ JanDvorak Saya tidak berpikir itu "terlalu" subjektif. Ini adalah panggilan yang cukup mudah untuk memanggil beberapa seni ASCII sebagai dino atau tidak
Pengoptimal
3
@Optimizer Tidak dalam semua kasus. Apakah huruf yunani lambda terlihat seperti dinosaurus? Saya cukup yakin.
John Dvorak
3
Beberapa komentar minor lainnya: Apakah "Please type the key phrase"dihitung sebagai 1 byte, atau hanya frasa yang dihitung dan frasa yang dikutip dihitung sebagai 3 byte ( ", frasa, ")? Apakah disengaja bahwa interval yang lebih lama dan interval yang lebih pendek akan "membatalkan" dan menjadi lebih lagi? Apakah program harus memverifikasi bahwa kedua frasa kunci cocok?
Gagang Pintu
3
Itu pada Juni 1984. Anda dapat melihat program aslinya di sini.
r3mainer

Jawaban:

9

Rubi, 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

Output truejika varians rata-rata di atas 20%, jika tidak output false.

Upaya seni Dinosaurus 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}###########\   \
            `-._    ,___...----...__,   ,__\  \
                |   |_|           |_|   |    \ \
                |___|               |___|      \\/)

Tidak Disatukan:

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' dapat dihapus ketika dijalankan di beberapa REPL Ruby, karena perpustakaan sudah dimuat.

Agustus
sumber
4

Java 768 byte

apa? Jawa? untuk kode golf?

Ini mungkin hal terburuk yang harus dilakukan, tetapi saya tetap mencobanya.

Ini menampilkan pesan apa pun di jendela konsol, tetapi pengetikan yang sebenarnya terjadi di JTextField. Tidak terlihat cantik. Oh, dan untuk menghemat 5 byte, Anda harus mengubah ukuran JFrame sendiri. Juga, itu tidak memeriksa kebenaran string untuk kedua kalinya. Tidak yakin apakah itu melanggar spesifikasi.

Menggunakan:

Ketikkan kunci Anda di bidang teks.

Jangan tekan enter, pergi ke konsol dan ketik sesuatu. Ini akan menampilkan pesan lain

Ketikkan hal yang sama di bidang teks (yang sekarang harus dihapus).

Pergi ke konsol dan tekan sesuatu lagi. Ini akan menampilkan apakah Anda seorang penyusup atau tidak.

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

golf:

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!");}}
Regangkan Maniac
sumber
Tidak ada cara untuk mengatur TTY dalam mode mentah dari java (kecuali jika Anda siap untuk menggunakan JNI). Jadi saya mengerti mengapa Anda membutuhkan JFrame. Tapi sungguh, ini adalah program yang paling tidak ramah pengguna yang pernah saya lihat di usia :-) Saya tidak yakin apakah saya ingin membatalkan atau menurunkan jawaban ini.
coredump
Saya memilih untuk banyaknya pengguna yang tidak ramah (apakah itu sepatah kata pun?). Ini pada dasarnya seni.
Ingo Bürk
Saya percaya ini bisa bermain golf lebih banyak dengan membuat kelas diperluas JFrame, jadi Anda tidak perlu f.
PurkkaKoodari
3

HTML, JavaScript (ES6), 328

Total jumlah byte kode adalah 402 byte dan pesan untuk berinteraksi dengan pengguna:

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

adalah total 78 byte, jadi total skor => 402 - 78 + 4 = 328

Jalankan cuplikan di bawah ini di Firefox terbaru dan ketik kunci di kotak input diikuti oleh tombol Enter.

Kode memeriksa apakah kunci yang dimasukkan dan yang dimasukkan kembali sama, (meminta untuk memasukkan kembali jika tidak), menghitung persentase perbedaan absolut rata-rata dan memeriksa apakah kurang dari nilai variabel. 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>

Pengoptimal
sumber
3

C, 154 (86 + 68 untuk bendera)

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

Mengkompilasi dengan -DY=(y=clock())-x, -DZ=a[d], -DE=getch(), -DW=);while, -DU=i++[d]=Ydan -DP=puts(. Baris baru ditambahkan untuk tujuan presentasi dan dapat dihapus (jumlah byte yang diberikan adalah tanpa).

+ Komentar tidak dikumpulkan:

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
}

Ini tidak memeriksa apakah frasa yang diketik ulang itu identik, juga tidak menghasilkan apa pun jika pengguna tidak diidentifikasi sebagai penipu.

Ini juga tidak mempertimbangkan waktu yang diambil setelah diminta sebelum penekanan tombol pertama.

es1024
sumber
Bukankah seharusnya getchbertaruh getcatau getchar? Saya memiliki referensi yang tidak jelas ke `getch ', yang jika saya ingat dengan benar sudah usang?
coredump
Saya juga punya "file.c: 1: 1: peringatan: definisi data tidak memiliki tipe atau kelas penyimpanan" (gcc). Saya menambahkan charsebelum deklarasi global, dan sekarang, ini memberikan kesalahan segmentasi saat runtime. Bisakah Anda memberikan detail tentang cara membangunnya? Kompiler apa yang Anda gunakan? Terima kasih.
coredump
@coredump Peringatan tidak berbahaya; meskipun jika Anda ingin menghapus peringatan, itu harus mengetik int, dan diinisialisasi ke 0. Saya sudah menguji ini menggunakan gcc pada Windows (menggunakan Window getch). getchdigunakan sebagai ganti getcatau getcharkarena getchtidak memerlukan tombol kembali untuk ditekan sebelum memproses karakter apa pun ( getchmemang sudah usang pada Windows, meskipun tidak ada yang salah dengan menggunakan fungsi yang sudah tidak digunakan lagi di sini).
es1024
Saya menguji di Linux dan beralih ke stackoverflow.com/questions/7469139/… untuk membuatnya bekerja. Terima kasih.
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

Dengan semua spasi dihapus, Anda memiliki:

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

Yang saya yakin seseorang yang lebih berbakat dari saya bisa menjadi dinosaurus!

Penjelasan singkat:

The lMetode membaca karakter dan membuat saluran dari nanoTimeketika masing-masing karakter yang diketik.

The mMetode cetak "Enter", istirahat lmetode atas memukul masukkan (karakter 13), maka peta untuk hanya nanoTimes, dan kemudian mendapat interval waktu antara masing-masing karakter.

2 baris berikutnya dibaca dalam 2 string, ritsleting, kemudian menemukan nilai absolut rata-rata dari perbedaan persentase antara interval kedua dan yang pertama, dan akhirnya mencetak apakah rata-rata ini kurang dari atau tidak 0.2.

Ben Reich
sumber
1

Gangguan Umum: 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)

Tidak disatukan

(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

Tanda tambahan

  • Mematuhi semua aturan
  • Ketika pengguna pertama kali memberikan kata sandi kosong, program ini dibatalkan dengan rapi
  • Saat mengetik Escape, program dibatalkan dengan rapi.
  • Diuji pada implementasi SBCL dan CCL baru-baru ini
  • Membutuhkan cl-charms, yang merupakan pembungkus di sekitar Ncurses. Ini adalah cara termudah untuk menangkap input mentah.
  • Ini terinspirasi oleh (tetapi tidak disalin dari) versi asli yang ditemukan oleh squeamish-ossifrage

Bonus dinosaurus

Saya harus mendapat bonus karena semua orang tahu bahwa " Common Lisp adalah dinosaurus yang hampir mati ".

coredump
sumber
Bisakah Anda beralih ke blok kode alih-alih blok kutipan? (untuk kode Anda)
Pengoptimal
@Optimizer selesai
coredump