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
- else
pernyataan 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;
}
e
dan o
. Perhatikan bahwa ini berbeda dari cara operator ini bekerja di c di mana trik ini tidak berfungsi karena tidak dapat menjadi nilai.
std::endl
dengan '\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 true
dalam ekspresi boolean, dan yang x&&y
mengevaluasi x*y
ketika 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++!=0
dengan 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 while
banyak 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=1000000000
lebih panjang dari a=1e9
. Ini dapat diperluas ke nomor lain seperti a=1e9+24
lebih baik daripada a=1000000024
.
1e9/x
tidak sama dengan 1000000000/x
atau 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++.h
adalah header yang dikompilasi terdiri dari semua header lainnya. Jika Anda perlu import
2 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)
#import
bukannya #include
memberi Anda satu byte lagi.
Selain itu, karakter spasi antara #import
dan tajuk belum tentu:
#include <map>
// vs
#import<map>
Dan jika Anda membutuhkan sesuatu dari stdlib
tajuk, Anda dapat mengimpor tajuk apa pun dengan wadah STL (lebih disukai set
atau 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;
x
sebagai 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 auto
untuk 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 a
dan z
dilewatkan 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 for
ke while
saya 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 for
bisa 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;
,t
di 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_puts
atau __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 auto
untuk 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::list
mungkin 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.