99의 통역사를 작성하십시오


99

99 ( "90-nine"으로 발음)는 완전히 새로운 밀교 프로그래밍 언어입니다 ( 99 와 혼동하지 말고 기울임 꼴을 참고하십시오). 이 도전에서 당신의 임무는 가능한 한 짧은 99 통역사를 작성하는 것입니다. 가장 적은 바이트를 가진 제출이 이깁니다. Tiebreaker는 먼저 게시 된 제출물로 이동합니다.

이 질문은 평소보다 조금 더 깊이 있고, 좋은 답변을보기를 간절히 원하므로, 내가 가장 좋아하는 답변 (승자 일 필요는 없음)에 250 명의 보상 현상금을 수여 할 것입니다.

99 사양

99필수 언어입니다. 99 프로그램의 각 줄은 단일 명령문 이며 실행 중에 명령 포인터는 맨 위 줄에서 시작하여 이후의 각 줄을 차례로 통과하여 실행합니다. 마지막 행이 실행되면 프로그램이 종료됩니다. Goto 문은 명령어 포인터의 경로를 다시 지정할 수 있습니다.

줄 바꿈, 공백 및 99 프로그램 9에서 중요한 유일한 세 문자입니다 . 다른 모든 문자는 완전히 무시됩니다. 또한 각 줄의 후행 공백은 무시되고 행의 여러 공백은 하나의 공백으로 읽 힙니다. ( "줄 바꿈"은 일반적인 줄 바꿈 인코딩을 의미 합니다. 통역사가 사용하는 것은 중요하지 않습니다.)

따라서이 프로그램 :

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

이 프로그램과 동일합니다 :

 9 99 9999
9 9

변수

의 변수 (99) 모두가 하나 더 있습니다 이름이 9(함께 중독 's의 9+정규식을). 예를 들어 9, 999999999999모든 별개의 변수입니다. 당연히 메모리 제한이 거의 없습니다.

각 변수의 값은 부호있는 임의 정밀도 정수입니다. 기본적으로 각 변수는 고유 한 숫자 표현에 할당됩니다. 따라서 다시 지정하지 않으면 변수의 값은 9숫자 9이고 변수의 값은 99숫자 99 등입니다. 변수가 명시 적으로 할당 될 때까지 변수를 일반 숫자로 취급하는 것으로 생각할 수 있습니다.

V아래에서 임의의 변수 이름을 참조하는 데 사용 합니다.
의 각 인스턴스 V로 대체 할 수있다 9, 99, 999, 9999, 등

진술

99 에는 다섯 가지 문 유형이 있습니다. 99 프로그램의 각 행 에는 정확히 하나의 명령문이 있습니다.

여기에 설명 된 구문은 모든 관련없는 문자가 제거되고 모든 후행 공백이 제거되었으며 여러 공백의 모든 시퀀스가 ​​단일 공백으로 대체되었다고 가정합니다.

1. 조작 없음


빈 줄은 no-op 입니다. 명령 포인터를 증가시키는 것 외에는 아무 것도 수행하지 않습니다.

2. 출력

V

V라인 의 단일 변수 는 해당 변수를 stdout에 인쇄합니다.

경우 V홀수 갖는 9S '( 9, 999다음 등)의 정수 값 V(십진수)를 인쇄한다 (9)에 의해 분할한다.

경우 V짝수 갖는 9S '( 99, 9999등) 다음 아스키 코드 문자 V9로 나눈 값을 개조 (128)가 인쇄된다. (이것은 (V / 9) % 1280에서 127 사이의 값입니다.)

: 프로그램

9
9999

인쇄 1W합니다. 첫 번째 줄은 19/9가 1이므로 인쇄합니다 . 두 번째 줄은 W9999/9가 1111이고 1111 mod 128이 87이고 87이에 대한 문자 코드이기 때문에 인쇄 합니다 W.

줄 바꿈은 출력 토큰 사이에 인쇄되지 않습니다. \n줄 바꿈을 위해 명시 적으로 인쇄해야합니다.

3. 입력

 V

선행 공백V있는 행 의 단일 변수 는 stdin에서 입력을 가져 와서 해당 변수에 저장합니다.

V수가 홀수이면 9사용자는 부호있는 정수를 입력 V할 수 있으며 해당 값의 9 배로 설정됩니다.

경우 V의 짝수 번호가 9의 다음 사용자는 ASCII 문자를 입력 할 수 있으며, V9 배 문자 코드로 설정됩니다.

: 주어 -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. Goto (모두 0 인 경우 점프)

이 진술은 또한 임의로 길 수 있습니다. 행에 두 개 이상의 변수이며 공백으로 구분되며 선행 공백이 있습니다 .

 V1 V2 V3 V4 V5 ...

이외의 값 중 일부가 0이 아닌 경우 이는 no-op처럼 동작합니다. 명령 포인터는 평소와 같이 다음 줄로 이동합니다.V1

경우 모든 값이 또한 있다 제로 다음 명령어 포인터 번호를 일렬로 이동된다 . 선은 0으로 색인화되므로 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 번째 도전 을 즐겼 기를 바랍니다 ! :디


9
나는
투표를

30
@WChargin은 지금 당신이 99를 얻으려고 노력해야 할 것 같습니다.
trlkly

5
확실히 자기 호스팅 (쓰기에 대한 보너스 거기에 99 에서 통역 99 ), 아니?
Gabe

5
@Gabe 그런 대답은 아마도 현상금을받을 것입니다. 그러나 그것이 유일한 대답이라면, 통역사는 어떻게 해석 할 것입니까? ;)
Calvin 's Hobbies

답변:


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 통역사를 작성할 수 있습니까? ;-)
코어 덤프 16:10에

9
@coredump *
Runer112

젠장, 난 단지 195를 얻을 수 있고 희망을 잃고 포기했다 : P
Optimizer

음수 값을 인쇄 할 때 올바른 모듈로를 사용하지 않습니다. 로 교체 128%하여 해결할 수 있습니다 128,=.
Martin Ender

26

파이썬 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 병"의 (오히려 가난한) 구현의 99 : http://pastebin.com/nczmzkFs


1
@DLosc : 첫 번째 포인트와 관련하여 : else숫자도 제거 할 수는 있지만 이전에 시도했을 때 구문 오류가 발생했습니다. 그래도 다른 팁은 대단히 감사합니다!
Mac

3
@coredump : 스펙이 작성되는 방식에 따라 각 변수는 항상 9로 나눌 수있는 값을 갖습니다. 변수가 어떤 값 을 취하고 필요에 따라 (특히 goto루틴에서 그리고 변수의 기본값을 가져올 때) 9로 곱하기 / 나누는 것이 더 간결하다는 것을 알았습니다 . 언어 사용자에 관한 한 아무런 차이가 없습니다.
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)에서는 작동하지 않습니다. 이 팁 게시물은 다음과 같이 설명합니다. 알파벳 알파벳 뒤에 오는 숫자는 일반적으로 작동하지만 또는로 시작하는 토큰 에는 적합 하지 않으며 (댓글에서) 그렇지 않습니다 . eE0or
DLosc

16

커먼 리스프, 1180 857 837 836 바이트

나는 이것이 이길 수 없다는 것을 알고 있지만, 나는이 골프를 즐겁게했습니다. CJam에서 작성한 99 개 이상의 인터프리터 인 343 바이트를 제거 했습니다.

또한 매우 재미있게 압축을 시도할수록 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

  • 클로저를 생성하지 않고 직접 해석 된 코드
  • 기타

언 골프, 댓글

(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 개의 프로그램을 실행할 때 입력이 완전히 위생 상태가되지는 않습니다 . 사용자는 어떤 종류의 값이 필요한지 알고 있다고 가정합니다.

변수 값을 평가하고 해당 값을 레이블과 일치시켜야하기 때문에 점프 할 때 가능한 런타임 오버 헤드 만 발생할 수 있습니다. 그 외에는 통역사가 매우 효율적이어야한다.

영리한을 기반 맥에서 obseravtion 우리가 때마다 분할하고 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)

Running 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 병의 프로그램의 컴파일 된 코드입니다 맥의 대답 : 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 를 디자인 한 것 입니다.
Calvin 's Hobbies

1
#댓글에 다른 문자를 사용하는 것이 좋습니다 . (NB : 실제 코드의 주석은 닫히지 않은 문자열 만있는 행으로 구현되어 Ans를
방해합니다

8
실제로 이것을 시도 했습니까? 나는 그것을 보지 못했지만 조금 더 살펴보면 적어도 6 개 이상의 버그가있는 것을 발견했습니다. 예를 들어, 변수가 값으로 초기화되지 않고 Ans입력이 덮어 써서 Ans->Str06 행에서 오류가 발생하며 sub()명령 의 길이 인수 가 0 일 수있는 오류가있는 여러 인스턴스 Ans가 있으며 11 행에서 문자열이됩니다. 그래서 Ans-J... 오류가 발생하지 그리고 나는 단지 프로그램의 첫 번째 절반에 대해 보았다.
Runer112

1
@Timtech 그래도 여전히 다른 문제는 남아 있습니다. 앞에서 언급했듯이 문자 I / O 부족, 변수 초기화 부족 및 sub()명령이 길이가 0이고 오류가 발생할 수있는 여러 인스턴스 가 있습니다. 그리고 일단 sub()호출이 수정되면 더 많은 문제가 드러 날까 걱정됩니다.
Runer112

1
@Timtech 저는 이것을 언급했습니다. "기본적으로 각 변수는 고유 한 숫자로 표시됩니다. 따라서 다시 할당하지 않으면 변수의 값은 9숫자 9이고 변수의 값은 99숫자 99입니다. 등등." 길이가 0 인 문자열은과 같은 방법으로 생성 할 수 ""있지만 기본적으로 문자열 조작 명령이 빈 문자열을 소비하거나 생성 할 수없는 버그입니다 sub().
Runer112

5

C 42645881 497

편집하다 어쩌면 너무 멀리 가고 있지만 이것은 Visual C에서 작동합니다. fdio 및 getc에 FILE * 대신 int를 사용하여 stdio.h를 제거했습니다.

편집 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로 컴파일!
EMBLEM

4

하스켈, 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

자바 스크립트 (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 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합니다. n필요에 따라 goto 기능이 업데이트 됩니다.


3

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.