Tulis penerjemah untuk 99


99

99 (diucapkan "sembilan puluh sembilan") adalah bahasa pemrograman Esoterik yang sama sekali baru (jangan dikelirukan dengan 99 , catat huruf miring). Tugas Anda dalam tantangan ini adalah menulis penerjemah untuk 99 yang sesingkat mungkin. Kiriman dengan byte paling sedikit menang. Tiebreaker pergi ke kiriman yang diposting terlebih dahulu.

Karena pertanyaan ini sedikit lebih dalam dari biasanya, dan saya ingin sekali melihat jawaban yang bagus, saya akan memberikan hadiah 250 rep untuk jawaban favorit saya (belum tentu pemenangnya).

99 Spesifikasi

99 adalah bahasa yang sangat penting . Setiap baris dalam program 99 adalah pernyataan tunggal , dan selama eksekusi, penunjuk instruksi dimulai di baris paling atas dan melewati setiap baris berikutnya secara berurutan, mengeksekusi mereka di sepanjang jalan. Program berakhir ketika baris terakhir telah dieksekusi. Pernyataan Goto dapat mengubah rute lintasan penunjuk instruksi.

Baris baru, spasi, dan 9hanya tiga karakter yang penting dalam program 99 . Semua karakter lain sepenuhnya diabaikan. Selain itu, spasi tambahan pada setiap baris diabaikan, dan beberapa spasi dalam satu baris dibaca sebagai satu spasi. ("Baris Baru" mengacu pada penyandian baris istirahat umum apa pun . Tidak masalah yang mana juru bahasa Anda gunakan.)

Jadi program ini:

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

Identik dengan program ini:

 9 99 9999
9 9

Variabel

Variabel dalam 99 semuanya memiliki nama yang satu atau lebih 9dirangkai ( 9+dalam regex). Sebagai contoh, 9, 99, dan 9999999999semua variabel yang berbeda. Secara alami, ada banyak sekali (pembatasan keterbatasan memori).

Nilai setiap variabel adalah bilangan bulat presisi bertanda tangan yang ditandatangani . Secara default, setiap variabel ditugaskan ke representasi numeriknya sendiri. Jadi, kecuali jika telah dipindahkan, nilai variabel 9adalah angka 9, dan nilai variabel 99adalah angka 99, dan seterusnya. Anda bisa menganggapnya sebagai memperlakukan variabel sebagai angka polos sampai mereka ditetapkan secara eksplisit.

Saya akan gunakan Vuntuk merujuk pada nama variabel arbitrer di bawah ini.
Setiap contoh Vbisa diganti dengan 9, 99, 999, 9999, dll

Pernyataan

Ada lima tipe pernyataan berbeda di 99 . Setiap baris dalam program 99 berisi tepat satu pernyataan.

Sintaks yang dijelaskan di sini mengasumsikan semua karakter asing telah dihapus, semua spasi tambahan telah dihapus, dan semua urutan banyak spasi telah diganti dengan spasi tunggal.

1. Tidak Ada Operasi


Baris kosong adalah no-op . Tidak melakukan apa-apa (selain menambah pointer instruksi).

2. Keluaran

V

Variabel tunggal Vpada baris mencetak variabel itu ke stdout.

Jika Vmemiliki angka ganjil dari 9( 9,, 999dll.) Maka nilai integer Vdibagi 9 akan dicetak (dalam desimal).

Jika Vmemiliki angka genap 9( 99,, 9999dll.) Maka karakter ASCII dengan kode Vdibagi 9, mod 128 akan dicetak. (Itu (V / 9) % 128, nilai dari 0 hingga 127.)

Contoh : Program

9
9999

akan dicetak 1W. Baris pertama mencetak 1karena 9/9 adalah 1. Baris kedua mencetak Wkarena 9999/9 adalah 1111, dan 1111 mod 128 adalah 87, dan 87 adalah kode karakter untuk W.

Perhatikan bahwa jeda baris tidak dicetak di antara token output. \nperlu dicetak secara eksplisit untuk jeda baris.

3. Input

 V

Variabel tunggal Vpada baris dengan spasi terdepan mengambil input dari stdin dan menyimpannya dalam variabel itu.

Jika Vmemiliki jumlah ganjil 9maka pengguna dapat mengetikkan bilangan bulat apa pun yang ditandatangani, dan Vakan disetel ke 9 kali dari nilai itu.

Jika Vmemiliki angka genap 9maka pengguna dapat mengetikkan karakter ASCII apa pun, dan Vakan ditetapkan hingga 9 kali kode karakternya.

Contoh : Diberikan -57dan Asebagai input, program ini

 9
9
 99
99

akan menghasilkan -57A. Secara internal, variabel 9akan memiliki nilai -513, dan 99akan memiliki nilai 585.

Penerjemah Anda dapat mengasumsikan bahwa input selalu valid secara sintaksis.

4. Penugasan

Pernyataan ini bisa lama sewenang-wenang. Ini adalah dua atau lebih variabel pada suatu garis, dipisahkan oleh spasi:

V1 V2 V3 V4 V5 ...

Ini menetapkan jumlah semua dengan indeks genap, dikurangi jumlah dari dengan indeks ganjil (tidak termasuk ). Tugas adalah berdasarkan nilai, bukan dengan referensi.V1VVV1

Ini dapat diterjemahkan dalam sebagian besar bahasa sebagai .V1 = V2 - V3 + V4 - V5 + ...

Jadi, jika hanya ada dua variabel, itu tugas normal:

V1 V2V1 = V2

Jika ada tiga, maka itu pengurangan:

V1 V2 V3V1 = V2 - V3

Dan tanda +/ -terus berpindah-pindah dengan setiap variabel tambahan:

V1 V2 V3 V4V1 = V2 - V3 + V4

Contoh : Program ini akan menampilkan 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 (melompat jika semuanya nol)

Pernyataan ini juga bisa panjang sewenang-wenang. Ini adalah dua atau lebih variabel pada garis, dipisahkan oleh spasi, dengan spasi terkemuka :

 V1 V2 V3 V4 V5 ...

Jika beberapa nilai selain itu bukan nol, maka ini berlaku seperti no-op. Penunjuk instruksi dipindahkan ke baris berikutnya seperti biasa.V1

Jika semua nilai-nilai selain yang nol, maka instruksi pointer dipindahkan ke baris nomor . Garis-garis diindeks nol, jadi jika nol, maka penunjuk bergerak ke baris atas. Program berakhir (biasanya, tanpa kesalahan) jika negatif atau lebih besar dari indeks tertinggi yang mungkin (jumlah garis minus satu).V1 V1V1V1

Catatan yang tidak dibagi dengan 9 di sini. Dan karena tidak mungkin memiliki variabel menjadi nilai yang bukan kelipatan dari 9, hanya nomor baris yang merupakan kelipatan dari 9 yang dapat dilompati.V1

Contoh:

Program ini akan mencetak 1selamanya:

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.

Program ini

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

akan menampilkan angka 11 hingga 1, dalam urutan menurun, dikelilingi oleh G:

G11G10G9G8G7G6G5G4G3G2G1G

detil tambahan

Interpreter ideal akan dijalankan dari baris perintah dengan nama file program 99 sebagai argumen. I / O juga akan dilakukan dengan cepat di baris perintah.

Anda dapat, bagaimanapun, hanya menulis fungsi juru bahasa yang mengambil dalam program sebagai string serta daftar token input (misalnya ["-57", "A"]). Fungsi harus mencetak atau mengembalikan string keluaran.

Cara yang sedikit berbeda dalam menjalankan juru bahasa dan menangani I / O baik-baik saja jika opsi ini tidak mungkin dalam bahasa Anda.


Bonus: Tulis sesuatu yang keren di 99 dan saya akan dengan senang hati memasukkannya di posting ini sebagai contoh.


Semoga Anda menikmati tantangan ke-99 saya ! : D


9
Saya mempertimbangkan upvoting, tetapi skor Anda saat ini adalah 9 ...
wchargin

30
@WChargin sepertinya sekarang Anda harus mencoba untuk mendapatkannya 99.
trlkly

5
Tentunya ada bonus untuk hosting sendiri (menulis 99 penerjemah dalam 99 ), bukan?
Gabe

5
@ Gabe Sebuah jawaban seperti itu mungkin akan mendapatkan karunia, tetapi jika itu adalah satu-satunya jawaban, apa yang akan menafsirkan penerjemah? ;)
Calvin Hobbies

1
@Optimizer berfungsi: pastebin.com/raw.php?i=h73q58FN
coredump

Jawaban:


16

CJam, 157 byte

{: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}

Cobalah online:

Penjelasan

Mencoba memformat ini dengan lekukan yang tepat dan komentar mungkin akan berlangsung selamanya, jadi saya hanya akan memberikan ringkasan algoritmik.

Kode ini adalah blok, fungsi analog ke anonim CJam. Blok mengharapkan string program dan daftar input pada stack ketika dieksekusi.

Inisialisasi terdiri dari tiga langkah. Pertama, daftar input disimpan. Kemudian, setiap karakter dalam program yang tidak berarti dihapus dan hasilnya dibagi menjadi daftar baris dan disimpan. Akhirnya, daftar variabel diinisialisasi. Daftar ini memetakan setiap variabel, yang diindeks berdasarkan panjang nama, ke nilainya dibagi dengan 9 (suatu variabel tidak pernah dapat menyimpan nilai yang bukan kelipatan dari 9, dan semua operasi kecuali mendapat manfaat dari perubahan ini). Daftar ini diinisialisasi hingga panjang garis terpanjang, yang merupakan batas atas pada nama terpanjang yang ada sekarang. Ada juga sedikit inisialisasi implisit karena nilai variabel awal: nomor baris adalah 0 dan indeks input -1.

Penerjemah diimplementasikan seperti yang diharapkan: loop yang membaca baris berikutnya, menambah nomor baris, dan mengeksekusi baris sementara nomor baris menunjuk ke baris yang ada. Penguraian baris pertama-tama memeriksa apakah garis tidak kosong, lalu bercabang berdasarkan apakah aritynya 1 atau> 1, kemudian bercabang berdasarkan apakah ada ruang terdepan. Keempat cabang ini meniru empat operasi (tidak termasuk operasi tanpa operasi) dalam cara yang kebanyakan langsung, meskipun golf secara agresif seperti yang lainnya. Mungkin salah satu optimasi dari catatan adalah bahwa, karena urutan input yang valid harus selalu menghasilkan elemen tipe yang diharapkan oleh program, saya dihilangkan membuat kasus terpisah untuk input berdasarkan pada panjang nama variabel. Secara sederhana diasumsikan bahwa elemen yang dibaca dari daftar input adalah tipe yang diharapkan.


15
+1. Cukup pendek. Sekarang, bisakah Anda menulis juru bahasa CJam dalam 99 ? ;-)
coredump

9
@coredump * shudders *
Runer112

Sial, saya hanya bisa mendapatkan 195 dan kemudian saya kehilangan harapan dan menyerah: P
Optimizer

Ini tidak mengambil modulo yang benar saat mencetak nilai negatif. Ini dapat diperbaiki dengan mengganti 128%dengan 128,=.
Martin Ender

26

Python 3, 421 414 410 404 388 395 401 byte

Golf:

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

Tidak Disatukan:

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

Cukup banyak implementasi spek literal, bermain sejauh yang saya bisa.

Jalankan dari baris perintah dengan menyediakan file kode sumber 99 sebagai argumen tunggal (mis. Contoh terakhir dari OP):

> python3 ninetynine.py countdown.txt
G11G10G9G8G7G6G5G4G3G2G1G
>

Sebagai bonus tambahan, inilah penerapan "99 botol" dalam 99 : http://pastebin.com/nczmzkFs


1
@ Duposc: mengenai poin pertama Anda: Saya juga berpikir bahwa elsesetelah nomor dapat dihapus, tetapi ketika saya mencobanya sebelumnya saya mendapat kesalahan sintaksis. Tips Anda yang lain sangat dihargai!
Mac

3
@coredump: cara spec ditulis, setiap variabel akan selalu memiliki nilai yang habis dibagi sembilan. Saya menemukan ini lebih ringkas untuk memungkinkan variabel untuk mengambil nilai apa pun , dan hanya mengalikan / membagi dengan sembilan sesuai kebutuhan (khususnya, dalam gotorutin dan ketika mendapatkan nilai default dari variabel). Sejauh menyangkut pengguna bahasa, tidak ada bedanya.
Mac

2
Bukan elseitu sendiri, hanya ruang sebelumnya. Misalnya 3*n+1if n%2else n//2.
DLosc

1
@ Duposc: maaf, saya salah mengeja - saya memang berarti ruang, bukan else. Misalnya, saya mencoba mengganti print(w if L(e)%2 else chr(w%128))dengan print(w if L(e)%2else chr(w%128))dan mendapatkan pengecualian sintaks.
Mac

1
Aneh - Saya menguji di ideone.com dan itu berhasil, tetapi Anda benar, itu tidak bekerja pada penerjemah Python3 yang sebenarnya (3.4.0 di Ubuntu). Kiat kiat ini menjelaskan: angka yang diikuti oleh token alfabet secara umum, tetapi tidak untuk token yang dimulai dengan eatau E, dan (dari komentar) tidak untuk 0orkeduanya.
DLosc

16

Common Lisp, 1180 857 837 836 byte

Saya tahu ini tidak akan menang, tapi saya senang bermain golf yang satu ini. Saya berhasil menghapus 343 byte, yang lebih dari dua 99 penerjemah ditulis dalam CJam.

Juga, cukup mengherankan, semakin saya mencoba untuk mengompresnya, semakin saya yakin bahwa untuk Common Lisp, lebih pendek untuk mengkompilasi kode daripada mencoba menafsirkannya dengan cepat.

(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)>))))
  • analisis leksikal dan pembuatan kode saling terkait: Saya tidak menyimpan representasi internal, tetapi memproses secara langsung setiap baris.
  • ada satu tagbodyuntuk melakukan 2 loop:

     (... (tagbody % ... (go %) $ ... (go $)) result)
    
  • variabel lokal dideklarasikan dalam &aux

  • tidak menghasilkan penutupan, tetapi langsung kode yang ditafsirkan
  • dll.

Tidak disatukan, berkomentar

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

Kami menggunakan input / output standar selama evaluasi, artinya kami menggunakan standar readdan princfungsi. Oleh karena itu, kode yang dihasilkan dapat dieksekusi pada command-line, seperti yang ditunjukkan di bawah ini.

Input tidak sepenuhnya disanitasi dengan baik ketika menjalankan 99 program: diasumsikan bahwa pengguna tahu nilai seperti apa yang diharapkan.

Satu-satunya overhead runtime yang mungkin dapat terjadi saat melompat, karena kita harus mengevaluasi nilai variabel dan mencocokkan nilai itu dengan label. Kecuali itu, juru bahasa harus cukup efisien.

Berdasarkan pengamatan cerdas dari Mac bahwa kita tidak perlu membagi dan mengalikan dengan 9 setiap kali, versi saat ini berhasil untuk tidak pernah membagi atau mengalikan dengan 9 selama eksekusi.

Contoh

Jika kita ganti defmacrodengan defun, kita melihat kode yang dihasilkan. Sebagai contoh:

(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

")

Ini kode yang dihasilkan:

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

Saat dijalankan, cetak "G11G10G9G8G7G6G5G4G3G2G1G"

Garis komando

Kita dapat membangun executable dengan membuang inti dan menentukan toplevelfungsi. Tentukan file bernama boot.lisptempat Anda meletakkan defmacro, dan kemudian tulis yang berikut ini:

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

Menjalankan sbcl --load boot.lispmemberikan output berikut:

$ 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]

Kemudian, jalankan program yang dikompilasi 99 :

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

99 botol

Jika Anda tertarik, berikut ini adalah kode kompilasi untuk program 99 botol yang ditulis dalam jawaban Mac : http://pastebin.com/ZXe839CZ (ini adalah versi lama tempat kami memiliki jmpdan endmemberi label, lambda sekitarnya dan aritmatika yang lebih cantik).

Berikut ini adalah eksekusi dengan versi baru, untuk membuktikannya masih berfungsi: http://pastebin.com/raw.php?i=h73q58FN


6

TI-84 Basic (Script Kalkulator), 376 373 377 381 byte

Jika ini berjalan pada kalkulator TI-84, Anda akan dapat menggunakannya pada tes standar ... jadi ini berguna;)

Versi sistem operasi minimum - 2.53MP (MathPrint) karena sigma penjumlahan

#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

Pedoman PS ASCII tidak bisa diikuti dengan tepat, tetapi dalam TI-Basic :adalah baris baru. Dengan demikian, semua baris baru aktual dalam kode berarti bahwa :atau #pada awal setiap baris tidak diperlukan. Token awal :dan #hanya membedakan antara komentar dan kode.

Hex Dump Asli (376 Bytes)

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

Sunting # 1 - Dioptimalkan 3 byte menggunakan observasi Mac. Suntingan # 2 & # 3 - Bug yang diperbaiki ditemukan oleh Runer112.


11
Menjadi mudah digunakan dalam situasi stres seperti tes standar adalah persis apa yang saya dirancang 99 untuk.
Calvin Hobbies

1
Dapatkah saya menyarankan menggunakan karakter yang berbeda, seperti #, untuk komentar? (NB: Komentar dalam kode aktual diimplementasikan sebagai garis dengan hanya string yang tidak tertutup, yang akan membuat Ans)
Riking

8
Sudahkah Anda mencoba menjalankan ini? Saya belum, tetapi hanya dari melihatnya sedikit lebih, saya telah melihat apa yang tampaknya setidaknya setengah lusin bug. Sebagai contoh: variabel tidak diinisialisasi dengan nilai-nilai mereka, Ansinput ditimpa sehingga Ans->Str0pada baris 6 akan kesalahan, ada beberapa contoh di mana argumen panjang suatu sub()perintah bisa nol yang menghasilkan kesalahan, Anspada baris 11 akan menjadi string jadi Ans-Jakan kesalahan ... Dan saya hanya melihat sekitar paruh pertama program.
Runer112

1
@Timtech Itu masih menyisakan masalah lain. Seperti yang saya sebutkan, ada kekurangan karakter I / O, kurangnya inisialisasi variabel, dan beberapa contoh di mana sub()perintah dapat memiliki panjang nol dan melemparkan kesalahan. Dan begitu sub()doa diperbaiki, saya khawatir itu dapat mengungkapkan lebih banyak masalah.
Runer112

1
@Timtech saya mengacu pada ini: "Secara default, setiap variabel ditugaskan untuk representasi numeriknya sendiri. Jadi, kecuali jika telah dipindahkan, nilai variabelnya 9adalah angka 9, dan nilai variabelnya 99adalah angka 99, dan seterusnya." Dan string dengan panjang 0 dapat diproduksi dengan cara seperti "", tapi itu semacam bug yang pada dasarnya tidak ada perintah manipulasi string dapat mengkonsumsi atau menghasilkan string kosong, termasuk sub().
Runer112

5

C 426 458 481 497

Sunting Mungkin saya melangkah terlalu jauh, tetapi ini bekerja dengan Visual C: dihapus stdio.h, menggunakan int bukan FILE * untuk fopen dan getc

Sunting 2 Susun ulang langkah eksekusi, lebih banyak kekacauan, 32 karakter tersimpan

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

Program konsol yang berdiri sendiri, nama program yang diambil pada baris perintah dan input / output melalui konsol.

K&R gaya lama, int standar untuk vars dan parameter global. Dengan asumsi EOF didefinisikan sebagai -1 (seperti dalam setiap implementasi C yang saya tahu)

Kompilasi dengan peringatan dengan Visual Studio 2010 (proyek Win32 konsol C ++, kompilasi sebagai C) Kompilasi pada Ideone, tetapi tidak dapat berjalan karena membutuhkan file.

Langkah pertama, kode sumber dibaca dan diuraikan, setiap baris disimpan sebagai urutan bilangan bulat berdasarkan angka 9s. Jika ada spasi awal, angka pertama negatif. Jadi: 9 BLAH 99 9a9bb9c9( 9 99 9999) menjadi -1,2,4 Ada pintasan - tidak terlalu legal: semua kode ascii yang kurang dari '' dianggap sebagai baris baru.

Pada langkah ini semua variabel yang digunakan diinisialisasi.

Langkah eksekusi mengikuti spesifikasi, tanpa embel-embel, menyimpan nomor penyimpanan dibagi dengan 9.

Kode yang sama lebih mudah dibaca (saya harap), spasi dan baris baru ditambahkan

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
Juga bekerja dengan GCC 4.8.2. Kompilasi sebagai C99!
EMBLEM

4

Haskell, 550 byte

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

Contoh dijalankan dengan program "hitung mundur" yang disimpan dalam file i.99

$ ./99 i.99
G11G10G9G8G7G6G5G4G3G2G1G

Versi tidak disatukan:

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

Fungsi dengan 2 parameter

  • kode program sebagai string multiline
  • masukan sebagai array

Parameter opsional ketiga (default 10k) adalah jumlah iterasi maksimum - Saya tidak suka program yang berjalan selamanya

JSFiddle Untuk menguji

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

Script adalah campuran dari q dan k, jadi pertama-tama saya mendefinisikan beberapa kata kunci q yang ingin saya gunakan beberapa kali dalam fungsi k. (pada dasarnya #define macro)

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

f membaca file yang diteruskan ke program dan menghapus karakter yang tidak perlu

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 mengambil daftar / vektor dan mengalikan indeks ganjil dengan -1

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

b hanyalah fungsi kosong, digunakan untuk jalur no-op

p adalah fungsi cetak.

Kadalah fungsi yang menguji suatu variabel. Jika variabel ada, ia mengembalikannya, jika tidak, ia hanya mengembalikan literal.

//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 adalah fungsi penugasan.

g adalah fungsi goto.

r mengambil string dan memutuskan operasi mana yang perlu diterapkan.

Dan akhirnya, saya hanya mengulang fdaftar string, dengan niterator. Fungsi goto akan diperbarui nsesuai kebutuhan.


3

Perl, 273 266 255 244 238

Jeda baris ditambahkan untuk kejelasan.

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

Nama program diambil pada baris perintah:

$ perl 99.pl 99beers.99

Setiap baris program diubah menjadi kode Perl, misalnya:

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

Keterangan lebih lanjut

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 $_)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.