Tips untuk bermain golf di CJam


43

CJam adalah bahasa golf berbasis stack yang terinspirasi dari GolfScript, dibuat oleh pengguna aditsu PPCG .

Jadi, di tengah pertanyaan kiat khusus bahasa lainnya:

Apa tips umum yang Anda miliki untuk bermain golf di CJam? Silakan kirim satu tip per jawaban.


4
Lihat juga Tip untuk bermain golf di GolfScript ; bahasanya cukup mirip sehingga banyak trik yang dapat diadaptasi dengan cara apa pun.
Ilmari Karonen

2
@IlmariKaronen Setelah melalui jawaban dalam pertanyaan itu, saya akan mengatakan hanya sekitar setengah dari mereka berlaku untuk CJam, karena perbedaan sintaksis atau logis dalam bahasa.
Pengoptimal

Jawaban:


23

Modulo yang benar untuk angka negatif

Seringkali menjengkelkan bahwa hasil operasi modulo memberikan tanda yang sama dengan operan pertama. Misalnya -5 3%memberi -2bukan 1. Lebih sering daripada tidak Anda inginkan yang terakhir. Perbaikan naif adalah untuk menerapkan modulo, tambahkan pembagi sekali dan menerapkan modulo lagi:

3%3+3%

Tapi itu panjang dan jelek. Sebagai gantinya, kita dapat menggunakan fakta bahwa pengindeksan array selalu modular dan tidak bekerja dengan benar dengan indeks negatif. Jadi kami hanya mengubah pembagi menjadi rentang dan mengaksesnya:

3,=

Diterapkan untuk -5, ini memberi 1seperti yang diharapkan. Dan itu hanya satu byte lebih panjang dari built-in %!

Jika modulus adalah kekuatan 2, Anda dapat menyimpan byte lain menggunakan bitwise arihmetic (yang juga jauh lebih cepat). Membandingkan:

32,=
31&

Untuk kasus khusus 65536 == 2^16byte lain dapat disimpan dengan memanfaatkan perilaku pembungkus tipe karakter:

ci

13

Mendorong rentang karakter gabungan

  • String yang berisi semua digit "0123456789"dapat ditulis sebagai

    A,s
    
  • Huruf ASCII huruf besar ( A-Z) dapat didorong sebagai

    '[,65>
    

    yang menghasilkan string semua karakter hingga Z , kemudian membuang 65 pertama (hingga @ ).

  • Semua huruf ASCII ( A-Za-z) dapat didorong sebagai

    '[,65>_el+
    

    yang berfungsi seperti di atas, lalu membuat salinan, mengonversi ke huruf kecil dan menambahkan.

    Tetapi ada cara yang lebih singkat untuk melakukannya!

    Kemudian sering diabaikan ^operator (perbedaan simetris untuk daftar) memungkinkan untuk membuat rentang yang sama sambil menghemat tiga byte:

    '[,_el^
    

    '[,membuat rentang semua karakter ASCII hingga Z , _elmembuat salinan huruf kecil dan ^hanya menyimpan karakter dari kedua string yang muncul dalam satu tetapi tidak keduanya.

    Karena semua huruf dalam string pertama adalah huruf besar, semua yang kedua adalah huruf kecil dan semua karakter non-huruf berada di kedua string, yang menghasilkan string huruf.

  • Alfabet RFC 1642 Base64 ( A-Za-z0-9+/) dapat didorong menggunakan teknik di atas dan menambahkan non-huruf:

    '[,_el^A,s+"+/"+
    

    Cara yang sama pendeknya untuk mendorong string ini hanya menggunakan perbedaan simetris:

    "+,/0:[a{A0":,:^
    

    Bagaimana kita dapat menemukan string di awal?

    Semua rentang karakter digunakan ( A-Z, a-z, 0-9, +, /) dapat didorong sebagai perbedaan simetris untuk rentang yang mulai byte null, yaitu 'A,'[,^, 'a,'{,^, '0,':,^, '+,',,^dan '/,'0,^.

    Karena itu, mengeksekusi :,:^pada "A[a{):+,/0"akan mendorong karakter yang diinginkan, tetapi tidak dalam urutan yang benar.

    Bagaimana kita menemukan urutan yang benar? Brute force untuk menyelamatkan! Program

    '[,_el^A,s+"+/"+:T;"0:A[a{+,/0"e!{:,:^T=}=
    

    iterates atas semua kemungkinan permutasi string, berlaku :,:^dan bandingkan hasilnya dengan output yang diinginkan ( permalink ).

  • Alfabet radix-64 yang digunakan, misalnya, oleh crypt ( .-9A-Za-z) dapat dihasilkan menggunakan metode di atas:

    ".:A[a{":,:^
    

    Ini adalah metode terpendek yang saya tahu.

    Karena semua karakter dalam output yang diinginkan adalah dalam urutan ASCII, iterasi dari permutasi tidak diperlukan.

  • Tidak semua rentang karakter gabungan dapat didorong dalam urutan yang diinginkan menggunakan :,:^.

    Misalnya, rentang 0-9A-Za-z;-?tidak dapat didorong dengan mengeksekusi :,:^pada permutasi dari "0:A[a{;@".

    Namun, kita dapat menemukan variasi yang dirotasi dari string yang diinginkan yang dapat, dengan menggunakan kode

    A,'[,_el^'@,59>]s2*:T;"0:A[a{;@"e!{:,:^T\#:I)}=Ip
    

    yang akan mencetak ( permalink ) berikut ini:

    10
    0:@[a{A;
    

    Ini artinya

    "0:@[a{A;":,:^Am>
    

    memiliki efek yang sama dengan

    A,'[,_el^'@,59>]s
    

    yang hanya dapat digunakan dengan tumpukan kosong tanpa harus menambahkan [.


11

Hindari {...} {...}?

Asumsikan Anda memiliki bilangan bulat di tumpukan. Jika aneh, Anda ingin mengalikannya dengan 3 dan menambahkan 1; jika tidak, Anda ingin membaginya dengan 2.

Pernyataan "normal" jika / else akan terlihat seperti ini:

_2%{3*)}{2/}?

Namun, menggunakan blok biasanya bukan cara untuk pergi, karena {}{}sudah menambahkan empat byte. ?juga dapat digunakan untuk memilih satu dari dua item di tumpukan:

_2%1$3*)@2/?

Ini lebih pendek satu byte.


Blok-? dengan pernyataan if kosong selalu merupakan larangan. Sebagai contoh,

{}{2/}?

dua byte lebih panjang dari

{2/}|

Jika sebaliknya Anda miliki

{2/}{}?

dan hal yang Anda periksa adalah bilangan bulat non-negatif, yang dapat Anda lakukan

g)/

Yang baru {}&dan {}|praktis, tetapi terkadang bermasalah jika Anda tidak dapat mengacaukan tumpukan.

Namun, dalam kasus

_{…}{;}?

Anda bisa menggunakan variabel sementara sebagai gantinya:

:T{T…}&

1
!)/dan g)/lebih pendek dalam contoh.
jimmy23013

11

Ganti pernyataan

CJam tidak memiliki pernyataan switch. Bersarang jika pernyataan bekerja dengan baik, tetapi {{}{}?}{}?sudah 12 byte ...

Jika kita dapat mengubah kondisi menjadi bilangan bulat kecil, non-negatif, kita dapat mengubah semua pernyataan kasus dalam string yang dibatasi dan mengevaluasi hasil yang sesuai.

Sebagai contoh, jika kita ingin mengeksekusi code0jika integer stack adalah 0 , code1jika itu adalah 1 , dan code2jika itu adalah 2 , kita dapat menggunakan

_{({code2}{code1}?}{;code0}?

atau

[{code0}{code1}{code2}]=~

atau

"code0 code1 code2"S/=~

S/memisahkan string menjadi ["code0" "code1" "code2"], =mengekstrak potongan yang sesuai, dan ~mengevaluasi kode.

Klik di sini untuk melihat pergantian pernyataan dalam aksi.

Akhirnya, seperti yang disarankan oleh @ jimmy23013 dan @RetoKoradi, kita dapat lebih mempersingkat sakelar dalam beberapa kasus. Katakan code0, code1dan masing-masing code2memiliki panjang L 0 , L 1 dan L 2 .

Jika L 0 = L 1 ≥ L 2

"code0code1code2"L/=~

dapat digunakan sebagai pengganti, di mana Ladalah L 0 . Alih-alih membelah pada pembatas, /pisahkan string menjadi potongan dengan panjang yang sama di sini.

Jika L 0 ≥ L 1 ≥ L 2 ≥ L 0 - 1 ,

"cccooodddeee012">3%~

dapat digunakan sebagai gantinya. >menghapus 0, 1 atau 2 elemen dari awal string, dan 3%mengekstrak setiap elemen ketiga (dimulai dengan yang pertama).


Sebagai contoh terakhir, apakah ada kelebihannya "code0code1code2"5/=~? Tampaknya jauh lebih mudah bagi saya, dan panjangnya sama.
Reto Koradi

@RetoKoradi Jika semua cuplikan memiliki panjang yang sama, tidak ada keuntungan. Untuk panjang yang berbeda, metode Anda bisa lebih pendek dan lebih panjang dari metode modulus.
Dennis

11

Golf array umum dan nilai string

Ada beberapa array atau string pendek yang muncul setiap saat, misalnya untuk menginisialisasi grid. Secara naif, ini bisa memakan biaya 4 byte atau lebih, jadi ada baiknya mencari operasi pada nilai bawaan yang akan memberikan hasil yang sama. Terutama konversi basis sering berguna.

  • [0 1]dapat ditulis sebagai 2,.
  • [1 0]dapat ditulis sebagai YYb(yaitu 2 dalam biner).
  • [1 1]dapat ditulis sebagai ZYb(yaitu 3 dalam biner).
  • Matriks [[0 1] [1 0]]dapat ditulis sebagai 2e!.
  • [LL] dapat ditulis sebagai SS/(membelah satu ruang dengan spasi).
  • "\"\""dapat ditulis sebagai L`.
  • "{}"dapat ditulis sebagai {}s.

Yang terakhir dapat diperluas ke kasus di mana Anda ingin semua tipe braket menyimpan byte lain:

  • "[{<()>}]"dapat ditulis sebagai {<()>}a`.
  • "()<>[]{}"dapat ditulis sebagai {<()>}a`$.

Terutama trik konversi basis dapat berguna untuk diingat untuk beberapa kasus tidak jelas yang muncul setiap saat. Misalnya [3 2]akan E4b(14 dalam basis 4).

Dalam kasus yang bahkan lebih jarang, Anda bahkan mungkin menemukan operator factorisation mfberguna. Misalnya [2 7]adalah Emf.

Silakan memperpanjang daftar ini jika Anda menemukan contoh lain.


10

Membersihkan tumpukan

Jika Anda hanya ingin menghapus seluruh tumpukan, bungkus dalam array dan letakan:

];

Yang sedikit lebih rumit adalah, jika Anda telah melakukan banyak perhitungan, tetapi hanya ingin mempertahankan elemen tumpukan teratas dan membuang semua yang ada di bawahnya. Pendekatan naif adalah menyimpan elemen atas dalam suatu variabel, menghapus tumpukan, mendorong variabel. Tapi ada alternatif yang jauh lebih pendek: bungkus stack dalam array dan ekstrak elemen terakhir:

]W=

(Terima kasih kepada Pengoptimal yang menunjukkan ini kepada saya tempo hari.)

Tentu saja, jika hanya ada dua elemen di stack, \;lebih pendek.


\;hanya akan memunculkan elemen di bawah TOS. Apakah maksud Anda ;;?
CalculatorFeline

1
@CalculatorFeline, bagian kedua dari jawabannya adalah tentang membersihkan semuanya kecuali TOS.
Martin Ender

9

e dan kekuatan sepuluh

Seperti dalam banyak bahasa lain, Anda dapat menulis 1e3alih-alih 1000dalam CJam.

Ini berfungsi untuk basis non-integer dan bahkan untuk eksponen non-integer juga. Misalnya, 1.23e2mendorong 123.0 dan 1e.5mendorong 3.1622776601683795 (akar kuadrat dari 10 ).

Yang tidak segera jelas adalah bahwa 1e3sebenarnya ada dua token:

  • 1mendorong bilangan bulat 1 pada tumpukan.

  • e3kalikan dengan 1000 .

Mengapa itu penting?

  • Anda dapat memanggil e<numeric literal>sesuatu yang sudah ada di tumpukan.

    2 3 + e3 e# Pushes 5000.
    
  • Anda dapat memetakan e<numeric literal>melalui array.

    5 , :e3  e# Pushes [0 1000 2000 3000 4000].
    

9

Norma Euclidean

Cara langsung menghitung norma Euclidean dari vektor, yaitu, akar kuadrat dari jumlah kuadrat elemen-elemennya, adalah

2f#:+mq

Namun, ada cara yang jauh lebih pendek.

mh, operator miring, muncul dua bilangan bulat a dan b dari tumpukan dan mendorong sqrt (a 2 + b 2 ) .

Jika kita memiliki vektor x: = [x 1 ... x n ], n> 1 pada stack, :mh(kurangi dengan sisi miring) akan mencapai yang berikut:

  • Pertama x 1 dan x 2 didorong dan mhdijalankan, meninggalkan sqrt (x 1 2 + x 2 2 ) , di tumpukan.

  • Kemudian, x 3 didorong dan mhdieksekusi lagi, meninggalkan
    sqrt (sqrt (x 1 2 + x 2 2 ) 2 + x 3 2 ) = sqrt (x 1 2 + x 2 2 + x 3 2 ) pada stack.

  • Setelah x n diproses, kita pergi dengan sqrt (x 1 2 + ... x n 2 ) , norma Euclidean dari x .

Jika n = 1 dan x 1 <0 , kode di atas akan menghasilkan hasil yang salah. :mhzbekerja tanpa syarat. (Terima kasih kepada @ MartinBüttner karena menunjukkannya.)

Saya menggunakan trik ini untuk pertama kali dalam jawaban ini .


2
Tentu saja, ini memiliki implikasi untuk analisis numerik program Anda ...
Peter Taylor

8

Konversi dari pangkalan n dengan daftar angka yang lebih besar dari n

CJam mengonversi daftar menjadi angka dengan rumus ini: A 0 * n l + A 1 * n l-1 + A 2 * n l-2 + A l * n 0 (dengan tidak negatif n). nadalah dasar dan lpanjang daftar. Ini berarti A i dapat berupa bilangan bulat apa pun, yang tidak harus berada dalam kisaran [0,n).

Beberapa contoh:

  • 0bmengekstrak item terakhir dan melemparkannya ke integer. Bekerja seperti W=idan menyimpan byte jika bukan bilangan bulat. Tetapi semua hal lain dalam daftar juga harus dapat dimasukkan ke dalam integer.
  • 1bmengembalikan jumlahnya. Bekerja seperti :i:+dan menyimpan dua byte jika bukan bilangan bulat. Ini juga berfungsi dengan daftar kosong sementara :+tidak.
  • [i{_1&9 32?_@\m2/}16*;]W%:cMengonversi karakter ke string akhiran dan tab, yang dapat dikonversi kembali dengan 2bc. Namun, fungsi pengodean tidak mudah untuk di-golf dalam program kode-golf. Tetapi Anda biasanya tidak membutuhkan itu.
  • Anda dapat menggunakan kode berikut untuk mengubah string menjadi karakter Unicode tidak dalam 16 bit, yang dapat dikonversi kembali dengan 2A#b128b:c. (Penjelasan akan ditambahkan nanti. Atau mungkin saya akan menulis versi baru nanti.)

    128b2A#b         " Convert to base 1024. ";
    W%2/)W%\:+       " Convert to two base 1024 digit groups. ";
    [0X@
    {
      _54+
      @I+_Am>@\-
      _Am<@+ 0@-@1^
    }fI
    ]);)
    @\+[~+]2A#b_2G#<!{2A#b}*
    \W%+:c
    

Metode serupa bekerja dengan set ninteger yang memiliki mod nilai yang berbeda n, jika Anda dapat menemukan cara untuk menghilangkan digit paling signifikan.


8

Menggunakan $sebagai terner jika

Ketika Anda tidak keberatan membocorkan memori, yaitu, meninggalkan elemen yang tidak digunakan pada tumpukan yang nantinya akan Anda bersihkan ];, operator penyalinan $dapat menjadi pengganti yang berguna untuk operator ternary ?.

? berfungsi dengan baik jika Anda berhasil menghitung kondisi sebelum mendorong dua item untuk dipilih, tetapi lebih sering daripada tidak, kondisi sebenarnya tergantung pada item-item itu, dan setelah itu hasilnya lebih alami.

Jika sudah ada A B Cdi stack, Anda bisa menjalankannya

!$

dari pada

\@?

untuk menyalin Bjika Citu benar dan Asebaliknya.

Jika CBoolean sebenarnya ( 0atau 1), Anda dapat mengeksekusi

$

dari pada

@@?

untuk menyalin Ajika Citu benar dan Bsebaliknya.


Kalau dipikir-pikir, ini adalah trik yang agak jelas, tetapi saya belum pernah memikirkannya sebelumnya. Saya sudah menggunakannya untuk pertama kalinya dalam jawaban ini .
Dennis

7

Peta untuk Daftar Bersarang

Katakanlah Anda punya daftar bersarang, seperti sebuah matriks:

[[0 1 2][3 4 5][6 7 8]]

Atau serangkaian string:

["foo""bar"]

Dan Anda ingin memetakan blok ke tingkat bersarang (yaitu menerapkannya ke setiap nomor atau setiap karakter). Solusi naif adalah bersarang %:

{{...}%}%

Namun, Anda dapat benar-benar mendorong blok bagian dalam ke tumpukan dan kemudian menggunakannya f%. fadalah "map dengan parameter tambahan", sehingga akan memetakan %ke daftar luar, menggunakan blok sebagai parameter kedua:

{...}f%

Menghemat dua byte.

Trik lain yang rapi untuk melakukan sesuatu for (i=0; i<5; ++i) for (j=0; j<5; ++j) {...}adalah

5,_f{f{...}}

Bagian luar fakan memetakan ke rentang pertama, memasok rentang kedua sebagai parameter tambahan. Tapi sekarang, jika Anda menggunakan flagi, hanya elemen stack atas adalah array, jadi Anda fmemetakan blok bagian dalam itu, memasok "variabel iterasi" luar sebagai parameter tambahan. Ini berarti blok dalam berjalan dengan idan jpada tumpukan.

Ini memiliki jumlah karakter yang sama dengan hanya memetakan blok ke produk Cartesian (meskipun yang terakhir semakin pendek jika Anda membutuhkan pasangan sebagai array):

5,_m*{~...}%

Perbedaannya adalah bahwa versi ini menghasilkan satu array hasil untuk semua pasangan, sedangkan double- fmenghasilkan daftar bersarang, yang dapat berguna jika Anda ingin menyimpan hasil dalam kotak, dengan variabel iterator menjadi koordinat.

Terima kasih kepada Dennis karena menunjukkan trik ini kepada saya.

0.6.4 Pembaruan

fdan :sekarang telah sangat ditingkatkan dengan mengambil operator lain termasuk mereka sendiri. Ini berarti Anda dapat menyimpan lebih banyak byte sekarang. Memetakan operator ke daftar bersarang menjadi lebih pendek sekarang:

{:x}%
{x}f%
::x

Ini tidak terlalu membantu dengan memetakan blok ke daftar bersarang.

Adapun blok atau operator yang menerapkan produk Cartesian, ini juga menjadi lebih pendek sekarang, untuk blok serta operator:

5,_f{f{...}}
5,_ff{...}

5,_f{fx}
5,_ffx

Apa yang baik adalah bahwa Anda sekarang dapat bersarang ini. Jadi, Anda dapat menerapkan operator dengan mudah ke tingkat bawah daftar:

:::x

Atau satu blok dengan beberapa tipu daya:

{...}ff%

Pembaruan hebat. Tetapi masih belum ada f~...
jimmy23013

@ user23013 fmengharapkan operator biner, ~tidak waspada; apakah kamu mungkin mau :~? Juga, kita dapat membahas ini di chat
aditsu

Apakah saya kehilangan sesuatu tentang pembaruan 0.6.4 ini? Saya masih mendapatkan pesan kesalahan dengan melakukan trik-trik itu, seperti Unhandled char after ':': :( tautan )
Runer112

2
@ Runer112 Bekerja untuk saya. Pastikan Anda memuat ulang dengan benar (mis. Bukan dari cache). Tergantung pada browser Anda, Ctrl + F5 harus berfungsi.
Martin Ender

@ MartinBüttner Itu memang disebabkan oleh caching konyol. Terima kasih.
Runer112

7

Operator vektor untuk seni ASCII

Bagi banyak tantangan seni ASCII, akan berguna untuk menghasilkan dua pola yang berbeda untuk menempatkannya nanti. Operator vektor dapat sangat membantu untuk mencapai berbagai jenis superposisi.

Satu sifat berguna dari vektorisasi operator adalah bahwa operator hanya dieksekusi satu kali untuk setiap elemen string / array yang lebih pendek, sedangkan elemen-elemen yang lebih besar yang tidak memiliki rekanan tetap tidak tersentuh.

  • .e<

    Operator minimum e<berfungsi untuk pasangan string, karakter, array dan integer; itu muncul dua item dari tumpukan dan mendorong yang lebih rendah pada e kembali.

    Karena spasi memiliki titik kode lebih rendah daripada semua karakter ASCII yang dapat dicetak lainnya, .e<dapat digunakan untuk "menghapus" bagian-bagian dari pola yang dihasilkan:

    "\/\/\/\/\/" "    " .e<
    
    e# This pushes "    \/\/\/".
    

    Untuk contoh lengkap, lihat jawaban saya untuk Me Want Honeycomb .

  • .e>

    Operator maksimum e>berfungsi sebagai operator minimum, dengan hasil sebaliknya.

    Sekali lagi, karena titik kode ruang yang rendah, .e>dapat digunakan untuk menyisipkan pola karakter yang dapat dicetak dalam blok ruang:

    [[" " " " " " " "] [" " " " " " " "]][["+" "" "-" ""]["" "*" "" "/"]] ..e>
    
    e# This pushes [["+" " " "-" " "] [" " "*" " " "/"]].
    

    Untuk contoh lengkap, lihat jawaban saya untuk Seven Slash Display .

  • .e&

    Operator logika DAN e&mendorong argumen kiri jika argumen palsu dan kanan sebaliknya.

    Jika tidak ada pola yang mengandung elemen falsy, ini dapat digunakan untuk memaksakan satu pola tanpa syarat:

    "################" " * * * *" .e&
    
    e# This pushes " * * * *########".
    

    Sebagai contoh lengkap, lihat jawaban saya untuk Mencetak Bendera Amerika! .

  • .e|

    Operator logika ATAU e|dapat digunakan seperti di atas, dengan urutan argumen terbalik:

    " * * * *" "################" .e|
    
    e# This pushes " * * * *########".
    

6

Gunakan &untuk memeriksa apakah suatu item ada dalam daftar

Untuk

1 [1 2 3] #W>
1 [1 2 3] #)

Anda dapat gunakan

1 [1 2 3] &,
1 [1 2 3] &

sebaliknya, yang mengembalikan 0/1 dan truthy / falsey masing-masing.


6

z dan array non-persegi panjang

Operator pos ztransposes baris dan kolom dari dua dimensi 1 Array A , yang unsur-unsurnya juga bisa iterables.

Untuk array non-persegi panjang - tidak seperti fungsi built-in zipdi, misalnya, Python (memotong baris dengan panjang yang sama) atau Ruby (bantalan baris dengan nil) - CJam hanya mengubah kolom array menjadi baris, mengabaikan panjangnya dan kesenjangan.

Misalnya, zipping array

[
  [1]
  [2 4]
  [3 5 6]
]

setara dengan zip array

[
  [1 4 6]
  [2 5]
  [3]
]

atau array

[
  [1]
  [2 4 6]
  [3 5]
]

karena ketiga tindakan mendorong

[
  [1 2 3]
  [4 5]
  [6]
]

di tumpukan.

Meskipun ini berarti bahwa zini bukan suatu involusi (yang akan berguna pada kesempatan tertentu), ini memiliki beberapa aplikasi.

Sebagai contoh:

  • Kita dapat menyelaraskan kolom-kolom array ke atas (yaitu, mengubah array pertama menjadi array kedua) dengan zip dua kali:

    zz
    
  • Modifikasi kecil dari metode di atas dapat digunakan untuk masalah yang serupa.

    Misalnya, untuk menyelaraskan kolom-kolom array ke bawah (yaitu, untuk mengubah array kedua menjadi yang pertama), kita dapat zip dua kali dengan urutan baris terbalik:

    W%zzW%
    
  • Diberikan array string, kita dapat menghitung panjang string terpanjang seperti ini:

    :,:e>
    

    Namun, dengan meng-zip dan menghitung jumlah baris dari hasil, kita dapat menyimpan tiga byte:

    z,
    

1 Jika salah satu dari "baris" A tidak dapat diubah, zperlakukan mereka sebagai lajang, jadi zipping berfungsi untuk array yang sewenang-wenang.


1
Hanya cara berbeda memvisualisasikan hal yang sama, tetapi bagi saya perilakunya jauh lebih logis jika saya membayangkan zmengubah kolom menjadi baris, sementara nilai kosong dilewati. Pada contoh, kolom pertama pada input adalah 1, 2, 3, kolom kedua adalah 4, 5 (posisi kosong dilewati), dan kolom ketiga adalah 6. Ini adalah baris dari hasil.
Reto Koradi

@RetoKoradi Itu cara yang lebih baik untuk menggambarkannya.
Dennis

6

Pengecualian

Semua pengecualian fatal dalam CJam. Karena output ke STDERR diabaikan secara default , kita dapat menggunakan ini untuk keuntungan kita.

Semua operator di CJam bekerja dengan mengeluarkan nol atau lebih elemen dari stack, melakukan beberapa tugas dan menekan nol atau lebih elemen pada stack. Pengecualian terjadi saat tugas dilakukan, jadi ini masih muncul elemen, tetapi tidak ada yang mendorong balasan.

Berikut beberapa kasus penggunaan:

  • Membersihkan tumpukan kecil

    Untuk menghapus tumpukan yang berisi dua elemen, @bisa digunakan. @mencoba pop tiga elemen stack, tetapi gagal setelah muncul yang kedua.

    Operator lain yang mengeluarkan tiga elemen akan memiliki tujuan yang sama.

    Lihat beraksi di sini .

  • Menghapus dua atau tiga elemen dari tumpukan

    Operator apa pun yang tidak diimplementasikan untuk elemen-elemen khusus ini dapat digunakan untuk mengeluarkan dua atau tiga elemen dari stack tepat sebelum keluar.

    Untuk memunculkan dua elemen, bberfungsi jika salah satunya adalah karakter atau tidak ada yang bilangan bulat.

    Untuk memunculkan tiga elemen, tberfungsi jika tidak satu pun dari terbawah dua adalah iterable, bawah-iterable paling kosong atau tidak ada yang bilangan bulat.

  • Keluar dari loop

    Terkadang, kita perlu keluar dari loop ketika integer menjadi nol atau string menjadi terlalu pendek. Daripada menguji untuk kondisi ini, jika operasi yang terlibat gagal untuk nol, string kosong atau lajang, kita dapat membiarkan program mengambil program alami.

    Untuk contoh yang melibatkan aritmatika, lihat di sini .

    Untuk contoh yang melibatkan string, lihat di sini .

  • Eksekusi bersyarat

    Jika kode sumber tidak boleh dieksekusi untuk jenis input tertentu, kami kadang-kadang dapat menggunakan operator yang gagal input semacam itu.

    Misalnya, iakan gagal untuk string yang tidak mengevaluasi ke bilangan bulat dan ewakan gagal untuk string dengan panjang 0 atau 1.

    Lihat beraksi di sini .


5

Maks / Min dari array

Ini satu untuk pemula!

Ketika Anda perlu menemukan angka maksimum atau minimum dari sebuah array, cara termudah dan terkecil adalah dengan mengurutkan array dan kemudian mengambil elemen pertama atau terakhir.

Jadi jika array dalam variabel A

A$W=

adalah maksimum dan

A$0=

adalah minimum.

Mendapatkan keduanya sekaligus juga dimungkinkan

A$)\0=

Ini mungkin tampak jelas setelah membaca, tetapi upaya pertama siapa pun cenderung mengarah ke penggunaan e<atau e>melalui iterasi melalui array, yang berjalan seperti

A{e<}*

yang 2 byte lebih lama, dan bahkan lebih lama jika Anda ingin maks dan min.


Tentu saja, jika Anda tidak keberatan dengan sisa array yang tersisa di stack, Anda dapat menggunakan (dan )bukannya 0=dan W=.
Martin Ender

Sekarang ada :e<dan:e>
aditsu

@aditsu Meskipun, mereka tidak lebih pendek dari tip di atas.
Pengoptimal

5

Gunakan cap waktu untuk jumlah besar

Jika Anda membutuhkan angka yang sangat besar, tetapi sewenang-wenang, Anda biasanya akan menggunakan notasi ilmiah suka 9e9atau menaikkan salah satu variabel bawaan besar ke kekuatan yang sama, seperti KK#. Namun, jika Anda tidak peduli berapa angka sebenarnya, dan tidak perlu secara konsisten sama (misalnya sebagai batas atas untuk angka acak), Anda dapat melakukannya dalam dua byte menggunakan

es

sebagai gantinya. Ini memberikan cap waktu saat ini dalam milidetik, dan berada di urutan 10 12


3
Perhatikan juga bahwa jika Anda ingin nomor arbitrer yang besar, dan ingin membuang angka positif secara bersamaan, Anda dapat menggunakannya e9.
jimmy23013

5

Memeriksa bahwa dua string / array tidak sama

Terkadang Anda menginginkan nilai kebenaran ketika dua string atau array tidak sama, dan nilai palsu jika mereka. Solusi yang jelas adalah dua byte:

=!

Periksa kesetaraan, dan balikkan hasilnya. Namun, dalam beberapa kondisi Anda dapat menggunakan

#

Ketika #diterapkan ke dua array itu sebenarnya mencari array kedua sebagai subarray yang pertama (dan memberi Anda indeks di mana subarray dimulai). Jadi, jika kedua array itu sama, subarray akan ditemukan tepat di awal dan memberi 0, yang salah. Tetapi jika array kedua tidak dapat ditemukan, itu akan memberikan -1mana yang benar.

Alasan kita memerlukan beberapa kondisi tambahan pada dua array adalah bahwa ini juga menghasilkan nilai falsy jika array kedua adalah awalan non-sepele dari array pertama, misalnya:

"abc""ab"#

memberi 0meskipun string tidak sama. Kondisi paling sederhana yang mengesampingkan kasus ini adalah jika Anda tahu bahwa kedua array akan memiliki panjang yang sama - dalam hal ini jika satu adalah awalan dari yang lain, Anda tahu bahwa keduanya sama. Tetapi dalam kondisi tertentu mungkin ada kondisi yang lebih lemah yang juga cukup. Misalnya, jika Anda tahu bahwa string diurutkan, awalan akan selalu menjadi string pertama, bukan yang kedua.


5

c dan bilangan bulat 16-bit

Untuk menambah (atau mengurangi) bilangan bulat 16-bit yang tidak ditandatangani dengan pembungkus yang tepat, Anda dapat menggunakan +65536%atau +2G#%.

Namun,

+ci

jauh lebih pendek. Bungkus karakter diseluruh pada 65536 , jadi casting ke Character ( c) lalu ke Long ( i) memiliki efek yang mirip dengan 65536%, dengan manfaat tambahan bahwa hasilnya tidak akan negatif.

Trik yang sama dapat digunakan untuk mendorong 65535 :

Wci

4

Set daya

Katakanlah Anda memiliki array dan Anda ingin array dengan semua himpunan bagian yang mungkin dari array itu. Caranya adalah mulai dengan array kosong, dan kemudian, untuk setiap elemen, duplikat himpunan bagian yang sudah Anda miliki, dan tambahkan elemen baru ke mereka (menjaga hasil sebelumnya di mana elemen tidak ditambahkan ). Perhatikan bahwa Anda perlu menginisialisasi tumpukan dengan kasing dasar, yaitu array yang hanya berisi array kosong: Itu bisa terlihat seperti ini:

[1 2 3 4 5]La\{1$f++}/

Yang menyenangkan tentang ini adalah, Anda dapat langsung menjalankan beberapa perhitungan pada subset, berpotensi tanpa karakter tambahan. Katakanlah Anda menginginkan produk dari semua himpunan bagian. Dalam hal ini, casing dasar adalah array yang berisi 1, dan pada setiap langkah, Anda mengambil daftar produk yang mungkin sebelumnya, menduplikasinya, dan melipatgandakan segala sesuatu dalam duplikat dengan elemen baru:

[1 2 3 4 5]1a\{1$f*+}/

4

Periksa apakah item dalam daftar semuanya sama

Saya pikir ini juga layak disebutkan. Menggunakan:

)-

Mengembalikan kebenaran jika tidak semua sama, atau daftar kosong jika semuanya sama. Kesalahan jika daftar kosong.

Jika item yang diekstraksi mungkin berupa array (atau string) itu sendiri:

)a-

Gunakan !atau !!untuk mendapatkan nilai boolean. Jika item yang diekstraksi mungkin berupa array, dan paling banyak ada dua jenis item yang berbeda, dan Anda ingin 1 jika tidak semuanya sama, ini lebih pendek:

_|,(

4

0= untuk string

Untuk mengambil elemen pertama dari sebuah array, Anda harus menggunakan 0=(atau (, jika Anda tidak keberatan meninggalkan sisa array pada stack).

Namun, jika array itu adalah string, casting ke karakter sudah cukup.

Contoh

"xyz"c e# Pushes 'x.

Saya tidak mengerti mengapa CJam tidak hanya membiarkan cmengekstraksi elemen pertama dari array apa pun, yang akan lebih bermanfaat dan konsisten.
Buah Esolanging

4

Memutar array (atau tumpukan) satu unit ke kiri

CJam memiliki operator rotate leftm< , yang biasanya apa yang harus Anda gunakan untuk memutar array jumlah unit sewenang-wenang ke kiri.

Dalam beberapa kasus, Anda juga dapat menggunakan (+untuk menggeser dan menambahkan:

[1 2 3]       (+ e# Pushes [2 3 1].
[[1] [2] [3]] (+ e# Pushes [[2] [3] 1].

Contoh kedua tidak berfungsi karena elemen array pertama juga merupakan iterable, jadi +disatukan alih-alih menambahkan.

Juga, jika Anda ingin membuang array yang diputar pada stack, Anda dapat menggunakan :\(kurangi dengan bertukar) tanpa syarat:

[1 2 3]       :\ e# Pushes 2 3 1.
[[1] [2] [3]] :\ e# Pushes [2] [3] [1].

Selama Anda tidak memiliki celah terbuka [, trik ini juga dapat digunakan untuk merotasi seluruh tumpukan, yaitu untuk membawa item tumpukan paling bawah ke atas:

]:\

3

Mencetak daftar dan membersihkan tumpukan

Katakanlah tumpukan Anda memiliki daftar string / angka / dll. di atas dan beberapa item tambahan lainnya di bawahnya. yaitu

123 "waste" ["a" "b" "rty" "print" "me" "please"]

Sekarang Anda tertarik untuk mencetak daftar terakhir saja, begitu juga Anda

S*]W=

output yang mana

a b rty print me please

Yang tampaknya benar-benar cerdas karena kami menggunakan pembersihan trik tumpukan dan hanya mencetak daftar yang digabungkan dengan spasi (yang mungkin bukan cara yang diinginkan untuk mencetak daftar di kali).

Ini bisa bermain golf lebih lanjut!

p];

Itu 2 byte lebih pendek !

dan jika Anda hanya memiliki 1 item di stack selain dari daftar, itu bahkan lebih pendek!

p;

Keindahannya padalah ia menghilangkan item terbanyak dari stack, merangkai itu (juga menambahkan baris baru di akhir) dan mencetak ke STDOUT secara instan, tanpa menunggu penyelesaian kode.

Jadi kode di atas akan ditampilkan

["a" "b" "rty" "print" "me" "please"]

yang merupakan representasi tepat dari daftar ketika berada di tumpukan!


3

Produk Cartesian atau semua kombinasi yang mungkin dari dua set atau lebih

CJam memiliki kalkulator produk Cartesian inbuilt m*yang mengambil dua daftar / string array di stack dan membuat semua pasangan yang memungkinkan darinya. Sebagai contoh

[1 2 3 4]"abc"m*

Daun-daun

[[1 'a] [1 'b] [1 'c] [2 'a] [2 'b] [2 'c] [3 'a] [3 'b] [3 'c] [4 'a] [4 'b] [4 'c]]

sebagai tumpukan

Tetapi bagaimana jika Anda ingin semua kemungkinan kombinasi dari lebih dari 2 daftar / string. Anda menggunakannya m*berkali-kali? Sebagai contoh

[1 2 3 4][5 6]"abc"m*m*

akan meninggalkan yang berikut di tumpukan

[[1 [5 'a]] [1 [5 'b]] [1 [5 'c]] [1 [6 'a]] [1 [6 'b]] [1 [6 'c]] [2 [5 'a]] [2 [5 'b]] [2 [5 'c]] [2 [6 'a]] [2 [6 'b]] [2 [6 'c]] [3 [5 'a]] [3 [5 'b]] [3 [5 'c]] [3 [6 'a]] [3 [6 'b]] [3 [6 'c]] [4 [5 'a]] [4 [5 'b]] [4 [5 'c]] [4 [6 'a]] [4 [6 'b]] [4 [6 'c]]]

Perhatikan bahwa produk masih berpasangan, di mana salah satu itemnya adalah pasangan itu sendiri. Ini tidak diharapkan dan kami ingin kombinasi rata.

Ada cara mudah untuk melakukan itu. Hanya membungkus setiap daftar yang Anda inginkan untuk produk kartesius Anda dalam sebuah array, buat secara berpasangan buat produk Cartesius dan ratakan setiap kali:

[1 2 3 4][5 6]"abc"]{m*{(+}%}*

Ini pergi

[['a 5 1] ['b 5 1] ['c 5 1] ['a 6 1] ['b 6 1] ['c 6 1] ['a 5 2] ['b 5 2] ['c 5 2] ['a 6 2] ['b 6 2] ['c 6 2] ['a 5 3] ['b 5 3] ['c 5 3] ['a 6 3] ['b 6 3] ['c 6 3] ['a 5 4] ['b 5 4] ['c 5 4] ['a 6 4] ['b 6 4] ['c 6 4]]

di tumpukan.

Ingin pesanan tetap terjaga? , cukup tukar sebelum menambahkan item yang muncul kembali ke array. yaitu

{m*{(\+}%}*

Ingin hanya permutasi?

{m*{(+$}%_&}*

Ingin hanya elemen unik dalam kombinasi?

{m*{(+_&}%}*

Itu semua orang. untuk sekarang .


1
Sekarang Anda juga dapat melakukannya ]:m*:e_, dengan sejumlah array
aditsu

3

Beroperasi dengan string

Terkadang jika Anda bekerja dengan struktur data yang kompleks, sementara item di dalamnya sederhana, mengonversi ke string dapat membantu.

Misalnya, jika Anda ingin mendapatkan item pertama atau terakhir dalam array 2D bit, dan tidak peduli dengan tipe yang dikembalikan, sA<simpan satu byte dari 0=A<atau :+A<.

Atau jika Anda ingin memodifikasi beberapa bit dalam input, Anda dapat memodifikasi string sebelum mengevaluasinya.

Atau jika Anda mendapatkan struktur ini dan ingin mengubahnya menjadi daftar sederhana:

[[[[[[[[[1]2]3]4]5]6]7]8]9]

Anda dapat melakukannya dengan banyak karakter dengan cara lain:

[a{~)\}h;]W%

Tetapi bisa jauh lebih pendek dengan string:

s:~

Ini lebih pendek bahkan jika mungkin memiliki angka dengan lebih dari satu digit:

[`La`-~]

Atau:

`']-~]

Jika Anda tidak memerlukan array lain yang mengandung banyak array seperti itu.


Ada e_sekarang
aditsu

@aditsu Lihat jawaban dan komentar ini . Terkadang smasih bekerja lebih baik.
jimmy23013

Tentu, ketika Anda bisa bekerja dengan string secara langsung, itu lebih pendek.
aditsu

3

Menggunakan NbukanLa

Dalam banyak kasus, Anda memerlukan sesuatu yang diinisialisasi ke array yang berisi array kosong sebagai satu-satunya elemen, yang Lasepertinya 1 byte lebih lama tidak perlu.

Dalam banyak kasus, Anda juga perlu menambahkan baris baru setelah setiap elemen sebelum mencetak, yang akan menjadi seperti Noatau N*.

Tetapi jika keduanya benar, kadang-kadang Anda mungkin menemukan bahwa Anda bisa menginisialisasi array dengan N, yang memiliki karakter baris baru sebagai satu-satunya elemen. Pastikan Anda hanya menambahkan beberapa hal ke elemen dalam sisa kode Anda, dan hal pertama yang bergantung pada selalu karakter atau array. Atau hanya menambahkan, jika suatu baris baru dapat diterima dan itu membuatnya lebih pendek.

Terkadang Sjuga berfungsi jika Anda perlu memisahkan output dengan spasi.

Dalam kasus yang lebih jarang, elemen awal harus berupa string. Tetapi Anda masih bisa menggunakan Nayang mungkin lebih pendek daripada menambahkan baris baru sesudahnya.


2

Membagi satu kejadian atau lebih

Katakanlah Anda memiliki string "abbcdbbfghbdbb"dan Anda ingin membaginyab

"abbcdbbfghbdbb"'b/

Ini meninggalkan tumpukan:

["a" "" "cd" "" "fgh" "d" "" ""]

Perhatikan senar kosong? Mereka ada di sana karena dua bbersama dan tidak ada di antara mereka. Terkadang, Anda ingin menghindari ini. Anda dapat melakukannya dengan

"abbcdbbfghbdbb"'b/La-

atau memfilter string kosong

"abbcdbbfghbdbb"'b/{},

tapi itu 3 byte tambahan.

Operator yang kurang dikenal untuk kasus penggunaan khusus ini adalah %. Selain melakukan mod dan memetakan dan pemisahan berdasarkan nomor ( "abcd"2%= "ac"), %juga dapat dibagi pada string / array. Jadi untuk use case di atas:

"abbcdbbfghbdbb"'b%

akan meninggalkan

["a" "cd" "fgh" "d"]

di tumpukan.

Terima kasih atas @ user23013 karena menunjukkan ini dalam salah satu jawaban saya hari ini.


Saya pikir ini harus dinamai "juga belajar GolfScript", yang memiliki contoh yang lebih baik dalam dokumentasi.
jimmy23013

@ user23013 tetapi kami tidak pernah yakin semuanya mirip dengan GS dan apa yang tidak.
Pengoptimal

2

Gunakan lipat / kurangi sebagai infix masing-masing

Kami memiliki :xsingkatan untuk {x}%dan atau {x}*(tergantung pada apakah xunary atau binary). Sayangnya, tidak ada operator infiks yang setara untuk dipersingkat {x}/. Namun, sangat sering ketika kita melakukannya {x}/, xsebenarnya adalah operator biner yang berulang kali memodifikasi item yang berada di bawah tumpukan. Jika itu yang terjadi, dan item tersebut bukan array, kita dapat menyimpan byte dengan menyalahgunakan flip / kurangi sebagai foreach:

5 [1 2 3 4]{-}/  e# Gives -5
5 [1 2 3 4]+:-

Ini berfungsi karena lipatan selalu membuat elemen pertama tidak tersentuh. Sayangnya, itu tidak menyimpan byte, ketika elemen yang diubah adalah sebuah array, karena menambahkannya akan membuka bungkusnya. Namun, kadang-kadang Anda cukup beruntung bahwa array Anda sudah mengandung elemen itu di depan, dalam hal ini pengurangan harus diingat (alih-alih menghapus elemen secara manual sebelum digunakan {}/pada sisanya).


2

cetak dan println

CJam memiliki printOperator: o. Ini bekerja tetapi tumpukan mencetak segera setelah semua kode dijalankan. Anda dapat menghentikannya jika Anda menghapus tumpukan di akhir program. Sederhananya di akhir:

];

Untuk mencetak, Anda dapat menggunakan oNoatau p(berfungsi sebagai `oNo)


3
Ada perbedaan yang lebih besar antara odan p. pdimulai dengan mengonversi item yang akan dicetak ke representasi string yang tidak ambigu. psetara untuk dieksekusi ​`oNo.
Dennis
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.