写一个99的翻译


99

99(读作“九十九”)是一种全新的Esoteric编程语言(请不要与99混淆,请注意斜体)。您在此挑战中的任务是为99写一个尽可能短的解释器。字节最少的提交将获胜。Tiebreaker转到第一个发布的提交。

由于这个问题比平时更深入,而且我渴望看到好的答案,因此,我将奖励我最喜欢的答案250 rep赏金(不一定是获胜者)。

99规格

99命令式语言。99程序中的每一行都是一条语句,并且在执行过程中,指令指针从第一行开始,依次遍历每行后续的行,并一路执行。当执行了最后一行时,程序结束。Goto语句可能会重新路由指令指针的路径。

换行符,空格和9是在99程序中唯一重要的三个字符。所有其他字符将被完全忽略。此外,每行上的尾随空格都将被忽略,并且一行中的多个空格将被视为一个空格。(“换行符”是指任何常见的换行编码。您的解释器使用哪种都没有关系。)

所以这个程序:

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

与此程序相同:

 9 99 9999
9 9

变数

99中的变量都具有一个或多个9串在一起的名称(9+在正则表达式中)。例如9999999999999是完全不同的变量。自然地,存在无限多个(除非存在内存限制)。

每个变量的值是一个有符号的任意精度整数。默认情况下,每个变量都分配给自己的数字表示形式。因此,除非已将其重新分配,否则变量的值9是数字9,变量的值99是数字99,依此类推。您可以将其视为在将变量明确分配之前将其视为纯数字。

我将V在下面用于指代任意变量名称。
的每个实例V可以替换为9999999999,等。

陈述

99中有五种不同的语句类型。每行99个程序中的包含一个语句。

此处描述的语法假定所有多余字符均已删除,所有尾随空格均已删除,多个空格的所有序列均已替换为单个空格。

1.无操作


空行是无操作。它什么都不做(除了增加指令指针)。

2.输出

V

V一行上的单个变量会将其打印到stdout。

如果V具有的奇数99999等)V,则将打印除以9 的整数(十进制)。

如果V具有偶数9999999等),则将打印代码除以9 的ASCII字符Vmod 128。(即(V / 9) % 128介于0到127之间的值。)

示例:程序

9
9999

将打印1W。第一行打印1是因为9/9是1。第二行打印W是因为9999/9是1111,而1111 mod 128是87,而87是的字符代码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.作业

该语句可以任意长。它是一行上的两个或多个变量,以空格分隔:

V1 V2 V3 V4 V5 ...

这会将所有具有偶数索引的的总和减去具有奇数索引的的总和(不包括)。分配是按值而不是参考。V1VVV1

它可以翻译成大多数语言 V1 = V2 - V3 + V4 - V5 + ...

因此,如果只有两个变量,则为正常分配:

V1 V2V1 = V2

如果有三个,则减去:

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.转到(如果全为零则跳转)

该语句也可以任意长。它是一行中的两个或多个变量,以空格隔开,并带有前导空格

 V1 V2 V3 V4 V5 ...

如果某些值不是零,则其行为就像无操作。指令指针照常移至下一行。V1

如果除此之外的所有均为零,则指令指针将移至行号。这些行的索引为零,因此如果为零,则指针将移至第一行。如果为负或大于最大可能索引(行数减一),程序将终止(通常无错误)。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 2015年

30
@WChargin貌似现在你必须设法得到它99
trlkly

5
当然,自托管也有好处(在99中编写99口译员),不是吗?
加布2015年

5
@Gabe这样的答案可能会得到赏金,但是如果那是唯一的答案,那么该解释器将如何解释?;)
卡尔文的爱好2015年

1
@Optimizer,它起作用了:pastebin.com/raw.php?
coredump

Answers:


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与匿名函数类似。该块在执行时需要程序字符串和堆栈上的输入列表。

初始化包括三个步骤。首先,保存输入列表。然后,删除程序中所有不有意义的字符,并将结果拆分为行列表并保存。最后,变量列表被初始化。此列表将按名称长度索引的每个变量映射为其值除以9(变量永远不能保存非9的倍数的值,除goto外的所有操作都将从此更改中受益)。该列表被初始化为最长的行的长度,这是当前最长的可变名称的上限。由于初始变量的值,还存在一些隐式初始化:行号为0,输入索引为-1。

解释器的实现与预期的一样:循环读取下一行,递增行号,并在该行号指向现有行时执行该行。行分析首先检查该行是否为空,然后根据Arity是1还是> 1进行分支,然后根据是否存在前导空格进行分支。这四个分支以最直接的方式模拟了四个操作(不包括无操作操作),尽管它像其他所有事物一样积极地打高尔夫球。可能需要注意的一个优化是,由于有效的输入序列应始终产生程序期望的类型的元素,因此我省略了根据变量名的长度对输入进行单独区分的情况。简单地假设从输入列表中读取的元素是预期的类型。


15
+1。很短。现在,您可以在99中编写CJam解释器吗?;-)
coredump

9
@coredump *
Runer112

该死的,我只能得到195,然后我失去了希望,放弃了:P
Optimizer

打印负值时,这不会采用正确的模数。可以通过替换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例程中以及获取变量的默认值时)。就语言的用户而言,这没有什么区别。
Mac

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)中不起作用。这篇技巧文章阐明了:一个数字后跟一个字母标记通常是有效的,但不适用于以e或开头的标记E,并且(从注释中)都不适用0or
DLosc

16

常见的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)>))))
  • 词法分析和代码生成交织在一起:我不存储内部表示,而是直接处理每一行。
  • 有一个tagbody可以执行2个循环:

     (... (tagbody % ... (go %) $ ... (go $)) result)
    
  • 局部变量在 &aux

  • 不生成闭包,而是直接生成解释代码
  • 等等

取消评论

(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个程序时,输入没有被完全清除:假定用户知道期望什么样的值。

跳转可能发生唯一的运行时开销,因为我们必须评估变量的值并将该值与标签匹配。除此之外,口译员将非常有效。

基于Mac的巧妙观察,我们不需要每次都除以9,因此当前版本在执行过程中不会除以9。

如果替换defmacrodefun,则会看到生成的代码。例如:

(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标签,周围的Lambda和漂亮算术)。

这是新版本的执行,以证明它仍然有效:http : //pastebin.com/raw.php?i=h73q58FN


6

TI-84基本(计算器脚本),376个 373 377 381字节

如果它在TI-84计算器上运行,则可以在标准化测试中使用它,因此非常有用;)

最低操作系统版本-2.53MP(MathPrint),由于求和sigma

#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中:是换行符。因此,代码中所有实际的换行符都意味着不需要每行的:#。起始令牌:#公正的意见和代码区分。

原始十六进制转储(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的设计中正是要在标准化测试等压力较大的情况下易于使用。
加尔文的爱好2015年

1
我可以建议使用其他字符(例如#)作为注释吗?(注意:实际代码中的注释被实现为仅包含未封闭字符串的行,从而使Ans变得很陈词滥调)
Riking

8
您是否真的尝试过运行此程序?我还没有,但是从更多的角度来看,我发现了似乎至少有六个bug。例如:变量未使用其值初始化,Ans输入被覆盖,因此Ans->Str0第6行将出错,在多个实例中,sub()命令的length参数可以为零,这将导致错误,Ans第11行将为字符串所以Ans-J会出错...而且我只看了程序的前半部分。
Runer112

1
@Timtech但是,仍然存在其他问题。正如我所提到的,缺少字符I / O,缺少变量初始化以及sub()命令可以具有零长度并引发错误的多个实例。一旦sub()调用固定,恐怕它可能会发现更多问题。
Runer112

1
@Timtech我指的是:“默认情况下,每个变量都分配有其自己的数字表示形式。因此,除非已将其重新分配,否则变量9的值为9,而变量的99值为99,等等。” 长度为0的字符串可以通过诸如此类生成"",但这是一个错误,基本上没有字符串操作命令可以消耗或产生空字符串,包括sub()
Runer112

5

C 426458481497

编辑也许我走得太远了,但是这与Visual C兼容:删除了stdio.h,使用int而不是FILE *作为fopen和getc

编辑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上进行编译,但由于需要文件而无法运行。

第一步,读取并解析源​​代码,将每行存储为基于9s的整数序列。如果有前导空白,则第一个数字为负。所以:9 BLAH 99 9a9bb9c99 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!
EMBLEM 2015年

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

使用文件中存储的“倒数”程序运行的示例 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个参数的函数

  • 程序代码为多行字符串
  • 输入为数组

第三个可选参数(默认为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 只是一个空函数,用于无操作行

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 $_)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.