Michael Crichton'ın Fare Kapanı


9

1984 yılında Michael Crichton BASIC'te Creative Computing dergisinde yayınlanan bir güvenlik programı yazdı. Program kullanıcıdan kendi seçtiği bir cümleyi yazmasını, tuş vuruşları arasındaki aralıkları kaydetmesini ve daha sonra cümleyi tekrar yazmasını ister. Zamanlamalar çok fazla farklılık gösterirse, program kullanıcıyı bir sahtekâr olarak tanımlar.

Ödeviniz: Seçtiğiniz dilde Crichton programının bir versiyonunu oluşturun.

Kurallar:

  1. Kullanıcı ile iletişim kurmak için kullanılan ifadeler ("Lütfen anahtar kelimeyi yazın," "Lütfen anahtar kelimeyi tekrar yazın," vb.) Gerçek uzunluk ne olursa olsun bir bayt olarak sayın. Bu yalnızca kullanıcı iletişimi içindir, dizelerde program kodunu saklamaya çalışmayın.

  2. Başarılı / başarısız testi, orijinal aralıklardan yüzde sapmaların ortalama mutlak değerini temel almalıdır. Dizeler eşleşmezse, geri dönüş başarısız olur veya kullanıcının takdirine bağlı olarak tekrar denemesine izin verir.

  3. Anahtar kelime grubu boş bir dizeye izin vermemelidir. Anahtar deyim, kendi takdirinize bağlı olarak, kısaltılmış veya izin vermemek ve baştan başlamak için dizgi veri türünüz için çok uzunsa.

  4. Testin hassasiyeti (başarılı / başarısız testi için eşik) kaynak kodunda ayarlanabilir olmalıdır.

  5. Kaynak kodunuz bir dinozora benzeyecek şekilde biçimlendirilebilirse, başlangıçta toplam bayt sayısının% 20'sini ekledim. Bunun son derece öznel ve belki de bir popülerlik yarışması için daha uygun olduğuna dikkat çekildi, bu yüzden bu bonusu kaldırdım. Ancak yine de dinozor biçimlendirmesini yürekten teşvik ediyorum ve kodunuzu bir dinozor gibi görünecek şekilde biçimlendirirseniz, bayt toplamınızdan tamamen kozmetik yorumlar, satır sonu veya boşluk karakterleri çıkarabilirsiniz.

  6. Dize uzunluğu ve dinozor biçimlendirme ayarlarına tabi olarak en kısa bayt sayısı kazanır.

Yukarıdaki spesifikasyonumun, kopyaları çevrimiçi olarak bulunabilen Crichton kodunun çalışmasıyla tam olarak eşleşmediğini unutmayın. Spesifikasyonu takip edin, orijinali klonlamaya çalışmayın.


5
"Bu Michael Crichton, kaynak kodunuz bir dinozorun farkına benzeyecek şekilde biçimlendirilebiliyorsa toplam bayt sayısından% 20 çıkarın." - umm ... hayır. Bu kural çok öznel. Lütfen kaldır. Bunun dışında lütfen devam edin.
John Dvorak

4
@ JanDvorak Onun "çok" öznel olduğunu sanmıyorum. Bazı ASCII sanatını dino olarak adlandırmak ya da çağırmamak oldukça kolay bir çağrı
Optimizer

3
@Optimizer Her durumda değil. Yunan harfi lambda bir dinozor gibi mi görünüyor? Eminim öyledir.
John Dvorak

3
Diğer birkaç küçük yorum: "Please type the key phrase"1 bayt olarak mı sayılır, yoksa yalnızca kelime öbeği ve alıntılanan kelime öbeği 3 bayt ( ", kelime öbeği ") olarak sayılır mı? Çok daha uzun bir aralık ve daha kısa bir aralığın "iptal edileceği" ve tekrar eşit hale gelmesi kasti midir? Programın iki temel ifadenin eşleştiğini doğrulaması gerekiyor mu?
Kapı tokmağı

Yanıtlar:


9

Yakut, 171 167 157 bayt

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

Çıkışlar trueortalama varyans% 20 üzerinde ise, aksi halde verir false.

Dinozor ASCII sanat girişimi:

(_=/\
  \ \
   \ \
    \ \              _...---..__
     \ \          .∕` #{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' kütüphane zaten yüklü olduğu için bazı Ruby REPL'lerde çalıştırıldığında kaldırılabilir.


4

Java 768 bayt

ne? Java? kod golf için?

Bu muhtemelen yapılacak en kötü şey, ama yine de denedim.

Konsol penceresinde tüm iletileri görüntüler, ancak gerçek yazma işlemi JTextField öğesinde gerçekleşir. Tam olarak hoş görünmüyor. Oh, ve 5 bayt kaydetmek için JFrame'i kendiniz yeniden boyutlandırmanız gerekiyor. Ayrıca, ikinci kez dize doğruluğunu kontrol etmez. Bunun teknik özelliklere aykırı olup olmadığından emin değilim.

Kullanmak:

Anahtarınızı metin alanına yazın.

Enter tuşuna basmayın, konsola gidin ve bir şeyler yazın. Başka bir mesaj görüntüleyecek

Aynı şeyi metin alanına yazın (şimdi silinmesi gerekir).

Konsola gidin ve bir şeylere tekrar basın. Davetsiz misafir olup olmadığınızı gösterir.

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

golfed:

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'dan ham modda TTY'yi ayarlamanın bir yolu yoktur (JNI kullanmaya hazır değilseniz). Bu yüzden neden bir JFrame'e ihtiyacınız olduğunu anlıyorum. Ama gerçekten, bu çağlarda gördüğüm en az kullanıcı dostu bir program :-) Bu cevabı yükseltmek veya düşürmek isteyip istemediğimden emin değilim.
coredump

Ben kullanıcı düşmanlığı sırf miktarı için upvote (bir kelime bile ist?). Temel olarak sanat.
Ingo Bürk

Sınıfı genişleterek daha fazla golf oynayabileceğine inanıyorum JFrame , bu yüzden gerek olmaz f.
PurkkaKoodari

3

HTML, JavaScript (ES6), 328

Kodun toplam bayt sayısı 402 bayt ve kullanıcıyla etkileşime girecek iletiler:

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

toplam 78 bayt olduğundan toplam puan => 402 - 78 + 4 = 328

Aşağıdaki snippet'i en son Firefox'ta çalıştırın ve anahtarı giriş kutusuna ve ardından Enter tuşuna yazın.

Kod, hem girilen hem de yeniden girilen anahtarların aynı olup olmadığını kontrol eder (eğer değilse tekrar tekrar girilmesini ister), ortalama mutlak fark yüzdesini hesaplar ve değişkenin değerinden küçük olup olmadığını kontrol eder 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 (bayraklar için 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");}

İle derlemek -DY=(y=clock())-x, -DZ=a[d], -DE=getch(), -DW=);while,-DU=i++[d]=Y ve -DP=puts(. Sunum amacıyla yeni satırlar eklendi ve kaldırılabilir (verilen bayt sayısı yoktur).

Ungolfed + yorumlar:

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
}

Bu, tekrarlanan ifadenin aynı olup olmadığını kontrol etmez veya kullanıcı bir taklitçi olarak tanımlanmazsa herhangi bir çıktı vermez.

Bu, ilk tuşa basmadan önce sorulduktan sonra geçen süreyi de dikkate almaz.


Gerekmiyor getchbahis getcveya getchar? `` Getch '' için tanımsız bir referansım var, doğru hatırlıyorsam reddedilir?
coredump

Ayrıca "file.c: 1: 1: uyarı: veri tanımının türü veya depolama sınıfı yok" (gcc) vardı. charGlobal bildirimlerden önce ekledim ve şimdi, bu çalışma zamanında bir segmentasyon hatası veriyor. Nasıl yapılacağı hakkında bilgi verebilir misiniz? Hangi derleyiciyi kullanıyorsunuz? Teşekkürler.
coredump

@coredump Uyarılar zararsızdır; ancak uyarıları kaldırmak istiyorsanız, türün yazılması intve başlatılması gerekir 0. Bunu Windows'ta gcc kullanarak (Window'ları kullanarak) test ettim getch. getchyerine kullanılır getcya getcharçünkü getchherhangi bir karakter işlemeden önce basılmalıdır dönüş anahtarı gerektirmez ( getchhiçbir şey yanlış burada kaldırılan işlevleri kullanarak orada olsa gerçekten, Windows üzerinde kullanımdan kaldırıldı).
es1024

Linux'ta test ediyorum ve çalışmasını sağlamak için stackoverflow.com/questions/7469139/… adresine başvurdum . Teşekkürler.
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

Tüm boşluklar kaldırıldığında, şunlara sahipsiniz:

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

Eminim ki benden daha yetenekli biri dinozor yapabilir!

Kısa açıklama:

lYöntem karakterleri okumak ve yoluna devam ediyornanoTime her karakter girildiğinde ne zaman.

mYöntem baskılar "Enter", kırar lgirmek isabet üzerine yöntemi (karakter 13), o zaman sadece onu eşlernanoTimes ve ardından her karakter arasındaki zaman aralıklarını alır.

Sonraki 2 satır 2 dizede okur, onları sıkıştırır, sonra ikinci aralıklar ve ilk arasındaki yüzde farkının ortalama mutlak değerini bulur ve son olarak bu ortalamanın daha küçük olup olmadığını yazdırır 0.2.


1

Yaygın Lisp: 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

Ek açıklamalar

  • Tüm kurallara uygundur
  • Kullanıcı boş bir parola ilk verdiğinde, program temiz bir şekilde durur
  • Yazarken Escape, program temiz bir şekilde durur.
  • Son SBCL ve CCL uygulamaları üzerinde test edilmiştir
  • Ncurses çevresinde bir sarıcı olan cl-charms gerektirir. Ham girdiyi yakalamanın en kolay yolu budur.
  • Bu, squeamish-ossifrage tarafından bulunan orijinal sürümden esinlenmiştir (ancak kopyalanmamıştır) .

Dinozor bonusu

Bir bonus almalıyım çünkü herkes “ Common Lisp'in can çekişen bir dinozor olduğunu” biliyor .


Alıntı bloğu yerine kod bloğuna geçebilir misiniz? (kodunuz için)
Optimize edici

@Optimizer done
coredump
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.