Buat bahasa pemrograman yang hanya tampaknya tidak dapat digunakan

85

Untaian perampok ada di sini .

Tantangan polisi: Merancang bahasa pemrograman yang tampaknya tidak dapat digunakan untuk pemrograman, tetapi mengakui perhitungan (atau setidaknya penyelesaian tugas) melalui beberapa mekanisme yang tidak jelas.

Anda harus merancang bahasa pemrograman sederhana yang membaca kode dari file input dan kemudian melakukan ... sesuatu. Anda harus menyiapkan program solusi yang menemukan angka terbesar ke-3 dalam input saat dijalankan dalam juru bahasa Anda. Anda harus membuatnya sesulit mungkin bagi perampok untuk menemukan program solusi. Perhatikan bahwa perampok dapat memposting solusi apa pun yang menyelesaikan tugas, bukan hanya yang Anda pikirkan.

Ini adalah kontes popularitas. Tujuan polisi adalah untuk mendapatkan suara sebanyak mungkin sambil bertahan 8 hari setelah memposting penerjemah tanpa retak. Untuk tujuan ini, praktik-praktik berikut harus membantu:

  • Menjelaskan semantik bahasa Anda dengan akurat
  • Menulis kode yang dapat dibaca

Taktik berikut sangat tidak dianjurkan:

  • Menggunakan enkripsi, hash, atau metode kriptografi lainnya. Jika Anda melihat bahasa yang menggunakan enkripsi RSA, atau menolak untuk menjalankan program kecuali hash SHA-3-nya sama dengan 0x1936206392306, jangan ragu untuk melakukan downvote.

Tantangan perampok: Tulis sebuah program yang menemukan bilangan bulat terbesar ketiga dalam input saat dijalankan dalam penerjemah polisi.

Yang ini relatif mudah. Untuk memecahkan jawaban polisi, Anda harus membuat program yang menyelesaikan tugas saat dijalankan dalam penerjemahnya. Ketika Anda memecahkan sebuah jawaban, kirim komentar yang mengatakan "Retak" pada jawaban polisi yang terhubung ke posting Anda. Siapa pun yang paling banyak meretas polisi akan memenangkan utas perampok.

Aturan I / O

  • Penerjemah harus mengambil nama file pada baris perintah untuk program, dan menggunakan input dan output standar saat menjalankannya.
  • Masukan akan diberikan secara unary dan hanya terdiri dari karakter 0dan 1(48 dan 49 di ASCII). Angka N dikodekan sebagai N 1s diikuti oleh a 0. Ada tambahan 0sebelum akhir file. Contoh: Untuk urutan (3, 3, 1, 14), inputnya adalah 11101110101111111111111100.
  • Input dijamin memiliki setidaknya 3 angka. Semua angka adalah bilangan bulat positif.
  • Output akan dinilai berdasarkan jumlah yang 1dicetak sebelum program dihentikan. Karakter lain diabaikan.

Dalam contoh berikut, baris pertama adalah input dalam format desimal; yang kedua adalah input program aktual; yang ketiga adalah output sampel.

1, 1, 3
101011100
1

15, 18, 7, 2, 15, 12, 3, 1, 7, 17, 2, 13, 6, 8, 17, 7, 15, 11, 17, 2
111111111111111011111111111111111101111111011011111111111111101111111111110111010111111101111111111111111101101111111111111011111101111111101111111111111111101111111011111111111111101111111111101111111111111111101100
111111,ir23j11111111111u

247, 367, 863, 773, 808, 614, 2
<omitted>
<contains 773 1's>

Aturan membosankan untuk jawaban polisi:

  • Untuk mencegah keamanan melalui ketidakjelasan, penerjemah harus ditulis dalam bahasa di atas 100 indeks TIOBE ini dan memiliki kompiler / penerjemah yang tersedia secara bebas.
  • Penerjemah tidak boleh menafsirkan bahasa yang diterbitkan sebelum tantangan ini.
  • Penerjemah harus sesuai dengan posting Anda dan tidak di-host secara eksternal.
  • Penerjemah harus deterministik
  • Penerjemah harus portabel dan mengikuti standar bahasanya sendiri; jangan gunakan perilaku atau bug yang tidak terdefinisi
  • Jika program solusi terlalu panjang untuk cocok dengan jawaban, Anda harus memposting program yang menghasilkannya.
  • Program solusi harus hanya terdiri dari ASCII yang dapat dicetak dan baris baru.
  • Anda harus menjalankan program solusi Anda dalam waktu kurang dari 1 jam di komputer Anda sendiri untuk masing-masing input contoh di atas.
  • Program harus bekerja untuk bilangan bulat apa pun yang kurang dari 10 6 , dan sejumlah bilangan bulat kurang dari 10 6 (tidak harus dalam waktu kurang dari satu jam), asalkan total panjang input kurang dari 10 9 .
  • Agar aman, seorang polisi harus mengedit program solusi menjadi jawaban setelah 8 hari berlalu.

Mencetak gol

Polisi yang menjadi aman dengan skor tertinggi, dan skor positif, memenangkan pertanyaan ini.

feersum
sumber
Anda tidak secara eksplisit menyatakan ini, tetapi apakah saya benar dengan berasumsi bahwa polisi benar-benar harus menulis dan memposting penerjemah dalam jawaban mereka?
Biru
@muddyfish Ya, penerjemah haruslah konten jawaban polisi.
feersum
1
@ kirbyfan64sos Output akan dinilai pada saat itu jumlah 1 yang dicetak sebelum program berhenti. Karakter lain diabaikan.
mbomb007
1
@ Luminous Rupanya tidak ada sama sekali.
Martin Ender
20
Saya membohongi diri sendiri dengan tantangan ini. Saya membuat bahasa pemrograman dan kemudian menghabiskan waktu berjam-jam pemrograman tugas untuk melihat apakah bahasa itu bisa bekerja hanya untuk mengetahui bahwa itu sebenarnya tidak dapat digunakan.
Sanchises

Jawaban:

24

Changeling (aman)

ShapeScript

ShapeScript adalah bahasa pemrograman yang muncul secara alami. Shape shifter (atau Perubahan , karena mereka lebih suka disebut) dapat berubah menjadi seperangkat instruksi yang memungkinkan mereka untuk memproses data.

ShapeScript adalah bahasa berbasis tumpukan dengan sintaksis yang relatif sederhana. Tidak mengherankan, sebagian besar kesepakatan bawaannya dengan mengubah bentuk string. Ditafsirkan, karakter demi karakter, sebagai berikut:

  • 'dan "mulai string literal.

    Sampai kutipan yang cocok ditemukan dalam kode sumber, semua karakter di antara kutipan yang cocok ini dikumpulkan dalam sebuah string, yang kemudian didorong pada tumpukan.

  • 0untuk 9mendorong bilangan bulat 0 hingga 9 pada tumpukan. Perhatikan bahwa 10mendorong dua bilangan bulat.

  • ! muncul string dari tumpukan, dan mencoba untuk mengevaluasinya sebagai ShapeScript.

  • ? muncul bilangan bulat dari tumpukan, dan mendorong salinan item tumpukan pada indeks itu.

    Indeks 0 sesuai dengan item tumpukan paling atas (LIFO) dan indeks -1 ke paling bawah.

  • _ muncul iterable dari stack, dan mendorong panjangnya.

  • @ muncul dua item dari tumpukan, dan mendorongnya dalam urutan terbalik.

  • $muncul dua string dari tumpukan, dan pisahkan yang terbawah pada kejadian yang paling atas. Daftar yang dihasilkan didorong sebagai imbalan.

  • &muncul string (paling atas) dan iterable dari stack, dan bergabung iterable, menggunakan string sebagai pemisah. String yang dihasilkan didorong sebagai balasan.

  • Jika ShapeScript digunakan di planet kita, karena ular adalah Changelings kerabat terdekat di Bumi, semua karakter lain c pop dua item x dan y (paling atas) dari stack, dan berusaha untuk mengevaluasi kode Python x c y.

    Misalnya, urutan karakter 23+akan mengevaluasi 2+3, sedangkan urutan karakter "one"3*akan mengevaluasi 'one'*3, dan urutan karakter 1''Aakan mengevaluasi 1A''.

    Dalam kasus terakhir, karena hasilnya adalah Python tidak valid, Changeling akan mengeluh bahwa bentuknya saat ini adalah unpurposed (kesalahan sintaks), karena itu tidak benar ShapeScript.

Sebelum mengeksekusi kode, interpreter akan menempatkan seluruh input pengguna dalam bentuk string pada stack. Setelah mengeksekusi kode sumber, juru bahasa akan mencetak semua item pada tumpukan. Jika ada bagian di antara gagal, Changeling akan mengeluh bahwa bentuknya saat ini tidak memadai (kesalahan runtime).

Bentuk bergeser

Dalam keadaan alami mereka, Perubahan tidak mengambil bentuk dari ShapeScript. Namun, beberapa dari mereka dapat berubah menjadi satu kode sumber potensial (yang belum tentu berguna atau bahkan secara sintaksis valid).

Semua Perubahan yang memenuhi syarat memiliki bentuk alami berikut:

  • Semua baris harus memiliki jumlah karakter yang sama.

  • Semua baris harus terdiri dari karakter ASCII yang dapat dicetak, diikuti oleh satu linefeed.

  • Jumlah garis harus sesuai dengan jumlah karakter yang dapat dicetak per baris.

Misalnya, urutan byte ab\ncd\nadalah Changeling yang memenuhi syarat.

Dalam upayanya untuk beralih ke ShapeScript, Changeling mengalami transformasi berikut:

  • Awalnya, tidak ada kode sumber.

  • Untuk setiap baris berikut terjadi:

    • Akumulator Changeling diatur ke nol.

    • Untuk setiap karakter c dari baris (termasuk trafeed linefeed), titik kode c adalah XOR dengan akumulator dibagi 2, dan karakter Unicode yang sesuai dengan titik kode yang dihasilkan ditambahkan ke kode sumber.

      Setelah itu, perbedaan antara titik kode c dan titik kode spasi (32) ditambahkan ke akumulator.

Jika ada bagian di atas gagal, Changeling akan mengeluh bahwa bentuknya saat ini tidak menyenangkan.

Setelah semua baris diproses, transformasi Changeling menjadi ShapeScript (mudah-mudahan valid) selesai, dan kode yang dihasilkan dieksekusi.

Solusi (ShapeScript)

"0"@"0"$"0"2*&"0"@+0?_'@1?"0"$_8>"1"*+@1?"0"+$""&'*!#

ShapeScript sebenarnya ternyata cukup bermanfaat; bahkan dapat melakukan pengujian primality ( bukti ) dan karena itu memenuhi definisi bahasa pemrograman kami.

Saya telah menerbitkan ulang ShapeScript di GitHub , dengan sintaks yang sedikit dimodifikasi dan I / O yang lebih baik.

Kode melakukan hal berikut:

"0"@    Push "0" (A) and swap it with the input string (S).
"0"$    Split S at 0's.
"0"2*   Push "00".
&       Join the split S, using "00" as separator.
"0"@+   Prepend "0" to S.
        The input has been transformed into
        "0<run of 1's>000<run of 1's>0...0<run of 1's>0000".
0?_     Push a copy and compute its length (L).
'       Push a string that, when evaluated, does the following:
  @1?     Swap A on top of S, and push a copy of S.
  "0"$    Split the copy of S at 0's.
  _8>     Get the length of the resulting array and compare it with 8.
          If this returns True, there are more than eight chunks, so there are
          more then seven 0's. With two 0's surrounding each run of 1's and
          three extra 0's at the end, this means that there still are three or
          more runs of 1's in the string.
  "1"*    Push "1" if '>' returned True and "" if it returned False.
  +       Append "1" or "" to A.
  @1?     Swap S on top of A, and push a copy of A.
  "0"+    Append "0" to the copy of A.
  $       Split S at occurrences of A+"0".
  ""&     Flatten the resulting array of strings.
'       This removes all occurrences of "010" in the first iteration, all
        occurrences of "0110" in the second, etc., until there are less than
        three runs of 1's left in S. At this point, A is no longer updated,
        and the code inside the string becomes a noop.
*!      Repeat the code string L times and evaluate.
#       Drop S, leaving only A on the stack.

Solusi (Changeling)

"1+-.......................
""B1.......................
"" 2)+7....................
"" 2)=<....................
""( $86=...................
""B8=......................
""247......................
""]`b......................
""B1.......................
""%D1=.....................
""%500=....................
""%&74?....................
""%&#.2....................
""%[bdG....................
""%D1=.....................
""%<5?.....................
""%:6>.....................
""%&65?....................
""%&-%7>...................
""%D1=.....................
""%500=....................
""%&74?....................
""%&,)5>...................
""%&%,79...................
"" )$?/=...................
""),-9=....................
""# !......................

Seperti semua program Changeling, kode ini memiliki linefeed tambahan.

ShapeScript akan segera melakukan kesalahan pada karakter apa pun yang tidak dimengerti, tetapi kita dapat mendorong string sewenang-wenang sebagai pengisi dan pop mereka nanti. Hal ini memungkinkan kita untuk menempatkan hanya sejumlah kecil kode pada setiap baris (di awal, di mana akumulator kecil), diikuti oleh pembukaan ". Jika kita memulai baris berikutnya dengan "#, kita menutup dan memunculkan string tanpa memengaruhi kode sebenarnya.

Selain itu, kita harus mengatasi tiga hambatan kecil:

  • String panjang dalam kode ShapeScript adalah token tunggal, dan kami tidak akan dapat memasangnya pada satu baris.

    Kami akan mendorong string ini dalam potongan ( '@', '1?', dll), yang akan kita gabungkan nanti.

  • Titik kode _agak tinggi, dan mendorong '_'akan bermasalah.

    Namun, kami dapat mendorong '_@'dengan mudah, diikuti oleh yang lain '@'untuk membatalkan swap.

Kode ShapeScript Changeling kami akan menghasilkan terlihat seperti ini 1 :

"0""
"#@"
"#"0"$"
"#"0"2"
"#*&"0""
"#@+"
"#0?"
"#_@"
"#@"
"#'@'"
"#'1?'"
"#'"0'"
"#'"$'"
"#'_@'"
"#'@'"
"#'8'"
"#'>'"
"#'"1'"
"#'"*+'"
"#'@'"
"#'1?'"
"#'"0'"
"#'"+$'"
"#'""&'"
"#"+"77"
"#+*!*"
"#!#"

Saya menemukan kode Changeling dengan menjalankan kode ShapeScript di atas melalui konverter ini . 2

Penerjemah (Python 3)

#!/usr/bin/env python3

import fileinput

def error(code):
  print("This shape is " + ["unpleasant", "unpurposed", "inadequate"][code - 1] + ".")
  exit(code)

def interpret(code):
  global stack
  stringing = 0
  for char in code:
    quote = (char == "'") + 2 * (char == '"')
    if quote or stringing:
      if not stringing:
        string = ""
        stringing = quote
      elif stringing == quote:
        stack.append(string)
        stringing = 0
      else:
        string += char
    elif char in "0123456789":
      stack.append(int(char))
    else:
      x = stack.pop()
      if char == '!':
        interpret(x)
      else:
        if char == '?':
          y = stack[~x]
        elif char == "_":
          y = len(x)
        else:
          y = stack.pop()
          if char == '@':
            stack.append(x)
          elif char == '$':
            y = y.split(x)
          elif char == '&':
            y = x.join(map(str, y))
          else:
            try:
              y = eval(repr(y) + char + repr(x))
            except SyntaxError:
              error(2)
        stack.append(y)

source = ""
lengths = []

for line in fileinput.input():
  if not line or sorted(line)[:2][-1] < " " or max(line) > "~":
    error(1)
  lengths.append(len(line))
  accumulator = 0
  for char in line:
    value = ord(char)
    try:
      source += chr(value ^ (accumulator >> 1))
    except:
      error(1)
    accumulator += value - 32

lengths.append(len(lengths) + 1)

if min(lengths) != max(lengths):
  error(1)

stack = ""

for line in fileinput.input("-"):
  stack += line

stack = [stack]

try:
  interpret(source)
except:
  error(3)

print("".join(map(str, stack)))

1 Setiap baris diisi dengan sampah acak dengan jumlah baris, dan umpan baris tidak benar-benar ada.
2 Angka-angka di bagian bawah menunjukkan titik kode terendah dan tertinggi dalam kode Changeling, yang harus tetap antara 32 dan 126.

Dennis
sumber
1
-1 untuk penggunaan xor / transformasi. Mengubah konversi ke ShapeScript terlihat seperti enkripsi bagi saya.
MegaTom
10
@MegaTom Anda dapat memilih sesuai keinginan Anda, namun pertanyaan mengerutkan kening pada enkripsi karena membutuhkan kunci , konstanta hanya diketahui polisi yang menempatkan para perampok pada kerugian yang signifikan. Konversi adalah unkeyed transformasi.
Dennis
1
ShapeScript, 67 bytes: 0"#002?'+'&'0'$'0?2?-@2?>*+00'&!++'1'*'0'+@1?$0?''&@_2-2?*@+@"3*!@#. Saya sudah menyerah menemukan Changeling untuk itu, meskipun. Bahkan diselingi dengan pernyataan yang kebanyakan tidak berguna, saya belum bisa mendapatkan lebih dari 20 byte.
Primo
2
@MegaTom Saya sebenarnya cukup kecewa dengan solusi yang diberikan. Saya mengharapkan sesuatu yang secara signifikan lebih pintar daripada 92,9% kode tidak berguna.
primo
2
@ primo Butuh sedikit lebih banyak mengutak-atik, tapi saya menemukan Changeling ini yang bekerja dengan Python 2 juga. Saya tidak tahu seberapa pintar jawaban saya, tetapi rencana saya untuk mengirim polisi dengan celah yang harus ditemukan untuk memecahkannya tampaknya berhasil.
Dennis,
30

Acak (ditulis dalam C ++), Retak! oleh Martin

Sunting Martin memecahkannya. Untuk melihat solusinya, klik tautannya. Solusi saya juga telah ditambahkan.

Edit perintah Tetap print-duntuk dapat menangani register dan tumpukan. Karena ini adalah perintah debug yang tidak diizinkan dalam suatu solusi, ini seharusnya tidak memengaruhi siapa pun yang menggunakan penerjemah versi sebelumnya.

Saya masih baru dalam hal ini, jadi jika ada yang salah dengan jawaban atau penerjemah saya, beri tahu saya. Silakan minta klarifikasi jika ada sesuatu yang tidak jelas.

Saya tidak membayangkan bahwa ini akan terlalu sulit, tetapi mudah-mudahan ini akan memberikan semacam tantangan. Apa yang membuat shuffle cukup tidak dapat digunakan adalah bahwa ia hanya akan mencetak ketika segala sesuatunya ada di tempatnya.

-> Dasar-dasar:

Ada 24 tumpukan, kami menyebutnya stack1, ... stack24. Tumpukan ini hidup dalam daftar. Pada awal setiap program, tumpukan ini memiliki nol dorongan dan mereka mulai di tempat yang tepat, yaitu tumpukan i pada posisi engan dalam daftar (Perhatikan bahwa kami akan mengindeks mulai dari 1, tidak seperti C ++). Selama program berlangsung, urutan tumpukan dalam daftar akan bergeser. Ini penting karena alasan yang akan dijelaskan ketika saya membahas perintah.

Ada 5 register yang tersedia untuk digunakan. Mereka diberi nama Alberto, Gertrude, Hans, Leopold, ShabbySam. Masing-masing diatur ke nol pada awal program.

Jadi, pada permulaan program apa pun, ada 24 tumpukan, masing-masing memiliki nomor yang cocok dengan indeksnya dalam daftar tumpukan. Setiap tumpukan memiliki tepat satu nol di atas. Masing-masing dari lima register diinisialisasi ke nol.

-> Perintah dan Sintaks :

Ada 13 perintah (perintah debugging +1) yang tersedia di Acak. Mereka adalah sebagai berikut

  • cinpushperintah ini tidak membutuhkan argumen. Itu menunggu input baris perintah dengan cara yang dijelaskan dalam pertanyaan (input lain akan mengarah pada hasil yang tidak ditentukan / tidak ditentukan). Kemudian membagi string input menjadi bilangan bulat, misalnya 101011100-> 1,1,3. Untuk setiap input yang diterima, ia melakukan hal berikut: (1) memungkinkan daftar tumpukan berdasarkan nilai. Biarkan nilai integer yang dimaksud disebut a . Jika a kurang dari 10 itu permutasi u . Jika a adalah antara 9 dan 30 (tidak termasuk) ia melakukan permutasi d . Kalau tidak, itu permutasi r . (2) Ini kemudian mendorong ake tumpukan yang pertama dalam daftar. Perhatikan bahwa saya tidak bermaksud stack1(walaupun mungkin itu yang stack1pertama dalam daftar). Permutasi didefinisikan di bawah ini. Karena cinpushsatu-satunya cara untuk mendapatkan input pengguna , itu harus muncul dalam solusi apa pun.
  • mov value registerThe movperintah pada dasarnya adalah tugas variabel. Itu ditugaskan valueuntuk register. valuedapat mengambil beberapa bentuk: bisa berupa (1) bilangan bulat, misalnya 47 (2) nama register yang berbeda, misalnya Hans (3) indeks tumpukan diikuti dengan 's', misalnya 4s. Perhatikan bahwa ini adalah indeks dalam daftar, bukan jumlah tumpukan. Dengan demikian, jumlahnya tidak boleh melebihi 24.

    Beberapa movcontoh:

    mov 4s Hans 
    mov Hans ShabbySam
    mov 9999 Gertrude
    
  • movfs index registerIni adalah singkatan dari 'move from stack'. Ini mirip dengan movperintah. Itu ada sehingga Anda dapat mengakses tumpukan yang diindeks oleh register. Misalnya, jika sebelumnya Anda menetapkan Hans sama dengan 4 ( mov 4 Hans) Maka Anda dapat menggunakan movfs Hans Gertrudeuntuk mengatur Gertrude sama dengan bagian atas tumpukan 4. Jenis perilaku ini tidak dapat diakses hanya dengan menggunakan mov.

  • inc register meningkatkan nilai register sebesar 1.
  • dec register mengurangi nilai register sebesar 1.
  • compg value value registerIni berarti 'bandingkan lebih besar'. Ini mengatur register sama dengan yang lebih besar dari dua nilai. valuebisa berupa bilangan bulat, register, atau indeks tumpukan diikuti oleh 's', seperti di atas.
  • compl value value register 'bandingkan lebih rendah' ​​sama seperti di atas, kecuali mengambil nilai lebih kecil.
  • gte value1 value2 registerCek jika value1 >= value2kemudian masukkan nilai Boolean (seperti 1 atau 0) register.
  • POP!! indexmuncul di bagian atas tumpukan diindeks oleh indexdalam daftar tumpukan.
  • jmp labelmelompat tanpa syarat ke label label. Ini adalah saat yang tepat untuk membicarakan label. Label adalah kata yang diikuti oleh ':'. Interpreter pra-parsing untuk label, sehingga Anda dapat melompat ke depan untuk label dan juga kembali.
  • jz value labelmelompat ke labeljika valuenol.
  • jnz value labelmelompat ke labeljika valuebukan nol.

    Contoh label dan lompat:

    this_is_my_label:
         jmp this_is_my_label
    
    mov 10 Hans
    jnz Hans infinite_loop
    
    infinite_loop:
         jmp infinite_loop
    
  • "shuffle" permutationIni adalah perintah shuffle. Ini memungkinkan Anda untuk mengubah daftar tumpukan. Ada tiga permutasi valid yang dapat digunakan sebagai argumen, l, f, dan b.

  • print registerIni memeriksa apakah semua tumpukan berada di posisi awalnya, yaitu tumpukan i berada pada indeks i dalam daftar tumpukan. Jika ini masalahnya, ia mencetak nilai registerdi unary. Kalau tidak, itu mencetak kesalahan buruk. Seperti yang Anda lihat, untuk menghasilkan apa pun, tumpukan harus berada di tempat yang benar.
  • done!ini memberitahu program untuk berhenti tanpa kesalahan. Jika program berakhir tanpa done!, itu akan mencetak ke konsol nomor di atas setiap tumpukan diikuti oleh nomor tumpukan itu. Urutan tumpukan dicetak adalah urutan yang muncul dalam daftar tumpukan. Jika tumpukan kosong, itu akan dihilangkan. Perilaku ini untuk tujuan debugging dan mungkin tidak digunakan dalam solusi.
  • print-d valueini mencetak nilai dari stack, register, atau integer diberikan (untuk mengakses stack i , lulus issebagai argumen, seperti yang dijelaskan di atas). Ini adalah alat debugging dan bukan bagian dari bahasa, karena itu tidak diizinkan dalam solusi.

-> Ini adalah kode juru bahasa

Semua penguraian terjadi di fungsi utama. Di sinilah Anda akan menemukannya parsing untuk perintah tertentu.

#include<fstream>
#include<iostream>
#include<string>
#include<stack>
#include<cmath>

using namespace std;

class superStack: public stack<long> {
    private:
        int m_place;
    public:
        static int s_index;


        superStack() {
            m_place = s_index;
            s_index++;
        }

        int place() {
            return m_place;
        }
};
int superStack::s_index=1;

superStack  stack1,stack2,stack3,stack4,stack5,stack6,stack7,stack8,stack9,stack10,stack11, \
            stack12,stack13,stack14,stack15,stack16,stack17,stack18,stack19,stack20,stack21,stack22,stack23,stack24;


superStack* stackptrs[]=    { \
                        &stack1,&stack2,&stack3,&stack4,&stack5,&stack6,&stack7,&stack8,&stack9,&stack10,&stack11, \
                        &stack12,&stack13,&stack14,&stack15,&stack16,&stack17,&stack18,&stack19,&stack20,&stack21,&stack22,&stack23,&stack24 \
                        };


long Gertrude=0;
long Hans=0;
long Alberto=0;
long ShabbySam=0;
long Leopold=0;


void SWAP( int i, int j) {    // 0 < i,j < 25

    i--;
    j--;


    superStack* tempptr = stackptrs[i];
    stackptrs[i]=stackptrs[j];
    stackptrs[j] = tempptr;



}

void u() {
    int list[3][4] = {
                        {1,9,6,13},
                        {2,10,5,14},
                        {17,19,20,18},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void d() {
    int list[3][4] = {
                        {3,11,8,15},
                        {4,12,7,16},
                        {22,24,23,21},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void r() {
    int list[3][4] = {
                        {2,17,8,24},
                        {4,18,6,23},
                        {9,10,12,11},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void l() {
    int list[3][4] = {
                        {1,19,7,22},
                        {3,20,5,21},
                        {14,13,15,16},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void f() {
    int list[3][4] = {
                        {20,9,24,16},
                        {18,11,22,14},
                        {1,2,4,3},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void b() {
    int list[3][4] = {
                        {19,10,23,15},
                        {17,12,21,13},
                        {5,6,8,7},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}

void splitpush(string input) {
    long value=0;

    for(long i=0;i<input.size();i++) {

        if(input[i]=='1'){
            value++;
        }
        else if(input[i]=='0' && value!=0 ) {
            if(value<10) {
                u();
            }
            else if (value<30) {
                d();

            }
            else {
                r();
            }
            (*stackptrs[0]).push(value);
            value=0;

        }
        else {
            break;
        }

    }

}

long strToInt(string str) { // IF STRING HAS NON DIGITS, YOU WILL GET GARBAGE, BUT NO ERROR
    long j=str.size()-1;
    long value = 0;
    for(long i=0;i<str.size();i++) {
        long x = str[i]-48;

        value+=x*floor( pow(10,j) );
        j--;
    }
    return value;
}

bool isEmpty(superStack stk) {
    if( stk.size()>0){return false; }
    else {return true;}

}    

long getValue(string str) {
    if(str=="ShabbySam") {
        return ShabbySam;
    }
    else if(str=="Hans") {
        return Hans;
    }
    else if(str=="Gertrude") {
        return Gertrude;
    }
    else if(str=="Alberto") {
        return Alberto;
    }   
    else if(str=="Leopold") {
        return Leopold;
    }
    else if(str[ str.size()-1 ]=='s'){
        str.pop_back();

        long index = strToInt(str)-1;

        if( !isEmpty( (*stackptrs[index]) ) ) {
            return (*stackptrs[index]).top();
        }
        else {
            cerr<<"Bad Expression or Empty Stack";


        }   
    }
    else {
        return strToInt(str);
    }

}

void printUnary(long i) {
    while(i>0) {
        cout<<1;
        i--;
    }
}

int main(int argc, char**argv) {

    if(argc<2){std::cerr<<"No input file given"; return 1;}
    ifstream inf(argv[1]);
    if(!inf){std::cerr<<"File open failed";return 1;}

    for(int i=0;i<24;i++) { 
        (*stackptrs[i]).push(0);         // Pre push a zero on every stack
    }

    string labels[20];
    unsigned labelPoints[20];
    int index=0;



    string str;
    while(inf) { //  parse for labels
        inf>>str;
        //cout<<inf.tellg()<<" ";
        if(inf) {
            if(str[str.size()-1]==':') {
                str.pop_back();
                bool alreadyExists = false;
                for(int i=0; i<index;i++){
                    if(labels[i] == str ) { alreadyExists=true;}
                }
                if(!alreadyExists) {
                    labels[index]=str;
                    labelPoints[index]= inf.tellg();
                    index++;
                }
            }

        }

    }
    inf.clear();
    inf.seekg(0,inf.beg);

    while(inf) { // parse for other commands 
        inf>>str;

        if(inf) {


            if(str=="cinpush") {
                string input;
                cin>>input;
                splitpush(input);
            }

            else if(str=="mov") {
                inf>>str;
                long value = getValue(str);

                inf>>str;
                if(str=="Gertrude"){Gertrude=value;}
                else if(str=="Hans"){Hans=value;}
                else if(str=="ShabbySam"){ShabbySam=value;}
                else if(str=="Alberto"){Alberto=value;}
                else if(str=="Leopold"){Leopold=value;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="movfs") {
                inf>>str;
                long index = getValue(str);
                if(!isEmpty( *stackptrs[index-1] )) {
                    inf>>str;
                    long value = (*stackptrs[index-1]).top();
                    if(str=="Gertrude"){Gertrude=value;}
                    else if(str=="Hans"){Hans=value;}
                    else if(str=="ShabbySam"){ShabbySam=value;}
                    else if(str=="Alberto"){Alberto=value;}
                    else if(str=="Leopold"){Leopold=value;}
                    else {cerr<<"Bad register name.";}
                }
                else {
                    cerr<<"Empty Stack";
                }



            }

            else if(str=="inc") {
                inf>>str;
                if(str=="Gertrude"){Gertrude++;}
                else if(str=="Hans"){Hans++;}
                else if(str=="ShabbySam"){ShabbySam++;}
                else if(str=="Alberto"){Alberto++;}
                else if(str=="Leopold"){Leopold++;}
                else {cerr<<"Bad register name. ";}
            }
            else if(str=="dec") {
                inf>>str;
                if(str=="Gertrude"){Gertrude--;}
                else if(str=="Hans"){Hans--;}
                else if(str=="ShabbySam"){ShabbySam--;}
                else if(str=="Alberto"){Alberto--;}
                else if(str=="Leopold"){Leopold--;}
                else {cerr<<"Bad register name. ";}
            }


            else if(str=="compg") {
                inf>>str;
                long value1 = getValue(str);
                inf>>str;
                long value2 = getValue(str);
                inf>>str;
                long larger;
                if(value1>value2){larger = value1;}
                else {larger = value2;}

                if(str=="Gertrude"){Gertrude=larger;}
                else if(str=="Hans"){Hans=larger;}
                else if(str=="ShabbySam"){ShabbySam=larger;}
                else if(str=="Alberto"){Alberto=larger;}
                else if(str=="Leopold"){Leopold=larger;}
                else {cerr<<"Bad register name. ";}

            }
            else if(str=="compl") {
                inf>>str;
                long value1 = getValue(str);
                inf>>str;
                long value2 = getValue(str);
                inf>>str;
                long larger; //LARGER IS REALLY SMALLER HERE
                if(value1>value2){larger = value2;}
                else {larger = value1;}

                if(str=="Gertrude"){Gertrude=larger;}
                else if(str=="Hans"){Hans=larger;}
                else if(str=="ShabbySam"){ShabbySam=larger;}
                else if(str=="Alberto"){Alberto=larger;}
                else if(str=="Leopold"){Leopold=larger;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="gte") {
                inf>>str;
                long value1= getValue(str);
                inf>>str;
                long value2= getValue(str);
                inf>>str;
                bool torf = value1 >= value2;

                if(str=="Gertrude"){Gertrude=torf;}
                else if(str=="Hans"){Hans=torf;}
                else if(str=="ShabbySam"){ShabbySam=torf;}
                else if(str=="Alberto"){Alberto=torf;}
                else if(str=="Leopold"){Leopold=torf;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="lte") {
                inf>>str;
                long value1= getValue(str);
                inf>>str;
                long value2= getValue(str);
                inf>>str;
                bool torf = value1 <= value2;

                if(str=="Gertrude"){Gertrude=torf;}
                else if(str=="Hans"){Hans=torf;}
                else if(str=="ShabbySam"){ShabbySam=torf;}
                else if(str=="Alberto"){Alberto=torf;}
                else if(str=="Leopold"){Leopold=torf;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="POP!!") {
                inf>>str;
                long index = getValue(str);
                index--; //because we (C++ and this interpreter) index differently
                if(!isEmpty( *stackptrs[index] )) {
                    (*stackptrs[index]).pop();
                }
                else {cerr<<"Can't POP!! from empty stack";}

            }

            else if(str=="push"){cerr<<" You can't. ";}

            /*
            else if(str[str.size()-1]==':') {
                str.pop_back();
                bool alreadyExists = false;
                for(int i=0; i<index;i++){
                    if(labels[i] == str ) { alreadyExists=true;}
                }
                if(!alreadyExists) {
                    labels[index]=str;
                    labelPoints[index]= inf.tellg();
                    index++;
                }
            }*/

            else if(str=="jmp") {
                inf>>str;
                for(int i=0;i<index;i++) {
                    if( labels[i]==str) {
                        inf.seekg( labelPoints[i], ios::beg);
                    }
                }
            }
            else if(str=="jz") {
                inf>>str;
                long value = getValue(str);

                if(value==0) {
                    inf>>str;
                    for(int i=0;i<index;i++) {
                        if( labels[i]==str) {
                            inf.seekg( labelPoints[i], ios::beg);
                        }
                    }
                }
            }

            else if(str=="jnz") {
                inf>>str;
                long value = getValue(str);

                if(value!=0) {
                    inf>>str;
                    for(int i=0;i<index;i++) {
                        if( labels[i]==str) {
                            inf.seekg( labelPoints[i], ios::beg);
                        }
                    }
                }
            }

            else if(str== "\"shuffle\"") {
                inf>>str;
                if(str=="l"){ l(); }
                else if(str=="f"){ f(); }
                else if(str=="b"){ b(); }
                else {cerr<<"Bad shuffle parameter";}

            }

            else if(str=="print") {

                for(int i=0;i<24;i++) {

                    if( (i+1) != (*stackptrs[i]).place() ) {
                        cerr<< "Sorry, your stacks are in the wrong place! You can't print unless you put them back! Exiting. ";
                        return 1;
                    }

                }
                inf>>str;
                if(str=="Gertrude"){printUnary(Gertrude);}
                else if(str=="Hans"){printUnary(Hans);}
                else if(str=="ShabbySam"){printUnary(ShabbySam);}
                else if(str=="Alberto"){printUnary(Alberto);}
                else if(str=="Leopold"){printUnary(Leopold);}
                else {cerr<<"Bad register name. ";}


            }

            else if(str=="done!") {return 0;}

            else if(str=="print-d" ){
                inf>>str;
                long value = getValue(str);
                cout<<str;
              }
        }

    }







    /*for(int i=1;i<25;i++) {
        (*(stackptrs[i-1])).push(i);
    }

    u();d();r();l();f();b();
    */

    cout<<"\n";
    for(int i=1;i<25;i++) {
        if( (*(stackptrs[i-1])).size()>0 ) {
            cout<<(*(stackptrs[i-1])).top()<<" "<<(*(stackptrs[i-1])).place()<<"\n";
            (*(stackptrs[i-1])).pop();
        }
    }
    /*
    for (int i=0;i<index;i++) {
        cout<<labels[i]<<": "<<labelPoints[i]<<"\n";
    }*/

    return 1;
}

-> Permutasi Permutasi memungkinkan elemen-elemen dari daftar tumpukan dengan cara berikut:

Dimana artinya

(Ini juga muncul dalam kode juru bahasa. Jika ada perbedaan, juru bahasa benar.)

-> Contoh Sederhana

Dua program sederhana ini mencetak angka dari 24 menjadi 1 (tanpa tanda) tanpa spasi.

mov 24 Hans
start:
    print Hans
    dec Hans
    jnz Hans start
done!

atau

mov 24 Hans start: print Hans dec Hans jnz Hans start done!

Mereka adalah program yang sama.

Penjelasan dan Solusi:

Martin juga memiliki penjelasan yang bagus dalam jawabannya .

Seperti yang diketahui Martin, bahasa ini terinspirasi oleh kubus saku (alias kubus 2x2 Rubik). 24 tumpukan itu seperti 24 kotak individu pada kubus. Permutasi adalah gerakan dasar yang diizinkan: atas, bawah, kanan, kiri, depan, belakang.

Perjuangan utama di sini adalah ketika nilai didorong, hanya tiga gerakan yang digunakan: atas, bawah, dan kanan. Namun, Anda tidak memiliki akses ke gerakan ini saat "mengocok" tumpukan. Anda hanya memiliki tiga gerakan lainnya.

Ternyata, kedua set dari tiga gerakan sebenarnya menjangkau seluruh kelompok (yaitu generator), sehingga masalahnya dapat dipecahkan. Ini berarti bahwa Anda benar-benar dapat menyelesaikan kubus 2x2 Rubik hanya menggunakan 3 langkah.

Yang tersisa untuk dilakukan adalah mencari tahu cara membatalkan gerakan naik, turun, dan kanan menggunakan tiga lainnya. Untuk tujuan ini, saya menggunakan sistem aljabar komputer yang disebut GAP .

Setelah membatalkan permutasi, menemukan angka terbesar ketiga cukup sepele.

cinpush
main:
    mov 1s ShabbySam
    POP!! 1
    jmp compare
    continue:
        gte 0 ShabbySam Leopold
        jnz Leopold end
        gte ShabbySam 9 Leopold
        jz Leopold uinverse
        gte ShabbySam 29 Leopold
        jz Leopold dinverse
        jnz Leopold rinverse
compare:
    gte ShabbySam Alberto Leopold
    jz Leopold skip
    mov Gertrude Hans
    mov Alberto Gertrude
    mov ShabbySam Alberto
    jmp continue
    skip:
        gte ShabbySam Gertrude Leopold
        jz Leopold skip_2
        mov Gertrude Hans
        mov ShabbySam Gertrude
        jmp continue
    skip_2:
        gte ShabbySam Hans Leopold
        jz Leopold continue
        mov ShabbySam Hans
        jmp continue
uinverse: 
    "shuffle" f
    "shuffle" f
    "shuffle" f
    "shuffle" l
    "shuffle" b
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" l
    "shuffle" l
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" l
    "shuffle" l
    "shuffle" l
    "shuffle" f
    jmp main
dinverse:
    "shuffle" f
    "shuffle" b
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" f
    "shuffle" f
    "shuffle" f
    jmp main
rinverse: 
    "shuffle" b "shuffle" l "shuffle" f "shuffle" l "shuffle" b
    "shuffle" f "shuffle" f "shuffle" f "shuffle" b
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" b "shuffle" b "shuffle" b
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" f "shuffle" l "shuffle" f
    "shuffle" l "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l 
    "shuffle" f "shuffle" l "shuffle" l 
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" l "shuffle" l "shuffle" l "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" f "shuffle" l "shuffle" f "shuffle" l "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    jmp main
end:
    print Hans
    done!
Liam
sumber
2
Retak. :) Saya sangat terkesan dengan bahasanya!
Martin Ender
Wow, itu lebih cepat dari yang saya harapkan. Terima kasih, saya senang itu menyenangkan untuk mengetahui seperti menulis.
Liam
Saya ingin tahu, apakah akan jauh lebih sulit jika saya mengubah nama permutasi menjadi sesuatu yang kurang jelas tentang kubus Rubik?
Liam
Mereka pasti tahu, tapi saya pikir itu tidak akan mengambil bahwa lebih lama jika mereka memiliki nama yang berbeda.
Martin Ender
Heh, sepertinya GAP tidak terlalu pintar membalikkan tiga permutasi input. ;)
Martin Ender
22

Brian & Chuck , Retak oleh cardboard_box

Saya telah tertarik untuk beberapa waktu sekarang oleh gagasan bahasa pemrograman di mana dua program berinteraksi satu sama lain (mungkin terinspirasi oleh ROCB ). Tantangan ini adalah insentif yang bagus untuk menangani konsep ini pada akhirnya sambil berusaha menjaga bahasa seminimal mungkin. Tujuan desainnya adalah untuk membuat bahasa Turing-lengkap sementara masing-masing bagian secara individual tidak Turing-lengkap. Selain itu, bahkan keduanya bersama-sama tidak boleh Turing-lengkap tanpa memanfaatkan manipulasi kode sumber. Saya pikir saya sudah berhasil dengan itu, tetapi saya belum membuktikan semua itu secara formal. Jadi tanpa basa-basi lagi saya hadir untuk Anda ...

Protagonis

Brian dan Chuck adalah dua program seperti Brainfuck. Hanya satu dari mereka yang dieksekusi pada waktu tertentu, dimulai dengan Brian. Tangkapannya adalah bahwa rekaman memori Brian juga merupakan kode sumber Chuck. Dan kaset memori Chuck juga merupakan kode sumber Brian. Selain itu, kepala kaset Brian juga merupakan penunjuk instruksi Chuck dan sebaliknya. Kaset semi-tak terbatas (yaitu tak terbatas ke kanan) dan dapat menyimpan bilangan bulat presisi arbitrer yang ditandatangani, diinisialisasi ke nol (kecuali ditentukan lain oleh kode sumber).

Karena kode sumber juga merupakan pita memori, perintah secara teknis ditentukan oleh nilai integer, tetapi sesuai dengan karakter yang masuk akal. Perintah berikut ada:

  • ,( 44): Baca byte dari STDIN ke dalam sel memori saat ini. Hanya Brian yang bisa melakukan ini. Perintah ini adalah no-op untuk Chuck.
  • .( 46): Tulis sel memori saat ini, modulo 256, sebagai byte ke STDOUT. Hanya Chuck yang bisa melakukan ini. Perintah ini adalah no-op untuk Brian.
  • +( 43): Meningkatkan sel memori saat ini.
  • -( 45): Mengurangi sel memori saat ini.
  • ?( 63): Jika sel memori saat ini nol, ini adalah larangan. Kalau tidak, serahkan kontrol ke program lain. Kaset kepala pada program yang menggunakan ?akan tetap di ?. Kepala tape program lain akan memindahkan satu sel ke kanan sebelum menjalankan perintah pertama (sehingga sel yang digunakan sebagai tes tidak dieksekusi sendiri).
  • <( 60): Pindahkan kepala kaset satu sel ke kiri. Ini adalah no-op jika kepala pita sudah di ujung kiri pita.
  • >( 62): Pindahkan kepala kaset satu sel ke kanan.
  • {( 123): Gerakkan kepala pita berulang kali ke kiri hingga sel saat ini nol atau ujung kiri pita tercapai.
  • }( 125): Gerakkan kepala kaset berulang kali ke kanan hingga sel saat ini nol.

Program berakhir ketika pointer instruksi program aktif mencapai titik di mana tidak ada instruksi lagi di sebelah kanannya.

Kode Sumber

File sumber diproses sebagai berikut:

  • Jika file berisi string ```, file akan dipecah menjadi dua bagian di sekitar kemunculan pertama string itu. Semua spasi putih terkemuka dan tertinggal dilucuti dan bagian pertama digunakan sebagai kode sumber untuk Brian dan bagian kedua untuk Chuck.
  • Jika file tidak mengandung string ini, baris pertama file akan digunakan sebagai sumber untuk Brian dan bagian kedua untuk Chuck (terlepas dari baris baru yang membatasi, tidak ada spasi putih yang akan dihapus).
  • Semua kejadian _di kedua program diganti dengan byte NULL.
  • Dua kaset memori diinisialisasi dengan kode karakter yang sesuai dengan string yang dihasilkan.

Sebagai contoh, file sumber berikut

  abc
```
0_1
23

Akan menghasilkan kaset awal berikut:

Brian: [97 98 99 0 0 0 0 ...]
Chuck: [48 0 49 10 50 51 0 0 0 0 ...]

Penerjemah

Penerjemah ditulis dalam Ruby. Dibutuhkan dua flag baris perintah yang tidak boleh digunakan oleh solusi apa pun (karena mereka bukan bagian dari spesifikasi bahasa aktual):

  • -d: Dengan bendera ini, Brian dan Chuck memahami dua perintah lagi. !akan mencetak representasi string dari kedua kaset memori, program aktif yang terdaftar pertama ( ^akan menandai kepala kaset saat ini). @juga akan melakukan ini, tetapi kemudian segera menghentikan program. Karena saya malas, tak satu pun dari mereka yang berfungsi jika mereka adalah perintah terakhir dalam program, jadi jika Anda ingin menggunakannya di sana, ulangi atau tulis no-op setelahnya.
  • -D: Ini adalah mode debug verbal. Ini akan mencetak informasi debug yang sama seperti !setelah setiap centang. @juga berfungsi dalam mode ini.

Ini kodenya:

# coding: utf-8

class Instance
    attr_accessor :tape, :code, :ip

    OPERATORS = {
        '+'.ord  => :inc,
        '-'.ord  => :dec,
        '>'.ord  => :right,
        '<'.ord  => :left,
        '}'.ord  => :scan_right,
        '{'.ord  => :scan_left,
        '?'.ord  => :toggle,
        ','.ord  => :input,
        '.'.ord  => :output,
        '!'.ord  => :debug,
        '@'.ord  => :debug_terminate
    }

    OPERATORS.default = :nop

    def initialize(src)
        @code = src.chars.map(&:ord)
        @code = [0] if code.empty?

        @ip = 0
    end

    def tick
        result = :continue
        case OPERATORS[@code[@ip]]
        when :inc
            @tape.set(@tape.get + 1)
        when :dec
            @tape.set(@tape.get - 1)
        when :right
            @tape.move_right
        when :left
            @tape.move_left
        when :scan_right
            @tape.move_right while @tape.get != 0
        when :scan_left
            @tape.move_left while @tape.ip > 0 && @tape.get != 0
        when :toggle
            if @tape.get != 0
                @tape.move_right
                result = :toggle
            end
        when :input
            input
        when :output
            output
        when :debug
            result = :debug
        when :debug_terminate
            result = :debug_terminate
        end

        return :terminate if result != :toggle && @ip == @code.size - 1

        move_right if result != :toggle

        return result
    end

    def move_right
        @ip += 1
        if @ip >= @code.size
            @code << 0
        end
    end

    def move_right
        @ip += 1
        if @ip >= @code.size
            @code << 0
        end
    end

    def move_left
        @ip -= 1 if @ip > 0
    end

    def get
        @code[@ip]
    end

    def set value
        @code[@ip] = value
    end

    def input() end
    def output() end

    def to_s
        str = self.class.name + ": \n"
        ip = @ip
        @code.map{|i|(i%256).chr}.join.lines.map do |l|
            str << l.chomp << $/
            str << ' '*ip << "^\n" if 0 <= ip && ip < l.size
            ip -= l.size
        end
        str
    end
end

class Brian < Instance
    def input
        byte = STDIN.read(1)
        @tape.set(byte ? byte.ord : -1)
    end
end

class Chuck < Instance
    def output
        $> << (@tape.get % 256).chr
    end
end

class BrianChuck

    class ProgramError < Exception; end

    def self.run(src, debug_level=0)
        new(src, debug_level).run
    end

    def initialize(src, debug_level=false)
        @debug_level = debug_level

        src.gsub!('_',"\0")

        if src[/```/]
            brian, chuck = src.split('```', 2).map(&:strip)
        else
            brian, chuck = src.lines.map(&:chomp)
        end

        chuck ||= ""

        brian = Brian.new(brian)
        chuck = Chuck.new(chuck)

        brian.tape = chuck
        chuck.tape = brian

        @instances = [brian, chuck]
    end

    def run
        (puts @instances; puts) if @debug_level > 1

        loop do
            result = current.tick

            toggle if result == :toggle

            (puts @instances; puts) if @debug_level > 1 || @debug_level > 0 && (result == :debug || result == :debug_terminate)

            break if result == :terminate || @debug_level > 0 && result == :debug_terminate
        end
    end

    private

    def current
        @instances[0]
    end

    def toggle
        @instances.reverse!
    end
end

case ARGV[0]
when "-d"
    debug_level = 1
when "-D"
    debug_level = 2
else
    debug_level = 0
end

if debug_level > 0
    ARGV.shift
end

BrianChuck.run(ARGF.read, debug_level)

Inilah solusi saya sendiri (tulisan tangan) untuk masalah ini:

>}>}>
brace left: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace left: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>} Append a bunch of 1s as a dummy list element:
+>+>+>+>+>+>+>+>+>+
Append two 1s and some code to the list; the first is a marker for later; the latter will be the integer
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow right: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_
{<<<<<<<<<{<{    Move back to the start
Read a character and subtract 48 to get actual 0 or 1
,------------------------------------------------
?   If 1 switch to Chuck otherwise continue
>}>}>>>>>>>>>}<<<<<<- Subtract 1 from the result to account for initial 1
?   If integer was positive switch to Chuck
@todo: process end
_
This code is run when reading 1:
}>}>>>>>>>>>}<<<<<<+ Move to the end of Chuck; skip one null cell; move to the end of the list
{<<<<<<<<<{<?   Move back to the code that resets this loop.
_
This code is run after finalising an integer:
change the code after the integer first
<<--<--<--}
Append two 1s and some code to the list; the first is a marker for later; the latter will be the integer
1: +
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow right: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{<<<<<<<+<<{<{    Move back to the start; incrementing the list length
Read a character and subtract 48 to get actual 0 or 1
,------------------------------------------------
?   If 1 switch to Chuck otherwise continue
>}>}>>>>>>>>>}
Leave the resetting code, but remove the rest of the last list element:
<<<--<--<--
1: <-
question mk: <---------------------------------------------------------------
arrow left: <------------------------------------------------------------
brace right: <-----------------------------------------------------------------------------------------------------------------------------
1: <-
<{< Move back to the cell we reserved for the counter
<<<<<<-- decrement list size by two so we don't process the two largest elements
_

<{<<<<<<{<{<{<{<{>}>}>>>>>>> This is the beginning of the loop which decrements all list elements by 1
+ Add 1 to the running total
>>- Set marker of dummy list element to zero
_ Beginning of loop that is run for each list element
<{<<<<<<{<{<{<{<{>}>}>}>}+ set last marker back to 1
>>>>>>>>>> move to next marker
? Skip the next bit if we're not at the end of the list
<? Move back to the beginning of the loop
@ we should never get here
_
This is run when we're not at the end of the list
<<<- Set marker to 0 to remember current position
>>>>- Move to the current value and decrement it
? Move back to loop beginning if value is not zero yet
- Make element negative so it's skipped in the future
{<{<{>- Move to remaining list length and decrement it
? If it's nonzero switch to Chuck
>>>>>>>>->->->->->->->->->- Remove the dummy list to make some space for new code:
>}+ Fill in the marker in the list
{<<<<<<<<< Add some loop resetting code after the result:
brace left: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_
This loop adds a print command to Chuck's code while decrementing the result
>>>>>>>>}>>>>>}>>>>>} Move to the very end of Chuck's code and leave some space to seek the 1
print: ++++++++++++++++++++++++++++++++++++++++++++++
{<<<<<{<<<<<{<<<<<<<{<
- decrement the result
? if nonzero run loop again
At this point we just need to make Chuck seek for the 1 at the end of this code print it often enough
>>}>>>>>>>}>>>>>}
arrow right: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<?1 Switch to Chuck which moves Brian's tape head onto the 1 and then prints it N times


```

_   Dummy cell to hold input
This code is run when reading a 1:
{<{<{<{ ensure we're at the start
}>}<? Skip 0 handling code and switch to Brian
_ This code is run after a 1 has been processed:
{<{<?

Kode ini dapat dijalankan seperti apa adanya, karena semua anotasi menggunakan no-ops dan dilewati oleh {dan }.

Ide dasarnya adalah:

  1. Tambahkan elemen nol baru ke daftar (di akhir kaset Chuck) dan tambah panjang daftar dengan 1.
  2. Sementara kita membaca 1s, tambahkan elemen itu.
  3. Saat kita membaca 0, lakukan pembersihan. Jika bilangan bulat yang dihasilkan lebih besar dari nol, kembali ke 1.

    Sekarang kita punya daftar nomor input di akhir rekaman Chuck dan kita tahu panjang daftar itu.

  4. Kurangi 2 dari panjang daftar (jadi langkah-langkah berikut mengabaikan dua elemen terbesar), sebut ini N.

  5. Sementara N > 0, tambahkan total yang berjalan dan kemudian kurangi semua elemen daftar. Setiap kali elemen daftar mencapai nol, penurunan N.

    Pada akhir ini, total yang berjalan akan berisi angka terbesar ketiga dalam input M,.

  6. Tulis Msalinan .hingga akhir kaset Chuck.

  7. Di Chuck, cari 1kaset Brian dan jalankan yang dihasilkan .di akhir.

Setelah menyelesaikan ini saya menyadari bahwa saya bisa menyederhanakannya di beberapa tempat. Misalnya, alih-alih melacak penghitung itu dan menulisnya .ke kaset Chuck, saya bisa langsung mencetaknya 1, setiap kali sebelum saya mengurangi semua elemen daftar. Namun, membuat perubahan pada kode ini cukup menyebalkan, karena menyebarkan perubahan lain di semua tempat, jadi saya tidak repot-repot melakukan perubahan.

Bit yang menarik adalah bagaimana melacak daftar dan cara mengulanginya. Anda tidak bisa hanya menyimpan angka berurutan di kaset Chuck, karena jika Anda ingin memeriksa kondisi pada salah satu elemen daftar, Anda berisiko mengeksekusi sisa daftar yang mungkin berisi kode yang valid. Anda juga tidak tahu berapa lama daftar itu, jadi Anda tidak bisa hanya menyimpan sedikit ruang di depan kode Chuck.

Masalah selanjutnya adalah kita perlu membiarkan daftar menurun Nketika kita sedang memprosesnya, dan kita harus kembali ke tempat yang sama seperti sebelumnya. Tapi {dan }akan melewati seluruh daftar.

Jadi kita perlu menulis beberapa kode secara dinamis ke Chuck. Faktanya, setiap elemen daftar imemiliki bentuk:

[1 <Code A> i <Code B>]

1adalah penanda yang dapat kita atur ke nol untuk menunjukkan di mana kita tinggalkan memproses daftar. Tujuannya adalah untuk menangkap {atau }yang hanya akan melewati kode dan i. Kami juga menggunakan nilai ini untuk memeriksa apakah kami berada di akhir daftar selama pemrosesan, jadi sementara kami tidak, ini akan menjadi 1dan kondisional ?akan beralih kontrol ke Chuck. Code Adigunakan untuk menangani situasi itu dan memindahkan IP pada Brian yang sesuai.

Sekarang ketika kita mengurangi ikita perlu memeriksa apakah isudah nol. Meskipun tidak, ?akan kembali beralih kontrol, begitu Code Bjuga untuk mengatasinya.

Martin Ender
sumber
Cracked
cardboard_box
@ cardboard_box Bagus!
mbomb007
15

HPR, ditulis dalam Python 3 ( Cracked oleh TheNumberOne )

HPR (namanya tidak berarti) adalah bahasa untuk memproses daftar bilangan bulat. Ini dirancang untuk menjadi minimalis , sangat terbatas , dan bebas dari batasan "buatan" . Memprogram dalam HPR itu menyakitkan, bukan karena Anda harus memecahkan teka-teki untuk mencegah penerjemah meneriaki Anda, tetapi karena sulit membuat program melakukan sesuatu yang bermanfaat. Saya tidak tahu apakah HPR mampu melakukan sesuatu yang jauh lebih menarik daripada menghitung elemen terbesar ketiga dalam daftar.

Spesifikasi bahasa

Program HPR dijalankan di lingkungan , yang merupakan kumpulan bilangan bulat non-negatif bebas-unordered dan daftar bilangan bulat non-negatif. Awalnya, lingkungan hanya berisi daftar input (penerjemah menguraikannya untuk Anda). Ada tiga perintah dan dua operator "aliran kontrol" yang mengubah lingkungan:

  • *menghapus elemen pertama dari setiap daftar yang tidak kosong di lingkungan, dan menempatkannya di lingkungan. Daftar kosong tidak terpengaruh. Misalnya, itu berubah

    {4,1,[0,2],[1,3],[]} -> {4,1,0,[2],[3],[]}
    
  • -mengurangi semua angka di lingkungan, dan kemudian menghilangkan elemen negatif. Misalnya, itu berubah

    {4,2,0,[0,2],[4,4,4]} -> {3,1,[0,2],[4,4,4]}
    
  • $memutar setiap daftar di lingkungan satu langkah ke kiri. Misalnya, itu berubah

    {4,1,[0,2],[3,4,1]} -> {4,1,[2,0],[4,1,3]}
    
  • !(A)(B), di mana Adan Bprogram, pada dasarnya adalah sebuah whileloop. Ia melakukan "aksi" Asampai "tes" Bakan menghasilkan lingkungan kosong. Ini dapat menghasilkan loop tak terbatas.
  • #(A)(B), di mana Adan Bprogram, berlaku Adan Buntuk lingkungan saat ini dan mengambil perbedaan hasil simetris.

Perintah dijalankan dari kiri ke kanan. Pada akhirnya, ukuran lingkungan dicetak secara unary.

Penerjemah

Penerjemah ini memiliki fitur perintah debug ?, yang mencetak lingkungan tanpa mengubahnya. Seharusnya tidak muncul dalam solusi apa pun untuk tugas tersebut. Setiap karakter kecuali *-$!#()?diabaikan, sehingga Anda dapat menulis komentar langsung ke dalam kode. Akhirnya, interpreter mengenali idiom !(A)(#(A)())sebagai "perform Asampai hasilnya tidak lagi berubah", dan optimalkan untuk kecepatan ekstra (saya membutuhkannya untuk mendapatkan solusi saya untuk menyelesaikan kurang dari satu jam pada test case terakhir).

import sys

def parse(prog):
    "Parse a prefix of a string into an AST. Return it and the remaining input."
    ret = []
    while prog:
        if prog[0] in "#!":
            sub1, prog1 = parse(prog[2:])
            sub2, prog2 = parse(prog1[1:])
            ret += [prog[0],sub1,sub2]
            prog = prog2
        elif prog[0] == ')':
            prog = prog[1:]
            break
        else:
            ret += [prog[0]]
            prog = prog[1:]
    return ret, prog

def intp(ast, L_env, N_env):
    "Interpret the AST on an environment, return the resulting environment."
    ptr = 0
    while ptr < len(ast):
        cmd = ast[ptr]
        if cmd == '*':
            N_env = N_env | set(L[0] for L in L_env if L)
            L_env = set(L[1:] for L in L_env)
            ptr += 1
        elif cmd == '-':
            N_env = set(N-1 for N in N_env if N>0)
            ptr += 1
        elif cmd == '$':
            L_env = set(L[1:]+L[:1] for L in L_env)
            ptr += 1
        elif cmd == '!':
            # Speed optimization
            cond = ast[ptr+2]
            if cond == ['#', ast[ptr+1], []]:
                L_next, N_next = intp(ast[ptr+1], L_env, N_env)
                while L_next != L_env or N_next != N_env:
                    L_env, N_env = L_next, N_next
                    L_next, N_next = intp(ast[ptr+1], L_env, N_env)
            else:
                while True:
                    L_test, N_test = intp(cond, L_env, N_env)
                    if not L_test and not N_test:
                        break
                    L_env, N_env = intp(ast[ptr+1], L_env, N_env)
            ptr += 3
        elif cmd == '#':
            L_env1, N_env1 = intp(ast[ptr+1], L_env, N_env)
            L_env2, N_env2 = intp(ast[ptr+2], L_env, N_env)
            L_env = L_env1 ^ L_env2
            N_env = N_env1 ^ N_env2
            ptr += 3
        elif cmd == '?':
            print(L_env | N_env)
            ptr += 1
        else:
            ptr += 1
    return L_env, N_env

def main(p, L):
    "Run the program on the input, return the output."
    # Parse the input list
    L = ''.join(c for c in L if c in "01")
    while "00" in L:
        L = L.replace("00","0")
    L = [-2] + [i for i in range(len(L)-1) if L[i:i+2] == "10"]
    L = tuple(b-a-1 for (a,b) in zip(L, L[1:]))
    # Parse the program
    ast = parse(p)[0]
    L_env, N_env = intp(ast, set([L]), set())
    return '1'*(len(L_env) + len(N_env))

if __name__ == "__main__":
    filename = sys.argv[1]
    f = open(filename, 'r')
    prog = f.read()
    f.close()
    L = input()
    print(main(prog, L))

Solusi saya

Solusi referensi saya adalah 484 byte, jadi cukup pendek dibandingkan dengan program 3271-byte TheNumberOne. Ini kemungkinan besar karena sistem makro TheNumberOne yang canggih dan mengagumkan yang dikembangkan untuk pemrograman dalam HPR. Gagasan utama dalam kedua program kami serupa:

  1. Cari tahu cara menghasilkan elemen maksimum daftar.
  2. Untuk menghapus elemen maksimum, putar daftar hingga elemen pertama sama dengan maksimum, lalu pop.
  3. Hapus maksimum dua kali, lalu cetak elemen maksimum baru.

Namun, sejauh yang saya tahu, detail implementasi yang tepat sangat berbeda. Inilah solusi saya:

!($)(!(-)(#(-)())#(!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())#(-)(#(!(-)(#(-)()))()))(*)#(!(-)(#(-)()))())*!(-)(#(-)())!($)(!(-)(#(-)())#(!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())#(-)(#(!(-)(#(-)()))()))(*)#(!(-)(#(-)()))())*!(-)(#(-)())!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())-#(!(-)(#(-)()))()

Dan inilah program Python yang berkomentar yang menghasilkannya (tidak ada yang mewah di sini, hanya manipulasi string dasar untuk menghilangkan semua pengulangan):

# No numbers in the environment
no_nums = "#(-)()"
# No non-empty lists in the environment
no_lists = "#(*)()"
# Remove all numbers from the environment
del_nums = "!(-)(" + no_nums + ")"
# Remove all lists from the environment
del_lists = "#(" + del_nums + ")()"
# Splat the list to the environment:
#  pop the list until it's empty and delete the empty list,
#  then take symmetric difference with all numbers removed
splat = "#(!(*)(" + no_lists + ")" + del_lists + ")(" + del_nums + ")"
# Put into the environment all numbers up to list maximum:
#  decrement and splat until a fixed point is reached.
#  Without the speed optimization, this is very slow if the list elements are large.
splat_upto = "!(-" + splat + ")(#(-" + splat + ")())"
# Copy maximum element to environment:
#  take all elements up to maximum,
#  then take symmetric difference of decrement and list deletion
copy_max = splat_upto + "#(-)(" + del_lists + ")"
# Delete maximum element from list:
#  rotate until first element is maximal, then pop and delete it
del_max = "!($)(" + del_nums + "#(" + copy_max + ")(*)" + del_lists + ")*" + del_nums
# Full program:
#  remove the maximum twice, then produce all numbers up to maximum,
#  then decrement and remove lists. The environment will contain exactly
#  the integers from 0 to third largest - 1, and their number is printed.
main = del_max + del_max + splat_upto + "-" + del_lists
print(main)
Zgarb
sumber
Retak!!!
TheNumberOne
@TheNumberOne Menambahkan solusi saya.
Zgarb
12

TKDYNS (Untuk Membunuh Naga, Kamu Membutuhkan Pedang) - Retak oleh Martin Büttner

EDIT: Saya telah menambahkan solusi dan penjelasan saya di bawah posting utama.

Latar Belakang

Dalam bahasa ini, Anda mengendalikan seorang pejuang pemberani yang telah ditugaskan untuk membunuh naga yang mengerikan. Naga itu hidup di labirin bawah tanah, penuh bahaya dan bahaya, dan sampai sekarang, tidak ada yang bisa memetakannya dan bertahan hidup. Ini berarti Anda harus menavigasi jalan ke naga dalam kegelapan pekat, dengan apa-apa selain intuisi dan keberanian untuk membimbing Anda.

...

Ya tidak cukup. Anda telah membawa persediaan antek sekali pakai yang hampir tanpa batas, dan mereka bersedia untuk mendahului Anda untuk menemukan rute yang aman. Sayangnya, semuanya setebal dua papan pendek, dan hanya akan melakukan persis apa yang Anda perintahkan. Terserah Anda untuk menemukan metode cerdas untuk memastikan bahwa antek Anda menemukan jalan yang benar.

Lebih detail

Sarang naga berbentuk kotak 10x10. Di antara titik-titik yang berdekatan di grid, ada jalan sempit; di antara yang lain, ada jurang yang dalam dan kematian yang pasti. Contoh tata letak untuk kisi 4x4 mungkin sebagai berikut:

 0---1   2---3
     |   |   |
 4---5---6   7
 |           |
 8   9--10  11
     |       |
12--13--14--15

Anda tahu bahwa selalu ada cara untuk mendapatkan dari satu titik ke titik lain, tetapi tidak lebih dari yang telah diungkapkan kepada Anda.

Untuk berhasil mengalahkan naga, pertama-tama Anda perlu mengumpulkan beberapa item yang Anda dapat gabungkan bersama untuk membuat pisau pembunuh naga ajaib. Mudahnya, semua potongan untuk senjata ini telah tersebar di sekitar sarang naga. Anda hanya perlu mengumpulkannya.

Memelintir adalah bahwa setiap bagian dari senjata telah terperangkap dalam tubuh. Setiap kali dikumpulkan, tata letak trotoar berubah. Jalur yang sebelumnya aman sekarang bisa mengarah pada kematian, dan sebaliknya.

Perintah

Hanya ada 5 perintah yang valid.

  • < - Ambil langkah ke kiri

  • > - Ambil langkah ke kanan

  • ^ - Ambil langkah ke atas

  • v - Ambil langkah ke bawah

  • c- Kumpulkan barang-barang yang berada di posisi Anda saat ini. Jika ada item, tata letak sarang berubah. Dengan posisi yang dinomori dalam baris di atas, ambil modulo posisi Anda 10. Ada 10 tata letak yang dikodekan secara keras ke dalam juru bahasa, dan tata letak berubah menjadi yang sesuai. Misalnya, jika Anda berada di posisi 13, maka tata letak berubah menjadilayouts[3]

Layout yang muncul di interpeter telah dikodekan ke integer dengan cara berikut:

  • Tata letak kosong dikodekan ke nol.

  • Untuk setiap tepi dalam tata letak, biarkan xyang lebih kecil dari dua posisi yang digabungkan.

    • Jika langkahnya horizontal, tambahkan 2^(2*x)ke pengkodean (itu kekuatan, bukan XOR)

    • Jika langkahnya vertikal, tambahkan 2^(2*x + 1)ke pengkodean.

Alur eksekusi

Interpreter dijalankan dengan nama file sumber sebagai argumen baris perintah.

Ketika penerjemah dijalankan, itu akan meminta pengguna untuk memberikan pencarian. Input ini harus dalam bentuk yang dijelaskan dalam pertanyaan, dan menentukan lokasi di sarang komponen senjata. Secara khusus, setiap integer input diambil modulo 100, dan ditempatkan di lokasi yang sesuai di sarang.

Setiap program sumber terdiri dari beberapa baris, setiap baris terdiri dari beberapa urutan 5 karakter yang valid di atas. Garis-garis ini mewakili kaki tangan Anda. Anda, sang pejuang, melacak urutan tindakan yang diketahui aman. Awalnya, Anda tidak tahu apa-apa tentang sarang, jadi urutan ini kosong. Mengambil setiap antek secara bergantian, berikut ini dilakukan, mulai dari posisi 0:

  • Minion diinstruksikan untuk melakukan semua tindakan yang diketahui aman, diikuti oleh tindakan dalam baris kode sendiri.

    • Jika antek mati pada titik mana pun, Anda diberi tahu tentang hal ini, dan sarang akan kembali ke konfigurasi awalnya. Semua item diganti, dan jalan setapak kembali ke posisi awal mereka.

    • Sebaliknya, jika antek itu bertahan, maka Anda tetap menguapnya - itu hanya antek. Seperti sebelumnya, ini memicu pengaturan ulang sarang ke keadaan awal, tetapi kali ini, Anda menambahkan tindakan dari baris kode antek ke urutan tindakan yang diketahui aman.

Setelah semua antek habis, Anda, prajurit, melakukan semua tindakan yang diketahui aman, sekali lagi mulai dari posisi 0. Ada dua hasil yang mungkin:

  • Anda mengumpulkan semua bagian senjata - dalam hal ini, Anda berhasil membunuh naga itu, dan pesan kemenangan yang menarik adalah output. Pesan kemenangan ini akan berisi, di antara karakter lain n, di mana nangka tertinggi ketiga diberikan sebagai input.

  • Anda gagal mengumpulkan beberapa bagian senjata - dalam kasus ini, naga hidup terus, dan Anda gagal dalam pencarian Anda.

Kode juru bahasa (Python 2)

import collections
import copy
import sys

size = 10
layouts = [108705550239329248440770931020110627243913363144548922111951,108386637020100924277694952798729434993885646706222210602969,133885860318189115027934177821170081234850573770998325845482,102397795295522647918061101991513921833376565032742993744791,131948019244359669407266662537098175265242405785636894694611,127512068876349726396523358265982765442984953916545984706958,106817519055019354200334114020150263381328246524221867629943,33472343358375525802921815863230485208221126168622186265959,133909781123963725874096031069972704024813281938330035579187,132244654022332695610020359820518831299843076834682749020986]

class Interpreter(object):

    def __init__(self, source_file):
        self.source_filename = source_file
        self.layout = layouts[0]
        self.position = 0
        self.ingredients = []
        self.quest_items = {}
        self.attempts = collections.deque()

        self.safe_position = 0
        self.safe_ingredients = []
        self.safe_quest_items = {}
        self.safe_layout = layouts[0]

    def get_input(self):
        s = raw_input("Which quest would you like to embark on today?")
        ind = s.find('00')
        s = s[:ind]
        items = map(len, s.split('0'))
        for item in items:
            if item not in self.safe_quest_items:
                self.safe_quest_items[item] = 1
            else:
                self.safe_quest_items[item] += 1

    def parse_attempts(self):
        with open(self.source_filename, 'r') as source:
            for line in source:
                self.attempts.append(line.strip())

    def enc(self, x, y):
        x, y = min(x, y), max(x, y)
        if x < 0:
            return 0
        if y == x + 1:
            return 1 << (2*x)
        elif y == x + size:
            return 1 << (2*x + 1)
        else:
            return 0

    def exec_command(self, char):
        if char == '<':
            if self.enc(self.position, self.position-1) & self.layout:
                self.position -= 1
            else:
                return False
        elif char == '>':
            if self.enc(self.position, self.position+1) & self.layout:
                self.position += 1
            else:
                return False
        elif char == '^':
            if self.enc(self.position, self.position-size) & self.layout:
                self.position -= size
            else:
                return False
        elif char == 'v':
            if self.enc(self.position, self.position+size) & self.layout:
                self.position += size
            else:
                return False
        elif char == 'c':
            for item in xrange(self.position, 10**6, size*size):
                if item in self.quest_items:
                    self.ingredients += ([item] * self.quest_items.pop(item))
                    self.ingredients.sort()
                    self.layout = layouts[self.position % 10]
        else:
            raise ValueError

        return True

    def run_minion(self):
        minion = self.attempts.popleft()
        self.position = self.safe_position
        self.ingredients = copy.copy(self.safe_ingredients)
        self.quest_items = copy.copy(self.safe_quest_items)
        self.layout = self.safe_layout
        dead = False

        for cmd in minion:
            if not self.exec_command(cmd):
                dead = True

        if not dead:
            self.safe_position = self.position
            self.safe_ingredients = copy.copy(self.ingredients)
            self.safe_quest_items = copy.copy(self.quest_items)
            self.safe_layout = self.layout

    def process_minions(self):
        while self.attempts:
            self.run_minion()

    def final_run(self):
        if len(self.safe_quest_items) == 0:
            print "You killed the dragon" + "!!1" * self.safe_ingredients[-3]
        else:
            print "The dragon lives on. Better luck next time..."

    def interpret(self):
        self.get_input()
        self.parse_attempts()
        self.process_minions()
        self.final_run()

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print "Wrong number of arguments"
    else:
        test = Interpreter(sys.argv[1])
        test.interpret()

Semoga sukses, prajurit gagah berani.

Solusi dan penjelasan saya

Berikut ini adalah skrip Python yang menghasilkan kode sumber untuk menyelesaikan masalah. Yang menarik, kode sumber terakhir Martin sekitar 5 kali lebih kecil dari kode yang dihasilkan oleh skrip saya. Di sisi lain, skrip saya untuk menghasilkan kode adalah sekitar 15 kali lebih kecil daripada program Mathematica Martin ...

size = 10
layouts = [108705550239329248440770931020110627243913363144548922111951,108386637020100924277694952798729434993885646706222210602969,133885860318189115027934177821170081234850573770998325845482,102397795295522647918061101991513921833376565032742993744791,131948019244359669407266662537098175265242405785636894694611,127512068876349726396523358265982765442984953916545984706958,106817519055019354200334114020150263381328246524221867629943,33472343358375525802921815863230485208221126168622186265959,133909781123963725874096031069972704024813281938330035579187,132244654022332695610020359820518831299843076834682749020986]

def enc(edge):
    x,y = min(edge), max(edge)
    if x < 0:
        return 0
    if y == x + 1:
        return 1 << (2*x)
    elif y == x + size:
        return 1 << (2*x + 1)

def path(x, y, tree):
    stack = [(x,'')]
    while stack[-1][0] != y:
        vertex, path = stack.pop()
        if (enc((vertex, vertex+1))&tree) and ((not path) or path[-1] != '<'):
            stack.append((vertex+1, path+'>'))
        if (enc((vertex, vertex-1))&tree) and ((not path) or path[-1] != '>'):
            stack.append((vertex-1, path+'<'))
        if (enc((vertex, vertex+size))&tree) and ((not path) or path[-1] != '^'):
            stack.append((vertex+size, path+'v'))
        if (enc((vertex, vertex-size))&tree) and ((not path) or path[-1] != 'v'):
            stack.append((vertex-size, path+'^'))
    return stack[-1][1]

def reverse(path):
    rev = ''
    for i in xrange(len(path)-1, -1 ,-1):
        if path[i] == '<':
            rev += '>'
        if path[i] == '>':
            rev += '<'
        if path[i] == 'v':
            rev += '^'
        if path[i] == '^':
            rev += 'v'
    return rev

def assert_at(x, tree):
    path_ul = path(x, 0, tree)
    path_dr = path(x, size*size - 1, tree)
    return path_ul + reverse(path_ul) + path_dr + reverse(path_dr)

def safe_path(x, y, tree):
    return assert_at(x, tree) + path(x, y, tree)

with open('source.txt', 'w') as f:
    for x in xrange(size*size - 1):
        for tree in layouts:
            f.write(safe_path(x, x+1, tree) + 'c\n')

Struktur dasar

Ini menghasilkan 990 baris kode sumber, yang datang dalam kelompok 10. 10 baris pertama semuanya berisi instruksi yang mencoba untuk memindahkan antek dari posisi 0ke posisi 1, dan kemudian mengumpulkan item - satu set untuk setiap tata letak yang mungkin. 10 baris berikutnya semuanya berisi instruksi yang mencoba untuk memindahkan antek dari posisi 1ke posisi 2, dan kemudian mengumpulkan item. Dan seterusnya ... Jalur ini dihitung dengan pathfungsi dalam skrip - hanya melakukan pencarian kedalaman-pertama yang sederhana.

Jika kita dapat memastikan bahwa, di setiap kelompok 10, tepatnya satu antek berhasil, maka kita akan menyelesaikan masalah.

Masalah dengan pendekatan

Ini mungkin tidak selalu menjadi kasus yang tepat satu antek dari kelompok 10 berhasil - misalnya, antek dirancang untuk mendapatkan dari posisi 0ke posisi 1mungkin sengaja berhasil bergerak dari posisi 1ke posisi 2(karena kesamaan dalam layout), dan bahwa salah perhitungan akan menyebar melalui, berpotensi menyebabkan kegagalan.

Bagaimana memperbaikinya

Perbaikan yang saya gunakan adalah sebagai berikut:

Untuk setiap antek yang berusaha bergerak dari posisi nke posisi n+1, pertama-tama buat dia berjalan dari posisi nke posisi 0(sudut kiri atas) dan kembali lagi, kemudian dari posisi nke posisi 99(sudut kanan bawah) dan kembali lagi. Instruksi ini hanya dapat dilakukan dengan aman dari posisi n- posisi awal lainnya dan antek akan berjalan menjauh.

Oleh karena itu, instruksi tambahan ini mencegah antek agar tidak sengaja pergi ke suatu tempat yang tidak seharusnya, dan ini memastikan bahwa satu antek dari masing-masing kelompok 10 berhasil. Perhatikan bahwa belum tentu antek yang Anda harapkan - mungkin antek yang percaya bahwa dia ada di tata letak 0 berhasil, bahkan ketika kita benar-benar di tata letak 7 - tetapi dalam kasus apa pun, fakta bahwa kita memiliki sekarang perubahan posisi berarti bahwa semua antek lainnya dalam grup akan mati. Langkah-langkah tambahan ini dihitung oleh assert_atfungsi, dan safe_pathfungsi mengembalikan jalur yang merupakan gabungan dari langkah-langkah tambahan ini dengan jalur biasa.

Sam Cappleman-Lynes
sumber
1
Retak. Ini sangat menyenangkan, tetapi saya pikir itu memunculkan masalah dengan aturan "bahasa pemrograman Anda hanya harus menyelesaikan tugas yang satu ini", karena memecahkan teka-teki Anda tidak ada hubungannya dengan benar-benar menyelesaikan tugas pemrograman itu. ;)
Martin Ender
Saya membuat jawaban ini terutama karena saya perhatikan bahwa ada masalah - dan sepertinya tidak ada yang menghentikan seseorang untuk menggunakan masalah komputasi yang benar-benar sulit sebagai gantinya. Larangan 'no crypto' nampak sempit ...
Sam Cappleman-Lynes
benar. Saya rasa itu sebabnya ini adalah kontes popularitas. Jika masalahnya lebih bersifat komputasi dan tidak dibungkus dengan cerita yang bagus, sebanyak suara sebagai jawaban dengan bahasa yang tepat (berpotensi Turing lengkap) yang sebenarnya hanya sangat sulit digunakan.
Martin Ender
Menambahkan solusi saya untuk minat. Juga untuk menarik, saya awalnya merancang teka-teki dengan grid 1000x1000 dalam pikiran, tetapi untuk kepentingan tidak memiliki tata letak yang dikodekan ke ~ angka 600.000 angka saya memilih untuk ukuran yang lebih kecil.
Sam Cappleman-Lynes
8

Firetype, Cracked oleh Martin Büttner

Campuran yang sangat aneh dari BF dan CJam. Dan siapa yang tahu apa lagi! Cukup yakin ini akan menjadi mudah, tapi itu tetap menyenangkan. FYI, namanya mengacu pada Vermillion Fire dari Final Fantasy Type-0 .

CATATAN : Maafkan saya atas ambiguitas dalam uraian ini. Saya bukan penulis terbaik ...: O

Martin memecahkan ini dengan sangat cepat! Ini adalah program asli saya untuk menyelesaikan masalah:

_
,
^
~
+
|
|
-
%
+
_
+
=











`
~
+
|
%

_
=

\
@
-
-
!
<
>
>
>

_
+
.
<
-
`
~
~
+
|
|
-
#
%

Sintaksis

Skrip Firetype pada dasarnya adalah daftar baris. Karakter pertama dari setiap baris adalah perintah untuk dijalankan. Baris kosong pada dasarnya adalah NOP.

Semantik

Anda memiliki array bilangan bulat dan pointer (pikirkan BF). Anda dapat memindahkan elemen ke kiri dan ke kanan atau "mendorong" ke dalam array.

Mendorong

Saat Anda "mendorong" suatu elemen dan Anda berada di ujung array, elemen tambahan akan ditambahkan ke bagian akhir. Jika Anda tidak pada akhirnya, elemen berikutnya akan diganti. Apapun, pointer akan selalu bertambah.

Perintah

_

Dorong nol ke array.

+

Tambahkan elemen pada pointer saat ini.

-

Mengurangi elemen di pointer saat ini.

*

Gandakan elemen pada pointer saat ini.

/

Membagi dua elemen pada pointer saat ini.

%

Ambil elemen pada pointer saat ini dan lompat ke depan banyak garis, dan gerakkan pointer ke kiri. Jika nilainya negatif, sebaliknya melompat mundur.

=

Ambil elemen pada pointer saat ini dan lompat ke garis itu + 1. Misalnya, jika elemen saat ini 0, ini akan melompat ke garis 1. Ini juga memindahkan pointer ke kiri.

,

Baca karakter dari input standar dan dorong nilai ASCII-nya.

^

Ambil elemen pada pointer saat ini, menafsirkannya sebagai nilai ASCII untuk karakter, dan mengubahnya menjadi integer. Misalnya, jika nilai saat ini adalah 49 (nilai ASCII 1), elemen pada pointer saat ini akan ditetapkan ke integer 1.

.

Tulis nomor saat ini ke layar.

!

Ambil elemen pada pointer saat ini dan ulangi baris berikutnya yang berkali-kali. Juga menggerakkan pointer ke kiri.

<

Pindahkan penunjuk ke kiri. Jika Anda sudah di awal, kesalahan dilemparkan.

>

Pindahkan penunjuk ke kanan. Jika Anda sudah di bagian akhir, kesalahan terjadi.

~

Jika elemen saat ini bukan nol, gantilah dengan 0; jika tidak, ganti dengan 1.

|

Kuadratkan elemen saat ini.

@

Setel elemen saat ini ke panjang array.

`

Gandakan elemen saat ini.

\

Urutkan elemen pada dan sebelum pointer.

#

Meniadakan elemen saat ini.

Penerjemah

Juga tersedia di Github .

#!/usr/bin/env python

# The FireType interpreter.
# Runs under Python 2 and 3.
import sys

class Array(object):
    def __init__(self):
        self.array = []
        self.ptr = 0

    def push_zero(self):
        if self.ptr == len(self.array):
            self.array.append(0)
        else:
            self.array[self.ptr] = 0
        self.ptr += 1

    def left(self):
        self.ptr -= 1
        assert self.ptr >= 0 and self.array, 'pointer underflow (at %d)' % i

    def right(self):
        self.ptr += 1
        assert self.ptr <= len(self.array), 'pointer overflow (at %d)' % i

    def sort(self):
        lhs = self.array[:self.ptr-1]
        rhs = self.array[self.ptr-1:]
        lhs.sort()
        lhs.reverse()
        self.array = lhs + rhs

    def __call__(self, *args):
        args = list(args)
        assert self.array, 'out-of-bounds (at %d)' % i
        if not args:
            return self.array[self.ptr-1]
        self.array[self.ptr-1] = args.pop()
        assert not args

    def __len__(self):
        return len(self.array)

    def __str__(self):
        return 'Array(array=%s, ptr=%s)' % (self.array, self.ptr)

    def __repr__(self):
        return 'Array(array=%r, ptr=%r)' % (self.array, self.ptr)

def execute(lines):
    global i, array
    i = 0
    array = Array()
    rep = 0
    while i < len(lines):
        line = lines[i]
        if not line:
            i += 1
            continue
        line = line[0]
        if line == '_':
            array.push_zero()
        elif line == '+':
            array(array() + 1)
        elif line == '-':
            array(array() - 1)
        elif line == '*':
            array(array() * 2)
        elif line == '/':
            array(int(array() / 2))
        elif line == '%':
            i += array()
            array.left()
        elif line == '=':
            i = array()-1
            array.left()
        elif line == ',':
            array.push_zero()
            array(ord(sys.stdin.read(1)))
        elif line == '.':
            sys.stdout.write(str(array()))
        elif line == '!':
            rep = array()
            array.left()
            i += 1
        elif line == '<':
            array.left()
        elif line == '>':
            array.right()
        elif line == '^':
            array(int(chr(array())))
        elif line == '~':
            array(int(not array()))
        elif line == '|':
            array(array() ** 2)
        elif line == '@':
            array(len(array))
        elif line == '`':
            top = array()
            array.push_zero()
            array(top)
        elif line == '\\':
            array.sort()
        elif line == '#':
            array(-array())

        if rep:
            rep -= 1
        else:
            i += 1

def main(args):
    try:
        _, path = args
    except ValueError:
        sys.exit('usage: %s <file to run, - for stdin>')

    if path == '-':
        data = sys.stdin.read()
    else:
        with open(path) as f:
            data = f.read()

    try:
        execute(data.split('\n'))
    except:
        print('ERROR!')
        print('Array was %r' % array)
        print('Re-raising error...')
        raise

if __name__ == '__main__':
    main(sys.argv)
kirbyfan64sos
sumber
Saya pikir pernyataan untuk batas bawah array buggy. Karena Anda menggunakan self.ptr-1akses, Anda mungkin harus memeriksa self.ptr>0tidak >=0. (Ini seharusnya tidak membatalkan program yang valid tetapi mungkin membuat beberapa program membuat pekerjaan tidak sengaja yang seharusnya.)
Martin Ender
Satu hal lagi: kode mengatakan =set nilai array() - 1, dokumentasi mengatakan +1?
Martin Ender
Retak. (Dengan anggapan bahwa penerjemah itu normatif, bukan deskripsi.)
Martin Ender
@ MartinBüttner Dang, itu lebih cepat dari yang saya kira! : OI memperbaiki masalah dokumen yang Anda sebutkan.
kirbyfan64sos
7

Acc !! (aman)

Itu Baack ...

masukkan deskripsi gambar di sini

... dan mudah - mudahan pasti lebih banyak jalan keluarnya.

Saya sudah membaca Acc! spek. Bagaimana Acc !! berbeda?

Di Acc !! , variabel loop keluar dari ruang lingkup ketika loop keluar. Anda hanya bisa menggunakannya di dalam loop. Di luar, Anda akan mendapatkan kesalahan "nama tidak didefinisikan". Selain perubahan ini, bahasa-bahasa itu identik.

Pernyataan

Perintah diurai baris demi baris. Ada tiga jenis perintah:

  1. Count <var> while <cond>

Menghitung <var>dari 0 selama <cond>bukan nol, setara dengan C ++ for(int <var>=0; <cond>; <var>++). Penghitung lingkaran dapat berupa huruf kecil tunggal. Kondisi dapat berupa ekspresi apa pun, tidak harus melibatkan variabel loop. Loop berhenti ketika nilai kondisi menjadi 0.

Loop membutuhkan kurung kurawal gaya K&R (khususnya, varian Stroustrup ):

Count i while i-5 {
 ...
}

Seperti disebutkan di atas, variabel loop hanya tersedia di dalam loop mereka ; mencoba merujuk mereka setelah itu menyebabkan kesalahan.

  1. Write <charcode>

Output karakter tunggal dengan nilai ASCII / Unicode yang diberikan ke stdout. Kode sandi dapat berupa ekspresi apa pun.

  1. Ekspresi

Ekspresi apa pun yang berdiri sendiri dievaluasi dan ditugaskan kembali ke akumulator (yang dapat diakses sebagai _). Jadi, misalnya, 3adalah pernyataan yang menetapkan akumulator ke 3; _ + 1menambah akumulator; dan _ * Nmembaca karakter dan mengalikan akumulator dengan kode sandi-nya.

Catatan: akumulator adalah satu-satunya variabel yang dapat ditugaskan secara langsung; variabel loop dan Ndapat digunakan dalam perhitungan tetapi tidak dimodifikasi.

Akumulator awalnya 0.

Ekspresi

Ekspresi dapat menyertakan bilangan bulat integer, variabel loop ( a-z), _untuk akumulator, dan nilai khusus N, yang membaca karakter dan mengevaluasi karakternya setiap kali digunakan. Catatan: ini berarti Anda hanya mendapatkan satu kesempatan untuk membaca setiap karakter; lain kali Anda gunakan N, Anda akan membaca yang berikutnya.

Operator adalah:

  • +, tambahan
  • -, pengurangan; negasi unary
  • *, penggandaan
  • /, pembagian bilangan bulat
  • %, modulo
  • ^, eksponensial

Kurung dapat digunakan untuk menegakkan prioritas operasi. Karakter lain dalam ekspresi adalah kesalahan sintaksis.

Spasi dan komentar

Ruang putih dan baris kosong terkemuka dan tertinggal diabaikan. Spasi putih dalam header loop harus persis seperti yang ditunjukkan, dengan satu ruang antara header loop dan kurung kurawal terbuka juga. Ekspresi di dalam spasi putih adalah opsional.

# memulai komentar satu baris.

Input output

Acc !! mengharapkan satu baris karakter sebagai input. Setiap karakter input dapat diambil secara berurutan dan karakternya diproses menggunakan N. Mencoba membaca melewati karakter terakhir dari baris menyebabkan kesalahan. Sebuah karakter dapat di-output dengan memberikan kode-nya ke Writepernyataan.

Penerjemah

Penerjemah (ditulis dengan Python 3) menerjemahkan Acc !! kode ke Python dan execs itu.

import re, sys

def main():
    if len(sys.argv) != 2:
        print("Please supply a filename on the command line.", file=sys.stderr)
        return
    codeFile = sys.argv[1]
    with open(codeFile) as f:
        code = f.readlines()
    code = translate(code)
    exec(code, {"inputStream": (ord(char) for char in input())})

def translate(accCode):
    indent = 0
    loopVars = []
    pyCode = ["_ = 0"]
    for lineNum, line in enumerate(accCode):
        if "#" in line:
            # Strip comments
            line = line[:line.index("#")]
        line = line.strip()
        if not line:
            continue
        lineNum += 1
        if line == "}":
            if indent:
                loopVar = loopVars.pop()
                pyCode.append(" "*indent + loopVar + " += 1")
                indent -= 1
                pyCode.append(" "*indent + "del " + loopVar)
            else:
                raise SyntaxError("Line %d: unmatched }" % lineNum)
        else:
            m = re.fullmatch(r"Count ([a-z]) while (.+) \{", line)
            if m:
                expression = validateExpression(m.group(2))
                if expression:
                    loopVar = m.group(1)
                    pyCode.append(" "*indent + loopVar + " = 0")
                    pyCode.append(" "*indent + "while " + expression + ":")
                    indent += 1
                    loopVars.append(loopVar)
                else:
                    raise SyntaxError("Line %d: invalid expression " % lineNum
                                      + m.group(2))
            else:
                m = re.fullmatch(r"Write (.+)", line)
                if m:
                    expression = validateExpression(m.group(1))
                    if expression:
                        pyCode.append(" "*indent
                                      + "print(chr(%s), end='')" % expression)
                    else:
                        raise SyntaxError("Line %d: invalid expression "
                                          % lineNum
                                          + m.group(1))
                else:
                    expression = validateExpression(line)
                    if expression:
                        pyCode.append(" "*indent + "_ = " + expression)
                    else:
                        raise SyntaxError("Line %d: invalid statement "
                                          % lineNum
                                          + line)
    return "\n".join(pyCode)

def validateExpression(expr):
    "Translates expr to Python expression or returns None if invalid."
    expr = expr.strip()
    if re.search(r"[^ 0-9a-z_N()*/%^+-]", expr):
        # Expression contains invalid characters
        return None
    elif re.search(r"[a-zN_]\w+", expr):
        # Expression contains multiple letters or underscores in a row
        return None
    else:
        # Not going to check validity of all identifiers or nesting of parens--
        # let the Python code throw an error if problems arise there
        # Replace short operators with their Python versions
        expr = expr.replace("^", "**")
        expr = expr.replace("/", "//")
        # Replace N with a call to get the next input character
        expr = expr.replace("N", "inputStream.send(None)")
        return expr

if __name__ == "__main__":
    main()

Larutan

Kejatuhan Acc asli ! adalah variabel loop yang terus dapat diakses di luar loop mereka. Ini memungkinkan penyimpanan salinan akumulator, yang membuat solusinya terlalu mudah.

Di sini, tanpa lubang loop ini (maaf), kami hanya memiliki akumulator untuk menyimpan barang. Namun, untuk menyelesaikan tugas, kita perlu menyimpan empat nilai besar yang sewenang-wenang. 1 Solusinya: interleave bit mereka dan simpan nomor kombinasi yang dihasilkan di akumulator. Misalnya, nilai akumulator 6437 akan menyimpan data berikut (menggunakan bit urutan terendah sebagai flag bit tunggal):

1100100100101  Binary representation of accumulator
321032103210F  Key

The flag is 1 and the four numbers are
Number 0: 010 = 2
Number 1: 001 = 1
Number 2: 100 = 4
Number 3: 110 = 6

Kita dapat mengakses bit nomor apa pun dengan membagi akumulator dengan kekuatan yang sesuai dari 2, mod 2. Ini juga memungkinkan untuk mengatur atau membalik bit individu.

Pada tingkat makro, algoritme melingkupi angka-angka unary dalam input. Bunyinya nilai ke angka 0, kemudian melakukan algoritma bubble sort untuk menempatkannya di posisi yang tepat dibandingkan dengan tiga angka lainnya. Akhirnya, ia membuang nilai yang tersisa di angka 0, karena itu adalah yang terkecil dari empat sekarang dan tidak pernah bisa menjadi terbesar ketiga. Ketika loop selesai, angka 1 adalah yang terbesar ketiga, jadi kami membuang yang lain dan mengeluarkannya.

Bagian tersulit (dan alasan saya memiliki variabel global loop dalam inkarnasi pertama) adalah membandingkan dua angka untuk mengetahui apakah akan menukar mereka. Untuk membandingkan dua bit, kita bisa mengubah tabel kebenaran menjadi ekspresi matematika; terobosan saya untuk Acc !! sedang menemukan algoritma perbandingan yang berjalan dari bit orde rendah ke orde tinggi, karena tanpa variabel global tidak ada cara untuk mengulang bit angka dari kiri ke kanan. Bit akumulator terendah menyimpan bendera yang memberi sinyal apakah akan menukar dua angka yang sedang dipertimbangkan.

Saya curiga bahwa Acc !! adalah Turing-complete, tapi saya tidak yakin saya ingin repot membuktikannya.

Inilah solusi saya dengan komentar:

# Read and process numbers until the double 0

Count y while N-48 {
    # Read unary number and store it (as binary) in number 0
    # The above loop header consumed the first 1, so we need to add 1 to number 0

    _ + 2

    # Increment number 0 for each 1 in input until next 0

    Count z while N-48 {
        # In this context, the flag indicates a need to carry; set it to 1
        _ - _%2 + 1

        # While carry flag is set, increment the next bit in line
        Count i while _%2 {
            # Set carry flag to 1 if i'th bit is 1, 0 if it's 0
            # Set i'th bit to 1 if it was 0, 0 if it was 1
            _ - _%2 + _/2^(i*4+1)%2 + (-1)^(_/2^(i*4+1)%2)*2^(i*4+1)
        }
    }

    # Bubble number 0 upwards

    Count n while n-3 {
        # The flag (rightmost bit of accumulator) needs to become 1 if we want to swap
        # numbers (n) and (n+1) and 0 if we don't
        # Iterate over bit-groups of accumulator, RTL
        Count i while _/2^(i*4+1) {
            # Adjust the flag as follows:
            # _/2^(i*4+n+1)%4 is the current bit of number (n+1) followed by the current
            # bit of number (n), a value between 0 and 3
            # - If this quantity is 1 (01), number (n) is bigger so far; set flag to 1
            # - If this quantity is 2 (10), number (n+1) is bigger so far; set flag to 0
            # - If this quantity is 0 (00) or 3 (11), the two bits are the same; keep
            #   current value of flag
            _ + (_/2^(i*4+n+1)%4%3 + 1)/2*(_/2^(i*4+n+1)%4%3%2 - _%2)
        }

        # Now swap the two if the flag is 1
        Count i while (_%2)*(_/2^(i*4+1)) {
            # _/2^(i*4+n+1)%2 is the current bit of number (n)
            # _/2^(i*4+n+2)%2 is the current bit of number (n+1)
            _ - (_/2^(i*4+n+1)%2)*2^(i*4+n+1) - (_/2^(i*4+n+2)%2)*2^(i*4+n+2) + (_/2^(i*4+n+2)%2)*2^(i*4+n+1) + (_/2^(i*4+n+1)%2)*2^(i*4+n+2)
        }
    }

    # Discard number 0, setting it to all zeros for the next iteration
    Count i while _/2^(i*4+1) {
        _ - _/2^(i*4+1)%2*2^(i*4+1)
    }
}

# Once the loop is over, all input has been read and the result is in number 1
# Divide by 2 to get rid of flag bit

_ / 2

# Zero out numbers 2 and 3

Count i while _/2^(i*4) {
    _ - _/2^(i*4+2)%2*2^(i*4+2)
}

Count i while _/2^(i*4) {
    _ - _/2^(i*4+3)%2*2^(i*4+3)
}

# Move bits of number 1 down to their final locations

Count i while _/2^i {
    _ - _/2^(i*4+1)%2*2^(i*4+1) + _/2^(i*4+1)%2*2^i
}

# _ now contains the correct answer in decimal; to output in unary:

Count z while z-_ {
    Write 49
}

1 Menurut spesifikasi pertanyaan, hanya nilai hingga 1 juta yang perlu didukung. Saya senang tidak ada yang memanfaatkan itu untuk solusi yang lebih mudah - walaupun saya tidak sepenuhnya yakin bagaimana Anda akan melakukan perbandingan.

DLosc
sumber
LOL @ the Bill the Cat
spaghetto
7

Picofuck (aman)

Picofuck mirip dengan Smallfuck . Ini beroperasi pada pita biner yang tidak terikat di sebelah kanan, terikat di sebelah kiri. Ini memiliki perintah berikut:

  • > gerakkan pointer ke kanan

  • <gerakkan pointer ke kiri. Jika penunjuk jatuh dari kaset, program berakhir.

  • * balikkan bit pada pointer

  • (jika bit pada pointer 0, lompat ke yang berikutnya)

  • )tidak melakukan apa pun - tanda kurung di Picofuck adalah ifblok, bukan whileloop.

  • .tulis untuk stdout bit pada pointer sebagai ascii 0atau 1.

  • ,dibaca dari stdin sampai kita menghadapi 0atau 1, dan menyimpan ini dalam bit pada pointer.

Kode Picofuck membungkus - setelah akhir program tercapai, ia berlanjut dari awal.

Selain itu, Picofuck melarang kurung bersarang. Tanda kurung yang muncul dalam program Picofuck harus bergantian antara (dan ), dimulai dengan (dan diakhiri dengan ).

Penerjemah

Ditulis dengan Python 2.7

pemakaian: python picofuck.py <source_file>

import sys

def interpret(code):
    # Ensure parentheses match and are not nested.
    in_if_block = False
    for c in code:
        if c == '(':
            if in_if_block:
                print "NESTED IFS DETECTED!!!!!"
                return
            in_if_block = True
        elif c == ')':
            if not in_if_block:
                print "Unmatched parenthesis"
                return
            in_if_block = False
    if in_if_block:
        print "Unmatched parenthesis"
        return


    code_ptr = 0
    array = [0]
    ptr = 0

    while 1:
        command = code[code_ptr]
        if command == '<':
            if ptr == 0:
                break
            ptr -= 1
        elif command == '>':
            ptr += 1
            if ptr == len(array):
                array.append(0)
        elif command == '*':
            array[ptr] = 1-array[ptr]
        elif command == '(':
            if array[ptr] == 0:
                while code[code_ptr] != ')':
                    code_ptr = (code_ptr + 1) % len(code)
        elif command == ',':
            while True:
                c = sys.stdin.read(1)
                if c in ['0','1']:
                    array[ptr] = int(c)
                    break
        elif command == '.':
            sys.stdout.write(str(array[ptr]))
        code_ptr = (code_ptr+1)%len(code)

if __name__ == "__main__":
    with open(sys.argv[1]) as source_file:
        code = source_file.read()
    interpret(code)

Larutan

Program python 2.7 berikut menghasilkan solusi saya yang dapat ditemukan di sini

Saya dapat mengedit posting ini nanti dengan penjelasan yang lebih menyeluruh tentang cara kerjanya, tetapi ternyata Picofuck adalah Turing-complete.

states = {
    "SETUP":(
        "*>",
        "GET_NUMBER",
        "GET_NUMBER"
    ),

    "GET_NUMBER":(
        ",",
        "CHANGE_A",
        "PREPARE_PRINT_C"
    ),

    "GET_DIGIT":(
        ",",
        "CHANGE_A",
        "GOT_DIGIT"
    ),

    "GOT_DIGIT":(
        ">>>>",
        "GO_BACK",
        "GO_BACK"
    ),

    "CHANGE_A":(
        ">",
        "CHANGE_B",
        "SET_A"
    ),

    "SET_A":(
        "*>>>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CHANGE_B":(
        ">",
        "CHANGE_C",
        "SET_B"
    ),

    "SET_B":(
        "*>>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CHANGE_C":(
        ">",
        "CONTINUE_GET_NUMBER",
        "SET_C"
    ),

    "SET_C":(
        "*>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CONTINUE_GET_NUMBER":(
        ">>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "GO_BACK":(
        "<<<<<",
        "FINISH_GO_BACK",
        "GO_BACK"
    ),

    "FINISH_GO_BACK":(
        ">",
        "GET_NUMBER",
        "GET_NUMBER"
    ),

    "PREPARE_PRINT_C":(
        ">>>",
        "PRINT_C",
        "PRINT_C"
    ),

    "PRINT_C":(
        ".>>>>>",
        "PRINT_C",
        "TERMINATE"
    ),

    "TERMINATE":(
        "<",
        "TERMINATE",
        "TERMINATE"
    ),
}

def states_to_nanofuck(states,start_state):
    state_list = list(states)
    state_list.remove(start_state)
    state_list.insert(0,start_state)

    states_by_index = []
    for i,state in enumerate(state_list):
        commands, next1, next0 = states[state]
        states_by_index.append((commands,state_list.index(next1),state_list.index(next0)))


    # setup first state
    fragments = ['*(*>>>>>*<<<<<)>>>>>']

    # reset states that don't match
    for index in range(len(states_by_index)):
        for bool in range(2):
            # at state_0_0
            state_dist = index*3 + bool
            # move state to curstate
            fragments.append('>'*state_dist)
            fragments.append('(*')
            fragments.append(  '<'*state_dist)
            fragments.append(  '<<*>>')
            fragments.append(  '>'*state_dist)
            fragments.append(')')
            fragments.append('<'*state_dist)

            # go to arr
            fragments.append('<<<')

            if bool == 0:
                #flip arr
                fragments.append('*')

            # compute match = arr & curstate
            fragments.append('(>)(>*<)<(<)>')

            if bool == 0:
                #flip arr
                fragments.append('*')

            # reset curstate
            fragments.append('>(*)')

            # move match to matchstate, go back to state_0_0
            matchstate_dist = index*3 + 2
            fragments.append('>(*>')
            fragments.append(  '>'*matchstate_dist)
            fragments.append(  '*')
            fragments.append(  '<'*matchstate_dist)
            fragments.append('<)>')

    #fragments.append('|')

    # do the commands of the matching state
    for index,state in enumerate(states_by_index):
        for bool in range(2):
            # at state_0_0
            matchstate_dist = index*3 + 2
            # move matchstate to curstate
            fragments.append('>'*matchstate_dist)
            fragments.append('(*')
            fragments.append(  '<'*matchstate_dist)
            fragments.append(  '<<*>>')
            fragments.append(  '>'*matchstate_dist)
            fragments.append(')')
            fragments.append('<'*matchstate_dist)

            # if curstate, reset curstate
            fragments.append('<<(*')

            # go to arr
            fragments.append('<')

            # do commands
            commands,next1,next0 = state
            for c in commands:
                if c in '<>':
                    fragments.append(c*(3*len(states_by_index)+5))
                else:
                    fragments.append(c)

            # go to state_0_0
            fragments.append('>>>')

            # set next states
            for dist in [next0*3, next1*3+1]:
                fragments.append('>'*dist)
                fragments.append('*')
                fragments.append('<'*dist)

            # go to curstate
            fragments.append('<<')

            # end if
            fragments.append(')')

            # go to state_0_0
            fragments.append('>>')


    # go back to setup and set it
    fragments.append('<<<<<*')

    code = ''.join(fragments)

    return code



print states_to_nanofuck(states, "SETUP")
kotak kardus
sumber
2
menunggu hampir 2 tahun Apakah ini belum?
CalculatorFeline
Hanya FYI, tautan yang Anda berikan sekarang mati. '
Conor O'Brien
Tautan tersebut memerlukan unduhan dan saya terlalu malas. Tolong perbaiki.
CalculatorFeline
@CalculatorFeline Ini 13KB, itu jauh lebih mudah ditangani sebagai unduhan.
mbomb007
7

PQRS - Aman! / Solusi Disediakan

Dasar-dasar

Semua instruksi yang tersirat memiliki empat operan alamat memori:

P₀ Q₀ R₀ S₀
P₁ Q₁ R₁ S₁
...
Pᵥ₋₁ Qᵥ₋₁ Rᵥ₋₁ Sᵥ₋₁

Di mana vukuran memori dalam kuartet.

Pᵢ, Qᵢ, Rᵢ, SᵢYang bilangan bulat dalam ukuran asli mesin anda menandatangani (misalnya 16, 32 atau 64 bit) yang akan kita sebut sebagai kata-kata.

Untuk setiap kuartet i, operasi tersirat, dengan []menunjukkan tipuan, adalah:

if (([Pᵢ] ← [Qᵢ] − [Rᵢ]) ≤ 0) go to Sᵢ else go to Pᵢ₊₁

Perhatikan bahwa Subleq adalah subset dari PQRS .

Subleq telah terbukti lengkap, jadi PQRS juga harus lengkap!

Struktur Program

PQRS mendefinisikan header awal sebagai berikut:

H₀ H₁ H₂ H₃ H₄ H₅ H₆ H₇

H₀ H₁ H₂ H₃selalu merupakan instruksi pertama P₀ Q₀ R₀ S₀. H₀untuk H₃perlu didefinisikan pada saat beban.

PQRS memiliki I / O yang belum sempurna, tetapi cukup untuk tantangan.

H₄ H₅: pada awal program, ia membaca maksimum H₅ASCII karakter dari input standar dan menyimpan sebagai kata pada indeks H₄dan seterusnya. H₄dan H₅perlu didefinisikan pada waktu buka. Setelah membaca, H₅akan diatur ke jumlah karakter yang dibaca (dan kata-kata disimpan).

H₆ H₇: pada saat terminasi program, mulai dari indeks H₆, ia mencetak semua byte yang terdiri dari H₇kata - kata ke output standar sebagai karakter ASCII. H₆dan H₇perlu didefinisikan sebelum program berakhir. Null byte '\0'dalam output akan dilewati.

Penghentian

Pengakhiran dicapai dengan menetapkan Sᵢbatas i < 0atau i ≥ v.

Trik

Kuartet Pᵢ Qᵢ Rᵢ Sᵢtidak perlu disejajarkan atau berurutan, percabangan diizinkan pada interval sub-kuartet.

PQRS memiliki tipuan sehingga, tidak seperti Subleq, ada cukup fleksibilitas untuk menerapkan subrutin.

Kode dapat dimodifikasi sendiri!

Penerjemah

Penerjemah ditulis dalam C:

#include <stdlib.h>
#include <stdio.h>

// The "architecture"
enum {P, Q, R, S, START_OF_INPUT, LENGTH_OF_INPUT, START_OF_OUTPUT, LENGTH_OF_OUTPUT};
const int NEXT = S + 1;

// Recommend optimized!
#define OPTIMIZED

#ifdef PER_SPECS
// This may not work on all OSes and architectures - just too much memory needed!
const int K = 1002000200;
#else // OPTIMIZED
// This provides enough space to run the test cases with challenge-optimized.pqrs
const int K = 5200;
#endif

int main(int argc, char *argv[])
{
    int i, *M;
    char *p;
    FILE *program;

    // Allocate enough memory
    M = calloc(K, sizeof(int));

    // Load the program
    for (i = 0, program = fopen(argv[1], "r"); i < K && !feof(program); i++)
        if (!fscanf(program, "%d", M + i))
            break;
    fclose(program);

    // Read in the input
    for (i = 0; i < M[LENGTH_OF_INPUT] && !feof(stdin); i++)
    {
        int c = fgetc(stdin);
        if (c != EOF)
            M[M[START_OF_INPUT] + i] = c;
        else
            break;
    }
    M[LENGTH_OF_INPUT] = i;

    // Execute until terminated
    for (i = 0; i >= 0 && i < K; )
        i = (M[M[P + i]] = M[M[Q + i]] - M[M[R + i]]) <= 0? M[S + i]: i + NEXT;

    // Write the output
    for (i = 0, p = (char *)(M + M[START_OF_OUTPUT]); i < M[LENGTH_OF_OUTPUT] * sizeof(int); i++)
        // Ignore '\0'
        if (p[i])
            fputc(p[i], stdout);

    // Done
    free(M);

    return 0;
}

Untuk menggunakan, simpan di atas sebagai pqrs.c lalu kompilasi:

gcc -o pqrs pqrs.c

Program sampel

Input gema hingga 40 karakter, didahului oleh 'PQRS-'.

8 8 8 -1 14 40 9 45 0 80 81 82 83 45

Untuk menjalankan, simpan di atas sebagai echo.pqrs, lalu:

$ ./prqs echo.pqrs
greetings[enter]
[ctrl-D]
PQRS-greetings

Menjalankan test case:

$ ./pqrs challenge-optimized.pqrs < test-1.txt
1

$ ./pqrs challenge-optimized.pqrs < test-2.txt
11111111111111111

$ ./pqrs challenge-optimized.pqrs < test-3.txt
[lots of ones!]

$ ./pqrs challenge-optimized.pqrs < test-3.txt | wc
0       1     773

Semua test case berjalan sangat cepat, mis. <500 ms.

Tantangan

PQRS dapat dianggap stabil, sehingga tantangannya dimulai 2015-10-31 13:00 dan berakhir pada 2015-11-08 13:00, kali dalam UTC.

Semoga berhasil!

Larutan

Bahasa ini sangat mirip dengan yang digunakan dalam "Baby" - mesin digital elektronik program tersimpan pertama di dunia. Pada halaman itu ada program untuk menemukan faktor integer tertinggi dalam memori (CRT!) Kurang dari 32 kata!

Saya menemukan menulis solusi agar sesuai dengan spesifikasi tidak kompatibel dengan OS dan mesin yang saya gunakan (turunan Ubuntu Linux pada perangkat keras yang sedikit lebih tua). Itu hanya meminta lebih banyak memori daripada yang tersedia, dan dumping inti. Pada OS dengan manajemen memori virtual canggih atau mesin dengan setidaknya 8 GB memori, Anda mungkin dapat menjalankan solusi sesuai spesifikasi. Saya telah memberikan kedua solusi.

Sangat sulit untuk kode dalam PQRS secara langsung, seperti menulis bahasa mesin, bahkan mungkin mikrokode. Alih-alih lebih mudah untuk menulis dalam semacam bahasa majelis kemudian "kompilasi". Di bawah ini adalah bahasa rakitan beranotasi untuk solusi yang dioptimalkan untuk menjalankan kasus uji:

; ANNOTATED PQRS ASSEMBLER CODE
; MINIMAL SIZED BUFFERS TO RUN THE TEST CASES

;OFFSET   LABEL       P-OP        Q-OP        R-OP        S-OP
0                     TEMP        ZERO        ZERO        L1

; INPUT AND OUTPUT LOCATIONS AND SIZES
4                     INPUT       4000        
6         L0:         OUTPUT      1000        

; GET CURRENT INPUT
8         L1:         TEMP        INPUT       ASCII_ZERO  L2
12                    SUM         SUM         INC         IGNORE
16                    L1+1        L1+1        INC         IGNORE
20                    TEMP        ZERO        ZERO        L1

; CHECK IF END OF NUMBERS
24        L2:         NUMBERS     SUM         ZERO        L3

; ADVANCE TO NEXT NUMBER
28                    L2          L2          INC         IGNORE

; ADVANCE COUNT
32                    COUNT       COUNT       INC         IGNORE
36                    L1+1        L1+1        INC         IGNORE

; CLEAR SUM AND GO BACK
40                    SUM         ZERO        ZERO        L1

; SORT NUMBERS                
44        L3:         P           NUMBERS     ZERO        LA
48        L4:         Q           NUMBERS+1   ZERO        L9

; COMPARE                
52                    TEMP        Q           P           L8

; SWAP IF OUT OF ORDER
56                    L5+1        L3+1        ZERO        IGNORE
60                    L6          L3+1        ZERO        IGNORE
64                    L6+1        L4+1        ZERO        IGNORE
68                    L7          L4+1        ZERO        IGNORE
72        L5:         TEMP        P           ZERO        IGNORE
76        L6:         P           Q           ZERO        IGNORE
80        L7:         Q           TEMP        ZERO        IGNORE

; INCREMENT INNER INDEX
84        L8:         L4+1        L4+1        INC         IGNORE
88                    TEMP        ZERO        ZERO        L3

; INCREMENT OUTER INDEX AND RESET INNER INDEX
92        L9:         L3+1        L3+1        INC         IGNORE
96                    L4+1        L3+1        INC         IGNORE
100                   TEMP        ZERO        ZERO        L3

; OUTPUT THIRD LARGEST NUMBER
104                   L0+1        NUMBERS+2   ZERO        IGNORE
108       LA:         TEMP        NUMBERS+2   ZERO        EXIT
112       LB:         OUTPUT      ASCII_ONE   ZERO        IGNORE
116                   LB          LB          INC         IGNORE
120                   NUMBERS+2   NUMBERS+2   DEC         EXIT
124                   TEMP        ZERO        ZERO        LA

; SAFETY LOOP – JUST IN CASE IGNORE DOESN'T WORK AS PLANNED!
128       IGNORE:     TEMP        ZERO        ZERO        IGNORE

; CONSTANTS
132       ZERO:        0
133       INC:        -1
134       DEC:         1
135       ASCII_ZERO: 48
136       ASCII_ONE:  49

; VARIABLES
137       TEMP:       [1]
138       SUM:        [1]
139       COUNT:      [1]
140       P:          [1]
141       Q:          [1]

; WORKING SPACE
142       NUMBERS:    [10]

; I/O SPACE
152       INPUT:      [4000]
4152      OUTPUT:     [1000]
5152

Apa yang dilakukannya adalah mengurai input, mengubah unary ke binary, kemudian menyortir angka-angka dengan nilai-nilai dalam urutan menurun, kemudian akhirnya menghasilkan nilai terbesar ketiga dengan mengubah biner kembali ke unary.

Perhatikan bahwa INC(kenaikan) negatif dan DEC(penurunan) positif! Di mana ia menggunakan L#atau L#+1sebagai P-atau Q-OPs, apa yang terjadi adalah memperbarui pointer: incrementing, decrementing, swapping, dll. Assembler dikompilasi dengan tangan ke PQRS dengan mengganti label dengan offset. Di bawah ini adalah solusi optimal PQRS :

137 132 132 8
152 4000
4152 1000
137 152 135 24
138 138 133 128
9 9 133 128
137 132 132 8
142 138 132 44
24 24 133 128
139 139 133 128
9 9 133 128
138 132 132 8
140 142 132 108
141 143 132 92
137 141 140 84
73 45 132 128
76 45 132 128
77 49 132 128
80 49 132 128
137 140 132 128
140 141 132 128
141 137 132 128
49 49 133 128
137 132 132 44
45 45 133 128
49 45 133 128
137 132 132 44
7 144 132 128
137 144 132 -1
4152 136 132 128
112 112 133 128
144 144 134 -1
137 132 132 108
137 132 132 128
0
-1
1
48
49

Kode di atas dapat disimpan challenge-optimized.pqrsuntuk menjalankan kasus uji.

Untuk kelengkapan, berikut adalah sumber per spesifikasi:

; ANNOTATED PQRS ASSEMBLER CODE
; FULL SIZED BUFFERS TO RUN ACCORDING TO SPECS

;OFFSET   LABEL       P-OP        Q-OP        R-OP        S-OP
0                     TEMP        ZERO        ZERO        L1

; INPUT AND OUTPUT LOCATIONS AND SIZES
4                     INPUT       10^9        
6         L0:         OUTPUT      10^6        

; GET CURRENT INPUT
8         L1:         TEMP        INPUT       ASCII_ZERO  L2
12                    SUM         SUM         INC         IGNORE
16                    L1+1        L1+1        INC         IGNORE
20                    TEMP        ZERO        ZERO        L1

; CHECK IF END OF NUMBERS
24        L2:         NUMBERS     SUM         ZERO        L3

; ADVANCE TO NEXT NUMBER
28                    L2          L2          INC         IGNORE

; ADVANCE COUNT
32                    COUNT       COUNT       INC         IGNORE
36                    L1+1        L1+1        INC         IGNORE

; CLEAR SUM AND GO BACK
40                    SUM         ZERO        ZERO        L1

; SORT NUMBERS                
44        L3:         P           NUMBERS     ZERO        LA
48        L4:         Q           NUMBERS+1   ZERO        L9

; COMPARE                
52                    TEMP        Q           P           L8

; SWAP IF OUT OF ORDER
56                    L5+1        L3+1        ZERO        IGNORE
60                    L6          L3+1        ZERO        IGNORE
64                    L6+1        L4+1        ZERO        IGNORE
68                    L7          L4+1        ZERO        IGNORE
72        L5:         TEMP        P           ZERO        IGNORE
76        L6:         P           Q           ZERO        IGNORE
80        L7:         Q           TEMP        ZERO        IGNORE

; INCREMENT INNER INDEX
84        L8:         L4+1        L4+1        INC         IGNORE
88                    TEMP        ZERO        ZERO        L3

; INCREMENT OUTER INDEX AND RESET INNER INDEX
92        L9:         L3+1        L3+1        INC         IGNORE
96                    L4+1        L3+1        INC         IGNORE
100                   TEMP        ZERO        ZERO        L3

; OUTPUT THIRD LARGEST NUMBER
104                   L0+1        NUMBERS+2   ZERO        IGNORE
108       LA:         TEMP        NUMBERS+2   ZERO        EXIT
112       LB:         OUTPUT      ASCII_ONE   ZERO        IGNORE
116                   LB          LB          INC         IGNORE
120                   NUMBERS+2   NUMBERS+2   DEC         EXIT
124                   TEMP        ZERO        ZERO        LA

; SAFETY LOOP – JUST IN CASE IGNORE DOESN'T WORK AS PLANNED!
128       IGNORE:     TEMP        ZERO        ZERO        IGNORE

; CONSTANTS
132       ZERO:        0
133       INC:        -1
134       DEC:         1
135       ASCII_ZERO: 48
136       ASCII_ONE:  49

; VARIABLES
137       TEMP:       [1]
138       SUM:        [1]
139       COUNT:      [1]
140       P:          [1]
141       Q:          [1]

; WORKING SPACE
142       NUMBERS:    [10^6]

; I/O SPACE
1000142   INPUT:      [10^9]
1001000142 OUTPUT:    [10^6]
1002000142

Dan solusi:

137 132 132 8
1000142 1000000000
1001000142 1000000
137 1000142 135 24
138 138 133 128
9 9 133 128
137 132 132 8
142 138 132 44
24 24 133 128
139 139 133 128
9 9 133 128
138 132 132 8
140 142 132 108
141 143 132 92
137 141 140 84
73 45 132 128
76 45 132 128
77 49 132 128
80 49 132 128
137 140 132 128
140 141 132 128
141 137 132 128
49 49 133 128
137 132 132 44
45 45 133 128
49 45 133 128
137 132 132 44
7 144 132 128
137 144 132 -1
1001000142 136 132 128
112 112 133 128
144 144 134 -1
137 132 132 108
137 132 132 128
0
-1
1
48
49

Untuk menjalankan di atas, Anda akan perlu untuk komentar #define OPTIMIZEDdan menambahkan #define PER_SPECSdalam pqrs.cdan mengkompilasi ulang.

Ini adalah tantangan besar - sangat menikmati latihan mental! Membawa saya kembali ke hari-hari assembler 6502 lama saya ...

Jika saya menerapkan PQRS sebagai bahasa pemrograman "nyata", saya mungkin akan menambahkan mode tambahan untuk akses tidak langsung langsung dan ganda di samping akses tidak langsung, serta posisi relatif dan posisi absolut, keduanya dengan opsi akses tidak langsung untuk percabangan!


sumber
3
Anda harus menyiapkan solusi sebelum memposting.
feersum
1
Ya, solusinya sudah siap. Saya mengerti ada beberapa keraguan karena bahasa ini benar-benar sangat sulit untuk digunakan. Bagi mereka yang ingin melihat cuplikan, saya dapat mengirimkannya kepada Anda, asalkan Anda berjanji untuk tidak mengungkapkannya sebelum akhir dari tantangan!
6

Seng, Retak! oleh @Zgarb

Juga tersedia di GitHub .

Anda membutuhkan Dart 1.12 dan Pub. Jalankan saja pub getuntuk mengunduh satu-satunya dependensi, parsing library.

Ini untuk berharap ini berlangsung lebih dari 30 menit! :HAI

Bahasa

Seng berorientasi pada operator yang mendefinisikan ulang. Anda dapat mendefinisikan ulang semua operator dalam bahasa dengan mudah!

Struktur program Zinc yang khas terlihat seperti:

let
<operator overrides>
in <expression>

Hanya ada dua tipe data: integer dan set. Tidak ada yang namanya himpunan literal, dan himpunan kosong tidak diizinkan.

Ekspresi

Berikut ini adalah ekspresi valid di Zinc:

Literal

Seng mendukung semua literal bilangan bulat normal, seperti 1dan -2.

Variabel

Seng memiliki variabel (seperti kebanyakan bahasa). Untuk referensi mereka, cukup gunakan namanya. Sekali lagi seperti kebanyakan bahasa!

Namun, ada variabel khusus yang disebut Sberperilaku seperti Pyth Q. Saat pertama kali menggunakannya, itu akan dibaca dalam satu baris dari input standar dan menafsirkannya sebagai satu set angka. Misalnya, jalur input 1234231akan berubah menjadi set {1, 2, 3, 4, 3, 2, 1}.

CATATAN PENTING!!! Dalam beberapa kasus, literal di ujung override operator diuraikan secara salah, jadi Anda harus mengelilinginya dengan tanda kurung.

Operasi biner

Operasi biner berikut ini didukung:

  • Selain melalui +: 1+1.
  • Pengurangan melalui -: 1-1.
  • Perkalian melalui *: 2*2.
  • Divisi melalui /: 4/2.
  • Kesetaraan dengan =: 3=3.

Selain itu, operasi unary berikut juga didukung:

  • Panjang dengan #: #x.

Diutamakan selalu asosiatif benar. Anda dapat menggunakan tanda kurung untuk mengganti ini.

Hanya persamaan dan panjang yang bekerja pada set. Saat Anda mencoba mendapatkan panjang bilangan bulat, Anda akan mendapatkan jumlah digit dalam representasi stringnya.

Tetapkan pemahaman

Untuk memanipulasi set, Zinc telah menetapkan pemahaman. Mereka terlihat seperti ini:

{<variable>:<set><clause>}

Klausa adalah klausa kapan atau semacam.

A ketika klausa terlihat seperti ^<expression>. Ekspresi yang mengikuti tanda sisipan harus menghasilkan bilangan bulat. Menggunakan klausa when hanya akan mengambil elemen dalam set yang expressiontidak nol. Di dalam ekspresi, variabel _akan diatur ke indeks saat ini di set. Ini kira-kira setara dengan Python ini:

[<variable> for _, <variable> in enumerate(<set>) when <expression> != 0]

Sebuah klausul semacam , yang terlihat seperti $<expression>, macam set turun oleh nilai <expression>. Itu sama dengan Python ini:

sorted(<set>, key=lambda <variable>: <expression>)[::-1]

Berikut adalah beberapa contoh pemahaman:

  • Ambil hanya elemen himpunan syang sama dengan 5:

    {x:s^x=5}
    
  • Urutkan set sberdasarkan nilainya jika elemen-elemennya kuadrat:

    {x:s$x*x}
    

Mengganti

Override operator memungkinkan Anda mendefinisikan ulang operator. Mereka terlihat seperti ini:

<operator>=<operator>

atau:

<variable><operator><variable>=<expression>

Dalam kasus pertama, Anda dapat mendefinisikan operator untuk menyamai operator lain. Sebagai contoh, saya dapat mendefinisikan+ untuk benar-benar mengurangi melalui:

+=-

Ketika Anda melakukan ini, Anda dapat mendefinisikan kembali operator untuk menjadi operator ajaib . Ada dua operator ajaib:

  • joinmengambil satu set dan integer dan bergabung dengan isi set. Misalnya, bergabung {1, 2, 3}dengan 4akan menghasilkan bilangan bulat 14243.

  • cutjuga mengambil set dan integer dan akan mempartisi set pada setiap kemunculan integer. Menggunakan cutdi {1, 3, 9, 4, 3, 2}dan 3akan membuat {{1}, {9, 4}, {2}}... TAPI setiap single-elemen set diratakan, sehingga hasilnya akan benar-benar {1, {9, 4}, 2}.

Berikut ini contoh yang mengubah arti +operator join:

+=join

Untuk kasus yang terakhir, Anda dapat mendefinisikan ulang operator ke ekspresi yang diberikan. Sebagai contoh, ini mendefinisikan operasi plus untuk menambahkan nilai dan kemudian menambahkan 1:

x+y=1+:x+:y

Tapi apa +:? Anda dapat menambahkan titik dua :ke operator untuk selalu menggunakan versi bawaan. Contoh ini menggunakan builtin+ via +:untuk menambahkan angka bersama, lalu menambahkan 1 (ingat, semuanya benar-asosiatif).

Mengganti operator panjang terlihat seperti:

#x=<expression>

Perhatikan bahwa hampir semua operasi builtin (kecuali persamaan) akan menggunakan operator panjang ini untuk menentukan panjang set. Jika Anda mendefinisikannya sebagai:

#x=1

setiap bagian dari Zinc yang bekerja pada set kecuali = hanya akan beroperasi pada elemen pertama dari set itu diberikan.

Beberapa penimpaan

Anda dapat mengganti beberapa operator dengan memisahkannya dengan koma:

let
+=-,
*=/
in 1+2*3

Pencetakan

Anda tidak dapat langsung mencetak apa pun di Zinc. Hasil dari ekspresi berikut inakan dicetak. Nilai-nilai dari himpunan akan digabungkan dengan ke pemisah. Misalnya, ambil ini:

let
...
in expr

Jika exprsudah diatur {1, 3, {2, 4}}, 1324akan dicetak ke layar setelah program selesai.

Menyatukan semuanya

Berikut adalah program Zinc sederhana yang tampaknya menambah 2+2tetapi menyebabkan hasilnya 5:

let
x+y=1+:x+:y
in 1+2

Penerjemah

Ini masuk bin/zinc.dart:

import 'package:parsers/parsers.dart';
import 'dart:io';

// An error.
class Error implements Exception {
  String cause;
  Error(this.cause);
  String toString() => 'error in Zinc script: $cause';
}


// AST.
class Node {
  Obj interpret(ZincInterpreter interp) => null;
}

// Identifier.
class Id extends Node {
  final String id;
  Id(this.id);
  String toString() => 'Id($id)';
  Obj interpret(ZincInterpreter interp) => interp.getv(id);
}

// Integer literal.
class IntLiteral extends Node {
  final int value;
  IntLiteral(this.value);
  String toString() => 'IntLiteral($value)';
  Obj interpret(ZincInterpreter interp) => new IntObj(value);
}

// Any kind of operator.
class Anyop extends Node {
  void set(ZincInterpreter interp, OpFuncType func) {}
}

// Operator.
class Op extends Anyop {
  final String op;
  final bool orig;
  Op(this.op, [this.orig = false]);
  String toString() => 'Op($op, $orig)';
  OpFuncType get(ZincInterpreter interp) =>
    this.orig ? interp.op0[op] : interp.op1[op];
  void set(ZincInterpreter interp, OpFuncType func) { interp.op1[op] = func; }
}

// Unary operator (len).
class Lenop extends Anyop {
  final bool orig;
  Lenop([this.orig = false]);
  String toString() => 'Lenop($orig)';
  OpFuncType get(ZincInterpreter interp) =>
    this.orig ? interp.op0['#'] : interp.op1['#'];
  void set(ZincInterpreter interp, OpFuncType func) { interp.op1['#'] = func; }
}

// Magic operator.
class Magicop extends Anyop {
  final String op;
  Magicop(this.op);
  String toString() => 'Magicop($op)';
  Obj interpret_with(ZincInterpreter interp, Obj x, Obj y) {
    if (op == 'cut') {
      if (y is! IntObj) { throw new Error('cannot cut int with non-int'); }
      if (x is IntObj) {
        return new SetObj(x.value.toString().split(y.value.toString()).map(
          int.parse));
      } else {
        assert(x is SetObj);
        List<List<Obj>> res = [[]];
        for (Obj obj in x.vals(interp)) {
          if (obj == y) { res.add([]); }
          else { res.last.add(obj); }
        }
        return new SetObj(new List.from(res.map((l) =>
          l.length == 1 ? l[0] : new SetObj(l))));
      }
    } else if (op == 'join') {
      if (x is! SetObj) { throw new Error('can only join set'); }
      if (y is! IntObj) { throw new Error('can only join set with int'); }
      String res = '';
      for (Obj obj in x.vals(interp)) {
        if (obj is! IntObj) { throw new Error('joining set must contain ints'); }
        res += obj.value.toString();
      }
      return new IntObj(int.parse(res));
    }
  }
}

// Unary operator (len) expression.
class Len extends Node {
  final Lenop op;
  final Node value;
  Len(this.op, this.value);
  String toString() => 'Len($op, $value)';
  Obj interpret(ZincInterpreter interp) =>
    op.get(interp)(interp, value.interpret(interp), null);
}

// Binary operator expression.
class Binop extends Node {
  final Node lhs, rhs;
  final Op op;
  Binop(this.lhs, this.op, this.rhs);
  String toString() => 'Binop($lhs, $op, $rhs)';
  Obj interpret(ZincInterpreter interp) =>
    op.get(interp)(interp, lhs.interpret(interp), rhs.interpret(interp));
}

// Clause.
enum ClauseKind { Where, Sort }
class Clause extends Node {
  final ClauseKind kind;
  final Node expr;
  Clause(this.kind, this.expr);
  String toString() => 'Clause($kind, $expr)';
  Obj interpret_with(ZincInterpreter interp, SetObj set, Id id) {
    List<Obj> res = [];
    List<Obj> values = set.vals(interp);
    switch (kind) {
    case ClauseKind.Where:
      for (int i=0; i<values.length; i++) {
        Obj obj = values[i];
        interp.push_scope();
        interp.setv(id.id, obj);
        interp.setv('_', new IntObj(i));
        Obj x = expr.interpret(interp);
        interp.pop_scope();
        if (x is IntObj) {
          if (x.value != 0) { res.add(obj); }
        } else { throw new Error('where clause condition must be an integer'); }
      }
      break;
    case ClauseKind.Sort:
      res = values;
      res.sort((x, y) {
        interp.push_scope();
        interp.setv(id.id, x);
        Obj x_by = expr.interpret(interp);
        interp.setv(id.id, y);
        Obj y_by = expr.interpret(interp);
        interp.pop_scope();
        if (x_by is IntObj && y_by is IntObj) {
          return x_by.value.compareTo(y_by.value);
        } else { throw new Error('sort clause result must be an integer'); }
      });
      break;
    }
    return new SetObj(new List.from(res.reversed));
  }
}

// Set comprehension.
class SetComp extends Node {
  final Id id;
  final Node set;
  final Clause clause;
  SetComp(this.id, this.set, this.clause);
  String toString() => 'SetComp($id, $set, $clause)';
  Obj interpret(ZincInterpreter interp) {
    Obj setobj = set.interpret(interp);
    if (setobj is SetObj) {
      return clause.interpret_with(interp, setobj, id);
    } else { throw new Error('set comprehension rhs must be set type'); }
  }
}

// Operator rewrite.
class OpRewrite extends Node {
  final Anyop op;
  final Node value;
  final Id lid, rid; // Can be null!
  OpRewrite(this.op, this.value, [this.lid, this.rid]);
  String toString() => 'OpRewrite($lid, $op, $rid, $value)';
  Obj interpret(ZincInterpreter interp) {
    if (lid != null) {
      // Not bare.
      op.set(interp, (interp,x,y) {
        interp.push_scope();
        interp.setv(lid.id, x);
        if (rid == null) { assert(y == null); }
        else { interp.setv(rid.id, y); }
        Obj res = value.interpret(interp);
        interp.pop_scope();
        return res;
      });
    } else {
      // Bare.
      if (value is Magicop) {
        op.set(interp, (interp,x,y) => value.interpret_with(interp, x, y));
      } else {
        op.set(interp, (interp,x,y) => (value as Anyop).get(interp)(x, y));
      }
    }
    return null;
  }
}

class Program extends Node {
  final List<OpRewrite> rws;
  final Node expr;
  Program(this.rws, this.expr);
  String toString() => 'Program($rws, $expr)';
  Obj interpret(ZincInterpreter interp) {
    rws.forEach((n) => n.interpret(interp));
    return expr.interpret(interp);
  }
}


// Runtime objects.
typedef Obj OpFuncType(ZincInterpreter interp, Obj x, Obj y);

class Obj {}

class IntObj extends Obj {
  final int value;
  IntObj(this.value);
  String toString() => 'IntObj($value)';
  bool operator==(Obj rhs) => rhs is IntObj && value == rhs.value;
  String dump() => value.toString();
}

class SetObj extends Obj {
  final List<Obj> values;
  SetObj(this.values) {
    if (values.length == 0) { throw new Error('set cannot be empty'); }
  }
  String toString() => 'SetObj($values)';
  bool operator==(Obj rhs) => rhs is SetObj && values == rhs.values;
  String dump() => values.map((x) => x.dump()).reduce((x,y) => x+y);
  List<Obj> vals(ZincInterpreter interp) {
    Obj lenobj = interp.op1['#'](interp, this, null);
    int len;
    if (lenobj is! IntObj) { throw new Error('# operator must return an int'); }
    len = lenobj.value;
    if (len < 0) { throw new Error('result of # operator must be positive'); }
    return new List<Obj>.from(values.getRange(0, len));
  }
}


// Parser.
class ZincParser extends LanguageParsers {
  ZincParser(): super(reservedNames: ['let', 'in', 'join', 'cut']);
  get start => prog().between(spaces, eof);
  get comma => char(',') < spaces;
  get lp => symbol('(');
  get rp => symbol(')');
  get lb => symbol('{');
  get rb => symbol('}');
  get colon => symbol(':');
  get plus => symbol('+');
  get minus => symbol('-');
  get star => symbol('*');
  get slash => symbol('/');
  get eq => symbol('=');
  get len => symbol('#');
  get in_ => char(':');
  get where => char('^');
  get sort => char('\$');

  prog() => reserved['let'] + oprw().sepBy(comma) + reserved['in'] + expr() ^
            (_1,o,_2,x) => new Program(o,x);
  oprw() => oprw1() | oprw2() | oprw3();
  oprw1() => (basicop() | lenop()) + eq + (magicop() | op()) ^
             (o,_,r) => new OpRewrite(o,r);
  oprw2() => (id() + op() + id()).list + eq + expr() ^
             (l,_,x) => new OpRewrite(l[1], x, l[0], l[2]);
  oprw3() => lenop() + id() + eq + expr() ^ (o,a,_,x) => new OpRewrite(o, x, a);
  magicop() => (reserved['join'] | reserved['cut']) ^ (s) => new Magicop(s);
  basicop() => (plus | minus | star | slash | eq) ^ (op) => new Op(op);
  op() => (basicop() + colon ^ (op,_) => new Op(op.op, true)) | basicop();
  lenop() => (len + colon ^ (_1,_2) => new Lenop(true)) |
             len ^ (_) => new Lenop();
  expr() => setcomp() | unop() | binop() | prim();
  setcomp() => lb + id() + in_ + rec(expr) + clause() + rb ^
               (_1,i,_2,x,c,_3) => new SetComp(i,x,c);
  clausekind() => (where ^ (_) => ClauseKind.Where) |
                  (sort  ^ (_) => ClauseKind.Sort);
  clause() => clausekind() + rec(expr) ^ (k,x) => new Clause(k,x);
  unop() => lenop() + rec(expr) ^ (o,x) => new Len(o,x);
  binop() => prim() + op() + rec(expr) ^ (l,o,r) => new Binop(l,o,r);
  prim() => id() | intlit() | parens(rec(expr));
  id() => identifier ^ (i) => new Id(i);
  intlit() => intLiteral ^ (i) => new IntLiteral(i);
}


// Interpreter.
class ZincInterpreter {
  Map<String, OpFuncType> op0, op1;
  List<Map<String, Obj>> scopes;
  ZincInterpreter() {
    var beInt = (v) {
      if (v is IntObj) { return v.value; }
      else { throw new Error('argument to binary operator must be integer'); }
    };
    op0 = {
      '+': (_,x,y) => new IntObj(beInt(x)+beInt(y)),
      '-': (_,x,y) => new IntObj(beInt(x)-beInt(y)),
      '*': (_,x,y) => new IntObj(beInt(x)*beInt(y)),
      '/': (_,x,y) => new IntObj(beInt(x)/beInt(y)),
      '=': (_,x,y) => new IntObj(x == y ? 1 : 0),
      '#': (i,x,_2) =>
        new IntObj(x is IntObj ? x.value.toString().length : x.values.length)
    };
    op1 = new Map<String, OpFuncType>.from(op0);
    scopes = [{}];
  }

  void push_scope() { scopes.add({}); }
  void pop_scope() { scopes.removeLast(); }
  void setv(String name, Obj value) { scopes[scopes.length-1][name] = value; }
  Obj getv(String name) {
    for (var scope in scopes.reversed) {
      if (scope[name] != null) { return scope[name]; }
    }
    if (name == 'S') {
      var input = stdin.readLineSync() ?? '';
      var list = new List.from(input.codeUnits.map((c) =>
        new IntObj(int.parse(new String.fromCharCodes([c])))));
      setv('S', new SetObj(list));
      return getv('S');
    } else throw new Error('undefined variable $name');
  }
}


void main(List<String> args) {
  if (args.length != 1) {
    print('usage: ${Platform.script.toFilePath()} <file to run>');
    return;
  }
  var file = new File(args[0]);
  if (!file.existsSync()) {
    print('cannot open ${args[0]}');
    return;
  }
  Program root = new ZincParser().start.parse(file.readAsStringSync());
  ZincInterpreter interp = new ZincInterpreter();
  var res = root.interpret(interp);
  print(res.dump());
}

Dan ini masuk pubspec.yaml:

name: zinc
dependencies:
  parsers: any

Solusi yang dimaksudkan

let
#x=((x=S)*(-2))+#:x,
/=cut
in {y:{x:S/0$#:x}^_=2}
kirbyfan64sos
sumber
1
Apakah saya mengerti benar bahwa set diatur dan dapat memiliki duplikat, sehingga pada dasarnya daftar? Juga, jika saya joinsatu set campuran suka {1,{3,2}}, apakah akan ada kesalahan? Saya tidak dapat menginstal Dart sekarang, jadi saya tidak dapat memeriksa diri saya sendiri.
Zgarb
@ Zgarb Ya, set pada dasarnya daftar dalam hal ini. Bergabung dengan set campuran harus menjadi kesalahan, tetapi penerjemah benar-benar crash ATM ...
kirbyfan64sos
Bagaimana cara saya menjalankan juru bahasa? Jika saya mencoba, dart bin/zinc.dart test.zncsaya mendapatkan kesalahan sintaks: 'file:///D:/Development/languages/zinc/bin/zinc.dart': error: line 323 pos 41: unexpected token '?'...var input = stdin.readLineSync() ?? '';
Martin Ender
1
Retak.
Zgarb
1
@ Zgarb Ingat kapan, dalam spec, saya katakan semua operasi bawaan kecuali kesetaraan menggunakan operator panjang? Saya memaksanya untuk kembali -2+#:Sketika diberikan S, yang memotong dua nol trailing. Itulah yang saya harapkan akan diselesaikan. Dan ^tidak seharusnya membalik set ... itu bug ...
kirbyfan64sos
5

Sup Kompas ( retak oleh cardboard_box )

Penerjemah: C ++

Kompas Soup adalah jenis seperti mesin Turing dengan pita 2 dimensi yang tak terbatas. Tangkapan utama adalah bahwa memori instruksi dan memori data berada dalam ruang yang sama, dan output dari program adalah seluruh isi ruang itu.

masukkan deskripsi gambar di sini

Bagaimana itu bekerja

Program adalah blok teks 2 dimensi. Ruang program dimulai dengan seluruh kode sumber ditempatkan dengan karakter pertama di (0,0). Sisa ruang program tidak terbatas dan diinisialisasi dengan karakter nol (ASCII 0).

Ada dua petunjuk yang dapat bergerak di sekitar ruang program:

  • Pointer eksekusi memiliki lokasi dan arah (Utara, Selatan, Timur, atau Barat). Setiap centang, instruksi di bawah pointer eksekusi dieksekusi, kemudian pointer eksekusi bergerak ke arah saat ini. Pointer eksekusi mulai bergerak ke timur (positif x), di lokasi! karakter atau di (0,0) jika itu tidak ada.
  • Pointer data hanya memiliki lokasi. Hal ini dipindahkan dengan petunjuk x, X, y, dan Y. Dimulai di lokasi @karakter atau di (0,0) jika itu tidak ada.

Memasukkan

Isi stdin dicetak ke dalam ruang program mulai dari lokasi >karakter, atau pada (0,0) jika itu tidak ada.

Keluaran

Program berakhir ketika pointer eksekusi berjalan di luar batas. Outputnya adalah seluruh isi ruang program pada waktu itu. Itu dikirim ke stdout dan 'result.txt'.

Instruksi

  • n - mengarahkan kembali pointer eksekusi Utara (negatif y)
  • e - mengalihkan pointer eksekusi Timur (positif x)
  • s - mengalihkan pointer eksekusi Selatan (positif y)
  • w - mengalihkan pointer eksekusi Barat (negatif x)
  • y - Memindahkan penunjuk data Utara (negatif y)
  • X - Memindahkan penunjuk data Timur (positif x)
  • Y - Memindahkan penunjuk data Selatan (positif y)
  • x - Memindahkan penunjuk data Barat (negatif x)
  • p- menulis karakter selanjutnya yang ditemukan oleh pointer eksekusi pada pointer data. Karakter itu tidak dieksekusi sebagai instruksi.
  • j- memeriksa karakter berikutnya yang dihadapi oleh pointer eksekusi terhadap karakter di bawah pointer data. Karakter itu tidak dieksekusi sebagai instruksi. Jika mereka sama, pointer eksekusi melompati karakter berikutnya.
  • c - menulis karakter nol pada penunjuk data.
  • * - breakpoint - hanya menyebabkan penerjemah putus.

Semua karakter lain diabaikan oleh pointer eksekusi.

Penerjemah

Interpreter mengambil file sumber sebagai argumen dan input pada stdin. Ini memiliki debugger steppable, yang dapat Anda gunakan dengan instruksi breakpoint dalam kode ( *). Ketika rusak, pointer eksekusi ditampilkan sebagai ASCII 178 (blok berbayang lebih gelap) dan pointer data ditampilkan sebagai ASCII 177 (blok berbayang lebih terang).

#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>

// Compass Soup programming language interpreter
// created by Brian MacIntosh (BMacZero)
// for https://codegolf.stackexchange.com/questions/61804/create-a-programming-language-that-only-appears-to-be-unusable
//
// 31 October 2015

struct Point
{
    int x, y;
    Point(int ix, int iy) { x = ix; y = iy; };
    bool operator==(const Point &other) const
    {
        return other.x == x && other.y == y;
    }
    bool operator!=(const Point &other) const
    {
        return other.x != x || other.y != y;
    }
};

struct Bounds
{
    int xMin, xMax, yMin, yMax;
    Bounds(int xmin, int ymin, int xmax, int ymax)
    {
        xMin = xmin; yMin = ymin; xMax = xmax; yMax = ymax;
    }
    bool contains(Point pt)
    {
        return pt.x >= xMin && pt.x <= xMax && pt.y >= yMin && pt.y <= yMax;
    }
    int getWidth() { return xMax - xMin + 1; }
    int getHeight() { return yMax - yMin + 1; }
    bool operator==(const Bounds &other) const
    {
        return other.xMin == xMin && other.xMax == xMax && other.yMin == yMin && other.yMax == yMax;
    }
    bool operator!=(const Bounds &other) const
    {
        return other.xMin != xMin || other.xMax != xMax || other.yMin != yMin || other.yMax != yMax;
    }
};

int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }

Bounds hull(Point a, Bounds b)
{
    return Bounds(min(a.x, b.xMin), min(a.y, b.yMin), max(a.x, b.xMax), max(a.y, b.yMax));
}

Bounds hull(Bounds a, Bounds b)
{
    return Bounds(min(a.xMin, b.xMin), min(a.yMin, b.yMin), max(a.xMax, b.xMax), max(a.yMax, b.yMax));
}

Bounds programBounds(0,0,0,0);
char** programSpace;

Point execPtr(0,0);
Point execPtrDir(1,0);
Point dataPtr(0,0);
Point stdInPos(0,0);

bool breakpointHit = false;
char breakOn = 0;

/// reads the character from the specified position
char read(Point pt)
{
    if (programBounds.contains(pt))
        return programSpace[pt.x - programBounds.xMin][pt.y - programBounds.yMin];
    else
        return 0;
}

/// read the character at the data pointer
char readData()
{
    return read(dataPtr);
}

/// read the character at the execution pointer
char readProgram()
{
    return read(execPtr);
}

/// gets the bounds of the actual content of the program space
Bounds getTightBounds(bool debug)
{
    Bounds tight(0,0,0,0);
    for (int x = programBounds.xMin; x <= programBounds.xMax; x++)
    {
        for (int y = programBounds.yMin; y <= programBounds.yMax; y++)
        {
            if (read(Point(x, y)) != 0)
            {
                tight = hull(Point(x, y), tight);
            }
        }
    }
    if (debug)
    {
        tight = hull(dataPtr, tight);
        tight = hull(execPtr, tight);
    }
    return tight;
}

/// ensure that the program space encompasses the specified rectangle
void fitProgramSpace(Bounds bounds)
{
    Bounds newBounds = hull(bounds, programBounds);

    if (newBounds == programBounds) return;

    // allocate new space
    char** newSpace = new char*[newBounds.getWidth()];

    // copy content
    for (int x = 0; x < newBounds.getWidth(); x++)
    {
        newSpace[x] = new char[newBounds.getHeight()];
        for (int y = 0; y < newBounds.getHeight(); y++)
        {
            Point newWorldPos(x + newBounds.xMin, y + newBounds.yMin);
            newSpace[x][y] = read(newWorldPos);
        }
    }

    // destroy old space
    for (int x = 0; x < programBounds.getWidth(); x++)
    {
        delete[] programSpace[x];
    }
    delete[] programSpace;

    programSpace = newSpace;
    programBounds = newBounds;
}

/// outputs the current program space to a file
void outputToStream(std::ostream &stream, bool debug)
{
    Bounds tight = getTightBounds(debug);
    for (int y = tight.yMin; y <= tight.yMax; y++)
    {
        for (int x = tight.xMin; x <= tight.xMax; x++)
        {
            char at = read(Point(x, y));
            if (debug && x == execPtr.x && y == execPtr.y)
                stream << (char)178;
            else if (debug && x == dataPtr.x && y == dataPtr.y)
                stream << (char)177;
            else if (at == 0)
                stream << ' ';
            else
                stream << at;
        }
        stream << std::endl;
    }
}

/// writes a character at the specified position
void write(Point pt, char ch)
{
    fitProgramSpace(hull(pt, programBounds));
    programSpace[pt.x - programBounds.xMin][pt.y - programBounds.yMin] = ch;
}

/// writes a character at the data pointer
void write(char ch)
{
    write(dataPtr, ch);
}

/// writes a line of text horizontally, starting at the specified position
void writeLine(Point loc, std::string str, bool isSource)
{
    fitProgramSpace(Bounds(loc.x, loc.y, loc.x + str.size(), loc.y));
    for (unsigned int x = 0; x < str.size(); x++)
    {
        programSpace[x + loc.x][loc.y] = str[x];

        // record locations of things
        if (isSource)
        {
            switch (str[x])
            {
            case '>':
                stdInPos = Point(loc.x + x, loc.y);
                break;
            case '!':
                execPtr = Point(loc.x + x, loc.y);
                break;
            case '@':
                dataPtr = Point(loc.x + x, loc.y);
                break;
            }
        }
    }
}

void advanceExecPtr()
{
    execPtr.x += execPtrDir.x;
    execPtr.y += execPtrDir.y;
}

void breakpoint()
{
    breakpointHit = true;
    outputToStream(std::cout, true);
    std::cout << "[Return]: step | [Space+Return]: continue | [<char>+Return]: continue to <char>" << std::endl;
    while (true)
    {
        std::string input;
        std::getline(std::cin, input);
        if (input.size() == 0)
        {
            break;
        }
        else if (input.size() == 1)
        {
            if (input[0] == ' ')
            {
                breakpointHit = false;
                break;
            }
            else
            {
                breakOn = input[0];
                breakpointHit = false;
                break;
            }
        }
    }
}

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        printf("Usage: CompassSoup <source-file>");
        return 1;
    }

    // open source file
    std::ifstream sourceIn(argv[1]);

    if (!sourceIn.is_open())
    {
        printf("Error reading source file.");
        return 1;
    }

    programSpace = new char*[1];
    programSpace[0] = new char[1];
    programSpace[0][0] = 0;

    // read starting configuration
    std::string line;
    int currentLine = 0;
    while (std::getline(sourceIn, line))
    {
        writeLine(Point(0, currentLine), line, true);
        currentLine++;
    }

    sourceIn.close();

    // take stdin
    std::string input;
    std::cout << ">";
    std::cin >> input;
    std::cin.ignore();
    writeLine(stdInPos, input, false);

    // execute
    while (programBounds.contains(execPtr))
    {
        if (execPtrDir.x == 0 && execPtrDir.y == 0)
        {
            printf("Implementation error: execPtr is stuck.");
            break;
        }

        advanceExecPtr();

        char command = readProgram();

        // breakpoint control code
        if (breakpointHit || (breakOn != 0 && command == breakOn))
        {
            breakOn = 0;
            breakpoint();
        }

        switch (command)
        {
        case 'n':
            execPtrDir = Point(0,-1);
            break;
        case 'e':
            execPtrDir = Point(1,0);
            break;
        case 's':
            execPtrDir = Point(0,1);
            break;
        case 'w':
            execPtrDir = Point(-1,0);
            break;
        case 'x':
            dataPtr.x--;
            break;
        case 'X':
            dataPtr.x++;
            break;
        case 'y':
            dataPtr.y--;
            break;
        case 'Y':
            dataPtr.y++;
            break;
        case 'p':
            advanceExecPtr();
            write(readProgram());
            break;
        case 'j':
            advanceExecPtr();
            if (readData() == readProgram())
            {
                advanceExecPtr();
            }
            break;
        case 'c':
            write(0);
            break;
        case '*':
            breakpoint();
            break;
        }
    }

    std::ofstream outputFile("result.txt");
    outputToStream(outputFile, false);
    outputToStream(std::cout, false);
    outputFile.close();
}

Contohnya

Halo Dunia

Hello, World!

Kucing

>

Parity: menerima serangkaian karakter yang diakhiri dengan nol ('0'). Output yespada baris pertama dari output jika jumlah 1s dalam input ganjil, jika tidak output |.

|>
!--eXj1s-c-eXj0s-c-exj|s-pyXpeXps
   c   |   c   |   |   |
  cn0j-w---n1j-w   n---w

Kiat

Anda harus menggunakan editor teks yang baik dan memanfaatkan fungsi tombol 'Sisipkan' dengan bijaksana, dan menggunakan 'Seret-Alt' untuk menambah atau menghapus teks pada beberapa baris sekaligus.

Larutan

Ini solusinya. Ini tidak sebagus cardboard_box karena saya harus membuat kode sumber hapus sendiri. Saya juga berharap dapat menemukan cara untuk menghapus semua kode dan hanya meninggalkan jawabannya, tetapi saya tidak bisa.

Pendekatan saya adalah untuk membagi urutan yang berbeda dari 1s ke baris yang berbeda, kemudian mengurutkan mereka dengan memiliki 1semua "jatuh" sampai mereka mencapai yang lain 1, dan akhirnya menghapus semuanya kecuali baris ketiga setelah input.

  • Blok besar di kanan bawah #A#reads 1s dan menyalinnya ke baris terakhir dari split sampai 0dibaca.
  • #B#memeriksa sebentar 0dan pergi ke utara ke #D#sana. Jika tidak, #C#mulailah garis pemisah baru dengan menempatkan |setelah yang terakhir, dan kembali ke #A#.
  • Blok di dan di atas #F#adalah kode gravitasi. Ia berjalan ke baris terakhir terakhir 1dan menggerakkannya hingga menyentuh 1atau -. Jika tidak bisa, itu menandai baris selesai dengan meletakkan +sebelumnya.
  • #G#menghapus semua pemisahan yang tidak diperlukan, dan #H#menghapus stdin dan semua kode di antara tanda kurung.

Kode:

 s-----------------------w
 s-c-w  s-c-w  s---w    e+-
 eXj)nc-eXj)nc-exj(ncyj(nn
(n-----------------------------------------w                      ))
(  #H#                             s---w   |                      ))
(                                  exj+ncyxn                      ))
(                                  |                              ))
(                      s---w   s-c-+w                             ))
(                      exj+ncy-eXj1nn                             ))
(                      |                                          ))
(         s---w    s-c-+w    s+pxw                                ))
(         eyj-n-YY-eXj1nn    |  sn1jX--w           e----s         ))
(         |                  Y  x     e+---s e---s ns1jyw         ))
(      ej+n------s           j  |     nn+jYw-n+jxw-Yw   |         ))
(      Y   ec----s      e---s|  |                       1         ))
(      c   ns1jX-wYcYYY-n-jyww  |                       p         ))
(      ns+jxw      #G#       e--s                       Y         ))
(       e---n                   |               s------w|         ))
(                               |               |   ej-nn         ))
(             s--w              e----s   exc----eyj1n---n         ))
(#A#          p e+---s   s---w       |#F#|                        ))
(e----se---s  1 ||   |   exj|n----p+YeXj1ns                       ))
(ns-jXwn-jyw--w-nn1jXw   c #D#       n----w                       ))
( |        |         |   |                                        ))
( |        n---------+---+-------------|pw            s---w s---w ))
( |                  |   |     exp)XYs   |            eyj-nYeXj0ns)
( |         s---ws---+w  n-----+-----+---+------------+----------w))
( |         |   ||   ||  e--yp)n     e---+--s         |           )
( |     e-c-exj|neYj|nn  |     #C#       |  |         p           ))
( |     |                |     s---w s---+w s---w s---+w          ))
( |     |          #B#  e+s    |   | |   || |   | |   ||          ))
(!ep-Yj0n-c----------Xj0nne----exj|n-eYj|nn exj|n-eYj|nn          ))
(-@
 |>
BMac
sumber
Retak
cardboard_box
Sial, sangat dekat! Saya akan membagikan solusi saya ketika saya pulang malam ini.
BMac
Saya tidak bisa menjalankan program paritas. Apakah seharusnya ada instruksi debug di awal? Jika saya melangkah melalui itu terjebak dalam loop tak terbatas, Adakah yang tahu apa yang saya lakukan salah?
feersum
Sepertinya ada tambahan cdi awal yang seharusnya tidak ada di sana. Aku telah memperbaikinya. Juga menambahkan solusi saya untuk masalah ini.
BMac
4

Acc! , Cracc'd oleh ppperry

Bahasa ini memiliki satu struktur pengulangan, matematika integer dasar, karakter I / O, dan akumulator (dengan demikian namanya). Hanya satu akumulator. Demikian namanya.

Pernyataan

Perintah diurai baris demi baris. Ada tiga jenis perintah:

  1. Count <var> while <cond>

Menghitung <var>dari 0 selama <cond>bukan nol, setara dengan C-style for(<var>=0; <cond>; <var>++). Penghitung lingkaran dapat berupa huruf kecil tunggal. Kondisi dapat berupa ekspresi apa pun, tidak harus melibatkan variabel loop. Loop berhenti ketika nilai kondisi menjadi 0.

Loop membutuhkan kurung kurawal gaya K&R (khususnya, varian Stroustrup ):

Count i while i-5 {
 ...
}
  1. Write <charcode>

Output karakter tunggal dengan nilai ASCII / Unicode yang diberikan ke stdout. Kode sandi dapat berupa ekspresi apa pun.

  1. Ekspresi

Ekspresi apa pun yang berdiri sendiri dievaluasi dan ditugaskan kembali ke akumulator (yang dapat diakses sebagai _). Jadi, misalnya, 3adalah pernyataan yang menetapkan akumulator ke 3; _ + 1menambah akumulator; dan _ * Nmembaca karakter dan mengalikan akumulator dengan kode sandi-nya.

Catatan: akumulator adalah satu-satunya variabel yang dapat ditugaskan secara langsung; variabel loop dan Ndapat digunakan dalam perhitungan tetapi tidak dimodifikasi.

Akumulator awalnya 0.

Ekspresi

Ekspresi dapat menyertakan bilangan bulat integer, variabel loop ( a-z), _untuk akumulator, dan nilai khusus N, yang membaca karakter dan mengevaluasi karakternya setiap kali digunakan. Catatan: ini berarti Anda hanya mendapatkan satu kesempatan untuk membaca setiap karakter; lain kali Anda gunakan N, Anda akan membaca yang berikutnya.

Operator adalah:

  • +, tambahan
  • -, pengurangan; negasi unary
  • *, penggandaan
  • /, pembagian bilangan bulat
  • %, modulo
  • ^, eksponensial

Kurung dapat digunakan untuk menegakkan prioritas operasi. Karakter lain dalam ekspresi adalah kesalahan sintaksis.

Spasi dan komentar

Ruang putih dan baris kosong terkemuka dan tertinggal diabaikan. Spasi putih dalam header loop harus persis seperti yang ditunjukkan, dengan satu ruang antara header loop dan kurung kurawal terbuka juga. Ekspresi di dalam spasi putih adalah opsional.

# memulai komentar satu baris.

Input output

Acc! mengharapkan satu baris karakter sebagai input. Setiap karakter input dapat diambil secara berurutan dan karakternya diproses menggunakan N. Mencoba membaca melewati karakter terakhir dari baris menyebabkan kesalahan. Sebuah karakter dapat di-output dengan memberikan kode-nya ke Writepernyataan.

Penerjemah

Penerjemah (ditulis dalam Python 3) menerjemahkan Acc! kode ke Python dan execs itu.

import re, sys

def main():
    if len(sys.argv) != 2:
        print("Please supply a filename on the command line.", file=sys.stderr)
        return
    codeFile = sys.argv[1]
    with open(codeFile) as f:
        code = f.readlines()
    code = translate(code)
    exec(code, {"inputStream": (ord(char) for char in input())})

def translate(accCode):
    indent = 0
    loopVars = []
    pyCode = ["_ = 0"]
    for lineNum, line in enumerate(accCode):
        if "#" in line:
            # Strip comments
            line = line[:line.index("#")]
        line = line.strip()
        if not line:
            continue
        lineNum += 1
        if line == "}":
            if indent:
                loopVar = loopVars.pop()
                if loopVar is not None:
                    pyCode.append(" "*indent + loopVar + " += 1")
                indent -= 1
            else:
                raise SyntaxError("Line %d: unmatched }" % lineNum)
        else:
            m = re.fullmatch(r"Count ([a-z]) while (.+) \{", line)
            if m:
                expression = validateExpression(m.group(2))
                if expression:
                    loopVar = m.group(1)
                    pyCode.append(" "*indent + loopVar + " = 0")
                    pyCode.append(" "*indent + "while " + expression + ":")
                    indent += 1
                    loopVars.append(loopVar)
                else:
                    raise SyntaxError("Line %d: invalid expression " % lineNum
                                      + m.group(2))
            else:
                m = re.fullmatch(r"Write (.+)", line)
                if m:
                    expression = validateExpression(m.group(1))
                    if expression:
                        pyCode.append(" "*indent
                                      + "print(chr(%s), end='')" % expression)
                    else:
                        raise SyntaxError("Line %d: invalid expression "
                                          % lineNum
                                          + m.group(1))
                else:
                    expression = validateExpression(line)
                    if expression:
                        pyCode.append(" "*indent + "_ = " + expression)
                    else:
                        raise SyntaxError("Line %d: invalid statement "
                                          % lineNum
                                          + line)
    return "\n".join(pyCode)

def validateExpression(expr):
    "Translates expr to Python expression or returns None if invalid."
    expr = expr.strip()
    if re.search(r"[^ 0-9a-z_N()*/%^+-]", expr):
        # Expression contains invalid characters
        return None
    elif re.search(r"[a-zN_]\w+", expr):
        # Expression contains multiple letters or underscores in a row
        return None
    else:
        # Not going to check validity of all identifiers or nesting of parens--
        # let the Python code throw an error if problems arise there
        # Replace short operators with their Python versions
        expr = expr.replace("^", "**")
        expr = expr.replace("/", "//")
        # Replace N with a call to get the next input character
        expr = expr.replace("N", "inputStream.send(None)")
        return expr

if __name__ == "__main__":
    main()
DLosc
sumber
2
Cracked
pppery
3

GoToTape (Aman)

(Sebelumnya dikenal sebagai Simp-plex.)

Bahasa ini sederhana. Kontrol aliran utama adalah goto, bentuk kontrol yang paling alami dan berguna.

Spesifikasi bahasa

Data disimpan pada kaset dan dalam akumulator. Ini berfungsi sepenuhnya dengan integrasi yang tidak ditandatangani. Setiap karakter adalah perintah. Berikut ini adalah semua perintah:

  • Surat: a- zadalah pernyataan kebagian, pergi ke A- Z, masing-masing.
  • :: setel akumulator ke nilai ASCII menjadi char dari input.
  • ~: output char untuk nilai ASCII di akumulator.
  • &: kurangi satu dari akumulator jika 1 atau lebih, tambahkan satu.
  • |: tambahkan satu ke akumulator.
  • <: setel pointer data ke 0.
  • +: menambah sel data pada penunjuk data; pindahkan penunjuk +1.
  • -: kurangi satu dari sel data di penunjuk data jika positif; pindahkan penunjuk +1.
  • [...]: jalankan kode n kali di mana n adalah angka pada rekaman di penunjuk data (tidak dapat disarangkan).
  • /: lewati instruksi berikutnya jika akumulatornya 0.

Penerjemah (C ++)

#include <iostream>
#include <memory.h>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int serch(char* str,char ch){
    for(int i = 0;str[i];i++){
        if(str[i]==ch)
            return i;
    }
    return -1;
}

void runCode(char* code){
    int i = 0;
    char c;
    unsigned int* tape;
    tape = new unsigned int[1000003];
    memset(tape,0,1000003*sizeof(int));
    unsigned int p=0;
    unsigned int a=0;
    unsigned int n;
    unsigned int s;

    while(c=code[i]){
        if('A'<=c && c<='Z');
        if('a'<=c && c<='z')i=serch(code, c+'A'-'a');
        if(':'==c)a=cin.get();
        if('+'==c)tape[p++]++;
        if('-'==c)tape[p++] += tape[p]?-1:0;
        if('|'==c)a++;
        if('&'==c)a=a?a-1:1;
        if('<'==c)p=0;
        if('['==c){if(tape[p]){n=tape[p];s=i;}else i+=serch(code+i,']');};
        if(']'==c)i=--n?i:s;
        if('~'==c)cout<<(char)a;
        if('/'==c)i+=a?0:1;
        if('$'==c)p=a;
        i++;
    }
    delete[](tape);
}

int main(int argc, char* argv[]) {
    if(argc == 2){

        ifstream sorceFile (argv[1]);
        string code(static_cast<stringstream const&>(stringstream() << sorceFile.rdbuf()).str());
        runCode((char*)code.c_str());
    }else
        cout << "Code file must be included as a command-line argument \n";
    return 0;
}

Selamat bersenang-senang!

Larutan

A:+&&&&&&&&&&/gbG&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&/a<aB<[|]C[&]-[|]/c<[|]D[&]-[|]/d<[|]+E[&]|||||||||||||||||||||||||||||||||||||||||||||||||~X&/x-[|]/e

MegaTom
sumber
2
Pengodean C ++ Anda mematikan saya! Apakah ada alasan Anda menggunakan callocalih-alih new char, menulis loop gaya-C sementara, menggunakan manajemen memori gaya-C, membuat kami mengkompilasi ulang file C ++ setiap kali kami mengubah kode, dan menggunakan 20 jika bukan sebagai ganti switch? Saya tidak mengeluh, tetapi mata saya berdarah sekarang ...: O
kirbyfan64sos
3
Saya telah memperbaiki bintik untuk memotong juru bahasa.
MegaTom
@ kirbyfan64sos Kode ini buruk. Saya agak menyatukan ini dengan cepat, dan mungkin tidak melakukannya sebaik yang seharusnya. fungsi utama dapat diubah untuk mengambil kode sebagai input. sebenarnya saya pikir saya akan melakukannya sekarang ...
MegaTom
1
Pertanyaannya mengatakan bahwa penerjemah harus mengambil nama file pada baris perintah untuk program ini .
Dennis
Berikut ini beberapa cara singkat membaca file menjadi string . Kemudian telepon str.c_str()untuk mendapatkan char*.
feersum
0

Ini adalah ide yang buruk karena hampir semua bahasa esoteris terlihat tidak dapat dibaca (lihat Jelly).
Tapi begini:

Pylongolf2 beta6

Mendorong ke Stack

Mendorong ke tumpukan bertindak berbeda dari bahasa lain.
Kode 78mendorong 7dan 8masuk ke tumpukan, namun di Pylongolf itu mendorong 78.
Dalam Pylongolf2 ini bisa diubah dengan Ü.

Perintah

) Print the stack.
Ü Toggle the method Pylongolf2 uses for pushing to stack.
a The useless command, removes and adds the selected item in the same place.
c Ask for input.
n Convert string to a number.
" Toggle string mode for pushing text to the stack.
s Convert a number to a string. ╨ Encode the selected item (it must be a string).
_ Duplicate the selected item next to itself.
b Swap places between the selected item and the one before.
d Set the selected item to the last one.
m Move the selected item to the end of the stack.
@ Select an item. (Number required after this command as an argument).
w Wait a specified amount of time (the time is taken from the stack).
= Compare the selected item to the one before. (WARNING. THIS DELETES THE 2 ITEMS AND PLACES A true OR A false) (V2 beta)
~ Print the stack nicely. (V2 beta)
² Square a number. (V3 beta)
| Split a string to an array by the character after |. (V4 beta)
♀ Pop the array. (the contents are left in the stack) (V4 beta)
> Begin a while statement. (V5 beta)
< Loop back to the beginning of the while statement. (V5 beta)
! Break out of the while statements. (V5 beta)
? An if statement, does nothing if the selected item is a `true` boolean. (V6 beta)
¿ If an if statement is `false`, the interpreter skips everything to this character. (V6 beta)

String Concatenation dan Menghapus Pola Regex dari String

Simbol + menyatukan string.
Anda dapat menggunakan simbol - untuk menghapus karakter mengikuti pola regex dari string:

c╨2"[^a-zA-Z]"-~

Kode ini mengambil input dan menghapus semua karakter non-abjad dengan menghapus semua pola yang cocok [^a-zA-Z].
Item yang dipilih harus berupa regex dan yang sebelumnya harus berupa string untuk diedit.

Jika Pernyataan

Untuk melakukan pernyataan if, beri tanda =untuk membandingkan item yang dipilih dan yang sesudahnya.
Ini menempatkan a trueatau a falsedi tempatnya.
Perintah ?memeriksa boolean ini.
Jika itu truemaka itu tidak melakukan apa-apa dan penerjemah berjalan.
Jika itu falsemaka penerjemah melompat ke ¿karakter terdekat .

Diambil dari halaman Github.

Penerjemah untuk Pylongolf2 (Jawa):

package org.midnightas.pylongolf2;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

public class Pylongolf {

    public static final void main(String[] args) throws Exception {
        String content = new String(Files.readAllBytes(Paths.get(new File(args[0]).toURI()))) + " ";
        boolean fullreadMode = true;
        List<Object> stack = new ArrayList<Object>();
        List<Integer> whileStatements = new ArrayList<Integer>();
        HashMap<String, Object> vars = new HashMap<String, Object>();
        int ifStatements = 0;
        Scanner scanner = new Scanner(new UnclosableDecorator(System.in));
        int selectedIndex = 0;
        for (int cl = 0; cl < content.length(); cl++) {
            char c = content.charAt(cl);
            if (isNumber(c)) {
                if (!fullreadMode) {
                    stack.add(Double.parseDouble(c + ""));
                } else {
                    String number = "";
                    for (int cl0 = cl; cl0 < content.length(); cl0++) {
                        if (isNumber(content.charAt(cl0))) {
                            number += content.charAt(cl0);
                        } else {
                            cl = cl0 - 1;
                            stack.add(Double.parseDouble(number));
                            break;
                        }
                    }
                }
            } else if (c == ')') {
                System.out.println(Arrays.toString(stack.toArray()));
            } else if (c == 'Ü') {
                fullreadMode = !fullreadMode;
            } else if (c == '+') {
                if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] obj = (Object[]) stack.remove(selectedIndex);
                    Double dbl = new Double(0d);
                    for (Object o : obj) {
                        dbl += (Double) o;
                    }
                    stack.add(selectedIndex, dbl);
                } else {
                    Object obj0 = stack.remove(selectedIndex);
                    Object obj1 = stack.remove(selectedIndex);
                    if (obj0 instanceof Number && obj1 instanceof Number)
                        stack.add(((Number) obj0).doubleValue() + ((Number) obj1).doubleValue());
                    else if (obj0 instanceof String) {
                        stack.add(obj0.toString() + obj1.toString());
                    }
                }
            } else if (c == '-') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() - ((Number) obj1).doubleValue());
                else if (obj0 instanceof String && obj1 instanceof String) {
                    stack.add(obj0.toString().replaceAll(obj1.toString(), ""));
                }
            } else if (c == '*') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() * ((Number) obj1).doubleValue());
            } else if (c == '/') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() / ((Number) obj1).doubleValue());
            } else if (c == 'a') {
                stack.add(selectedIndex, stack.remove(selectedIndex));
            } else if (c == 'c') {
                stack.add(scanner.nextLine());
            } else if (c == 'n') {
                if (stack.get(selectedIndex) instanceof String) {
                    stack.add(selectedIndex, Double.parseDouble(stack.remove(selectedIndex).toString()));
                } else if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] oldArray = (Object[]) stack.remove(selectedIndex);
                    Object[] newArray = new Object[oldArray.length];
                    for (int i = 0; i < oldArray.length; i++) {
                        newArray[i] = Double.parseDouble(oldArray[i].toString());
                    }
                    stack.add(selectedIndex, newArray);
                }
            } else if (c == '"') {
                String string = "\"";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    string = string + content.charAt(cl0);
                    if (content.charAt(cl0) == '"') {
                        stack.add(string.substring(1, string.length() - 1));
                        cl = cl0;
                        break;
                    }
                }
            } else if (c == 's') {
                Object obj = stack.remove(selectedIndex);
                if (obj instanceof Double) {
                    Double dbl = (Double) obj;
                    if (dbl.doubleValue() == Math.floor(dbl)) {
                        stack.add(selectedIndex, "" + dbl.intValue() + "");
                    } else {
                        stack.add(selectedIndex, "" + dbl + "");
                    }
                }
            } else if (c == '╨') {
                cl++;
                char editmode = content.charAt(cl);
                if (editmode == '0') {
                    stack.add(selectedIndex, rot13(stack.remove(selectedIndex).toString()));
                } else if (editmode == '1') {
                    stack.add(selectedIndex,
                            new StringBuilder(stack.remove(selectedIndex).toString()).reverse().toString());
                } else if (editmode == '2') {
                    stack.add(selectedIndex, stack.remove(selectedIndex).toString().toLowerCase());
                } else if (editmode == '3') {
                    stack.add(selectedIndex, stack.remove(selectedIndex).toString().toUpperCase());
                }
            } else if (c == '_') {
                stack.add(selectedIndex, stack.get(selectedIndex));
            } else if (c == 'b') {
                stack.add(selectedIndex + 1, stack.remove(selectedIndex));
            } else if (c == 'd') {
                selectedIndex = stack.size() == 0 ? 0 : stack.size() - 1;
            } else if (c == 'm') {
                stack.add(stack.remove(selectedIndex));
            } else if (c == '@') {
                String number = "";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    if (isNumber(content.charAt(cl0)))
                        number += content.charAt(cl0);
                    else {
                        cl = cl0 - 1;
                        selectedIndex = Integer.parseInt(number);
                        break;
                    }
                }
            } else if (c == 'w') {
                String number = "";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    if (isNumber(content.charAt(cl0)))
                        number += content.charAt(cl0);
                    else {
                        cl = cl0 - 1;
                        Thread.sleep(Long.parseLong(number));
                        break;
                    }
                }
            } else if (c == '=') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                stack.add(new Boolean(obj0.equals(obj1)));
            } else if (c == '~') {
                for (Object o : stack)
                    System.out.print(o);
                System.out.println();
            } else if (c == '²') {
                if (stack.get(selectedIndex) instanceof Double) {
                    Double dbl = (Double) stack.remove(selectedIndex);
                    stack.add(selectedIndex, dbl * dbl);
                } else if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] obj = (Object[]) stack.remove(selectedIndex);
                    Object[] newArray = new Object[obj.length];
                    for (int i = 0; i < obj.length; i++) {
                        newArray[i] = Math.pow((Double) obj[i], 2);
                    }
                    stack.add((Object[]) newArray);
                }
            } else if (c == '|') {
                String string = (String) stack.remove(selectedIndex);
                cl++;
                char splitChar = content.charAt(cl);
                stack.add((Object[]) string.split(splitChar + ""));
            } else if (c == '♀') {
                for (Object obj : (Object[]) stack.remove(selectedIndex)) {
                    stack.add(selectedIndex, obj);
                }
            } else if (c == '>') {
                whileStatements.add(new Integer(cl));
            } else if (c == '<') {
                cl = whileStatements.get(whileStatements.size() - 1);
            } else if (c == '!') {
                whileStatements.remove(whileStatements.size() - 1);
            } else if (c == '?') {
                if (stack.get(selectedIndex) instanceof Boolean) {
                    Boolean bool = (Boolean) stack.remove(selectedIndex);
                    if (bool == false) {
                        ifStatements++;
                        for (int cl0 = cl; cl0 < content.length(); cl0++) {
                            if (content.charAt(cl0) == '¿') {
                                ifStatements--;
                                cl = cl0;
                            }
                        }
                    }
                }
            } else if (c == 't') {
                break;
            } else if (c == '(') {
                stack.remove(selectedIndex);
            } else if (c == ':') {
                cl++;
                char charToVar = content.charAt(cl);
                vars.put(charToVar + "", stack.remove(selectedIndex));
            } else if (c >= 'A' && c <= 'Z') {
                stack.add(vars.get(c + ""));
            } else if (c == 'r') {
                stack.add(selectedIndex,
                        (double) new Random().nextInt(((Double) stack.remove(selectedIndex)).intValue() + 1));
            }
        }
        scanner.close();
    }

    public static String rot13(String input) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            if (c >= 'a' && c <= 'm')
                c += 13;
            else if (c >= 'A' && c <= 'M')
                c += 13;
            else if (c >= 'n' && c <= 'z')
                c -= 13;
            else if (c >= 'N' && c <= 'Z')
                c -= 13;
            sb.append(c);
        }
        return sb.toString();
    }

    public static boolean isNumber(char c) {
        return c >= '0' && c <= '9';
    }

}

sumber
Apakah ini seharusnya sulit digunakan? : /
CalculatorFeline
0

Rainbow (Catatan: Penerjemah segera hadir)

Saya tahu tantangan ini berakhir.

Pelangi adalah campuran ... banyak hal.

Rainbow adalah bahasa berbasis tumpukan 2D dengan dua tumpukan (Seperti Brain-Flak) dan 8 arah ( N NE E SE S SW W NW). Ada 8 perintah:

  • 1, +, *, "Melakukan persis apa yang mereka lakukan di 1+.
  • ! matikan tumpukan aktif.
  • > putar IP searah jarum jam.
  • , masukan karakter dan tekan.
  • . pop dan output karakter.

Namun, karakter dalam kode sumber tidak segera dieksekusi. Sebaliknya, [The Character in the source code]^[Top Of Stack]dimasukkan ke dalam hal dugaan Collatz, dan jumlah langkah yang diperlukan untuk mencapai 1 dikonversi menjadi karakter oleh tabel ASCII. Karakter ini kemudian dieksekusi.

  • Jika dibutuhkan lebih dari 127 langkah untuk mencapai 1, jumlah langkah total dibagi dengan 127, ambil pengingat, lalu tambahkan pengingat ke hasil bagi.

Di awal program, kode sumber (kecuali untuk karakter terakhir) didorong ke stack.

Ketika IP mencapai tepi kode sumber, itu berakhir.

Wahyu

n dan m adalah dua register. Ketika >instruksi dieksekusi, m bertambah. Kiamat hanya dipicu jika m melebihi n. Ketika Kiamat terjadi, itu:

  • Putar berlawanan arah jarum jam, bukan searah jarum jam.
  • m menjadi 0.
  • n menjadi bagian atas tumpukan. Dan kemudian, tumpukan itu muncul.

m awalnya nol, dan n awalnya karakter terakhir dari kode sumber.

Enkripsi

Setelah menjalankan eksekusi apa pun, kode sumber dienkripsi. ASCII karakter 1 bertambah satu, karakter 2 dikurangi satu, karakter ketiga ditambah dua, karakter keempat dikurangi dua, dll.

Sangat Radioaktif
sumber
1
cukup yakin Anda membutuhkan juru bahasa agar ini menjadi jawaban yang valid ...
Conor O'Brien
@ ConorO'Brien Karena tantangan ini sudah berakhir, ini hanya untuk bersenang-senang. Saya AKAN menyediakan penerjemah.
HighlyRadioactive
@ HighlyRadioactive ... Anda mengatakan hampir sebulan yang lalu.
pppery