99の通訳を書く


99

99(「ナインティーナイン」と発音)は、まったく新しい難解なプログラミング言語です99と混同しないでください、イタリック体に注意してください)。このチャレンジでのあなたの仕事は、可能な限り短い99のインタープリターを書くことです。最少バイト送信が勝ちです。Tiebreakerは、最初に投稿されたサブミッションに進みます。

この質問の深さは通常よりも少し深いため、良い答えを探しているので、お気に入りの答え(必ずしも勝者とは限りません)に対して250の報奨金を授与します。

99スペック

99必須言語です。99プログラムの各行は1つのステートメントであり、実行中、命令ポインターは先頭行から始まり、後続の各行を順番に通過して、途中で実行します。プログラムは、最後の行が実行されると終了します。Gotoステートメントは、命令ポインターのパスを再ルーティングできます。

改行、スペース、および99のプログラム9で重要な唯一の3文字です。他のすべての文字は完全に無視されます。さらに、各行の末尾のスペースは無視され、行の複数のスペースは1つのスペースとして読み取られます。(「改行」とは、一般的な改行エンコーディングを指します。インタープリターがどちらを使用するかは関係ありません。)

したがって、このプログラム:

   9      BLAH        99   9a9bb9c9
9 this line and the next have 6 trailing spaces 9      
      

このプログラムと同じです:

 9 99 9999
9 9

変数

99の変数はすべて、1つ以上9の(9+正規表現で)結合された名前を持っています。たとえば、999、および9999999999すべての異なる変数です。当然、無限に多くあります(メモリの制限がなければ)。

各変数の値は、符号付きの任意精度整数です。デフォルトでは、各変数は独自の数値表現に割り当てられます。したがって、再割り当てされていない限り、変数の値は99番、変数の値は9999番などとなります。明示的に割り当てられるまで、変数を単純な数字として扱うと考えることができます。

V以下の任意の変数名を参照するために使用します。
各インスタンスVに置き換えることができ9999999999、など

声明

99には5つの異なるステートメントタイプがあります。99プログラムの各行には、1つのステートメントのみが含まれています。

ここで説明する構文は、無関係な文字がすべて削除され、末尾のスペースがすべて削除され、複数のスペースのシーケンスがすべて単一のスペースに置き換えられていることを前提としています。

1.操作なし


空の行は何もしません。何もしません(命令ポインタをインクリメントする以外)。

2.出力

V

行の1つの変数Vは、その変数を標準出力に出力します。

V奇数99999など)がある場合、V9 で割った整数値が(10進数で)出力されます。

場合Vの偶数有する9S」( 999999など)をアスキーコードで文字V9で除算し、MOD 128が印刷されます。(つまり(V / 9) % 128、0〜127の値です。)

:プログラム

9
9999

印刷します1W19/9が1であるため、最初の行が印刷されますW。9999/ 9が1111であり、1111 mod 128が87であり、87がの文字コードであるため、2行目が印刷されWます。

出力トークン間では改行が印刷されないことに注意してください。\n改行のために明示的に印刷する必要があります。

3.入力

 V

Vの先頭にスペースがある単一の変数は、stdinから入力を受け取り、その変数に格納します。

V数が奇数9の場合、ユーザーは任意の符号付き整数を入力でき、Vその値の9倍に設定されます。

V数が9の場合、ユーザーは任意のASCII文字を入力できV、文字コードの9倍に設定されます。

:与えられ-57A入力として、このプログラム

 9
9
 99
99

出力されます-57A。内部的には、変数9の値は-513で99、値は585です。

インタープリターは、入力が常に構文的に有効であると想定する場合があります。

4.割り当て

このステートメントは任意に長くすることができます。1行に2つ以上の変数があり、スペースで区切られています。

V1 V2 V3 V4 V5 ...

これにより、偶数インデックスのすべてのの合計から、奇数インデックスのの合計(を除く)が差し引かれます。割り当ては、参照によるものではなく、値によるものです。V1VVV1

それはほとんどの言語でとして翻訳できました。V1 = V2 - V3 + V4 - V5 + ...

したがって、変数が2つしかない場合は、通常の割り当てです。

V1 V2V1 = V2

3つある場合、それは減算です。

V1 V2 V3V1 = V2 - V3

また、+/ -記号は、追加の変数ごとに切り替えを続けます。

V1 V2 V3 V4V1 = V2 - V3 + V4

:このプログラムは以下を出力します1110123

999           Prints triple-nine divided by nine (111).
999 9 9       Assigns triple-nine to zero (nine minus nine).
999           Prints triple-nine divided by nine (0)
9 999 9       Assigns single-nine to negative nine (zero minus nine).
999 999 9     Adds nine to triple-nine (really subtracts negative nine).
999           Prints triple-nine divided by nine (1).
999 999 9     Adds nine to triple-nine (really subtracts negative nine).
999           Prints triple-nine divided by nine (2).
999 999 9     Adds nine to triple-nine (really subtracts negative nine).
999           Prints triple-nine divided by nine (3).

5.ジャンプ(すべてゼロの場合ジャンプ)

この文は任意に長くすることもできます。これは、スペースで区切られ、先頭にスペースが付いた 1行の2つ以上の変数です。

 V1 V2 V3 V4 V5 ...

それ以外の値の一部がゼロ以外の場合、これは何もしないように動作します。命令ポインタは通常どおり次の行に移動します。V1

場合、すべての値が他にあるゼロは、命令ポインタが行番号に移動されます。行はインデックスがゼロであるため、が0の場合、ポインタは一番上の行に移動します。プログラムは、負の値であるか、可能な限り最高のインデックス(行数から1を引いた値)より大きい場合、(通常、エラーなしで)終了します。V1 V1V1V1

ここでは9で割られていないことに注意してください。また、変数を9の倍数でない値にすることはできないため、ジャンプできるのは9の倍数である行番号だけです。V1

例:

このプログラムはを1永久に出力します:

9          Prints single-nine divided by nine (always 1).
99 9 9     Assigns double-nine to zero.
 99 99     Jumps to line zero (top line) if double-nine is zero.

このプログラム

99999999                                              Print G.
999 99                                                Set triple-nine to ninety-nine.
9999999999 9999999999 9999999999 99 99 9 9 999 999    Set 10-nine to zero.
99999999999 9999999999                                Set 11-nine to zero.





999                                                   Print triple-nine's value divided by nine. (This is the ninth line.)
99999999                                              Print G.
999 999 9                                             Subtract nine from triple-nine.
 99999 999                                            Jump to line 5-nines if triple-nine is zero (ends program).
 9 99999999999 9999999999                             Jump to line nine if 10-nine and 11-nine are zero (always jumps).

で囲まれた11から1までの数字を降順に出力しますG

G11G10G9G8G7G6G5G4G3G2G1G

さらなる詳細

理想的なインタープリターは、99プログラムファイル名を引数としてコマンドラインから実行されます。I / Oもコマンドラインでオンザフライで実行されます。

ただし、プログラムを文字列および入力トークンのリスト(例:)として取り込むインタープリター関数を作成することもでき["-57", "A"]ます。関数は、出力文字列を出力または返す必要があります。

これらのオプションが使用言語で不可能な場合は、インタープリターを実行してI / Oを処理する少し異なる方法で問題ありません。


おまけ:99年にクールなものを書いてください。この投稿に例として喜んで掲載します。


99回目のチャレンジを楽しんでください。:D


9
私は投票を検討しましたが、あなたの現在のスコアは9です
...-wchargin

30
@WCharginは、今では99を取得する必要があるように見えます。
trlkly

5
確かにセルフホスティング(書き込みのためのボーナスがあります99で通訳を99)、ありませんか?
ゲイブ

5
@Gabeそのような答えはおそらく賞金を得るでしょうが、それが唯一の答えであるなら、何が通訳を解釈するでしょうか?;)
カルビンの趣味

1
それが動作します@Optimizer:pastebin.com/raw.php?i=h73q58FN
コアダンプ

回答:


16

CJam、157バイト

{:I;_N" 9"+--N/:P:,$W=){1a*Ab}%:V;{PT):T(=:LS%_{LS#\:,_,({(\{V=}%@{V-1@{2$*+0@-\}*\;t:V;}{:|T@V=9*?:T;}?}{~\{_V=\1&!{128%c}*o}{VIW):W=it:V;}?}?}R?Tg)TP,<*}g}

オンラインで試してください:

説明

適切なインデントとコメントを使用してこれをフォーマットしようとすると、おそらく永遠に時間がかかるので、アルゴリズムの概要を示します。

コードはブロックであり、CJamの匿名関数に類似しています。ブロックは、実行時にスタック上のプログラム文字列と入力のリストを予期します。

初期化は3つのステップで構成されます。最初に、入力リストが保存されます。次に、プログラム内の意味のないすべての文字が削除され、結果が行のリストに分割されて保存されます。最後に、変数リストが初期化されます。このリストは、名前の長さでインデックス付けされた各変数を、9で割った値にマッピングします(変数は、9の倍数でない値、およびgotoを除くすべての操作がこの変更の恩恵を受けることはできません)。リストは、最長の行の長さまで初期化されます。これは、存在する最長の可変名の上限です。また、初期変数値による暗黙的な初期化も少しあります。行番号は0で、入力インデックスは-1です。

インタープリターは、次の行を読み取り、行番号をインクリメントし、行番号が既存の行を指している間に行を実行するループのように実装されます。行解析では、最初に行が空でないことを確認し、次にアリティが1または> 1であるかどうかに基づいて分岐し、次に先行スペースがあるかどうかに基づいて分岐します。これらの4つのブランチは、他のすべてと同様に積極的にゴルフを行いますが、4つの(no-opを除く)操作をほとんど簡単な方法でエミュレートします。おそらく注意すべき最適化の1つは、有効な入力シーケンスは常にプログラムが期待する型の要素を生成するはずなので、変数名の長さに基づいて入力用の個別のケースを作成することを省略したことです。入力リストから読み取られた要素は予想されるタイプであると単純に想定されます。


15
+1。非常に短いです。さて、99で CJamインタプリタを書くことができますか?;-)
コアダンプ

9
@coredump * shudders *
Runer112

くそー、私は195しか得ることができず、それから私は希望を失い、あきらめました:P-
オプティマイザー

これは、負の値を印刷するときに正しいモジュロを取りません。これは交換することによって固定することが可能128%128,=
マーティンエンダー

26

Python 3、421 414 410 404 388 395 401バイト

ゴルフ:

import sys,re
v,i,c,g,L={},0,[re.sub('( ?)[^9]+','\\1',l).rstrip().split(' ')for l in open(sys.argv[1])],lambda i:v.get(i,int(i)//9),len
while-1<i<L(c):
 d=c[i];l=L(d);e,*f=d;i+=1
 if l>1:
  x,*y=f
  if e:w=list(map(g,f));v[e]=sum(w[::2])-sum(w[1::2])
  elif l==2:j=input();v[x]=int(j)if L(x)%2 else ord(j)
  elif~-any(g(j)for j in y):i=g(x)*9
 elif e:w=g(e);print(w if L(e)%2 else chr(w%128),end='')

ゴルフをしていない:

import sys, re

# Intialise variable table.
vars_ = {}
get_var = lambda i: vars_.get(i, int(i)//9)

# Parse commands.
commands=[re.sub('( ?)[^9]+','\\1',l).rstrip().split(' ') for l in open(sys.argv[1])]

# Run until the current instruction index is out of bounds.
index=0
while 0 <= index < len(commands):
    # Get the current command and increment the index.
    command = commands[index]
    l = len(command)
    first = command[0]
    index += 1

    if l > 1:
        # Handle the "assignment" command.
        if first:
            operands = [get_var(i) for i in command[1:]]
            vars_[first] = sum(operands[0::2]) - sum(operands[1::2])
        # Handle the "input" command.
        elif l==2:
            inp = input()
            vars_[command[1]] = int(inp) if len(command[1]) % 2 else ord(inp)
        # Handle the "goto" command.
        elif not any(get_var(i) for i in command[2:]):
            index = get_var(command[1]) * 9
    # Handle the "output" command.
    elif first:
        val = get_var(first)
        print(val if len(first) % 2 else chr(val % 128),end='')

仕様の単なる文字通りの実装であり、私が手に入れることができる限りゴルフをしました。

99ソースコードファイルを唯一の引数として指定して、コマンドラインから実行します(たとえば、OPの最後の例)。

> python3 ninetynine.py countdown.txt
G11G10G9G8G7G6G5G4G3G2G1G
>

追加ボーナスとして、ここでは「99本のボトル」の(かなり貧弱)の実装だ99http://pastebin.com/nczmzkFs


1
@DLosc:あなたの最初の点について:私もelse数字を削除することができましたが、以前に試したときに構文エラーが発生しました。他のヒントも大歓迎です!
Mac

3
@coredump:仕様の記述方法。各変数は常に9で割り切れる値を持ちます。変数が任意の値を取り、必要に応じて(特にgotoルーチン内および変数のデフォルト値を取得するときに)9だけを乗算/除算できるようにする方がより簡潔であることがわかりました。言語のユーザーに関する限り、違いはありません。
マック

2
それelse自体ではなく、その前のスペースだけです。例3*n+1if n%2else n//2
DLosc

1
@DLosc:すみません、私は間違えました-私は確かに、スペースではなく、スペースを意味しましたelse。例えば、私が交換しようとしたprint(w if L(e)%2 else chr(w%128))print(w if L(e)%2else chr(w%128))し、構文の例外が発生しました。
Mac

1
奇数-ideone.comでテストし、動作しましたが、実際、Python3インタープリター(Ubuntuの3.4.0)では動作しません。このヒント投稿では、数字の後にアルファベットのトークンが続くことは一般的に機能しますが、またはで始まるトークンには機能せず、(コメントから)どちらにも機能しません。eE0or
DLosc

16

Common Lisp、1180 857 837 836バイト

私はこれが勝つつもりはないことを知っていますが、私はこのゴルフを楽しんでいた。私は、二つ以上である343バイトで、削除する管理99 CJamで書かれた通訳を。

また、非常に面白いことに、圧縮しようとすればするほど、Common Lispの場合、コードをコンパイルするほうが、オンザフライで解釈するよりも短くなると納得します。

(defmacro g(g &aux a(~ -1)> d x q(m 0)r v(n t)c(w 0)? u z)(flet((w(n p)(intern(format()"~a~a"p n))))(#1=tagbody %(case(setf c(ignore-errors(elt g(incf ~))))(#\  #2=(when(> w 0)(pushnew w v)(if u()(setq ?(oddp w)))(#5=push(w w'V)u)(setf w 0))(setf z t))(#\9(incf w)(setf >(or >(and n z))z()n()))((#\Newline())#2#(#5#(when u(setf u(reverse u)a(pop u))(if >(if u`(when(every'zerop(list,@u))(setf @,a)(go ^))`(setf,a,(if ?'(read)'(char-code(read-char)))))(if u`(setf,a,(do(p m)((not u)`(-(+,@p),@m))(#5#(pop u)p)(#5#(if u(pop u)0)m)))`(princ,(if ? a`(code-char(mod,a 128)))))))r)(incf m)(setf ?()u()z()>()n t)))(if c(go %))$(decf m)(setq d(pop r))(if d(#5# d x))(when(=(mod m 9)0)(#5#(w #3=(/ m 9)'L)x)(#5#`(,#3#(go,(w #3#'L)))q))(if(>= m 0)(go $)))`(let(@,@(mapcar(lambda(n)`(,(w n'V),(/(1-(expt 10 n))9)))v))(#1#,@x(go >)^(case @,@q)>))))
  • 字句解析とコード生成はインターリーブされます。内部表現は保存せず、各行を直接処理します。
  • tagbody2つのループを実行するシングルがあります:

     (... (tagbody % ... (go %) $ ... (go $)) result)
    
  • ローカル変数はで宣言されています &aux

  • クロージャを生成しないで、直接解釈されたコード

Ungolfed、コメント付き

(defmacro parse-99
    (string &aux
              (~ -1) ; current position in string
              a      ; first variable in a line 
              >      ; does current line starts with a leading space?
              d      ; holds a statement during code generation
              x      ; all statements (labels + expressions)
              q      ; all generated case statements 
              (m 0)  ; count program lines (first increases, then decreases) 
              r      ; list of parsed expressions (without labels)
              v      ; set of variables in program, as integers: 999 is 3
              (n t)  ; are we in a new line without having read a variable? 
              c      ; current char in string 
              (w 0)  ; currently parsed variable, as integer 
              ?      ; is first variable odd? 
              u      ; list of variables in current line, as integers
              z)     ; is the last read token a space?
  (flet((w(n p)
          ;; produce symbols for 99 variables
          ;; e.g. (10 'V) => 'V10
          ;;      (4 'L)  => 'L4
          (intern(format()"~a~a"p n))))
    (tagbody
     parse
       (case (setf c
                   ;; read current char in string,
                   ;; which can be NIL if out-of-bounds
                   (ignore-errors(aref string (incf ~))))

         ;; Space character
         (#\Space
          #2=(when(> w 0)
               (pushnew w v)            ; we were parsing a variable, add it to "v"
               (if u()(setq ?(oddp w))) ; if stack is empty, this is the first variable, determine if odd
               (push(w w'V)u)           ; add to stack of statement variable
               (setf w 0))              ; reset w for next variable

          ;; Space can either be significant (beginning of line,
          ;; preceding a variable), or not. We don't know yet.
          (setf z t))

         ;; Nine
         (#\9
          (incf w) ; increment count of nines
          (setf >(or >(and n z)) ; there is an indent if we were
                                 ; starting a newline and reading a
                                 ; space up to this variable (or if we
                                 ; already know that there is an
                                 ; indent in current line).
                ;; reset z and n
                z()n()))

         ;; Newline, or end of string
         ((#\Newline())
          #2#  ;; COPY-PASTE the above (when(> w 0)...) statement,
               ;; which adds previously read variable if necessary.

          ;; We can now convert the currently read line.
          ;; We push either NIL or a statement into variable R.

          (push(when u
                     (setf u (reverse u) ; we pushed, we must reverse
                           a (pop u))    ; a is the first element, u is popped
                     (if >
                         ;; STARTS WITH LEADING SPACE
                         (if u
                             ;; JUMP
                             `(when(every'zerop(list,@u))(setf @,a)(go ^))

                             ;; READ
                             `(setf,a,(if ?'(read)'(char-code(read-char)))))

                         ;; STARTS WITH VARIABLE
                         (if u

                             ;; ARITHMETIC
                             `(setf,a,(do(p m) ; declare p (plus) and m (minus) lists

                                         ;; stopping condition: u is empty
                                         ((not u)
                                          ;; returned value: (- (+ ....) ....)
                                          `(-(+,@p),@m))

                                        ;; alternatively push
                                        ;; variables in p and m, while
                                        ;; popping u

                                        (push(pop u)p)

                                        ;; first pop must succeed, but
                                        ;; not necessarly the second
                                        ;; one.  using a zero when u
                                        ;; is empty covers a lot of
                                        ;; corner cases.

                                        (push(if u (pop u) 0) m)))

                             ;; PRINT
                             `(princ,(if ? a`(code-char(mod,a 128)))))))
               r)
          ;; increase line count
          (incf m)
          ;; reset intermediate variables
          (setf ?()u()z()>()n t)))

       ;; loop until end of string
       (if c (go parse))


     build
       ;;; Now, we can add labels in generated code, for jumps

       ;; decrease line count M, which guards our second loop
       (decf m)

       ;; Take generated statement from R
       (setq d(pop r))

       ;; we pop from R and push in X, which means X will eventually
       ;; be in the correct sequence order. Here, we can safely
       ;; discard NIL statements.

       ;; We first push the expression, and THEN the label, so that
       ;; the label ends up being BEFORE the corresponding statement.
       (if d(push d x))

       ;; We can only jump into lines multiple of 9
       (when (=(mod m 9)0)
         ;; Push label
         (push(w #3=(/ m 9)'L)x)
         ;; Also, build a case statement for the jump table (e.g. 2(go L2))
         (push`(,#3#(go,(w #3#'L)))q))
       ;; loop
       (if(>= m 0)(go build)))

    ;; Finally, return the code
    `(let(@ ; target of a jump instruction

          ;; other variables: V3 represents 999 and has a default value of 111
          ,@(mapcar(lambda(n)`(,(w n'V),(/(1-(expt 10 n))9)))v))

       ;; build a tagbody, inject statements from X and case statements from Q
       ;; label ^ points to jump table : we go to ^ each time there is a JUMP
       ;; label > is the end of program

       ;; note that if the case does not match any authorized target
       ;; address, we simply end the programs.
       (tagbody,@x(go >)^(case @,@q)>))))

評価中は標準の入出力を使用readprincます。つまり、標準と関数を使用します。したがって、結果のコードは、以下に示すように、コマンドラインで実行可能にすることができます。

99個のプログラムを実行する場合、入力は完全にサニタイズされません。ユーザーはどのような値が期待されるかを知っていると想定されます。

ジャンプの際に発生する可能性がある唯一のランタイムオーバーヘッドは、変数の値を評価し、その値をラベルと一致させる必要があるためです。それ以外は、インタープリターは非常に効率的でなければなりません。

毎回9で除算したり乗算したりする必要がないというMacの賢明な観察に基づいて、現在のバージョンでは、実行中に9を除算したり乗算したりすることはありません。

私たちが代わる場合defmacroによってdefun、私たちは、生成されたコードを参照してください。例えば:

(g
"99999999                                              Print G.
999 99                                                Set triple-nine to ninety-nine.
9999999999 9999999999 9999999999 99 99 9 9 999 999    Set 10-nine to zero.
99999999999 9999999999                                Set 11-nine to zero.





999                                                   Print triple-nine's value divided by nine. (This is the ninth line.)
99999999                                              Print G.
999 999 9                                             Subtract nine from triple-nine.
 99999 999                                            Jump to line 5-nines if triple-nine is zero (endsprogram).
 9 99999999999 9999999999                             Jump to line nine if 10-nine and 11-nine are zero (alwa

")

結果のコードは次のとおりです。

(LET (@
      (V5 11111)
      (V11 11111111111)
      (V1 1)
      (V10 1111111111)
      (V2 11)
      (V3 111)
      (V8 11111111))
  (TAGBODY
   L0
    (PRINC (CODE-CHAR (MOD V8 128)))
    (SETF V3 (- (+ V2) 0))
    (SETF V10 (- (+ V3 V1 V2 V10) V3 V1 V2 V10))
    (SETF V11 (- (+ V10) 0))
   L1
    (PRINC V3)
    (PRINC (CODE-CHAR (MOD V8 128)))
    (SETF V3 (- (+ V3) V1))
    (WHEN (EVERY 'ZEROP (LIST V3)) (SETF @ V5) (GO ^))
    (WHEN (EVERY 'ZEROP (LIST V11 V10)) (SETF @ V1) (GO ^))
    (GO >)
   ^
    (CASE @ (0 (GO L0)) (1 (GO L1)))
   >))

実行すると、「G11G10G9G8G7G6G5G4G3G2G1G」が印刷されます

コマンドライン

コアをダンプしてtoplevel関数を指定することにより、実行可能ファイルをビルドできます。boot.lispを置く場所という名前のファイルを定義しdefmacro、次のように記述します。

(defun main()(parse-99 <PROGRAM>))
(save-lisp-and-die "test-99" :executable t :toplevel #'main)

実行sbcl --load boot.lispすると、次の出力が得られます。

$ sbcl --load boot.lisp 
This is SBCL 1.2.8.32-18c2392, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
[undoing binding stack and other enclosing state... done]
[saving current Lisp image into test-99:
writing 5824 bytes from the read-only space at 0x20000000
writing 3120 bytes from the static space at 0x20100000
writing 55771136 bytes from the dynamic space at 0x1000000000
done]

次に、コンパイルされた99プログラムを実行します。

$ time ./test-99
G11G10G9G8G7G6G5G4G3G2G1G
real    0m0.009s
user    0m0.008s
sys     0m0.000s

99本

興味のある方は、ここに書かれた99瓶プログラムのコンパイルされたコードであるMacの答えhttp://pastebin.com/ZXe839CZは(これは古い我々が持っているバージョンであるjmpendラベル、周囲のラムダときれい算術)。

以下は、それがまだ機能することを証明するために、新しいバージョンでの実行です:http : //pastebin.com/raw.php?i=h73q58FN


6

TI-84の基本的な(電卓スクリプト)、376の 373 377 381バイト

TI-84計算機で実行すると、標準化されたテストで使用できるようになります...ので便利です;)

オペレーティングシステムの最小バージョン-合計シグマによる2.53MP(MathPrint)

#Get input from STDIN
:Ans+":"->Str0
#Initialize instruction pointer
:1->I
#Initialize variable set
:DelVar L1999->dim(L1
#Strip out those pesky non-newline/space/9 characters
:For(J,1,length(Ans
:sub(Str0,J,1
:If not(inString(": 9",Ans
:sub(Str0,1,J-1)+sub(Str0,J+1,length(Str0)-J->Str0
:End
#Main interpreting loop
:While I<length(Str0
:sub(Str0,I+1,inString(Str0,":",I+1)-I-1->Str1
:DelVar A" "=sub(Ans,1,1->A
:inString(Str0,":",I+1->I
:If A
:sub(Str1,2,length(Str1)-1->Str1
:End
:length(Str1->L
#0 is Output, 1 is Input, 2 is Assignment, 3 is Goto
:2A+inString(Str1," ->B
:If not(Ans
:Disp L1(L
:If Ans=1
:Then
:Input C
:C->L1(L
:End
#Get those delimited variables
:If B>1
:Then
:"{"+Str1->Str2
:While inString(Ans," 
:inString(Ans," 
:sub(Str2,1,Ans-1)+sub(Str2,Ans+1,length(Str2)-Ans->Str2
:End
:log(expr(Ans)+1->L2
:End
:If B=2
#Gotta expand that -+ pattern
:Ans(2->L1(Ans(1
;Love that summation Σ
:If B=3 and Σ(L2(K),K,2,dim(L2
:Then
:DelVar IFor(K,0,9L2(1
:inString(Str0,":",I+1->I
:End
:End

PS ASCIIのガイドラインに正確に準拠することはできませんでしたが、TI-Basic :では改行です。したがって、コード内のすべての実際の改行は、各行の先頭:または#先頭が不要であることを意味します。最初のトークンは:#コメントとコードを区別するだけです。

オリジナルの16進ダンプ(376バイト)

49 3f bb 54 5d 20 39 39 39 04 b5 5d 20 3f 72 04 aa 09 3f d3 4a 2b 31 2b bb 2b 72 3f bb 0c aa 09 2b 4a 2b 31 3f ce b8 bb 0f 2a 3e 29 39 2a 2b 72 3f bb 0c aa 09 2b 31 2b 4a 71 31 11 70 bb 0c aa 09 2b 4a 70 31 2b 72 71 4a 04 aa 09 3f d4 3f d1 49 6b bb 2b aa 09 3f bb 0c aa 09 2b 49 70 31 2b bb 0f aa 09 2b 2a 3e 2a 2b 49 70 31 11 71 49 71 31 04 aa 20 3f bb 54 41 2a 29 2a 6a bb 0c 72 2b 31 2b 31 04 41 3f bb 0f aa 09 2b 2a 3e 2a 2b 49 70 31 04 49 3f ce 41 3f bb 0c aa 20 2b 32 2b bb 2b aa 20 11 71 31 04 aa 20 3f d4 3f bb 2b aa 20 04 4c 3f 32 41 70 bb 0f aa 20 2b 2a 29 04 42 3f ce b8 72 3f de 5d 20 10 4c 11 83 39 3f ce 72 6a 31 3f cf 3f dc 43 3f 39 43 04 5d 20 10 4c 3f d4 3f ce 42 6c 31 3f cf 3f 2a 08 2a 70 aa 20 04 aa 01 3f d1 bb 0f 72 2b 2a 29 3f bb 0f 72 2b 2a 29 3f bb 0c aa 01 2b 31 2b 72 71 31 11 70 bb 0c aa 01 2b 72 70 31 2b bb 2b aa 01 11 71 72 04 aa 01 3f d4 3f c0 bb 2a 72 11 70 31 04 5d 01 3f d4 3f ce 42 6a 32 3f 72 10 32 04 5d 20 10 72 10 31 3f ce 42 6a 33 40 ef 33 5d 01 10 4b 11 2b 4b 2b 32 2b b5 5d 01 3f cf 3f bb 54 49 d3 4b 2b 30 2b 5d 01 10 31 3f bb 0f aa 09 2b 2a 3e 2a 2b 49 70 31 04 49 3f d4 3f d4 2e 76

編集#1 - Macの観測 を使用して最適化された3バイト編集#2および#3 -Runer112によって発見されたバグを修正しました。


11
標準化されたテストのようなストレスの多い状況で使いやすくすることは、まさに99のために設計したものです。
カルバンの趣味

1
#コメントにのような別の文字を使用することを提案できますか?(注:実際のコードのコメントは、閉じられていない文字列のみの行として実装され、Ansを破壊します)
-Riking

8
実際にこれを実行してみましたか?私はまだ知りませんが、もう少し見てみると、少なくとも半ダースのバグと思われるものを見つけました。たとえば、変数は値で初期化されず、Ans入力が上書きされるためAns->Str0、6行目でエラーが発生します。sub()コマンドの長さ引数がゼロになる可能性がある複数のインスタンスがあり、エラーが発生します。11 Ans行目は文字列ですだからAns-Jエラーになります...そして、私はプログラムの前半だけを見ました。
Runer112

1
@Timtechただし、他の問題は残っています。前述したように、文字I / Oの欠如、変数の初期化の欠如、およびsub()コマンドの長さがゼロでエラーをスローする可能性のある複数のインスタンスがあります。そして、sub()呼び出しが修正されると、より多くの問題が明らかになる可能性があると思います。
Runer112

1
@Timtech私はこれについて言及していました。「デフォルトでは、各変数は独自の数値表現に割り当てられます。再割り当てされていない限り、変数の値は99で、変数の値は9999です。等々。" また、長さ0の文字列はなどの手段で生成できますが""、基本的には、文字列操作コマンドがを含む空の文字列を消費または生成できないというバグですsub()
Runer112

5

C 426458 481 497

編集多分私は行き過ぎですが、これはVisual Cで動作します:stopen.hを削除し、fopenとgetcにFILE *の代わりにintを使用します

編集2の実行手順の順序を変更し、より整理し、32文字を保存しました

B[99999],*r,*i[9999],V[999],v,w,m,n;unsigned p,s;
main(b,a)char*a[];{r=i[0]=B;m=fopen(a[1],"r");
do if(w=getc(m),n+=w==57,w<33){
if(n){for(v=1,b=n;--b;)v=v*10+1;V[n]=v;*r++=p?-n:n;b=n=0;};
w-32?(*r=p=0,b=i[++s]=++r):(p=b,b=0);}while(w>=0);
while(p<s)if(w=0,r=i[p++],v=*r++)
if(m=v>0,*r){for(;b=*r++;m=-m)w=w+m*V[b]|!m*V[b];m?V[v]=w:(p=w?p:9*V[-v]);
}else~v&1?!m?V[-v]=getchar():putchar(V[v]&127):m?printf("%d",V[v]):scanf("%d",V-v);
}

スタンドアロンのコンソールプログラム、コマンドラインで取得したプログラム名、およびコンソールを介した入出力。

古いスタイルのK&R、グローバル変数およびパラメーターのデフォルトの型int。EOFが-1として定義されていると仮定します(私が知っているすべてのC実装でそうです)

Visual Studio 2010で警告付きでコンパイルします(Win32コンソールC ++プロジェクト、Cとしてコンパイル)Ideoneでコンパイルしますが、ファイルが必要なので実行できません。

最初のステップでは、ソースコードが読み取られて解析され、各行は9の数に基づいて整数のシーケンスとして格納されます。先行ブランクがある場合、最初の数値は負です。だから、: 9 BLAH 99 9a9bb9c9(は9 99 9999)となり-1,2,4 ショートカットがあります-ので、有効ではありません:「」とみなされる改行以外のすべてのASCIIコード少ないです。

このステップでは、使用されるすべての変数が事前初期化されます。

実行ステップは仕様に従い、フリルはなく、保存数を9で割って保存します。

より読みやすい同じコード(私は願っています)、スペースと改行が追加されました

B[99999],*r,*i[9999],V[999],v,w,m,n;
unsigned p,s;
main(b,a)char*a[];
{
  r=i[0]=B;
  m=fopen(a[1],"r");
  do if(w=getc(m),n+=w==57,w<33)
  {
     if(n){for(v=1,b=n;--b;)v=v*10+1;V[n]=v;*r++=p?-n:n;b=n=0;};
     w-32?(*r=p=0,b=i[++s]=++r):(p=b,b=0);
  }
  while (w>=0);
  while (p<s)
    if (w = 0, r = i[p++], v = *r++)
        if (m = v > 0, *r){
            for(; b = *r++; m = -m)
                w = w + m*V[b] | !m*V[b];
            m ? V[v]=w : (p = w ? p : 9*V[-v]);
        } else
            ~v & 1 
            ? !m ? V[-v] = getchar() : putchar(V[v] & 127)  
            : m ? printf("%d", V[v]) : scanf("%d", V - v);
}

1
GCC 4.8.2でも動作します。C99としてコンパイルします!
エンブレム

4

Haskell、550バイト

import Data.List.Split
import System.Environment
a#b=takeWhile(/=a)b
(!)=map
main=do(f:_)<-getArgs;readFile f>>=e.(p!).lines
p l=(if ' '#l<'9'#l then[0]else[])++length!(wordsBy(/='9')l)
e l=(\x->div(10^x-1)9)%l where
 _%[]=return()
 v%([]:r)=v%r
 v%([n]:r)=putStr(if odd n then show(v n)else[toEnum$v n`mod`128])>>v%r
 v%([0,n]:r)=do i<-getLine;u n(if odd n then read i else fromEnum$head i)v%r
 v%((0:n:m):r)|any(/=0)(v!m)=v%r|v n<0=v%[]|1<2=v%drop(9*v n)l
 v%((n:m):r)=u n(sum$zipWith(*)(v!m)(cycle[1,-1]))v%r
u n i v= \x->if x==n then i else v x

ファイルに「countdown」プログラムを保存して実行する例 i.99

$ ./99 i.99
G11G10G9G8G7G6G5G4G3G2G1G

ゴルフされていないバージョン:

import Data.List.Split
import System.Environment

-- The main function takes the first command line argument as a file name,
-- reads the content, splits it into lines, parses each line and evaluates
-- the list of parsed lines.
main = do
 (f:_)<-getArgs
 readFile f >>= eval.map parse.lines

-- each line is coverted into a list of integers, which represent the number
-- of 9s (e.g. "999 99 9999" -> [3,2,4]). If there's a space before the first
-- 9, a 0 is put in front of the list (e.g. " 9 9 999" -> [0,1,1,3]).
parse l = (if takeWhile (/=' ') l < takeWhile (/='9') l then [0] else [])
   ++ map length (wordsBy(/='9') l)

-- The work is done by the helper function 'go', which takes two arguments
--   a) a functions which takes an integer i and returns the value of the
--      variable with i 9s (e.g: input: 4, output: value of 9999). To be
--      exact, the value divided by 9 is returned.
--   b) a list of lines to work on
-- 'eval' starts the process with a function that returns i 1s for every i and
-- the list of the parsed input. 'go' checks which statement has to be
-- executed for the next line and calls itself recursively
eval list = go (\x -> div (10^x-1) 9) list
   where
   go _ []                  = return ()
   go v ([]:r)              = go v r
   go v ([n]:r)             = putStr (if odd n then show(v n) else [toEnum (v n`mod`128)]) >> go v r
   go v ([0,n]:r)           = do i<-getLine ; go (update n (if odd n then read i else fromEnum$head i) v) r
   go v ((0:n:m):r)
      | any (/=0) (map v m) = go v r
      | v n < 0             = go v []
      | otherwise           = go v (drop (9*v n) list)
   go v ((n:m):r)           = go (update n (sum $ zipWith (*) (map v m) (cycle[1,-1])) v) r

-- updates a function for retrieving variable values.
-- n = position to update
-- i = new value
-- v = the function to update
update n i v = \x->if x==n then i else v x

4

JavaScriptの(ES6)340 352

2つのパラメーターを持つ関数

  • 複数行の文字列としてのプログラムコード
  • 配列として入力

3番目のオプションのパラメーター(デフォルトは10k)は、反復の最大数です-永久に実行されるプログラムは好きではありません

JSFiddleテストする

I=(c,i,k=1e5,
  V=v=>v in V?V[v]:v/9 // variable getter with default initial value
)=>(c=>{
 for(p=o='';--k&&p<c[L='length'];)
   (v=(r=c[p++].split(' '))[S='shift']())? // no leading space
      r[r.map(t=>w-=(m=-m)*V(t),w=0,m=1),0]?V[v]=w // Assign
      :o+=v[L]&1?V(v):String.fromCharCode(V(v)&127) // Output
   : // else, leading space
    (v=r[S]())&&
       (r[0]?r.some(t=>V(t))?0:p=9*V(v) // Goto
       :(t=i[S](),V[v]=v[L]&1?t:t.charCodeAt()) // Input
    )
})(c.replace(/ (?=[^9])|[^9\s]/g,'').split('\n'))  // code cleaning
||o

4

q / k、490 469

M:mod;T:trim;R:read0;S:set;s:" "
f:(rtrim')(f:R -1!`$.z.x 0)inter\:"9 \n"
k)m:{@[x;&M[!#x;2];-:]}
b:{}
k)p:{1@$$[1=M[#x;2];(K x)%9;"c"$M[(K x)%9;128]];}
k)i:{S[(`$T x);$[1=M[#T x;2];9*"J"$R 0;*9*"i"$R 0]]}
k)K:{$[#!:a:`$x;.:a;"I"$x]}
k)v:{(S).(`$*:;+/m@K'1_)@\:T's\:x}
k)g:{$[&/0=C:K'c:1_J:s\:T x;n::-1+K@*J;|/~0=C;;(d<0)|(d:*C)<#f;exit 0]}
k)r:{`b`p`i`v`g@*&(&/x=s;q&1=c;(e~s)&1=C;(q:e~"9")&1<c:#s\:x;((e:*x)~s)&1<C:#s\:1_x)}
k)n:0;while[~n>#o:(r')f;(o n)f n;n+:1]
\\

$ q 99.q countdown.txt -q
G11G10G9G8G7G6G5G4G3G2G1G

スクリプトはqとkの混合物なので、最初に、k個の関数で複数回使用したいいくつかのqキーワードを定義します。(基本的には#defineマクロ)

M:mod;T:trim;R:read0;S:set

f プログラムに渡されたファイルを読み取り、不要な文字を取り除きます

q)f
"99999999"
"999 99"
"9999999999 9999999999 9999999999 99 99 9 9 999 999"
"99999999999 9999999999"
""
""
""
""
""
"999"
"99999999"
"999 999 9"
" 99999 999"
" 9 99999999999 9999999999"

m リスト/ベクトルを受け取り、奇数のインデックスに-1を掛けます

q)m 1 2 3 4 5
1 -2 3 -4 5

b no-op行に使用される単なる空の関数です

p は印刷機能です。

K変数を調べる関数です。変数が存在する場合はそれを返し、そうでない場合は単にリテラルを返します。

//999 not defined, so just return 999
q)K "999"
999
//Set 999 to 9
q)v "999 9"
//K now returns 9
q)K "999"
9

v 割り当て関数です。

g goto関数です。

r 文字列を受け取り、どの操作を適用する必要があるかを決定します。

そして最後に、反復子として、f文字列のリストを繰り返し処理しnます。goto関数はn必要に応じて更新されます。


3

Perl、273 266 255 244 238

明確にするために改行が追加されました。

open A,pop;
for(@c=<A>){
y/ 9//cd;s/ +/ /g;s/ $//;
$p="((99)+|9+)";$a='+';
s/^ $p$/$1='$2'?ord<>:<>/;
s/^$p$/print'$2'?chr$1%128:$1/;
s/^ $p /\$_=$1*011unless/&&y/ /|/;
s/ /=/;s/ /$a=-$a/ge;
s!9+!${x.$&}=$&/9;"\$x$&"!eg}
eval$c[$_++]until/-/|$_>@c

コマンドラインで取得したプログラム名:

$ perl 99.pl 99beers.99

プログラムの各行は、たとえば次のようなPerlコードに変換されます。

print'$x99'?chr$x99999999%128:$x99999999
$x999=$x99
$x9999999999=$x9999999999-$x9999999999+$x99-$x99+$x9-$x9+$x999-$x999
$x99999999999=$x9999999999





print''?chr$x999%128:$x999
print'$x99'?chr$x99999999%128:$x99999999
$x999=$x999-$x9
$_=$x99999*011unless$x999
$_=$x9*011unless$x99999999999|$x9999999999

詳細

open A,pop; # open the source file
for(@c=<A>){ # read all lines into @c and iterate over them
y/ 9//cd; # remove all but spaces and 9's
s/ +/ /g;s/ $//; # remove duplicate and trailing spaces
$p="((99)+|9+)";$a='+';
s/^ $p$/$1='$2'?ord<>:<>/; # convert input
s/^$p$/print'$2'?chr$1%128:$1/; # convert output
s/^ $p /\$_=$1*011unless/&&y/ /|/; # convert goto
s/ /=/;s/ /$a=-$a/ge; # convert assignment
s!9+!${x.$&}=$&/9;"\$x$&"!eg} # initialize and convert variables
eval$c[$_++]until/-/|$_>@c # run (program counter is in $_)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.