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.
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.
Jawaban:
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;
}
edan o. Perhatikan bahwa ini berbeda dari cara operator ini bekerja di c di mana trik ini tidak berfungsi karena tidak dapat menjadi nilai.
std::endldengan '\n'yang menghemat 5 karakter
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()
{
// ...
}
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.
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.
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 .
&&memiliki perilaku hubung singkat yang *kurang. Misalnya, Anda tidak dapat mengganti i++!=0&&j++!=0dengan i++*j++.
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. )
Jika Anda ingin menggunakan C ++ 0x, Anda dapat menggunakan fitur-fitur baru seperti lambdas .
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.
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.
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.
for(int* i=array; i<array+25*25; i++)? Maka Anda hanya perlu melacak satu variabel.
Cukup jelas, tetapi Anda menggunakan banyak perpustakaan standar, using namespace std;mungkin menyimpan beberapa karakter.
using std::name;mungkin lebih pendek.
std::lima kali atau lebih.
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.
1e9/xtidak sama dengan 1000000000/xatau int(1e9)/x.
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()
}
Ini khusus GCC, mungkin dapat diperluas ke kompiler lain.
Dalam G ++ bits/stdc++.hadalah header yang dikompilasi terdiri dari semua header lainnya. Jika Anda perlu import2 yang berbeda, Anda bisa menggunakan ini.
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)
#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.
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;
xsebagai nilai dan x++sebagai nilai. poin perilaku dan urutan yang tidak ditentukan
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.
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;}
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.
int x=(a*10>5)*2-1;, tidak bisakah Anda melakukannya int x=a*10>5?1:-1;, yang lebih pendek 1 byte?
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;
,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 . :(
a^=b;b^=a;a^=b;bekerja dengan baik di java.
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!
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!");}
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;}
Jangan gunakan string(""), gunakan "". Menghemat 8 byte.
"" + 'a'adalah char* + char, yang selain pointer, sedangkan std::string("") + 'a'adalah std::string + char- string concatenation. string()akan bekerja.