Apa tips umum yang Anda miliki untuk bermain golf di QBasic? Saya mencari ide yang dapat diterapkan pada masalah kode golf secara umum yang setidaknya agak spesifik untuk QBasic (mis. "Hapus komentar" bukan jawaban).
Tips yang berkaitan dengan emulator QB64 juga diterima. Ini memiliki beberapa fitur tambahan yang tidak ada di Microsoft QBasic.
Jawaban:
Ketahui konstruksi perulangan Anda
QBasic memiliki beberapa konstruksi perulangan:
FOR ... NEXT
,WHILE ... WEND
, danDO ... LOOP
. Anda juga dapat menggunakanGOTO
atau (dalam beberapa situasi)RUN
untuk mengulang.FOR ... NEXT
cukup bagus dalam apa yang dilakukannya. Tidak seperti di Python, itu hampir selalu lebih pendek dari yang setaraWHILE
atauGOTO
loop, bahkan ketika itu menjadi sedikit lebih menarik:Perhatikan bahwa Anda tidak perlu mengulang nama variabel setelahnya
NEXT
, dan Anda dapat menghilangkan spasi di antara angka dan sebagian besar kata kunci berikut.WHILE ... WEND
bagus untuk ketika Anda memiliki loop yang mungkin perlu dijalankan 0 kali. Tetapi jika Anda tahu loop akan mengeksekusi setidaknya sekali,GOTO
mungkin satu byte lebih pendek:DO ... LOOP
untuk loop tak terbatas (kecuali di manaRUN
dapat digunakan sebagai gantinya). Walaupun biayanya sama dengan jumlah karakter sebagai tanpa syaratGOTO
, itu sedikit lebih intuitif untuk dibaca. (Perhatikan bahwa "loop tak terbatas" dapat mencakup loop yang Anda keluar dari menggunakanGOTO
.) TheDO WHILE
/DO UNTIL
/LOOP WHILE
/LOOP UNTIL
sintaks terlalu verbose; Anda lebih baik menggunakanWHILE
atauGOTO
jika perlu.GOTO
adalah, seperti yang disebutkan di atas, cara umum terpendek untuk menulis do / while. Gunakan nomor baris satu digit, bukan label. Perhatikan bahwa ketika aGOTO
adalah satu-satunya hal diTHEN
bagianIF
pernyataan, ada dua sintaks shortcut yang sama pendeknya yang tersedia:GOTO
juga dapat digunakan untuk membuat aliran kontrol yang lebih rumit . Para penentang menyebut ini sebagai "kode spageti," tetapi ini adalah kode golf: tidak terbaca hampir merupakan suatu kebajikan!GOTO
kebanggaan!RUN
berguna ketika Anda harus melompat ke tempat yang tetap dalam program dan Anda tidak perlu menyimpan nilai variabel apa pun.RUN
dengan sendirinya akan memulai kembali program dari atas; dengan label atau nomor baris, itu akan dimulai lagi di baris itu. Saya terutama menggunakannya untuk membuat loop tanpa batas stateless .sumber
Gunakan pintasan untuk
PRINT
danREM
Anda dapat menggunakan
?
sebagai gantiPRINT
, dan'
bukannyaREM
(komentar).'
mungkin juga berguna ketika melakukan polyglot dengan bahasa yang mendukung'
sebagai bagian dari sintaksis char atau string.sumber
Pengujian keterbagian
Dalam program yang mengharuskan Anda menguji apakah satu bilangan bulat dapat dibagi oleh yang lain, cara yang jelas adalah menggunakan
MOD
:Tetapi cara yang lebih singkat adalah menggunakan pembagian integer:
Artinya,
x
int-div3
sama denganx
float-div3
.Perhatikan bahwa kedua pendekatan ini akan kembali
0
untuk falsey dan-1
untuk truey, jadi Anda mungkin perlu meniadakan hasilnya, atau mengurangi itu alih-alih menambahkan.Jika Anda membutuhkan kondisi yang berlawanan (yaitu
x
adalah tidak habis dibagi3
), pendekatan yang jelas adalah dengan menggunakan tidak-sama Operator:Tetapi jika
x
dijamin tidak negatif, kita bisa menghemat satu byte. Divisi integer memotong hasilnya, sehingga akan selalu kurang dari atau sama dengan divisi float. Oleh karena itu, kita dapat menulis kondisinya sebagai:Demikian pula, jika
x
dijamin negatif, pemotongan akan meningkatkan hasilnya, dan kita bisa menulisx\3>x/3
. Jika Anda tidak tahu tandanyax
, Anda harus patuh<>
.sumber
Penyalahgunaan scanner
Seperti dalam banyak bahasa, mengetahui karakter mana yang bisa dan tidak bisa dihapus itu penting.
IF""=a$THEN?0
FOR i=1TO 10STEP 2
. Ada beberapa perbedaan antara QBasic 1.1 (tersedia di archive.org ) dan QB64 :?123x
menjadiPRINT 123; x
. Pengecualian untuk di atas adalah urutan seperti1e2
dan1d+3
, yang diperlakukan sebagai notasi ilmiah dan diperluas ke100!
dan1000#
(presisi tunggal dan ganda, masing-masing).d
,e
atauf
sama sekali kecuali mereka adalah bagian dari notasi literal ilmiah well-formed. (Misalnya, Anda tidak bisa menghilangkan spasi setelah nomor baris dalam1 FOR
atau9 END
, seperti yang Anda bisa dalam QBasic.) Ini hanya menyimpulkan tanda koma dalam pernyataan cetak jika salah satu ekspresi adalah string:?123"abc"
berfungsi, tetapi tidak?TAB(5)123
atau?123x
.PRINT
pernyataan yang diakhiri dengan panggilan keTAB
atauSPC
. (QB64 tidak.)0
dapat dihilangkan sebelum atau setelah titik desimal (.1
atau1.
), tetapi tidak keduanya (.
).ENDIF
setara denganEND IF
.sumber
endif
sebenarnya berfungsi di QB64, lihat jawaban iniKombinasikan
Next
PernyataanDapat dipadatkan menjadi
dimana iterator untuk
For
loopi
,j
dank
- dalam urutan itu.Misalnya di bawah ini (69 Bytes)
Dapat dipadatkan hingga 65 Bytes
Dan sejauh bagaimana hal ini memengaruhi pemformatan dan lekukan, saya pikir pendekatan terbaik untuk menangani ini dibiarkan menyelaraskan pernyataan berikutnya dengan yang paling luar untuk pernyataan. Misalnya.
sumber
Ketahui metode input Anda
QBasic memiliki beberapa cara untuk mendapatkan input keyboard pengguna:
INPUT
,LINE INPUT
,INPUT$
, danINKEY$
.INPUT
adalah pernyataan input multiguna standar Anda. Program menghentikan apa yang dilakukannya, menampilkan kursor, dan memungkinkan pengguna mengetik beberapa input, diakhiri oleh Enter.INPUT
dapat membaca angka atau string, dan dapat membaca beberapa nilai yang dipisahkan koma. Anda dapat menentukan string sebagai prompt, Anda bisa pergi dengan prompt tanda-tanya default, dan Anda bahkan dapat (saya baru saja belajar ini malam ini) menekan prompt sama sekali. Beberapa contoh doa:INPUT x$,y
Menggunakan
?
prompt default dan membaca string dan angka, dipisahkan koma.INPUT"Name";n$
Meminta
Name?
dan membaca string.INPUT"x=",x
Meminta dengan
x=
(tidak ada tanda tanya! Catat koma di sintaks) dan membaca nomor.INPUT;"",s$
Menekan prompt (menggunakan sintaks koma di atas dengan string prompt kosong), membaca string, dan tidak pindah ke baris berikutnya ketika pengguna menekan masuk (itulah yang titik koma setelahnya
INPUT
tidak). Misalnya, jika AndaPRINT s$
segera setelah ini, layar Anda akan terlihat sepertiUser_inputUser_input
.INPUT
adalah bahwa Anda tidak dapat membaca string dengan koma di dalamnya, karenaINPUT
menggunakan koma sebagai pemisah bidang. Untuk membaca satu baris karakter arbitrer (dapat dicetak ASCII), gunakanLINE INPUT
. Itu punya opsi sintaks yang sama sepertiINPUT
, kecuali dibutuhkan tepat satu variabel yang harus menjadi variabel string. Perbedaan lainnya adalahLINE INPUT
tidak menampilkan prompt secara default; jika Anda menginginkannya, Anda harus menentukannya secara eksplisit.INPUT$(n)
tidak menampilkan prompt atau kursor tetapi hanya menunggu sampai pengguna memasukkann
karakter, dan kemudian mengembalikan string yang mengandung karakter tersebut. Tidak sepertiINPUT
atauLINE INPUT
, pengguna tidak perlu menekan Entersetelah itu, dan pada kenyataannya Enterbisa menjadi salah satu karakter (itu akan memberi ASCII karakter 13, dikenal sebagai bahasa seperti C\r
).Paling sering, ini berguna karena
INPUT$(1)
, biasanya dalam satu lingkaran.INPUT$
bagus dalam program interaktif di mana penekanan tombol tunggal melakukan sesuatu . Sayangnya, ini hanya berfungsi dengan kunci yang memiliki kode ASCII; ini termasuk hal-hal seperti Escdan Backspace, tetapi bukan tombol panah, Insertdan Delete, dan lainnya.Di situlah
INKEY$
masuk. Ini serupa denganINPUT$(1)
di mana ia mengembalikan hasil penekanan tombol tunggal 1 , tetapi berbeda dalam hal itu:INKEY$
tidak membutuhkan argumen.Saat
INPUT$(n)
menghentikan eksekusi hingga pengguna memasukkann
karakter,INKEY$
tidak menghentikan eksekusi. Jika pengguna saat ini menekan tombol,INKEY$
mengembalikan string yang mewakili kunci itu; jika tidak, ia kembali""
. Ini berarti bahwa jika Anda ingin menggunakanINKEY$
untuk mendapatkan penekanan tombol berikutnya, Anda harus membungkusnya dalam loop menunggu-sibuk : 2Keduanya
INPUT$
danINKEY$
mengembalikan karakter ASCII untuk kunci yang sesuai dengan karakter ASCII (termasuk karakter kontrol seperti escape, tab, dan backspace). Namun,INKEY$
dapat juga menangani beberapa kunci yang tidak memiliki kode ASCII. Untuk ini (kata file bantuan), "INKEY $ mengembalikan string 2-byte yang terdiri dari karakter null (ASCII 0) dan kode pindai keyboard."Jelas seperti lumpur? Inilah beberapa contohnya. Jika Anda menggunakan
INKEY$
loop di atas untuk menangkap penekanan tombol tombol panah kiri,k$
akan berisi string"␀K"
(denganK
kode pindaian yang mewakili 75). Untuk panah kanan, ini"␀M"
(77). Halaman ke bawah adalah"␀Q"
(81). F5 adalah"␀?"
(63).Masih bening seperti lumpur? Ya. Itu bukan hal yang paling intuitif di dunia. File bantuan memiliki tabel kode pindaian, tetapi saya selalu hanya menulis program kecil untuk mencetak hasil
INKEY$
dan tekan banyak tombol untuk mencari tahu apa nilai yang benar. Setelah Anda tahu karakter mana yang sesuai dengan tombol mana, Anda dapat menggunakanRIGHT$(k$,1)
danLEN(k$)
untuk membedakan antara semua kasus yang berbeda yang mungkin Anda temui.Intinya?
INKEY$
itu aneh, tapi itu satu-satunya cara untuk pergi jika program Anda membutuhkan input non-pemblokiran atau perlu menggunakan tombol panah .1 Tidak termasuk Shift, Ctrl, Alt, PrntScr, Caps Lock, dan yang sejenis. Itu tidak masuk hitungan. : ^ P
2 The
WHILE ... WEND
idiom di sini adalah apa yang saya pelajari dalam buku-buku QBasic saya. Untuk bermain golf tujuan, bagaimanapun, sebuahGOTO
lingkaran yang lebih pendek .sumber
LOKASI bisa sangat kuat
The
LOCATE
pernyataan memungkinkan Anda untuk menempatkan di mana saja kursor pada layar (dalam biasa 80x40 batas ruang karakter) dan mencetak sesuatu di lokasi itu. Jawaban untuk tantangan ini benar-benar menunjukkan hal ini (dan juga dikombinasikan dengan banyak tips lain dari topik ini).Tantangannya meminta kami untuk menampilkan setiap karakter yang ditekan pengguna dalam kotak 16x6. Dengan
LOCATE
ini hanyalah masalah div dan mod atas kode ASCII (a
dalam kode ini):Dan kemudian mencetak karakter:
sumber
Di QBasic, sudah biasa menggunakan
DIM
pernyataan untuk membuat variabel, memberi mereka nama dan tipe. Namun, ini tidak wajib, QBasic juga bisa mendapatkan tipe dengan akhiran nama variabel. Karena Anda tidak dapat mendeklarasikan dan menginisialisasi variabel pada saat yang bersamaan, sering kali bijaksana untuk melewatkanDIM
codegolf. Dua cuplikan yang identik secara fungsional *:* Perhatikan bahwa ini membuat dua nama variabel yang berbeda.
Kita dapat menentukan jenis variabel dengan menambahkan
$
ke akhir nama variabel untuk string,!
untuk angka presisi tunggal dan%
untuk ganda. Single diasumsikan ketika tidak ada tipe yang ditentukan.Perhatikan bahwa ini juga berlaku untuk array. Biasanya, sebuah array didefinisikan sebagai:
Tetapi array juga tidak perlu
DIM
med:a$
sekarang merupakan array untuk string dengan 11 slot: dari indeks 0 hingga dan termasuk indeks 10. Ini dilakukan karena QBasic memiliki opsi yang memungkinkan pengindeksan berbasis-0 dan berbasis-1 untuk array. Jenis array default mendukung keduanya dengan cara ini.Ingat array dua puluh slot yang kita
DIM
buat di atas? Itu sebenarnya memiliki 21 slot, karena prinsip yang sama berlaku untuk array redup dan non-redup.sumber
IF
Pernyataan pemendekanIF
pernyataan agak mahal, dan menurunkannya bisa menghemat banyak byte.Pertimbangkan hal berikut (diadaptasi dari jawaban oleh Erik the Outgolfer):
Hal pertama yang dapat kita lakukan adalah menyimpan
ENDIF
dengan menggunakan pernyataan satu barisIF
:Ini berfungsi selama Anda tidak mencoba untuk meletakkannya di baris yang sama dengan yang lainnya. Khususnya, jika Anda memiliki
IF
pernyataan bersarang , hanya yang paling dalam yang dapat dibuat satu baris.Tetapi dalam hal ini, kita bisa menghilangkan
IF
matematika sepenuhnya menggunakan. Pertimbangkan apa yang sebenarnya kita inginkan:RND<.5
benar (-1
), kami ingin:x
berkurang 1y
untuk tetap samaa(i)
menjadi 1RND<.5
salah (0
), kami ingin:x
untuk tetap samay
berkurang 1a(i)
menjadi 0Sekarang jika kita menyimpan hasil dari kondisional dalam variabel (
r=RND<.5
), kita dapat menghitung nilai-nilai barux
,y
dana(i)
:r
adalah-1
,x=x-1
; saatr
ini0
,x=x+0
.r
adalah-1
,y=y+0
; saatr
ini0
,y=y-1
.r
adalah-1
,a(i)=1
; saatr
ini0
,a(i)=0
.Jadi kode akhir kita terlihat seperti:
menghemat 20 byte (40%) kekalahan dari versi aslinya.
Pendekatan matematika sering dapat diterapkan secara mengejutkan, tetapi ketika ada perbedaan dalam logika antara kedua kasus (misalnya ketika Anda perlu memasukkan sesuatu dalam satu kasus tetapi tidak dalam yang lain), Anda masih harus menggunakan
IF
.sumber
Terkadang, Anda harus menghindari array
Array dalam QBasic, ketika dipakai tanpa
DIM
hanya memiliki 11 slot. Jika tantangan membutuhkan lebih dari 11 slot (atau N slot, di mana N bisa lebih besar dari 11), Anda harusDIM
menggunakan array. Juga, mari kita asumsikan kita ingin mengisi array ini dengan data:Bahkan bermain golf, ini bisa memakan banyak ruang. Pada kesempatan seperti itu, mungkin lebih murah dalam byte untuk melakukan ini:
Di sini, kami menempatkan semuanya dalam 1 string gabungan. Kemudian, kami mengaksesnya seperti ini:
Untuk pendekatan ini, penting bahwa semua nilai memiliki panjang yang sama. Ambil nilai terpanjang dan padukan yang lainnya:
Anda tidak perlu menambahkan nilai terakhir, dan Anda bahkan dapat melewati kuotasi penutupan! Jika tantangan menentukan bahwa spasi putih tidak diizinkan dalam jawaban, gunakan
RTRIM$()
untuk memperbaikinya.Anda dapat melihat teknik ini beraksi di sini .
sumber
PRINT
(?
) memiliki beberapa kebiasaanAngka dicetak dengan ruang terdepan dan belakang.
Mencetak menambah linebreak. Perilaku ini dapat diubah dengan menambahkan koma di akhir pernyataan untuk memasukkan tab, atau titik koma untuk menghindari penyisipan:
Tidak perlu menggunakan
&
atau di;
antara operasi yang berbeda saat mencetak, mis.?1"x"s$
harus mencetak nomor1
, dengan spasi di setiap sisi, suratx
dan isis$
Keluaran
Mencetak linebreak dapat dilakukan dengan adil
?
sumber
-
dicetak di sana. Spasi juga dicetak setelah nomor tersebut. Cara terbaik yang saya temukan untuk menghilangkan spasi ini adalah - tidakPRINT USING
tahu apakah Anda ingin menambahkannya ke jawaban ini atau jika itu harus menjadi jawaban yang terpisah.WRITE
semoga bermanfaat di tempatPRINT
PRINT
biasanya cara Anda ingin melakukan output, karena cukup fleksibel dan memiliki jalan?
pintas. Namun,WRITE
perintah itu dapat menyelamatkan Anda byte dalam situasi tertentu:WRITE
bungkus dengan tanda kutip ganda ("
). Jika Anda membutuhkan output dengan tanda kutip ganda,WRITE s$
jauh lebih pendek daripada?CHR$(34);s$;CHR$(34)
. Lihat, misalnya, QBasic quine terpendek yang diketahui .WRITE
jangan tambahkan spasi sebelum dan sesudahnya , janganPRINT
.WRITE n
jauh lebih pendek dari?MID$(STR$(n),2)
. Lihat, misalnya, FizzBuzz di QB64 .WRITE
pisahkan dengan koma:WRITE 123,"abc"
keluaran123,"abc"
. Saya tidak bisa memikirkan skenario di mana ini akan berguna, tetapi itu tidak berarti tidak ada.Keterbatasan
WRITE
:PRINT a;b
.LOCATE
, tetapi itu membutuhkan banyak byte.)sumber
Terkadang, QBasic mangles masuk ke fungsi. Abuse itu!
Ada beberapa fungsi yang berfungsi pada karakter alih-alih string, tetapi tidak ada
char
tipe data di QBasic, hanya adastring ($)
tipe. Ambil contohASC()
fungsi, yang mengembalikan kode kunci ASCII untuk sebuah karakter. Jika kita mau masukhanya yang pertama yang
l
akan dipertimbangkan oleh QBasic. Dengan cara ini, kita tidak perlu repot memotong talinya menjadi panjang 1.Contoh lain datang dari pertanyaan ini di mana
STRING$()
fungsi tersebut digunakan dalam salah satu jawaban.Perhatikan bahwa QBasic, ketika ditawari string multi-char dan hanya membutuhkan satu char, secara otomatis mengambil char pertama dan mengabaikan sisanya.
sumber