Напишіть перекладача для 99


99

99 (вимовляється "дев'яносто дев'ять") - це абсолютно нова мова програмування езотерики (не плутати з 99 , зверніть увагу на курсив). Ваше завдання в цьому виклику - написати перекладача на 99, який є максимально коротким. Виграє подання з найменшими байтами . Tiebreaker переходить до подання, розміщеного першим.

Оскільки це питання трохи глибше, ніж зазвичай, і я хочу бачити хороші відповіді, я буду нагороджувати улюбленою відповіддю у розмірі 250 реп. (Не обов'язково переможця).

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+у регулярному вираженні). Так , наприклад, 9, 99і 9999999999всі різні змінні. Природно, їх нескінченно багато (обмеження обмеження пам'яті).

Значення кожної змінної - це підписане ціле число довільної точності . За замовчуванням кожній змінній присвоюється власне числове представлення. Отже, якщо вона не була перепризначена, значення змінної 9- це число 9, а значення змінної 99- це число 99 тощо. Ви можете подумати про це як про обробку змінних як прості числа, поки вони не будуть явно призначені.

Я буду використовувати Vдля позначення довільної назви змінної нижче.
Кожен екземпляр Vможе бути замінений 9, 99, 999, 9999і т.д.

Заяви

У 99 є п'ять різних типів операторів . Кожен рядок програми 99 містить рівно один вислів.

Синтаксис, описаний тут, передбачає, що всі сторонні символи були видалені, всі пробіли були видалені, а всі послідовності декількох пробілів були замінені на одиничні пробіли.

1. Немає операції


Порожній рядок - неоперативний . Він нічого не робить (крім збільшення покажчика інструкції).

2. Вихід

V

Одна змінна Vв рядку друкує цю змінну для stdout.

Якщо Vмає непарне число 9's ( 9, 999тощо), то Vдрукується ціле значення, поділене на 9 (у десятковій кількості).

Якщо Vмає парне число 9's ( 99, 9999і т.д.), то символ ASCII з кодом, Vрозділеним на 9, mod 128 буде надруковано. (Це (V / 9) % 128значення від 0 до 127.)

Приклад : Програма

9
9999

надрукував би 1W. Перший рядок друкується, 1оскільки 9/9 дорівнює 1. Другий рядок друкується, Wоскільки 9999/9 - це 1111, а 1111 мод 128 - 87, а 87 - код символів для W.

Зверніть увагу, що розриви рядків не друкуються між вихідними маркерами. \nпотрібно чітко надрукувати для розриву рядка.

3. Введення

 V

Єдина змінна Vна рядку з провідним простором приймає вхід від stdin і зберігає його в цій змінній.

Якщо Vмає непарне число 9's, то користувач може ввести будь-яке підписане ціле число і Vбуде встановлено в 9 разів більше цього значення.

Якщо Vмає парне число 9's, то користувач може ввести будь-який символ ASCII і Vбуде встановлений у 9 разів більше його символьного коду.

Приклад : дана програма -57і Aяк вхідна програма

 9
9
 99
99

виведе -57A. Внутрішня змінна 9мала б значення -513 і 99мала б значення 585.

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

4. Призначення

Це твердження може бути довільним довгим. Це дві або більше змінних у рядку, розділених пробілами:

V1 V2 V3 V4 V5 ...

Це призначає суму всіх "s" з парними індексами, за вирахуванням суми "s" з непарними індексами (без урахування ). Призначення мають значення, а не посилання.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 (стрибок, якщо все нульове)

Це твердження також може бути довільним довгим. Це дві або більше змінних на лінії, розділених пробілами, з провідним пробілом :

 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's:

G11G10G9G8G7G6G5G4G3G2G1G

Додаткові відомості

Ідеальний перекладач буде працювати з командного рядка з ім'ям 99 програмного файлу як аргумент. Введення / виведення також буде виконано на льоту в командному рядку.

Однак ви можете просто написати функцію інтерпретатора, яка приймає в програмі як рядок, а також список вхідних жетонів (наприклад ["-57", "A"]). Функція повинна друкувати або повертати вихідний рядок.

Трохи різні способи роботи перекладача та обробки вводу-виводу є прекрасними, якщо ці можливості неможливі для вашої мови.


Бонус: Напишіть щось класне в 99 році, і я з радістю викладу це на цій посаді як приклад.


Сподіваюся, вам сподобався мій 99-й виклик! : D


9
Я розглядав питання проголошення, але ваш поточний бал - 9…
вхід

30
@WChargin виглядає так, що зараз вам доведеться спробувати його отримати 99.
trlkly

5
Напевно, є бонус за самостійний хостинг (написання 99 перекладача в 99 ), ні?
Гейб

5
@Gabe Така відповідь, ймовірно, отримала би нагороду, але якби це була єдина відповідь, що б інтерпретувало перекладача? ;)
Захоплення Кальвіна

1
@Optimizer це працює: pastebin.com/raw.php?i=h73q58FN
coredump

Відповіді:


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.

Інтерпретатор реалізований так, як можна було очікувати: цикл, який читає наступний рядок, збільшує номер рядка та виконує рядок, тоді як номер рядка вказує на існуючий рядок. Розбір рядків спочатку перевіряє, чи рядок не порожній, потім гілки залежно від того, чи є арить 1 або> 1, а потім гілки на основі того, чи був провідний пробіл. Ці чотири гілки імітують чотири (за винятком неоперативних) операцій здебільшого прямо, хоча й агресивно гольфують, як і все. Можливо, одна оптимізація зауваження полягає в тому, що, оскільки дійсна послідовність введення завжди повинна створювати елемент типу, який очікується програмою, я пропустив створення окремих випадків для введення на основі довжини імені змінної. Просто передбачається, що елемент, прочитаний зі списку вхідних даних, очікуваного типу.


15
+1. Досить короткий. Тепер ви можете написати інтерпретатора CJam в 99 ? ;-)
coredump

9
@coredump * здригається *
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 як єдиний аргумент (наприклад, останній приклад з ОП):

> python3 ninetynine.py countdown.txt
G11G10G9G8G7G6G5G4G3G2G1G
>

Як додатковий бонус, ось (досить погана) реалізація "99 пляшок" у 99 : http://pastebin.com/nczmzkFs


1
@DLosc: щодо вашого першого пункту: Я теж хоч і elseпісля номера може бути видалений, але коли я спробував це раніше, у мене з’явилася помилка синтаксису. Ваші інші поради дуже вдячні!
Мак

3
@coredump: у способі написання специфікації кожна змінна завжди матиме значення, яке ділиться на дев'ять. Я вважаю більш стислим дозволити змінним приймати будь-яке значення і лише помножувати / ділити на дев'ять за потребою (зокрема, в gotoрутині та при отриманні значення змінної за замовчуванням). Що стосується користувача мови, то це не має ніякого значення.
Мак

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))і отримав виняток синтаксису.
Мак

1
Незнайко - я протестував на ideone.com, і він працював, але ви маєте рацію, він не працює у фактичному інтерпретаторі Python3 (3.4.0 на Ubuntu). Цей підказка в поясненні пояснює: число, за яким в основному працює алфавітний маркер, але не для лексем, що починаються з eабо E, і (з коментарів) не для 0orжодного.
DLosc

16

Ліпп звичайний, 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

  • створюють не закриття, а безпосередньо інтерпретований код
  • тощо.

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)>))))

Ми використовуємо стандартні введення / виведення під час оцінювання, тобто ми використовуємо стандарт readі princфункції. Отже, отриманий код можна зробити виконаним у командному рядку, як показано нижче.

Введення даних не є повністю належним чином очищеним при виконанні 99 програм: передбачається, що користувач знає, які значення очікуються.

Єдиний можливий накладний час виконання може виникнути під час стрибків, оскільки ми повинні оцінити значення змінної і співставити це значення з міткою. Крім того, перекладач повинен бути досить ефективним.

Виходячи з розумної нав'язливості з Mac, що нам не потрібно ділити та множувати по 9 кожен раз, поточна версія примудряється ніколи не ділитися і не множуватися на 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 (це стара версія, де у нас є jmpі endмітки, навколишня лямбда і краща арифметика).

Ось виконання з новою версією, щоб довести, що вона все ще працює: http://pastebin.com/raw.php?i=h73q58FN


6

TI-84 Basic (сценарій калькулятора), 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 :це новий рядок. Таким чином, всі фактичні нові рядки в коді означають, що :або #на початку кожного рядка не потрібно. Початок лексеми :і #просто розмежувати коментарі та код.

Оригінальний шістнадцятковий дамп (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 - Оптимізовано 3 байти за допомогою редакцій спостереження Mac №2 та №3 - Виправлені помилки, виявлені Runer112.


11
Будучи простим у використанні в стресових ситуаціях, таких як стандартизовані тести, - це саме те , для чого я створив 99 .
Захоплення Кальвіна

1
Чи можу я запропонувати використовувати інший символ, наприклад #, для коментарів? (Примітка: Коментарі у фактичному коді реалізовані як рядок із лише незамкнутим рядком, який клобує Ans)
Riking

8
Ви справді спробували це запустити? Я ні, але лише переглянувши це трохи більше, я помітив, що здається, як мінімум півдесятка помилок. Наприклад: змінні не ініціалізуються зі своїми значеннями, Ansвведення перезаписується, тому Ans->Str0в рядку 6 буде помилка, є кілька випадків, коли аргумент довжини sub()команди може бути нульовим, що призводить до помилки, Ansу рядку 11 буде рядок так Ans-Jбуде помилка ... І я лише дивився приблизно на першу половину програми.
Runer112

1
@Timtech Це все ще залишає інші проблеми. Як я вже згадував, є відсутність вводу-виводу символів, відсутність ініціалізації змінної та декілька випадків, коли sub()команда може мати нульову довжину і помиляти помилку. І коли sub()виклики будуть виправлені, я боюся, що це може виявити більше проблем.
Runer112

1
@Timtech я мав на увазі це: "За замовчуванням кожній змінній присвоюється власне числове представлення. Отже, якщо вона не була перепризначена, значення змінної 9- це число 9, а значення змінної 99- це число 99, і так далі." І рядки довжиною 0 можуть бути створені за допомогою подібних "", але це щось на зразок помилки, в основному жодна команда маніпуляції з рядком не може споживати або створювати порожню рядок, у тому числі sub().
Runer112,

5

C 426 458 481 497

Редагувати Можливо, я заходжу занадто далеко, але це працює з 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 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

Приклад запустіть із програмою "відлік часу", що зберігається у файлі 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 параметрами

  • програмний код у вигляді багаторядкового рядка
  • введення як масив

Третій необов’язковий параметр (за замовчуванням 10 к) - це максимальна кількість ітерацій - мені не подобається програма, яка працює вічно

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, тому спочатку я визначаю кілька ключових слів q, які я хочу використовувати кілька разів у k функціях. (в основному #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

Перл, 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 $_)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.