Kiat untuk bermain golf di GolfScript

35

Apa, pos ini belum ada?

Tentu saja, GolfScript yang dibuat untuk golf, sehingga Anda mungkin berpikir bahwa tidak ada tips khusus yang benar-benar dibutuhkan. Tetapi untuk memanfaatkan fitur GolfScript sepenuhnya, Anda perlu mempelajari beberapa trik yang tidak jelas. Posting ini untuk mengumpulkan tips dan trik yang sangat membantu.

Untuk memulainya, berikut adalah halaman referensi GolfScript resmi. Anda harus benar-benar membiasakan diri dengan ini terlebih dahulu:

Secara khusus, saya akan sangat menyarankan membaca halaman dalam urutan ini - referensi cepat tidak banyak digunakan sampai Anda sudah cukup terbiasa dengan built-in, dan tutorial mencakup beberapa detail penting yang tidak dijelaskan pada halaman lain. .


Ps. Demi inspirasi dan minat pribadi, berikut adalah beberapa pertanyaan yang ingin saya lihat jawabannya:

  • Bagaimana cara melakukan transliterasi terbatas dalam GolfScript? {FROM?TO=}%berfungsi jika Anda dapat yakin semua input ditemukan FROM(atau tidak keberatan semuanya dipetakan ke elemen terakhir TO), tetapi semua cara yang saya lihat untuk membiarkan nilai yang tidak dipetakan tidak berubah lebih kurang klugey.

  • Bagaimana cara terbaik mengubah string menjadi array kode ASCII dan kembali? Operasi apa yang melakukan ini sebagai efek samping? Apa cara terbaik untuk membuang karakter dalam string ke stack (seperti ~halnya untuk array)?

Ilmari Karonen
sumber
Pertanyaan lain: apakah ada cara yang baik untuk berubah ... xmenjadi ... [x]? Yang terbaik yang bisa saya lihat adalah [.;].
Peter Taylor
@ Peter: Jika xangka, maka []+berfungsi dan satu karakter lebih pendek. Dan tentu saja, jika xsatu-satunya hal di stack, maka hanya ]akan dilakukan.
Ilmari Karonen
Saya ingin menanyakan cara terbaik untuk melakukan: min, maks, dan nilai absolut. Semua solusi saya tampaknya mengambil lebih banyak karakter daripada yang seharusnya.
Claudiu
Apa cara terbaik untuk memodifikasi array pada indeks yang diberikan?
user1502040
@ user1502040: Dijawab di bawah. (Jika ada yang tahu cara yang lebih baik, silakan bagikan!)
Ilmari Karonen

Jawaban:

29

Rasional / Float / Kompleks

Saya telah membaca berkali-kali sehingga GolfScript hanya memiliki bilangan bulat yang mulai saya percayai. Ya itu tidak benar.

2-1? # Raise 2 to the power of -1. Result: 0.5
4-1? # Raise 4 to the power of -1. Result: 0.25
+    # Add. Result: 0.75

Outputnya adalah

3/4

dengan interpreter GolfScript standar dan

0.75

di Web GolfScript .

Retasan serupa memungkinkan untuk melakukan cast ke Rational, Float atau bahkan Complex:

{-2.?./*}:rational
{2.-1??./*}:float
{-2.-1??./*}:complex
Dennis
sumber
9
OMGWTFHAX o_O !!!
Ilmari Karonen
3
WAT! Cukup yakin ini adalah bug pada penerjemah, tapi wow
Doorknob
3
Baris 82 dari interpreter terbaru: Gint.new(@val**b.val). Tampaknya Gintkonstruktor kehilangan pemain int ...
primo
10

Menegasikan angka

Satu hal yang tidak dimiliki GolfScript adalah operator negasi bawaan. Cara yang jelas untuk mengubah angka pada tumpukan menjadi negatif, seperti -1*atau 0\-, membutuhkan tiga karakter. Namun, ada cara untuk melakukannya dalam dua:

~)

Ini berfungsi karena GolfScript menggunakan aritmatika komplemen dua , sehingga ~ x sama dengan - x −1.

Tentu saja, varian ini (~juga berfungsi; memilih di antara mereka umumnya masalah selera.

Ilmari Karonen
sumber
9

Mengocok array

Cara termudah untuk mengocok array dalam GolfScript adalah dengan mengurutkannya dengan kunci sortir acak. Jika Anda hanya perlu secara acak mengocok beberapa nilai, kode berikut akan melakukannya:

{;9rand}$

Perhatikan bahwa, bahkan untuk daftar pendek, ini tidak akan memberikan pengocokan yang sangat baik. Karena paradoks ulang tahun , untuk mendapatkan pengocokan yang cukup seragam, argumen untuk randperlu secara signifikan lebih besar daripada kuadrat dari panjang daftar yang dikocok.

Mengganti yang di 9atas dengan 99demikian memberikan hasil yang cukup baik untuk daftar hingga sepuluh elemen, tetapi menunjukkan bias yang terlihat untuk daftar yang lebih panjang.

Kode berikut, yang menggunakan 9 9 = 387.420.489 nilai yang mungkin, baik untuk sekitar 1000 item atau lebih (dan dapat diterima hingga sekitar 20.000):

{;9.?rand}$

Untuk daftar yang sangat panjang, tambahkan satu lagi untuk nilai 99 99 ≈ 3,7 × 10 197 :

{;99.?rand}$

Pengujian:

Berikut distribusi elemen pertama dalam daftar 10-elemen yang dikocok menggunakan berbagai varian yang ditunjukkan di atas, sampel lebih dari 10.000 percobaan:

  • Output dari 10,{;9rand}$0=menunjukkan bias yang sangat jelas, dengan 0kemungkinan lebih dari tiga kali berakhir di posisi pertama seperti 1:

    0 16537 #######################################################
    1 5444  ##################
    2 7510  #########################
    3 8840  #############################
    4 9124  ##############################
    5 12875 ##########################################
    6 9534  ###############################
    7 8203  ###########################
    8 7300  ########################
    9 14633 ################################################
    
  • Dengan 10,{;99rand}$0=, sebagian besar bias hilang, tetapi jumlah yang nyata masih tetap:

    0 10441 ##################################
    1 9670  ################################
    2 9773  ################################
    3 9873  ################################
    4 10134 #################################
    5 10352 ##################################
    6 10076 #################################
    7 9757  ################################
    8 9653  ################################
    9 10271 ##################################
    
  • Dengan 10,{;9.?rand}$0=, output pada dasarnya tidak bisa dibedakan dari sampel yang benar-benar acak:

    0 9907  #################################
    1 9962  #################################
    2 10141 #################################
    3 10192 #################################
    4 9965  #################################
    5 9971  #################################
    6 9957  #################################
    7 9984  #################################
    8 9927  #################################
    9 9994  #################################
    

Ps. Untuk pengacakan array atau string numerik yang benar - benar buruk, kode berikut terkadang dapat diterima:

{rand}$

Ini umumnya akan menjadi sangat bias, tetapi selama semua elemen dari array input (atau semua kode karakter dalam string) lebih besar dari satu, ia memiliki probabilitas nol untuk menghasilkan permutasi array, yang kadang-kadang dapat memuaskan persyaratan tantangan yang ditulis dengan buruk.

Ilmari Karonen
sumber
3
Saya ingat saya pernah ragu-ragu melakukan matematika untuk paradoks ulang tahun setelah kakak saya memberi tahu saya tentang hal itu, dia benar :(
ajax333221
8

Untuk mengatasi subquestion tertentu:

Bagaimana cara terbaik mengubah string menjadi array kode ASCII dan kembali? Operasi apa yang melakukan ini sebagai efek samping? Apa cara terbaik untuk membuang karakter dalam string ke stack (seperti ~ lakukan untuk array)?

Bagi mereka yang tidak mengerti masalahnya, sistem tipe GolfScript memberikan prioritas pada jenis dalam integer pesanan, array, string, blok. Ini berarti bahwa operasi array biasa yang diterapkan ke string hampir selalu memberi Anda string. Misalnya

'ABC123'{)}%

akan meninggalkan 'BCD234'di tumpukan.

Akibatnya, cara terbaik untuk mengubah string menjadi array kode ASCII hampir pasti membuang karakter pada stack dan kemudian mengumpulkannya ke dalam array.

Apa cara terbaik untuk membuang karakter dalam string ke tumpukan? {}/

Apa cara terbaik untuk mengubah string menjadi array kode ASCII? [{}/](dengan peringatan biasa bahwa jika tidak ada hal lain di tumpukan Anda dapat melewati [)

Apa cara terbaik untuk mengubah array kode ASCII menjadi string? ''+(Perhatikan bahwa ini juga meratakan array, jadi mis. [65 [66 67] [[[49] 50] 51]]''+Memberi 'ABC123')

Peter Taylor
sumber
Apa cara terbaik untuk mengubah kode ASCII tunggal menjadi string? []+''+? (sepertinya agak lama)
Justin
@ Quincunx, ini agak panjang, tapi saya tidak tahu cara yang lebih baik. Hal yang harus dilakukan mungkin untuk melihat dari mana kode ASCII berasal dan melihat apakah Anda bisa mendapatkannya sudah dalam array.
Peter Taylor
6

Jika program Anda rusak secara misterius, periksa variabel Anda

Saya baru saja menghabiskan waktu debugging program yang tampaknya benar yang digunakan !sebagai variabel (dengan alasan bahwa saya tidak akan menggunakannya lagi). Sayangnya saya memang menggunakan if, dan ternyata implementasi ifpanggilan !untuk memutuskan cabang mana yang harus diikuti.

Peter Taylor
sumber
6

Membungkus item teratas tumpukan ke dalam array

Apakah ada cara yang baik untuk berubah ... xmenjadi ... [x]?

Untuk generalisasi penuh, opsi terbaik tampaknya adalah 4 karakter. Namun, dalam kasus-kasus khusus tertentu dimungkinkan untuk mengurangi ini.

1 char

]bekerja dalam kasus khusus yang xmerupakan satu-satunya hal di stack.

3 karakter

[]+bekerja dalam kasus khusus yang xmerupakan bilangan bulat.

.,/bekerja dalam kasus khusus yang xmerupakan array atau string yang benar. Misalnya "AB".,/memberi ["AB"]; 3,.,/memberi [[0 1 2]]. Namun, "".,/dan [].,/keduanya memberi [].

4 karakter

[.;] bekerja tanpa syarat.

Peter Taylor
sumber
6

Apa cara terbaik untuk memodifikasi array pada indeks yang diberikan? - user1502040

Itu pertanyaan yang bagus. Tidak ada cara langsung untuk menetapkan nilai ke elemen array di GolfScript, jadi, dengan satu atau lain cara, Anda harus membangun kembali seluruh array.

Cara umum terpendek yang saya tahu untuk memasukkan nilai baru xdi indeks idalam array adalah dengan membagi array pada indeks yang diberikan dan menambahkan xke babak pertama sebelum bergabung bersama mereka lagi:

  • .i<[x]+\i>+(11 karakter) - masukkan nilai xke dalam array dengan indeks (berbasis-0)i

Untuk mengganti nilai pada indeks idengan x, kita hanya perlu mempersingkat paruh kedua array dengan satu elemen:

  • .i<[x]+\i)>+(12 karakter) - ganti elemen pada indeks (berbasis-0) idengan nilainyax

Sebagai alternatif, memperpendek paruh pertama akan secara efektif melakukan hal yang sama, tetapi dengan pengindeksan berbasis 1, yang kadang-kadang lebih disukai:

  • .i(<[x]+\i>+(12 karakter) - ganti elemen pada indeks (berbasis-1) idengan nilainyax

Dalam semua contoh di atas, jika xangka, tanda kurung di sekitarnya mungkin dihilangkan untuk menyimpan dua karakter, karena bagaimanapun akan secara otomatis dipaksa ke dalam array dengan cara +:

  • .i<x+\i>+(9 karakter) - masukkan angka xke dalam array dengan indeks (berbasis-0)i
  • .i<x+\i)>+(10 karakter) - ganti elemen di (0-based) index idengan angkax
  • .i(<x+\i>+(10 karakter) - ganti elemen di (1-based) index idengan angkax

Tanda kurung juga dapat dihilangkan jika salah satu xatau "array" input (atau keduanya) benar-benar string, dalam hal ini hasilnya juga akan dipaksa menjadi string (menggunakan array biasa → aturan konversi string).


Ps. Sebagai kasus khusus, jika kita tahu bahwa array memiliki elemen antara idan 2 × i, kita dapat memasukkan elemen baru xpada indeks (berbasis 0) idengan i/[x]*(6 karakter). Apa ini sebenarnya adalah membagi array menjadi potongan-potongan hingga ielemen dan menyisipkan di xantara setiap potongan. Perhatikan bahwa, dalam hal ini, tanda kurung diperlukan meskipun xangka.


Pps. Pendekatan alternatif adalah menggunakan variabel yang dinamai secara dinamis. Sebagai contoh,

 'foo' 42 ':x'\+~

akan menetapkan nilai 'foo'ke variabel x42, sementara

 42 'x'\+~

akan mengambilnya.

Anda dapat mengoptimalkan ini lebih jauh dengan menghilangkan xawalan dan hanya menetapkan langsung ke literal angka - ini benar-benar legal di GolfScript, dan memungkinkan Anda untuk menyimpan satu char dari kode tugas dan memperpendek kode pengambilan menjadi adil `~(atau tidak sama sekali, jika indeksnya konstan!). Sisi buruknya, tentu saja, adalah bahwa menetapkan literal numerik akan menimpa nilai literal itu di tempat lain dalam kode Anda. Namun, sering kali, penggunaan jumlah literal dapat dihindari (atau setidaknya dibatasi pada awal program, sebelum salah satu dari mereka dipindahkan), dalam hal ini trik ini baik-baik saja.

Ilmari Karonen
sumber
3
Benar-benar di luar topik: selamat atas 10k! :-D
Gagang Pintu
1
Jika Anda tahu bahwa array tidak memiliki nilai duplikat, Anda dapat mengganti nilai pada indeks iselama 9 byte:.[i=]/[x]*
Martin Ender
5

Manipulasi hasil akhir

Secara default, ketika program Anda berakhir, interpreter GolfScript menampilkan semua yang ada di stack, ditambah baris baru final, persis seperti jika program Anda berakhir dengan:

]puts

Apa yang tidak disebutkan secara langsung oleh dokumentasi adalah bahwa penerjemah secara harfiah memanggil built-in putsuntuk menghasilkan output ini, dan bahwa built-in ini secara harfiah didefinisikan sebagai:

{print n print}:puts;

Dengan demikian, Anda dapat menekan atau memanipulasi hasil akhir dengan mendefinisikan ulang puts, print dan / atau n(atau  jika Anda merasa benar-benar bengkok). Berikut ini beberapa contohnya:

Menekan baris terakhir final:

'':n;

(Tentu saja Anda dapat meninggalkan ;jika Anda tidak keberatan string kosong ekstra di tumpukan.)

Menekan hasil akhir sepenuhnya:

:puts

Ini menimpa putsdengan apa pun yang terjadi di atas tumpukan. Jika itu adalah sesuatu yang tidak ingin Anda lakukan, Anda dapat menggunakan mis 0:puts;. Perhatikan bahwa ini juga menekan p(yang didefinisikan sebagai {`puts}:p;), tetapi Anda masih bisa menggunakan printuntuk output jika Anda mau.

Ilmari Karonen
sumber
Dan nothingmaksud Anda \n?
CalculatorFeline
Jika Anda tidak keberatan dengan trailing newline, Anda juga dapat menggunakan ];untuk menekan hasil akhir.
wastl
5

Saya ingin menanyakan cara terbaik untuk melakukan: min, maks, dan nilai absolut. Semua solusi saya tampaknya mengambil lebih banyak karakter daripada yang seharusnya. - Claudiu

min / maks

Untuk menemukan nilai terkecil / terbesar dalam array, cukup sortir dan ambil elemen pertama / terakhir:

  • $0= (3 karakter) - elemen minimum dalam suatu arry
  • $-1= (4 karakter) - elemen maksimum dalam array

Jika Anda tahu panjang array, dan itu 10 elemen atau kurang, Anda dapat menemukan maksimum dalam tiga karakter dengan mengganti -1dengan indeks elemen terakhir.

Jika Anda memiliki nilai pada stack, Anda bisa mengumpulkannya ke dalam array terlebih dahulu. Untuk ini, trik yang kadang-kadang bermanfaat adalah [\]mengumpulkan dua elemen teratas dari tumpukan ke dalam array, sementara [@]mengumpulkan tiga teratas. Jadi, kita mendapatkan:

  • [\]$0= (6 karakter) - minimal dua nilai pada stack
  • [@]$0= (6 karakter) - minimal tiga nilai pada stack
  • [\]$1= (6 karakter) - maksimum dua nilai pada stack
  • [@]$2= (6 karakter) - maksimum tiga nilai pada stack

Trik yang sama juga dapat digunakan untuk menemukan median dari tiga nilai, yang kadang-kadang berguna:

  • [@]$1= (6 karakter) - median tiga nilai pada stack

Berikut ini adalah trik lain yang berpotensi bermanfaat untuk menemukan min / maks dari dua nilai sambil meninggalkan nilai asli di tumpukan :

  • .2$>$ (5 karakter) - temukan minimum dua nilai pada stack, sambil membiarkan nilai asli tidak tersentuh
  • .2$<$ (5 karakter) - temukan maksimum dua nilai pada stack, sambil membiarkan nilai asli tidak tersentuh

Cara kerjanya adalah .2$mengkloning dua elemen teratas pada stack dalam urutan terbalik (yaitu a ba b b a), </ >membandingkan salinan dan mengembalikan 0 atau 1, dan skalar $kemudian menyalin salah satu dari dua nilai input tergantung pada hasil perbandingan.


Jika Anda memiliki dua bilangan bulat negatif pada tumpukan, Anda dapat menggunakan ,\,&,(5 karakter) untuk menemukan nilai minimum dan ,\,|,(5 karakter) untuk menemukan nilai maksimumnya. Trik ini menggunakan set persimpangan dan gabungan, masing-masing, pada rentang. Anda dapat menyimpan karakter lain jika memungkinkan untuk diterapkan ,pada setiap argumen secara terpisah tanpa harus menukarnya. Karena metode ini menghitung rentang untuk setiap argumen, itu tidak sangat efisien untuk angka yang lebih besar, tetapi bisa sangat berguna untuk input yang lebih kecil.

Cara yang lebih pendek untuk menemukan minimum dua bilangan bulat non-negatif pada stack adalah ,<,(3 karakter). Sayangnya, trik ini tidak berfungsi untuk menemukan yang maksimal.


nilai mutlak

Operator nilai absolut bawaan GolfScript adalah abs(3 karakter). Walaupun ini dua karakter lebih dari yang saya inginkan, secara umum sulit dikalahkan.

Dalam beberapa kasus (misalnya untuk mengurutkan berdasarkan nilai absolut) Anda mungkin menemukan kuadrat angka sebagai pengganti yang memadai untuk nilai absolutnya; ini dapat dihitung dalam dua karakter, baik 2?atau .*. Jadi, kita mendapatkan:

  • {.*}$0= (7 karakter) - elemen minimum dengan nilai absolut dalam array
  • {.*}$-1= (8 karakter) - elemen maksimum dengan nilai absolut dalam array

Demikian pula, alih-alih pengujian misalnya jika nilai absolut angka kurang dari 3 dengan abs 3<(6 karakter, termasuk spasi), Anda dapat menguji apakah kuadratnya kurang dari 9 dengan .*9<(4 karakter, tanpa ruang yang diperlukan).

Ilmari Karonen
sumber
Jika Anda memiliki dua bilangan bulat negatif pada tumpukan, Anda dapat menggunakan ,\,&,(5 karakter) untuk menemukan nilai minimum dan ,\,|,(5 karakter) untuk menemukan nilai maksimumnya. Trik ini menggunakan set persimpangan dan gabungan, masing-masing, pada rentang. Anda dapat menyimpan karakter lain jika memungkinkan untuk diterapkan ,pada setiap argumen secara terpisah tanpa harus menukarnya. Karena metode ini menghitung rentang untuk setiap argumen, itu tidak sangat efisien untuk angka yang lebih besar, tetapi bisa sangat berguna untuk input yang lebih kecil.
KirarinSnow
@ KirarinSnow: Terima kasih! Saya telah menambahkannya ke jawabannya.
Ilmari Karonen
4

Menghapus duplikat dari array

Operator yang ditetapkan |(gabungan), &(persimpangan) dan ^(perbedaan simetris) akan memecah beberapa elemen array menjadi satu. Dengan demikian, cara paling sederhana untuk menghapus elemen duplikat dari array adalah dengan mengambil persatuan atau persimpangan dengan itu sendiri:

.|

atau:

.&

Operator-operator ini akan memperlakukan string sebagai array karakter, sehingga mereka juga dapat digunakan untuk menghapus karakter duplikat dari string.

Ilmari Karonen
sumber
4

Transliterasi terbatas

Untuk mengatasi subquestion tertentu: diberi string, apa cara terbaik untuk melakukan a tr ? Misalnyatr/ABC/abc/

Jika semua karakter dalam string akan terpengaruh, ini cukup mudah: {'ABC'?'abc'=}%(overhead: 9 karakter).

Namun, itu rusak jika beberapa karakter tidak transliterasi dan 'ABC'?memberi -1.

Jika transliterasinya non-siklik, maka dapat dilakukan satu per satu penggantian dengan pemisahan string dan bergabung: 'AaBbCc'1/2/{~@@/\*}/(overhead: 15 karakter). Ini mungkin bisa diperbaiki, tetapi ada pendekatan alternatif yang saat ini lebih baik dan berfungsi untuk transliterasi siklik.

Saat ini, solusi umum terpendek memiliki overhead 14 karakter:

  • Satu pendekatan melibatkan karakter pelarian:, di mana menunjukkan byte nol literal. (Tentu saja, metode ini tidak sepenuhnya umum: metode ini tidak dapat memetakan karakter lain ke dalam byte nol.){.'ABC'?'abc0'=\or}%0

  • Atau, {.'ABC'?'abc'@),+=}%memiliki overhead yang sama, tetapi hanya menggunakan karakter ASCII yang dapat dicetak. Ini @),+adalah cara berbelit-belit (tapi, tampaknya, yang terpendek) untuk memastikan bahwa string pengganti selalu berakhir dengan karakter input.

Peter Taylor
sumber
Menggunakan pendekatan terakhir, untuk string input 'ABCDEF'saya mendapatkan hasilnya 'abc000', tetapi hasil yang tepat adalah 'abcDEF'. Apakah saya melewatkan sesuatu?
Cristian Lupascu
1
@ w0lf, 0 itu dicetak tebal karena itu karakter pelarian yang disebutkan sebelumnya - yaitu byte 0.
Peter Taylor
4

Ubah string menjadi array char

Anda dapat melakukan ini dengan mengetik: 1/setelahnya.

Contoh: "String"1/mendorong untuk menumpuk array ['S''t''r''i''n''g'].

Ini berguna saat Anda ingin memindahkan karakter di sekitar string.

pengguna3700847
sumber
1
Bisakah Anda memberi contoh bagaimana ini bisa berguna? String sudah bertindak seperti array jadi ini sepertinya tidak berguna.
Justin
@Quincunx berguna ketika Anda ingin mengeluarkan karakter dan bukan nilai ascii mereka
user3700847
Dan kapan Anda ingin melakukan itu?
Justin
5
@ Quincunx: Memutar string, misalnya. "abc"1/(+-> "bca", tetapi "abc"(+-> bc97.
Dennis
4

Menugaskan ke sejumlah literal

Seringkali, alih-alih menulis 1:xdan kemudian menggunakan / memperbarui variabel x, Anda bisa menggunakan dan memperbarui 1secara langsung:

1:^;{^.p.+:^;}5*
{1.p.+:1;}5*       (4 bytes shorter)

Tentu saja, ini juga berfungsi untuk nilai awal lainnya, tetapi akan rusak jika nilai itu terjadi di tempat lain dalam kode Anda.

Tanda baca sebagai nama variabel

Jika Anda memiliki untuk menggunakan variabel, itu juga sering bijaksana untuk menggunakan tanda baca yang tidak sudah dalam kode Anda - banyak program dapat melakukannya tanpa &, |, ^, atau ?. Dengan cara ini, misalnya, Anda dapat menulis &nalih-alih x nuntuk mendorong variabel Anda dan kemudian mendorong baris baru.

Lynn
sumber
3
Namun, beberapa tugas dapat memiliki efek samping yang tidak terduga. Secara khusus, menugaskan ke !seringkali merupakan ide yang buruk, karena akan merusak ifdan do(serta while, until, and, ordan xor). Demikian pula, ordidefinisikan oleh penerjemah sebagai alias untuk 1$\if, jadi mendefinisikan ulang 1, $atau \juga akan merusaknya. Mendefinisikan ulang `istirahat p.
Ilmari Karonen
3

Memfilter array

Cara paling umum untuk memfilter array adalah dengan menggunakan { },, yang mengevaluasi blok kode untuk setiap elemen array, dan memilih elemen-elemen yang nilai hasilnya benar (yaitu bertindak sepertigrep dalam Perl).

Namun, menggunakan operator pengurangan array -seringkali lebih pendek. Operator ini mengambil dua array, dan menghapus setiap elemen yang terjadi di array kedua dari yang pertama. Itu tidak mengubah urutan elemen dalam array pertama atau menutup duplikat. Trik yang berguna adalah menerapkan operasi pengurangan dua kali untuk menghasilkan operator persimpangan array yang tidak runtuh:

  • a b -: hapus semua elemen yang ditemukan dalam array bdari arraya
  • a. b --: hapus semua elemen yang tidak ditemukan dalam array bdari arraya

Secara khusus, ini dapat digunakan untuk menghitung berapa kali suatu elemen terjadi dalam array:

  • a.[c]--,: hitung berapa kali elemen tersebut cmuncul dalam arraya

Secara umum, metode ini tidak optimal, karena salah satu dari:

  • a[c]/,(: hitung berapa kali elemen tersebut cmuncul dalam arraya
  • a{c=},,: hitung berapa kali elemen tersebut cmuncul dalam arraya

lebih pendek satu karakter (dan, jika OK untuk hitungan dimatikan oleh satu, a[c]/,menghemat satu karakter lebih banyak). Namun, dalam kasus khusus di mana cangka dan aarray normal (bukan string), tanda kurung di sekitar cdapat dihilangkan karena -operator memaksa argumennya ke tipe yang sama:

  • a.c--,: hitung berapa kali jumlah itu cterjadi dalam array (bukan string!)a

(Jika aadalah string dan cangka antara 0 dan 9, a.c--akan menghitung berapa kali digit itu c muncul a.)


Trik serupa dapat digunakan untuk menemukan elemen paling umum dalam array :

:a{a\[.]-,}$0=

Sekali lagi, jika input adalah array angka, seluruh [.]urutan dapat dihilangkan. Sayangnya, ini tidak berfungsi untuk string tanpa [.].

Ilmari Karonen
sumber
Untuk menghitung kejadian (general case), a[c]/,(dan a{c=},,satu byte lebih pendek.
Dennis
@ Dennis: Terima kasih! Saya sudah mengeditnya.
Ilmari Karonen
3

Baca dari STDIN

GolfScript dapat membaca dari stdin:

"#{STDIN.read}"

Ini akan terus membaca dari STDIN sampai EOF tercapai. Kalau tidak:

"#{STDIN.gets}"

atau

"#{STDIN.readline}"

Hal lain yang tersedia:

getbyte
getc
gets([sep])
gets(limit)
gets(sep, limit)
inspect # perhaps useful for an underhanded contest
isatty
read([length])
readbyte
readchar
readline([sep])
readline(limit)
readline(sep, limit)
readlines([sep])
readlines(limit)
readlines(sep, limit)
readpartial(maxlen [, outbuf])

Untuk masing-masing, mereka hanya dapat digunakan sekali (dan juga sekali untuk setiap perubahan parameter, juga sekali lagi dengan tanda kurung kosong); setelah itu, nilai asli adalah apa yang akan Anda dapatkan alih-alih nilai baru.

Justin
sumber
2
Anda mungkin ingin menambahkan komentar yang {"#{STDIN.readline}"p}2*tidak membaca 2 baris tetapi string dievaluasi hanya sekali.
Howard
2
Jika Anda menginisialisasi ike bilangan bulat apa pun, '"#{'i):i';STDIN.gets}"'++~akan memberikan hasil yang berbeda setiap kali dievaluasi. Backticks juga layak disebut. Jika kita menganggap Linux, kita bisa menggunakan, misalnya, `head -1`bukan STDIN.gets.
Dennis
@ Dennis: "#{var'g','gpush Gstring.new(STDIN.gets)'.cc}";juga akan membiarkan Anda menentukan operator GolfScript baru g yang membaca garis dari stdin dan mendorongnya di tumpukan.
Ilmari Karonen
2

Mendekode input heksadesimal

GolfScript tidak memiliki hex integer literals, jadi, sayangnya, Anda tidak bisa hanya menguraikan input heksadesimal ~ . Sebaliknya, jika kode Anda harus mengambil input hex, Anda harus menguraikannya secara manual.

Loop 8-char ini, diterapkan pada string, akan mengonversi digit heks huruf kecil menjadi setara numeriknya:

{39%9-}%

Jika Anda harus (juga) menerima angka hex huruf besar, solusi termudah (dan mungkin yang terpendek) adalah dengan terlebih dahulu menggunakan huruf kecil 32|, dengan total 11 karakter:

{32|39%9-}%

Perhatikan bahwa output secara teknis masih berupa string (terdiri dari karakter ASCII 0 - 15), tetapi sebagian besar fungsi array GolfScript akan menerima string juga. Jika Anda benar-benar membutuhkan array, Anda selalu dapat menggunakan [{39%9-}/](di mana yang pertama [adalah opsional jika tumpukannya kosong).

Untuk mengubah output dari kode di atas menjadi bilangan bulat, Anda cukup menggunakan 16base(6 karakter). Jika Anda menginginkan array byte sebagai gantinya, solusi terpendek yang saya temukan hanya dengan mendekode setiap pasangan digit hex dengan 2/{16base}%(11 karakter). Semua disatukan, kode terpendek yang saya temukan untuk mengubah string hex menjadi array byte adalah 8 + 11 = 19 karakter:

{39%9-}%2/{16base}%

Perhatikan bahwa output dari kode ini memang berupa array, bukan string. Jika perlu, Anda dapat mengencangkannya dengan menggabungkannya misalnya dengan ""+atau, jika Anda tidak keberatan dengan baris baru tambahan di akhir n+,.

Ilmari Karonen
sumber
2

Menentukan operator bawaan baru

Standar GolfScript interpreter memiliki jarang digunakan fitur yang yang memungkinkan kode Ruby interpolasi dalam string literal yang dikutip ganda.

Salah satu alasan mengapa fitur ini tidak lebih umum digunakan adalah bahwa, canggung, kode interpolasi dijalankan pada waktu kompilasi , dan output di-cache oleh interpreter GolfScript sehingga string literal yang sama akan selalu menghasilkan nilai yang sama, bahkan di dalam string eval.

Namun, satu hal fitur ini ternyata bagus untuk mendefinisikan operator GolfScript baru diimplementasikan dalam kode Ruby. Sebagai contoh, berikut ini cara mendefinisikan operator penjumlahan biner baru yang berfungsi seperti operator bawaan standar +:

"#{var'add','gpush a+b'.cc2}";

Tidak masalah di mana Anda memasukkan definisi dalam kode Anda; operator baru akan ditentukan segera setelah string yang dikutip ganda berisi kode Ruby diuraikan. The addOperator didefinisikan di atas karya persis seperti built-in +operator, dan dapat digunakan dengan cara yang persis sama:

1 2 add          # evaluates to 3
"foo" "bar" add  # evaluates to "foobar"

Tentu saja, mendefinisikan operator tambahan baru sangat tidak berguna, kecuali Anda telah melakukan sesuatu yang konyol seperti menghapus +operator bawaan . Tetapi Anda dapat menggunakan trik yang sama untuk mendefinisikan operator baru yang melakukan hal-hal yang tidak dapat (dengan mudah) dilakukan oleh Golfscript seperti, misalnya, menyeret array secara seragam:

"#{var'shuf','gpush a.factory(a.val.shuffle)'.cc1}";

10,shuf          # evaluates to 0,1,2,...,9 in random order

atau mencetak isi seluruh tumpukan:

"#{var'debug','puts Garray.new($stack).ginspect'.cc}";

4,) ["foo" debug  # prints ["" [0 1 2] 3 "foo"], leaving the stack untouched

atau input interaktif:

"#{var'gets','gpush Gstring.new(STDIN.gets)'.cc}";

]; { "> " print gets ~ ]p 1 } do   # simple GolfScript REPL

atau bahkan akses web:

"#{
  require 'net/http'
  require 'uri'
  var'get','gpush Gstring.new(Net::HTTP.get_response(URI.parse(a.to_s)).body)'.cc1
}";

"http://example.com" get

Tentu saja, implementasi yang lebih golf (dan lebih berisiko!) Dari yang terakhir akan misalnya:

"#{var'get','gpush Gstring.new(`curl -s #{a}`)'.cc1}";

Meskipun tidak terlalu bersifat golf, ini memungkinkan Anda memperluas kemampuan GolfScript melampaui apa yang disediakan perintah bawaan.


Bagaimana cara kerjanya?

Referensi otoritatif tentang cara mendefinisikan operator GolfScript baru dengan cara ini, tentu saja, kode sumber untuk penerjemah . Yang mengatakan, inilah beberapa tips cepat:

  • Untuk menetapkan operator baru nameyang menjalankan kode Ruby code, gunakan:

    var'name','code'.cc
  • Di dalam kode, gunakan gpopuntuk membaca nilai dari stack, dan gpushuntuk mendorongnya kembali. Anda juga dapat mengakses stack secara langsung melalui array $stack. Misalnya, untuk mendorong kedua adan bke stack, itu Golfier untuk melakukan $stack<<a<<bdaripada gpush a;gpush b.

    • Posisi [penanda mulai array disimpan dalam $lbarray. The gpopFungsi mengurus menyesuaikan tanda tersebut turun jika tumpukan menyusut di bawah posisi mereka, tetapi memanipulasi $stackarray yang langsung tidak.
  • The .ccMetode string yang mengkompilasi kode Ruby dalam string ke operator GolfScript hanya bungkus-toko di sekitar Gblock.new(). Ini juga memiliki varian .cc1, .cc2dan .cc3itu membuat operator secara otomatis mengeluarkan argumen 1, 2 atau 3 dari stack dan menetapkannya ke variabel a, bdan c. Ada juga .ordermetode yang berfungsi seperti itu .cc2, kecuali bahwa itu secara otomatis mengurutkan argumen berdasarkan jenis prioritas .

  • Semua nilai-nilai pada stack GolfScript adalah (dan harus!) Objek dari jenis Gint, Garray, Gstringatau Gblock. Integer atau array asli yang mendasarinya, di mana diperlukan, dapat diakses melalui .valmetode.

    • Namun, perhatikan bahwa Gstring.valmengembalikan array Gints! Untuk mengubah Gstringmenjadi string Ruby asli, panggil .to_ssaja (atau gunakan dalam konteks yang melakukannya secara otomatis, seperti interpolasi string). Memanggil .to_gsnilai GS apa pun mengubahnya menjadi Gstring, sehingga nilai GS apa pun dapat dirangkum dengan .to_gs.to_s.
  • The gpushFungsi tidak auto-wrap nomor Ruby asli, string atau array ke dalam jenis GS yang sesuai, sehingga Anda akan sering harus melakukannya sendiri dengan secara eksplisit menyebut misalnya Gstring.new(). Jika Anda mendorong apa pun selain salah satu dari tipe nilai GS ke tumpukan, kode apa pun yang kemudian mencoba untuk memanipulasinya kemungkinan akan mogok.

  • Tipe nilai GS juga memiliki .factorymetode yang memanggil konstruktor tipe tersebut, yang dapat berguna misalnya untuk menyusun ulang array / string setelah memanipulasi kontennya. Semua tipe juga memiliki .coercemetode yang melakukan pemaksaan tipe : a.coerce(b)mengembalikan pasangan yang mengandung adan bdipaksa ke tipe yang sama.

Ilmari Karonen
sumber