マイケルクライトンのネズミ捕り


9

1984年、マイケルクリクトンはクリエイティブコンピューティング誌に掲載されたBASICのセキュリティプログラムを書きました。プログラムは、ユーザーに自分の選択した語句を入力するように要求し、キーストローク間の間隔を記録してから、語句を再入力するように要求します。タイミングの違いが大きすぎる場合、プログラムはユーザーを詐称者として識別します。

課題:選択した言語でバージョンのCrichtonのプログラムを作成します。

ルール:

  1. ユーザーとのコミュニケーションのためのフレーズ(「キーフレーズを入力してください」、「キーフレーズをもう一度入力してください」など)は、実際の長さに関係なく、それぞれ1バイトとしてカウントされます。これはユーザー通信専用です。文字列内のプログラムコードを非表示にしないでください。

  2. 合格/不合格テストは、元の間隔からのパーセンテージ分散の平均絶対値に基づいている必要があります。文字列が一致しない場合、失敗を返すか、ユーザーの裁量でユーザーが再試行できるようにします。

  3. キーフレーズはnull文字列を許可しないでください。キーフレーズが文字列データ型に対して長すぎる場合は、自由に切り捨てるか、許可せずにやり直してください。

  4. テストの感度(合否テストのしきい値)は、ソースコードで調整可能である必要があります。

  5. 私はもともと、恐竜によく似たソースコードをフォーマットできる場合、合計バイト数の20%のボーナスを提供しました。これは非常に主観的であり、人気コンテストにおそらくより適切であると指摘されたので、このボーナスを削除しました。ただし、恐竜のフォーマットを心から推奨しています。恐竜のようにコードをフォーマットすると、純粋な表面的なコメント、改行、または空白文字をバイト合計から差し引くことができます。

  6. 文字列長と恐竜のフォーマット調整に応じて、最短のバイト数が優先されます。

上記の私の仕様は、リッチトンのコードの操作と完全には一致していないことに注意してください。そのコピーはオンラインで見つけることができます。仕様に従ってください。オリジナルのクローンを作成しないでください。


5
「それはMichael Crichtonなので、恐竜によく似たソースコードにフォーマットできる場合は、総バイト数から20%を引きます。」-うーん...いいえ。このルールは主観的すぎます。削除してください。それ以外はどうぞ。
— John Dvorak

4
@JanDvorak「あまりにも」主観的ではないと思います。一部のASCIIアートをdinoと呼ぶのはかなり簡単な呼び出し
— オプティマイザー

3
@Optimizerすべての場合ではありません。ギリシャ文字のラムダは恐竜のように見えますか?確かにそうだと思います。
— John Dvorak

3
その他のいくつかのマイナーなコメント:"Please type the key phrase"1バイトとしてカウントされますか、それともフレーズカウントと引用されたフレーズのみが3バイトとしてカウントされますか("、フレーズ、")?間隔を長くしたり、間隔を短くしたりすると、「キャンセル」されて再び同じになることが意図されていますか?プログラムは、2つのキーフレーズが一致することを確認する必要がありますか?
— ドアノブ

回答:


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。

恐竜アスキーアートの試み:

(_=/\
  \ \
   \ \
    \ \              _...---..__
     \ \          .∕` #{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 REPLで実行すると、ライブラリがすでにロードされているため、削除できます。


4

Java 768バイト

何?Java?コードゴルフ?

これはおそらく最悪のことですが、とにかくやってみました。

コンソールウィンドウにメッセージが表示されますが、実際の入力はJTextFieldで行われます。見栄えがよくない。ああ、5バイトを節約するには、JFrameのサイズを自分で変更する必要があります。また、文字列が正しいかどうかは2度チェックされません。それが仕様に反しているかどうかはわかりません。

使用するには:

テキストフィールドにキーを入力します。

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

javaからrawモードでTTYを設定する方法はありません(JNIを使​​用する準備ができている場合を除く)。JFrameが必要な理由を理解しました。しかし、実際には、これは私が年齢で見た中で最もユーザーフレンドリーなプログラムです:-)この回答に賛成するか反対するかはわかりません。
— コアダンプ2014年

私はユーザーの無愛想さの純粋な量に賛成です(それは一言でさえ?)。基本的にはアートです。
— IngoBürk2014年

クラスを延長することJFrameでもっとゴルフができると思うので、あなたは必要ないでしょうf。
— PurkkaKoodari 2014年

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 + comments:

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 'への未定義の参照があります。正しく思い出せば、非推奨になりますか?
— コアダンプ2014年

「file.c:1:1:警告:データ定義にタイプまたはストレージクラスがありません」(gcc)もありました。charグローバル宣言の前に追加しましたが、実行時にセグメンテーション違反が発生します。構築方法の詳細を教えていただけますか?どのコンパイラを使用していますか?ありがとう。
— コアダンプ2014年

@coredump警告は無害です。ただし、警告を削除する場合は、タイプintで、に初期化する必要があります0。私はWindowsでgccを使用してこれをテストしました(Windowを使用getch)。getch代わりに使用されgetcたりgetcharするのでgetch任意の文字を処理する前に押されるリターンキーを必要としない(getch何も間違っているが、ここでは非推奨の機能を使用してありますけれども、実際、Windows上で推奨されません)。
— es1024 2014年

私はLinuxでテストしていて、それを機能させるためにstackoverflow.com/questions/7469139/…に頼っています。ありがとう。
— コアダンプ2014年

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)Enterキーを押す時に方法は、それからだけにマッピングnanoTimesし、各文字間の時間間隔を取得します。

次の2行は2つの文字列を読み込み、それらを圧縮してから、2番目の間隔と最初の間隔の差のパーセンテージの平均絶対値を見つけ、最後にこの平均がより小さいかどうかを出力し0.2ます。


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)

未ゴルフ

(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実装でテスト済み
  • Ncursesのラッパーであるcl-charmsが必要です。これは、生の入力をキャプチャする最も簡単な方法です。
  • これに触発(ただしからコピーされていない)されている原稿を、squeamish-ossifrageが見つけバージョンに

恐竜ボーナス

「Common Lispは瀕死の恐竜」であることは誰もが知っているので、私はボーナスを持っている必要があります。


引用ブロックの代わりにコードブロックに切り替えることはできますか?(あなたのコード用)
— オプティマイザ

@Optimizer完了
— コアダンプ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.