Kiat untuk bermain golf di C ++

48

Apa tips umum yang Anda miliki untuk bermain golf di C ++? Saya mencari ide yang dapat diterapkan pada masalah kode golf secara umum yang setidaknya agak spesifik untuk C ++ (mis. "Hapus komentar" bukan jawaban). Silakan kirim satu tip per jawaban.

marcog
sumber
4
Banyak tips untuk bermain golf di C juga berlaku untuk C ++, jadi silakan berasumsi bahwa pembaca sudah terbiasa dengan pertanyaan itu; hanya posting di sini jika Anda memiliki sesuatu yang bukan tip golf C yang valid.
Toby Speight
@TobySpeight Mungkin karena mereka memiliki url yang sama di samping ID pertanyaan.
NoOneIsHere
C dan C ++, bahkan jika bukan tipe 'golf', adalah benar dan mudah (jika orang menganggap subset yang tepat dari C ++)
RosLuP

Jawaban:

24

Operator kondisional terner ?:sering dapat digunakan sebagai berdiri di untuk sederhana if- elsepernyataan di tabungan yang cukup.

Ini bernilai khusus karena dapat digunakan untuk memilih nilai alternatif seperti pada

#include <iostream>
#include <cstdlib>
int main(int c, char**v){
  int o=0,e=0,u;
  while(--c) ((u=atoi(v[c]))%2?o:e)+=u;
  std::cout << "Sum of odds " << o <<std::endl
            << "Sum of evens " << e <<std::endl;
}
dmckee
sumber
belum menjalankan kode, tapi saya pikir itu tidak berfungsi seperti yang Anda katakan. ((u = atoi (v [c]))% 2? o: e) + = u tidak melakukan apa-apa selain menambahkan nilai u ke ekspresi di sebelah kiri yang mendapatkan nilai o atau e, tetapi variabel o dan e tetap tidak berubah sehingga mereka akan selalu 0. memeriksa kode untuk melihat apa yang terjadi. Anda harus menggunakan alamat untuk membuatnya berfungsi
Bogdan Alexandru
4
@BogdanAlexandru Er ... lakukan jalankan. Ini benar-benar bekerja. Nilai ekspresi kurung adalah referensi ke satu atau yang lain dari edan o. Perhatikan bahwa ini berbeda dari cara operator ini bekerja di c di mana trik ini tidak berfungsi karena tidak dapat menjadi nilai.
dmckee
Ganti std::endldengan '\n'yang menghemat 5 karakter
Mukul Kumar
3
@MukulKumar Baiklah, ya. Tetapi untuk tujuan menunjukkan tip ini saya meninggalkan segalanya kecuali persyaratan-persyaratan ternary un-golfed untuk kejelasan.
dmckee
22

Kadang-kadang Anda dapat menyimpan dua karakter dengan menggunakan fakta bahwa variabel durasi penyimpanan statis (yang terutama mencakup semua variabel lingkup global) secara otomatis nol diinisialisasi pada awal (tidak seperti variabel otomatis di mana Anda tidak memiliki jaminan seperti itu). Jadi, bukannya

int main()
{
  int a=0;
  // ...
}

kamu bisa menulis

int a;
int main()
{
  // ...
}
celtschk
sumber
+1 namun jelas praktik yang buruk
mondlos
@mondlos: Golf pada dasarnya menyiratkan praktik buruk.
celtschk
15

Beberapa kompiler (misalnya GCC) mendukung konstanta multi-karakter . Ini dapat menyimpan beberapa karakter ketika nilai integer besar diperlukan. Contoh:

int n='  ';

Nilainya spesifik implementasi. Biasanya nilai 'ab'is 256*'a'+'b'atau 'a'+256*'b'. Anda dapat menentukan hingga 4 karakter di antara tanda kutip.

marcog
sumber
3
GCC? Maksud Anda g ++ ?
Nathan Osman
6
@George Edison: GCC adalah kependekan dari GNU Compiler Collection , yang mencakup semua bagian depannya, termasuk yang untuk C, C ++, Go, dll.
Joey Adams
@ Joey: Saya tahu, tapi itu juga nama GNU C Compiler.
Nathan Osman
25
@ George: Kompiler GNU C disebut gcc, bukan GCC.
fredoverflow
Mungkin ingat itu, saya bisa lupa.
12

Salah satu yang saya temukan berguna:

Mengambil keuntungan dari kenyataan bahwa nilai-nilai non-nol dievaluasi truedalam ekspresi boolean, dan yang x&&ymengevaluasi x*yketika berhadapan dengan boolean

(x!=0 && y!=0)

mengevaluasi ke

(x*y)

Anda hanya harus mewaspadai luapan, seperti yang ditunjukkan di bawah ini.

Baldrickk
sumber
2
Secara teknis, itu x!=0 && y!=0. Tetapi ketika menggunakan perkalian, Anda harus berhati-hati dengan luapan. Saat menggunakan bilangan bulat 32-bit x = y = 65536 (dan beberapa kombinasi kekuatan keduanya) juga akan menghasilkan x * y = 0 .
Martin Ender
Ya itu betul. Saya menggunakannya sebagai batas array dua dimensi periksa di sini: codegolf.stackexchange.com/a/37571/31477 di mana itu tidak masalah. Saya akan mengedit poin-poin itu.
Baldrickk
1
Namun perlu dicatat bahwa &&memiliki perilaku hubung singkat yang *kurang. Misalnya, Anda tidak dapat mengganti i++!=0&&j++!=0dengan i++*j++.
celtschk
@celtschk ya, bagus. Tetapi jika Anda murni melakukan aljabar boolean, maka itu akan berhasil
Baldrickk
11

Gunakan tipe berikut:

u64, s64, u32, s32 (or int)

Untuk kata / jenis yang berulang, gunakan #defines:

#define a while

Ini hanya layak jika Anda menggunakan whilebanyak untuk mengganti 10 karakter tambahan. ( Tentang 4. )

Mateen Ulhaq
sumber
1
Tipe u64, s64, u32 dan s32 bukan bagian dari C ++. Mereka mungkin merupakan ekstensi non-standar dari kompiler Anda (saya belum pernah melihatnya).
celtschk
5
Dua tips ini akan lebih baik ditempatkan di dua jawaban terpisah sehingga mereka dapat dipilih secara individual.
trichoplax
11

Jika Anda ingin menggunakan C ++ 0x, Anda dapat menggunakan fitur-fitur baru seperti lambdas .

Siput mekanik
sumber
10

Jika memungkinkan, ubah &&dan ||ke &dan |masing - masing.

Saat menggunakan pernyataan if sederhana:

if(<condition>)<stuff>;

dapat diubah menjadi:

<condition>?<stuff>:<any single letter variable>;

yang menyimpan karakter.

Alex Gittemeier
sumber
8

Alih-alih menggunakan while(1), menggunakan for(;;), menyimpan satu karakter :)

NaCl
sumber
8

Menggunakan operator koma sebagai pengganti kurung buka dan tutup dapat menyimpan beberapa karakter, jika Anda memiliki situasi di mana klausa Anda memiliki lebih dari satu pernyataan di dalamnya:

if(c){x=1;cout<<"Hi";y=2;}else{x=2;cout<<"Bye";y=3;}

vs.

if(c)x=1,cout<<"Hi",y=2;else x=2,cout<<"Bye",y=3;###

Dua karakter disimpan pada IF biasa, atau tiga total untuk IF / ELSE.

Sebagai titik perbedaan antara C dan C ++, hasil dari ekspresi koma dalam C ++ secara keseluruhan dapat digunakan sebagai nilai lv ... FWIW.

Rebmu
sumber
7

Karena elemen array disimpan secara langsung setelah satu sama lain dalam memori, bukannya sesuatu seperti ini:

for(int x = 0; x < 25; x++) {
    for(int y = 0; y < 25; y++)
        array[x][y] = whatever;
}

Anda dapat melakukan sesuatu seperti ini:

int* pointer = array;
for(int i = 0; i < 25*25; i++, pointer++)
    *pointer = whatever;

Jelas tidak satu pun di atas golf, untuk keterbacaan, tetapi secara eksplisit menggunakan pointer dapat menghemat banyak ruang.

Stuntddude
sumber
Jangan lupa Anda bisa memotong semua spasi putih itu! (Tip berbeda sama sekali, tetapi harus disebutkan)
stokastic
@stokastic Contoh-contoh tidak dimaksudkan untuk golf, hanya untuk menunjukkan bagaimana menggunakan teknik ini.
Stuntddude
6
mengapa tidak for(int* i=array; i<array+25*25; i++)? Maka Anda hanya perlu melacak satu variabel.
Lucas
6

Cukup jelas, tetapi Anda menggunakan banyak perpustakaan standar, using namespace std;mungkin menyimpan beberapa karakter.

pengembang
sumber
5
Jika Anda hanya menggunakan satu nama, tetapi itu cukup sering, using std::name;mungkin lebih pendek.
celtschk
10
Ini hanya menghemat karakter jika Anda menggunakan std::lima kali atau lebih.
nyuszika7h
6

Yang perlu diingat adalah a[i]sama dengan *(a+i).

Ganti a[0]dengan *auntuk penghematan dua karakter. Juga, a[i][0]sama dengan *a[i]dan a[0][i]menyusut ke i[*a]. Jadi jika Anda meng-coding 0indeks dalam array Anda, cara yang lebih baik mungkin ada.

MegaTom
sumber
5

Alih-alih menulis kekuatan besar 10, gunakan notasi . Misalnya, a=1000000000lebih panjang dari a=1e9. Ini dapat diperluas ke nomor lain seperti a=1e9+24lebih baik daripada a=1000000024.

Pranjal Jain
sumber
1
Perhatikan bahwa ini tidak persis sama, perlu dilemparkan ke tipe integer sebelum menggunakan. Misalnya 1e9/xtidak sama dengan 1000000000/xatau int(1e9)/x.
user202729
5

Anda dapat menggunakan operator ternary ?:tanpa ekspresi di blok-benar (ini menghemat satu byte)

#include <iostream>

int foo()
{
    std::cout << "Foo\n";
}

int main()
{
    1?foo():0;  // if (true) foo()
    0?:foo();   // if (!false) foo()
}

Lihat di sini

x1Mike7x
sumber
5
Ini tampaknya merupakan ekstensi GNU dan bukan dalam standar C ++. https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Conditionals.html#Conditionals
ceilingcat
r? foo (): 0; // jika (r) foo () ini tidak apa-apa ;;;;; tapi Untuk ini r?: foo (); saya tidak tahu itu
RosLuP
5

Header lebih pendek

Ini khusus GCC, mungkin dapat diperluas ke kompiler lain.

Header yang dikompilasi.

Dalam G ++ bits/stdc++.hadalah header yang dikompilasi terdiri dari semua header lainnya. Jika Anda perlu import2 yang berbeda, Anda bisa menggunakan ini.

Header lebih pendek.

Ini semua tajuk yang terdaftar di http://en.cppreference.com/w/cpp/header :

diurutkan dalam peningkatan urutan panjang.

Beberapa dari mereka sudah lebih lama dari bits/stdc++.h, dan beberapa dari mereka memerlukan dukungan C ++ 17. Beberapa lainnya tidak didukung oleh TIO G ++ (untuk alasan yang saya tidak tahu). Saring mereka yang kita miliki:

Mungkin saja beberapa dari mereka dapat diganti dengan yang lebih pendek. Hanya pencarian biner apakah yang Anda butuhkan dapat diganti. Khususnya:

cstdio -> ios        (-3 bytes)
algorithm -> regex   (-4 bytes)
vector -> queue      (-1 byte)
string -> map        (-3 bytes)
bitset -> regex      (-1 byte)
numeric -> random    (-1 byte)
pengguna202729
sumber
4

#importbukannya #includememberi Anda satu byte lagi.

Selain itu, karakter spasi antara #importdan tajuk belum tentu:

#include <map>
// vs
#import<map>

Dan jika Anda membutuhkan sesuatu dari stdlibtajuk, Anda dapat mengimpor tajuk apa pun dengan wadah STL (lebih disukai setatau map) sebagai gantinya cstdlib.

x1Mike7x
sumber
3

Operasi aritmatika di Boolean:

Meskipun

a*=b>0?.5:-.5

lebih baik dari

if(b>0)a*=.5;else a*=-.5;

itu tidak sebagus

a*=(b>0)-.5

Juga, menggunakan #define pada apa pun yang sering digunakan. Seringkali lebih pendek daripada menggunakan fungsi, karena nama jenis tidak diperlukan.

Gabungkan hal-hal sebanyak mungkin:

a+=a--;

sama dengan

a=2*a-1;
Lucas
sumber
Meskipun contoh Anda benar, berhati-hatilah dalam menerapkan perilaku yang tidak terdefinisi saat digunakan xsebagai nilai dan x++sebagai nilai. poin perilaku dan urutan yang tidak ditentukan
ceilingcat
Ya, mungkin + = a--; memiliki Perilaku yang Tidak
Terdefinisi
3

Gunakan lambda generik sebagai templat murah

Untuk tipe selain int, menggunakannya sebagai argumen fungsi bisa jadi mahal. Namun, lambda generik diperkenalkan (dalam C ++ 14?) Dan memungkinkan lambda menjadi templat - menggunakan autountuk tipe argumen dapat menghemat byte. Membandingkan:

double f(double x, double y)
[](auto x, auto y)

Lambda Generik juga sangat nyaman untuk menerima iterator - mungkin cara terbaik untuk menerima input array di C ++ adalah [](auto a, auto z), di mana adan zdilewatkan sebagai begin()dan end()dari array / vektor / daftar / dll.

Toby Speight
sumber
2

Dalam upaya pertama saya di kode golf untuk tugas "Kurangi angka berikutnya" Saya sudah mulai dari fungsi (58 byte)

int f(int N, int P){int F;for(F=N;P;F-=++N,P--);return F;}

kemudian amankan 5 byte dengan menggeser ke lambda dan memindahkan inisialisasi dari for(53)

[](int N,int P){int F=N;for(;P;F-=++N,P--);return F;}

dan akhirnya setelah beralih dari forke whilesaya mendapat 51 byte:

[](int N,int P){int F=N;while(P--)F-=++N;return F;}

Kode tes yang tidak disatukan adalah seperti:

#include <iostream>
int main(void)
{
    int N, P;
    std::cin >> N >> P;
    auto f = [](int N,int P)
    {
        int F = N;
        while (P--)
            F -= ++N;
        return F;
    };
    std::cout << f(N, P) << std::endl;
    return 0;
}

MEMPERBARUI:

Sebenarnya forbisa mencapai panjang yang sama dengan while:

[](int N,int P){int F=N;for(;P--;F-=++N);return F;}
VolAnd
sumber
2

Agak terlambat ke pesta, kurasa ...

Jika Anda ingin mengubah ekspresi menjadi -1 dan 1 alih-alih 0 dan 1, alih-alih ini:

int x;
if (a * 10 > 5)
    x = 1;
else
    x = -1;

melakukan hal ini:

int x = (a * 10 > 5) * 2 - 1;

Ini dapat menghemat beberapa byte tergantung pada penggunaan.

Yuval Meshorer
sumber
Alih-alih int x=(a*10>5)*2-1;, tidak bisakah Anda melakukannya int x=a*10>5?1:-1;, yang lebih pendek 1 byte?
girobuz
2

Jika Anda ingin menukar dua variabel integer a dan b,

a^=b^=a^=b;

dapat digunakan, menyimpan 5 karakter dari cara standar

a+=b;
b=a-b;
a-=b;
joker007
sumber
1
Tentang cara standar itu. ,tdi ints dibuat sebelumnya dan kemudian t=a;a=b;b=t;sudah lebih pendek 3 byte dari a+=b;b=a-b;a-=b;. Namun, Anda a^=b^=a^=b;bahkan lebih pendek dari itu, jadi +1 dari saya. Saya tidak tahu C ++, tapi itu memang berfungsi . Sebagai pegolf kode Java saya sedih sepertinya tidak bekerja di sana . :(
Kevin Cruijssen
1
@KevinCruijssen Ya, saya seharusnya menyebutkan C ++, saya tidak terlalu mengenal java, tetapi a^=b;b^=a;a^=b;bekerja dengan baik di java.
joker007
1
Tidak perlu menyebutkan C ++ secara eksplisit. Semua tips ini untuk C ++. :) Sebagai pengembang Java, saya hanya ingin tahu apakah hal serupa dapat dilakukan di Jawa, tetapi ternyata tidak. a^=b;b^=a;a^=b;memang berfungsi, tetapi lebih panjang dari ,t+ t=a;a=b;b=t;. Maaf karena menyebut Java, karena di luar topik di sini. Tapi tip yang bagus untuk C ++ codegolfers!
Kevin Cruijssen
2

Gunakan GCC bawaan daripada mengimpor

Jika Anda menggunakan kompiler GCC, terkadang membantu menggunakan fungsi bawaannya, seperti __builtin_putsatau __builtin_clz. Sebagai contoh,

44 byte:

int main(){__builtin_puts("Hello, world!");}`

50 byte:

#import<cstdio>
int main(){puts("Hello, world!");}
dingledooper
sumber
1

Jika Anda menggunakan C ++ 11 atau lebih baru (yang seharusnya selalu menjadi masalah sekarang), gunakan autountuk tipe yang kompleks, jika memungkinkan.

Contoh: 54 Bytes, bukan 66

#include<vector>
std::vector<int> f(std::vector<int> l){return l;}
#include<vector>
auto f(std::vector<int> l){return l;}

Juga, karena kinerja tidak masalah, untuk beberapa tantangan, std::listmungkin hanya melakukan pekerjaan untuk beberapa byte lebih sedikit:

#include<list>
auto f(std::list<int> l){return l;}
movatica
sumber
1

Fungsi dalam <algorithm>sering membutuhkan passing a.begin(),a.end()yang benar-benar panjang, bukannya Anda dapat menggunakan &a[0],&*end(a)untuk menyimpan 3 byte jika aini vectoratau string.

sort(a.begin(),a.end());
sort(begin(a),end(a));
sort(&a[0],&*end(a));
JayXon
sumber
0

Jangan gunakan string(""), gunakan "". Menghemat 8 byte.

Rɪᴋᴇʀ
sumber
Itu tidak persis setara. Sebagai contoh "" + 'a'adalah char* + char, yang selain pointer, sedangkan std::string("") + 'a'adalah std::string + char- string concatenation. string()akan bekerja.
user202729