Piège à souris de Michael Crichton

9

En 1984, Michael Crichton a écrit un programme de sécurité en BASIC qui a été publié dans le magazine Creative Computing. Le programme demanderait à l'utilisateur de taper une phrase de son choix, enregistrer les intervalles entre les frappes, puis lui demander de retaper la phrase. Si les horaires différaient trop, le programme identifierait l'utilisateur comme imposteur.

Votre mission: créez une version du programme de Crichton dans la langue de votre choix.

Règles:

  1. Les phrases pour communiquer avec l'utilisateur («Veuillez saisir la phrase clé», «Veuillez saisir à nouveau la phrase clé», etc.) comptent pour un octet chacune, quelle que soit la longueur réelle. Ceci est uniquement pour la communication utilisateur, n'essayez pas de masquer le code du programme dans les chaînes.

  2. Le test de réussite / échec doit être basé sur la valeur absolue moyenne des écarts en pourcentage par rapport aux intervalles d'origine. Si les chaînes ne correspondent pas, retournez en cas d'échec ou autorisez l'utilisateur à réessayer, à votre discrétion.

  3. La phrase clé ne doit pas autoriser une chaîne nulle. Dans le cas où la phrase clé est trop longue pour votre type de données de chaîne, tronquer ou interdire et recommencer, à votre discrétion.

  4. La sensibilité du test (le seuil du test de réussite / d'échec) doit être réglable dans le code source.

  5. À l'origine, j'ai fourni un bonus de 20% du nombre total d'octets si votre code source peut être formaté pour ressembler de manière reconnaissable à un dinosaure. Il a été souligné que cela est très subjectif et peut-être plus approprié pour un concours de popularité, j'ai donc supprimé ce bonus. Cependant, j'encourage toujours vivement le formatage des dinosaures, et si vous formatez votre code pour ressembler à un dinosaure, vous pouvez déduire tous les commentaires purement cosmétiques, les sauts de ligne ou les espaces blancs de votre total d'octets.

  6. Le nombre d'octets le plus court gagne, sous réserve de la longueur de la chaîne et des ajustements de formatage des dinosaures.

Notez que mes spécifications ci-dessus ne correspondent pas exactement au fonctionnement du code de Crichton, dont des copies peuvent être trouvées en ligne. Suivez les spécifications, n'essayez pas de cloner l'original.

Michael Stern
la source
5
"C'est Michael Crichton, alors soustrayez 20% du nombre total d'octets si votre code source peut être formaté pour ressembler à un dinosaure." - euh ... non. Cette règle est trop subjective. S'il vous plaît retirer. Sinon, allez-y.
John Dvorak
4
@JanDvorak Je ne pense pas que ce soit "trop" subjectif. C'est un appel assez facile pour appeler un art ASCII comme dino ou non
Optimizer
3
@Optimizer Pas dans tous les cas. La lettre grecque lambda ressemble-t-elle à un dinosaure? Je suis presque sûr que oui.
John Dvorak
3
Quelques autres commentaires mineurs: "Please type the key phrase"compte comme 1 octet, ou seulement la phrase compte et la phrase citée compte comme 3 octets ( ", phrase, ")? Est-il intentionnel qu'un intervalle beaucoup plus long et un intervalle beaucoup plus court "s'annulent" et redeviennent encore? Le programme doit-il vérifier que les deux phrases clés correspondent?
Poignée de porte
3
C'était en juin 1984. Vous pouvez voir le programme original ici.
r3mainer

Réponses:

9

Rubis, 171 167 157 octets

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

Sorties truesi la variance moyenne est supérieure à 20%, sinon sorties false.

Tentative artistique des dinosaures 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}###########\   \
            `-._    ,___...----...__,   ,__\  \
                |   |_|           |_|   |    \ \
                |___|               |___|      \\/)

Non golfé:

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' pourrait être supprimé lors de l'exécution dans certains REPL Ruby, car la bibliothèque est déjà chargée.

août
la source
4

Java 768 octets

quelle? Java? pour le golf de code?

C'est probablement la pire chose à faire, mais je l'ai quand même essayé.

Il affiche tous les messages dans la fenêtre de la console, mais la saisie réelle se produit dans le JTextField. Pas vraiment beau. Oh, et pour économiser 5 octets, vous devez redimensionner le JFrame vous-même. En outre, il ne vérifie pas l'exactitude de la chaîne la deuxième fois. Je ne sais pas si c'est contre les spécifications.

Utiliser:

Tapez votre clé dans le champ de texte.

N'appuyez pas sur Entrée, accédez à la console et tapez quelque chose. Il affichera un autre message

Tapez la même chose dans le champ de texte (qui devrait maintenant être effacé).

Accédez à la console et appuyez à nouveau sur quelque chose. Il affichera si vous êtes un intrus ou non.

non golfé:

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
la source
Il n'y a aucun moyen de définir TTY en mode brut à partir de java (sauf si vous êtes prêt à utiliser JNI). Je comprends donc pourquoi vous avez besoin d'un JFrame. Mais vraiment, c'est le programme le moins convivial que j'ai vu depuis des lustres :-) Je ne sais pas si je veux augmenter ou diminuer cette réponse.
coredump du
Je vote positivement pour la grande inamitié de l'utilisateur (est-ce que même un mot?). C'est essentiellement de l'art.
Ingo Bürk
Je crois que cela pourrait être joué davantage en élargissant la classe JFrame, donc vous n'en auriez pas besoin f.
PurkkaKoodari
3

HTML, JavaScript (ES6), 328

Le nombre total d'octets du code est de 402 octets et les messages pour interagir avec l'utilisateur:

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

sont au total 78 octets, donc score total => 402 - 78 + 4 = 328

Exécutez l'extrait de code ci-dessous dans un dernier Firefox et tapez la clé dans la zone de saisie suivie de la touche Entrée.

Le code vérifie que les clés saisies et ressaisies sont identiques (invite à entrer à nouveau sinon), calcule le pourcentage moyen de différence absolue et vérifie s'il est inférieur à la valeur de la variable 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>

Optimiseur
la source
3

C, 154 (86 + 68 pour les drapeaux)

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

Compiler avec -DY=(y=clock())-x, -DZ=a[d], -DE=getch(), -DW=);while, -DU=i++[d]=Yet -DP=puts(. Les nouvelles lignes sont ajoutées à des fins de présentation et peuvent être supprimées (le nombre d'octets donné est sans).

Ungolfed + commentaires:

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
}

Cela ne vérifie pas que la phrase retapée est identique, ni ne produit quoi que ce soit si l'utilisateur n'est pas identifié comme imposteur.

Cela ne prend pas non plus en compte le temps nécessaire après l'invite avant la première frappe.

es1024
la source
Ne devrait pas getchparier getcou getchar? J'ai une référence indéfinie à `getch ', qui si je me souviens bien est obsolète?
coredump
J'ai également eu "file.c: 1: 1: avertissement: la définition des données n'a pas de type ou de classe de stockage" (gcc). J'ai ajouté charavant les déclarations globales, et maintenant, cela donne un défaut de segmentation au moment de l'exécution. Pouvez-vous donner des détails sur la façon de le construire? Quel compilateur utilisez-vous? Merci.
coredump
@coredump Les avertissements sont inoffensifs; si vous souhaitez supprimer les avertissements, il doit être de type intet initialisé à 0. J'ai testé cela en utilisant gcc sur Windows (en utilisant Windows getch). getchest utilisé à la place de getcou getcharcar getchne nécessite pas d'appuyer sur la touche de retour avant de traiter des caractères ( getchest en effet obsolète sous Windows, bien qu'il n'y ait rien de mal à utiliser des fonctions obsolètes ici).
es1024
Je teste sur Linux et j'ai recours à stackoverflow.com/questions/7469139/… pour le faire fonctionner. Merci.
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

Avec tout l'espacement supprimé, vous avez:

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

Je suis sûr que quelqu'un de plus talentueux que moi pourrait en faire un dinosaure!

Brève explication:

La lméthode lit les caractères et conserve une partie de la nanoTimelorsque chaque caractère a été tapé.

La mméthode s'imprime "Enter", rompt la lméthode en appuyant sur Entrée (caractère 13), puis la mappe sur juste le nanoTimes, puis obtient les intervalles de temps entre chaque caractère.

Les 2 lignes suivantes lisent en 2 chaînes, les zippent, puis trouvent la valeur absolue moyenne de la différence en pourcentage entre le deuxième intervalle et le premier, et imprime finalement si cette moyenne était inférieure ou non 0.2.

Ben Reich
la source
1

Lisp commun: 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)

Non golfé

(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

Remarque additionnelle

  • Conforme à toutes les règles
  • Lorsque l'utilisateur donne pour la première fois un mot de passe vide, le programme abandonne proprement
  • Lors de la frappe Escape, le programme s'interrompt proprement.
  • Testé sur les récentes implémentations SBCL et CCL
  • Nécessite cl-charms, qui est un wrapper autour de Ncurses. C'est le moyen le plus simple de capturer des données brutes.
  • Ceci est inspiré par (mais pas copié de) la version originale trouvée par squeamish-ossifrage

Bonus de dinosaure

Je devrais avoir un bonus parce que tout le monde sait que " Common Lisp est un dinosaure moribond ".

coredump
la source
Pouvez-vous passer au bloc de code au lieu du bloc de devis? (pour votre code)
Optimizer
@Optimizer fait
coredump