Мышеловка Майкла Крайтона

9

В 1984 году Майкл Крайтон написал программу BASIC для обеспечения безопасности, которая была опубликована в журнале Creative Computing. Программа попросит пользователя ввести фразу по своему выбору, запишет интервалы между нажатиями клавиш, а затем попросит ее повторить фразу. Если время слишком сильно отличается, программа определит пользователя как самозванца.

Ваше задание: создать версию программы Crichton на выбранном вами языке.

Правила:

  1. Фразы для связи с пользователем («Пожалуйста, введите ключевую фразу», «Пожалуйста, введите ключевую фразу еще раз» и т. Д.) Считаются одним байтом каждый независимо от фактической длины. Это только для общения с пользователем, не пытайтесь скрыть программный код в строках.

  2. Пройденный / неудачный тест должен основываться на среднем абсолютном значении процентного отклонения от исходных интервалов. Если строки не совпадают, либо верните ошибку, либо разрешите пользователю повторить попытку на ваше усмотрение.

  3. Ключевая фраза не должна допускать пустую строку. В случае, если ключевая фраза слишком длинная для вашего строкового типа данных, либо усекать, либо запрещать и начинать заново, на ваше усмотрение.

  4. Чувствительность теста (порог для теста на прохождение / неудачу) должна быть изменена в исходном коде.

  5. Первоначально я предоставил бонус в 20% от общего числа байтов, если ваш исходный код может быть отформатирован так, чтобы он был похож на динозавра. Было отмечено, что это очень субъективно и, возможно, больше подходит для конкурса популярности, поэтому я убрал этот бонус. Однако я по-прежнему от всей души рекомендую форматировать динозавров, и если вы отформатируете свой код так, чтобы он выглядел как динозавр, вы можете вычесть любые чисто косметические комментарии, разрыв строки или пробельные символы из общего байтового числа.

  6. Побеждает кратчайший счетчик байтов, с учетом настроек длины строки и форматирования динозавров.

Обратите внимание, что моя спецификация выше не совсем соответствует работе кода Crichton, копии которого можно найти в Интернете. Следуйте спецификации, не пытайтесь клонировать оригинал.

Майкл Стерн
источник
5
«Это Майкл Крайтон, поэтому вычтите 20% от общего числа байтов, если ваш исходный код может быть отформатирован так, чтобы он был похож на динозавра». - ммм ... нет. Это правило слишком субъективно. Пожалуйста, удалите. Кроме этого, пожалуйста, продолжайте.
Джон Дворжак
4
@JanDvorak Я не думаю, что это "слишком" субъективно. Достаточно легко назвать ASCII-арт динозавром или нет
Оптимизатор
3
@Optimizer Не во всех случаях. Греческая буква лямбда выглядит как динозавр? Я уверен, что это так.
Джон Дворжак
3
Несколько других незначительных комментариев: "Please type the key phrase"считается ли 1 байт, или только фраза считается, а цитируемая фраза считается 3 байтами ( ", фраза, ")? Является ли намеренным, что гораздо более длинный интервал и гораздо более короткий интервал "отменится" и станет еще одним? Должна ли программа проверять совпадение двух ключевых фраз?
Дверная ручка

Ответы:

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 REPL, так как библиотека уже загружена.

августейший
источник
4

Java 768 байт

что? Ява? для кода гольф?

Это, наверное, самое плохое, но я все равно попробовал.

Он отображает любые сообщения в окне консоли, но фактическая типизация происходит в 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!");
    }
}

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!");}}
Стрейч маньяк
источник
Нет никакого способа установить TTY в сыром режиме из Java (если вы не готовы использовать JNI). Так что я понимаю, почему вам нужен JFrame. Но на самом деле, это наименее удобная программа, которую я когда-либо видел :-) Я не уверен, хочу ли я повысить или понизить этот ответ.
coredump
Я одобряю огромное количество недружелюбия пользователей (это даже слово?). Это в основном искусство.
Инго Бюрк
Я полагаю, что это может быть больше в гольфе, если расширить класс 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

С, 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
}

Это не проверяет идентичность перепечатанной фразы и ничего не выводит, если пользователь не идентифицирован как самозванец.

Это также не учитывает время, которое потребовалось после запроса до первого нажатия клавиши.

es1024
источник
Не должны getchставить getcили getchar? У меня есть неопределенная ссылка на `getch ', которая, если я правильно помню, устарела?
coredump
У меня также было «file.c: 1: 1: предупреждение: определение данных не имеет типа или класса хранения» (gcc). Я добавил charдо глобальных объявлений, и теперь это дает ошибку сегментации во время выполнения. Можете ли вы рассказать подробнее о том, как его построить? Какой компилятор вы используете? Спасибо.
coredump
@coredump Предупреждения безвредны; хотя, если вы хотите удалить предупреждения, они должны быть напечатаны intи инициализированы 0. Я проверил это с помощью gcc в Windows (используя Window getch). getchиспользуется вместо getcили getcharпотому, getchчто не требует нажатия клавиши возврата перед обработкой каких-либо символов ( getchдействительно не рекомендуется в Windows, хотя здесь нет ничего плохого в использовании устаревших функций).
es1024
Я тестирую на Linux и прибегаю к stackoverflow.com/questions/7469139/… чтобы заставить его работать. Спасибо.
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

Со всем удаленным промежутком у вас есть:

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 - умирающий динозавр ».

CoreDump
источник
Можете ли вы переключиться на блок кода вместо блока цитаты? (для вашего кода)
Оптимизатор
@ Оптимизатор готов
coredump