Мишоловка Майкла Кріктона


9

У 1984 році Майкл Кріктон написав програму безпеки в BASIC, що була опублікована в журналі Creative Computing. Програма попросить користувача ввести фразу за власним вибором, записати інтервали між натисканнями клавіш, а потім попросити її повторно ввести фразу. Якщо таймінги відрізнялися занадто великою кількістю, програма ідентифікувала б користувача як самозванець.

Ваше завдання: створити версію програми Кріктона мовою, яку ви обрали.

Правила:

  1. Фрази для спілкування з користувачем ("Будь ласка, введіть ключову фразу", "Будь ласка, введіть ключову фразу ще раз" тощо), рахуються як один байт кожен незалежно від фактичної довжини. Це лише для спілкування з користувачем, не намагайтеся приховувати програмний код у рядках.

  2. Тест проходження / відмови повинен базуватися на середньому абсолютному значенні відсоткових відхилень від початкових інтервалів. Якщо рядки не збігаються, або повертаються невдало, або дозволяють користувачу спробувати ще раз, на ваш розсуд.

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

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

  5. Я спочатку надав бонус у розмірі 20% від загальної кількості байтів, якщо ваш вихідний код може бути відформатований так, що він може нагадувати динозавра. Було зазначено, що це дуже суб'єктивно і, можливо, більше підходить для конкурсу на популярність, тому я видалив цей бонус. Однак я все ще від душі заохочую форматування динозавра, і якщо ви відформатуєте свій код, щоб він виглядав як динозавр, ви можете вирахувати будь-які чисто косметичні коментарі, символи пробілів чи пробілів із загальної кількості байтів.

  6. Виграє найменший кількість байтів, залежно від коригування формату довжини рядка та динозавра.

Зауважте, що моя специфікація, що описана вище, точно не відповідає дії коду Кріктона, копії якого можна знайти в Інтернеті. Дотримуйтесь специфікації, не намагайтеся клонувати оригінал.


5
"Це Майкл Кріктон, тому відніміть 20% від загальної кількості байтів, якщо ваш вихідний код можна відформатувати так, щоб він пізнавав схожий на динозавра." - гмм ... ні. Це правило є занадто суб'єктивним. Видаліть, будь ласка. Крім цього, будь ласка, продовжуйте.
Іван Дворак

4
@JanDvorak Я не вважаю його "занадто" суб'єктивним. Це досить простий заклик називати деяке мистецтво ASCII як дино чи ні
Optimizer

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

Безголівки:

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 REPLs, оскільки бібліотека вже завантажена.


4

Java 768 байт

що? Java? для коду гольфу?

Це, мабуть, найгірше, що потрібно зробити, але я все-таки спробував це.

Він відображає будь-які повідомлення у вікні консолі, але фактичне введення тексту відбувається у полі JTextField. Не зовсім приємно виглядає. О, і щоб зберегти 5 байт, вам доведеться змінити розмір JFrame самостійно. Крім того, він не перевіряє правильність рядків вдруге. Не впевнений, чи це проти специфікацій.

Використовувати:

Введіть ключ у текстовому полі.

Не натискайте клавішу Enter, перейдіть до консолі та введіть щось. Він відобразить інше повідомлення

Введіть те саме в текстовому полі (яке тепер слід очистити).

Перейдіть до консолі і знову натисніть щось. Він покаже, чи ви зловмисник чи ні.

неозорений:

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

гольф:

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

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

Це не перевіряє, чи є повторно введена фраза однаковою, а також не видає нічого, якщо користувач не ідентифікується як самозванець.

Це також не враховує час, який пройшов після запрошення до першого натискання клавіші.


Не варто робити getchставку getcчи getchar? У мене не визначене посилання на `getch ', яке, якщо я пригадую правильно, застаріло?
coredump

У мене також було "file.c: 1: 1: попередження: визначення даних не має типу або класу зберігання" (gcc). Я додав charдо глобальних декларацій, і тепер це дає помилку сегментації під час виконання. Чи можете ви дати детальну інформацію про те, як його побудувати? Який компілятор ви використовуєте? Дякую.
coredump

@coredump Попередження нешкідливі; хоча якщо ви хочете видалити попередження, його слід ввести intта ініціалізувати до 0. Я перевірив це за допомогою gcc в Windows (за допомогою Windows 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)

Безумовно

(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-шарм, який є обгорткою навколо Ncurses. Це найпростіший спосіб зафіксувати вихідні дані.
  • На це надихає (але не скопійовано з) оригінальну версію, знайдену врізкою-кості

Бонус за динозавра

Я мав би отримати бонус, тому що всі знають, що " звичайний Лисп - це динозавр, що замирає ".


Чи можете ви перейти на код коду замість блоку цитат? (для вашого коду)
оптимізатор

@Optimizer зроблено
CoreDump
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.