Michael Crichtons Mausefalle

9

Im Jahr 1984 schrieb Michael Crichton ein Sicherheitsprogramm in BASIC, das in der Zeitschrift Creative Computing veröffentlicht wurde. Das Programm fordert den Benutzer auf, eine Phrase seiner Wahl einzugeben, die Intervalle zwischen den Tastenanschlägen aufzuzeichnen und ihn dann aufzufordern, die Phrase erneut einzugeben. Wenn sich die Timings zu stark unterscheiden würden, würde das Programm den Benutzer als Betrüger identifizieren.

Ihre Aufgabe: Erstellen Sie eine Version von Crichtons Programm in der Sprache Ihrer Wahl.

Regeln:

  1. Sätze für die Kommunikation mit dem Benutzer ("Bitte geben Sie den Schlüsselbegriff ein", "Bitte geben Sie den Schlüsselbegriff erneut ein" usw.) zählen unabhängig von der tatsächlichen Länge jeweils als ein Byte. Dies ist nur für die Benutzerkommunikation gedacht. Versuchen Sie nicht, Programmcode in den Zeichenfolgen zu verbergen.

  2. Der Pass / Fail-Test sollte auf dem durchschnittlichen absoluten Wert der prozentualen Abweichungen von den ursprünglichen Intervallen basieren. Wenn die Zeichenfolgen nicht übereinstimmen, können Sie nach eigenem Ermessen entweder fehlschlagen oder den Benutzer erneut versuchen lassen.

  3. Die Schlüsselphrase sollte keine Nullzeichenfolge zulassen. Falls die Schlüsselphrase für Ihren String-Datentyp zu lang ist, können Sie sie nach eigenem Ermessen abschneiden oder nicht zulassen und neu beginnen.

  4. Die Empfindlichkeit des Tests (der Schwellenwert für den Pass / Fail-Test) sollte im Quellcode einstellbar sein.

  5. Ich habe ursprünglich einen Bonus von 20% der Gesamtbytezahl bereitgestellt, wenn Ihr Quellcode so formatiert werden kann, dass er erkennbar einem Dinosaurier ähnelt. Es wurde darauf hingewiesen, dass dies sehr subjektiv und möglicherweise besser für einen Beliebtheitswettbewerb geeignet ist, daher habe ich diesen Bonus entfernt. Ich empfehle jedoch weiterhin von Herzen, Dinosaurier zu formatieren. Wenn Sie Ihren Code so formatieren, dass er wie ein Dinosaurier aussieht, können Sie rein kosmetische Kommentare, Zeilenumbrüche oder Leerzeichen von Ihrer Bytesumme abziehen.

  6. Die kürzeste Byteanzahl gewinnt, abhängig von der Anpassung der Zeichenfolgenlänge und der Dinosaurierformatierung.

Beachten Sie, dass meine obige Spezifikation nicht genau mit der Funktionsweise des Crichton-Codes übereinstimmt, von dem Kopien online verfügbar sind. Befolgen Sie die Spezifikation, versuchen Sie nicht, das Original zu klonen.

Michael Stern
quelle
5
"Es ist Michael Crichton. Ziehen Sie also 20% von der Gesamtbytezahl ab, wenn Ihr Quellcode so formatiert werden kann, dass er erkennbar einem Dinosaurier ähnelt." - Ähm nein. Diese Regel ist zu subjektiv. Bitte entfernen. Ansonsten bitte weitermachen.
John Dvorak
4
@ JanDvorak Ich denke nicht, dass es "zu" subjektiv ist. Es ist ein ziemlich einfacher Aufruf, einige ASCII-Grafiken als Dino zu bezeichnen oder nicht
Optimizer
3
@ Optimizer Nicht in allen Fällen. Sieht der griechische Buchstabe Lambda aus wie ein Dinosaurier? Ich bin mir ziemlich sicher, dass es so ist.
John Dvorak
3
Ein paar andere kleine Kommentare: Zählt "Please type the key phrase"als 1 Byte oder zählt nur die Phrase und die zitierte Phrase als 3 Bytes ( ", Phrase, ")? Ist es beabsichtigt, dass ein viel längeres und ein viel kürzeres Intervall "aufheben" und wieder gleichmäßig werden? Muss das Programm überprüfen, ob die beiden Schlüsselphrasen übereinstimmen?
Türknauf
3
Es war im Juni 1984. Das Originalprogramm finden Sie hier.
r3mainer

Antworten:

9

Rubin, 171 167 157 Bytes

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

Ausgabe, truewenn die durchschnittliche Varianz über 20% liegt, andernfalls Ausgabe false.

Dinosaurier ASCII Kunstversuch:

(_=/\
  \ \
   \ \
    \ \              _...---..__
     \ \          .∕` #{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önnte entfernt werden, wenn es in einigen Ruby REPLs ausgeführt wird, da die Bibliothek bereits geladen ist.

August
quelle
4

Java 768 Bytes

Was? Java? für Code Golf?

Dies ist wahrscheinlich das Schlimmste, aber ich habe es trotzdem versucht.

Es werden alle Nachrichten im Konsolenfenster angezeigt, aber die eigentliche Eingabe erfolgt im JTextField. Nicht gerade gut aussehend. Oh, und um 5 Bytes zu sparen, müssen Sie die Größe des JFrame selbst ändern. Außerdem wird beim zweiten Mal nicht überprüft, ob die Zeichenfolge korrekt ist. Ich bin mir nicht sicher, ob das gegen die Spezifikationen verstößt.

Benutzen:

Geben Sie Ihren Schlüssel in das Textfeld ein.

Drücken Sie nicht die Eingabetaste, gehen Sie zur Konsole und geben Sie etwas ein. Es wird eine weitere Meldung angezeigt

Geben Sie dasselbe in das Textfeld ein (das jetzt gelöscht werden sollte).

Gehen Sie zur Konsole und drücken Sie erneut etwas. Es wird angezeigt, ob Sie ein Eindringling sind oder nicht.

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!");}}
Stretch Maniac
quelle
Es gibt keine Möglichkeit, TTY von Java aus in den Raw-Modus zu versetzen (es sei denn, Sie sind bereit, JNI zu verwenden). Ich verstehe also, warum Sie einen JFrame benötigen. Aber wirklich, dies ist das am wenigsten benutzerfreundliche Programm, das ich seit Ewigkeiten gesehen habe :-) Ich bin mir nicht sicher, ob ich diese Antwort positiv oder negativ bewerten möchte.
Coredump
Ich stimme für die schiere Menge an Unfreundlichkeit der Benutzer (ist das überhaupt ein Wort?). Es ist im Grunde Kunst.
Ingo Bürk
Ich glaube, das könnte mehr Golf gespielt werden, wenn man die Klasse erweitert JFrame, also würde man es nicht brauchen f.
PurkkaKoodari
3

HTML, JavaScript (ES6), 328

Die Gesamtanzahl der Bytes des Codes beträgt 402 Bytes und die Nachrichten, die mit dem Benutzer interagieren sollen:

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

sind insgesamt 78 Bytes, also Gesamtpunktzahl => 402 - 78 + 4 = 328

Führen Sie das folgende Snippet in einem aktuellen Firefox aus und geben Sie den Schlüssel in das Eingabefeld ein, gefolgt von der Eingabetaste.

Der Code überprüft, ob sowohl der eingegebene als auch der erneut eingegebene Schlüssel identisch sind (fordert zur erneuten Eingabe auf, wenn dies nicht der Fall ist), berechnet den durchschnittlichen Prozentsatz der absoluten Differenz und prüft, ob er unter dem Wert der Variablen liegt 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>

Optimierer
quelle
3

C, 154 (86 + 68 für Flaggen)

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

Kompilieren Sie mit -DY=(y=clock())-x, -DZ=a[d], -DE=getch(),-DW=);while , -DU=i++[d]=Yund -DP=puts(. Zeilenumbrüche wurden zu Präsentationszwecken hinzugefügt und können entfernt werden (die angegebene Byteanzahl ist ohne).

Ungolfed + Kommentare:

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
}

Dies überprüft weder, ob die neu eingegebene Phrase identisch ist, noch gibt sie etwas aus, wenn der Benutzer nicht als Betrüger identifiziert wird.

Dies berücksichtigt auch nicht die Zeit, die nach der Eingabeaufforderung vor dem ersten Tastendruck benötigt wird.

es1024
quelle
Sollte nicht getchwetten getcoder getchar? Ich habe einen undefinierten Verweis auf "getch", der, wenn ich mich richtig erinnere, veraltet ist.
Coredump
Ich hatte auch "file.c: 1: 1: Warnung: Datendefinition hat keinen Typ oder keine Speicherklasse" (gcc). Ich habe charvor globalen Deklarationen hinzugefügt , und jetzt gibt dies zur Laufzeit einen Segmentierungsfehler. Können Sie Details dazu geben, wie man es baut? Welchen Compiler verwenden Sie? Vielen Dank.
Coredump
@coredump Die Warnungen sind harmlos; Wenn Sie die Warnungen entfernen möchten, sollten Sie sie eingeben intund auf initialisieren 0. Ich habe dies mit gcc unter Windows getestet (mit Windows getch). getchwird anstelle von getcoder verwendet, getcharweil getchvor dem Verarbeiten von Zeichen nicht die Eingabetaste gedrückt werden muss ( getchist unter Windows zwar veraltet, obwohl hier nichts falsch daran ist, veraltete Funktionen zu verwenden).
Es1024
Ich teste unter Linux und greife auf stackoverflow.com/questions/7469139/… zurück, damit es funktioniert. Vielen Dank.
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

Wenn alle Abstände entfernt sind, haben Sie:

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

Ich bin mir sicher, dass jemand, der talentierter ist als ich, einen Dinosaurier machen könnte!

Kurze Erklärung:

Die lMethode liest Zeichen und zeichnet nanoTimeauf, wann jedes Zeichen eingegeben wurde.

Die mMethode druckt "Enter", unterbricht die lMethode beim Drücken der Eingabetaste (Zeichen 13), ordnet sie dann nur dem zu nanoTimesund ruft dann die Zeitintervalle zwischen den einzelnen Zeichen ab.

Die nächsten 2 Zeilen lesen 2 Zeichenfolgen ein, komprimieren sie, ermitteln dann den durchschnittlichen absoluten Wert der prozentualen Differenz zwischen dem zweiten und dem ersten Intervall und drucken schließlich, ob dieser Durchschnitt kleiner als war oder nicht 0.2.

Ben Reich
quelle
1

Common 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

Zusätzliche Bemerkungen

  • Entspricht allen Regeln
  • Wenn der Benutzer zum ersten Mal ein leeres Passwort angibt, wird das Programm sauber abgebrochen
  • Während Escapeder Eingabe bricht das Programm sauber ab.
  • Getestet auf aktuellen SBCL- und CCL-Implementierungen
  • Benötigt Cl-Charms, ein Wrapper um Ncurses. Dies ist der einfachste Weg, um Rohdaten zu erfassen.
  • Dies ist inspiriert von der Originalversion von squeamish-ossifrage (aber nicht kopiert von dieser)

Dinosaurier Bonus

Ich sollte einen Bonus haben, weil jeder weiß, dass " Common Lisp ein sterbender Dinosaurier ist ".

Core-Dump
quelle
Können Sie zum Codeblock anstelle des Anführungsblocks wechseln? (für Ihren Code)
Optimizer
@ Optimizer fertig
Coredump