Mẹo chơi gôn trong C ++


48

Bạn có lời khuyên chung nào cho việc chơi golf trong C ++? Tôi đang tìm kiếm những ý tưởng có thể được áp dụng cho các vấn đề về mã golf nói chung ít nhất là cụ thể đối với C ++ (ví dụ: "xóa bình luận" không phải là một câu trả lời). Xin vui lòng gửi một lời khuyên cho mỗi câu trả lời.


4
Nhiều lời khuyên cho việc chơi golf trong C cũng có thể áp dụng cho C ++, vì vậy vui lòng giả sử rằng độc giả đã quen thuộc với câu hỏi đó; chỉ đăng ở đây nếu bạn có thứ gì đó không phải là mẹo chơi gôn C hợp lệ.
Toby Speight

@TobySpeight Có lẽ vì họ có cùng một url bên cạnh ID câu hỏi.
NoOneIsHãy là

C và C ++, ngay cả khi không phải loại 'chơi gôn', đều đúng và dễ dàng (nếu ai đó xem xét tập hợp con đúng của C ++)
RosLuP

Câu trả lời:


24

Toán tử điều kiện ternary ?:thường có thể được sử dụng như một cách thay thế cho các câu lệnh đơn giản if- elsevới mức tiết kiệm đáng kể.

Nó có giá trị đặc biệt ở chỗ nó có thể được sử dụng để chọn các giá trị thay thế như trong

#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;
}

Chưa chạy mã, nhưng tôi không nghĩ nó hoạt động như bạn nói. ((u = atoi (v [c]))% 2? o: e) + = u không làm gì ngoài việc thêm giá trị u vào biểu thức bên trái sẽ nhận giá trị o hoặc e, nhưng các biến o và e không thay đổi để chúng luôn luôn là 0. kiểm tra mã để xem những gì bản lề. bạn nên sử dụng địa chỉ để làm cho nó hoạt động
Bogdan Alexandru

4
@BogdanAlexandru Er ... hãy chạy nó. Nó thực sự làm việc. Giá trị của biểu thức ngoặc đơn là một tham chiếu đến một hoặc khác của eo. Lưu ý rằng điều này khác với cách toán tử này hoạt động trong c khi thủ thuật này không hoạt động vì nó không thể là giá trị.
dmckee

Thay thế std::endlbằng cách '\n'tiết kiệm 5 ký tự
Mukul Kumar

3
@MukulKumar Vâng, vâng. Nhưng với mục đích thể hiện mẹo này, tôi đã bỏ lại tất cả mọi thứ trừ trường hợp không có điều kiện ternary không được đánh gôn cho rõ ràng.
dmckee

22

Đôi khi bạn có thể lưu hai ký tự bằng cách sử dụng thực tế là các biến thời lượng lưu trữ tĩnh (đặc biệt bao gồm tất cả các biến phạm vi toàn cầu) sẽ tự động được khởi tạo bằng 0 ngay từ đầu (không giống như các biến tự động mà bạn không có bảo đảm như vậy). Vì vậy, thay vì

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

bạn có thể viết

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

+1 nhưng thực tế không tốt
mondlos

@mondlos: Chơi golf về cơ bản ngụ ý thực hành xấu.
celtschk

15

Một số trình biên dịch (ví dụ GCC) hỗ trợ các hằng số nhiều ký tự . Điều này có thể lưu một vài ký tự khi cần một giá trị số nguyên lớn. Thí dụ:

int n='  ';

Giá trị là cụ thể thực hiện. Thông thường giá trị của 'ab'256*'a'+'b'hoặc 'a'+256*'b'. Bạn có thể chỉ định tối đa 4 ký tự giữa các dấu ngoặc kép.


3
GCC? Ý bạn là g ++ ?
Nathan Osman

6
@George Edison: GCC là viết tắt của Bộ sưu tập trình biên dịch GNU , bao gồm tất cả các mặt trận của nó, bao gồm cả các phần tử cho C, C ++, Go, v.v.
Joey Adams

@Joey: Tôi biết, nhưng đó cũng là tên của Trình biên dịch GNU C.
Nathan Osman

25
@George: Trình biên dịch GNU C được gọi là gcc, không phải GCC.
dòng chảy

Cũng có thể nhớ điều đó, tôi có thể quên.

12

Một cái mà tôi thấy tiện dụng:

Lợi dụng thực tế là các giá trị khác không đánh giá truetrong các biểu thức boolean và x&&yđánh giá x*ykhi xử lý các booleans

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

đánh giá

(x*y)

Bạn chỉ cần nhận thức được tràn, như được chỉ ra dưới đây.


2
Về mặt kỹ thuật, đó là x!=0 && y!=0. Nhưng khi sử dụng phép nhân bạn cần cẩn thận với tràn. Khi sử dụng số nguyên 32 bit x = y = 65536 (và một số tổ hợp sức mạnh khác của hai) cũng sẽ mang lại x * y = 0 .
Martin Ender

Vâng đúng vậy. Tôi đã sử dụng nó như một kiểm tra giới hạn hai chiều ở đây: codegolf.stackexchange.com/a/37571/31477 khi điều đó không quan trọng. Tôi sẽ chỉnh sửa những điểm đó.
Baldrickk

1
Tuy nhiên, lưu ý rằng &&có một hành vi ngắn mạch *thiếu. Ví dụ: bạn không thể thay thế i++!=0&&j++!=0bằng i++*j++.
celtschk

@celtschk vâng, điểm tốt. Nhưng nếu bạn hoàn toàn làm đại số boolean, thì nó hoạt động
Baldrickk

11

Sử dụng các loại sau:

u64, s64, u32, s32 (or int)

Đối với các từ / loại lặp đi lặp lại, sử dụng #defines:

#define a while

Nó chỉ có giá trị nếu bạn sử dụng whilenhiều để bù thêm 10 ký tự. ( Khoảng 4. )


1
Các loại u64, s64, u32 và s32 không phải là một phần của C ++. Chúng có thể là một phần mở rộng không chuẩn của trình biên dịch của bạn (mặc dù tôi chưa bao giờ thấy chúng).
celtschk

5
Hai lời khuyên này sẽ được đặt tốt hơn trong hai câu trả lời riêng biệt để chúng có thể được bỏ phiếu riêng lẻ.
trichoplax


10

Khi có thể, thay đổi &&||để &|tương ứng.

Khi sử dụng câu lệnh if đơn giản:

if(<condition>)<stuff>;

có thể thay đổi thành:

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

mà tiết kiệm một nhân vật.


8

Thay vì sử dụng while(1), sử dụng for(;;), lưu một ký tự :)


8

Sử dụng toán tử dấu phẩy thay cho dấu ngoặc nhọn đóng và mở có thể lưu một vài ký tự, nếu bạn gặp trường hợp mệnh đề của bạn có nhiều hơn một câu lệnh trong đó:

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

so với

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

Hai ký tự được lưu trên IF đơn giản hoặc ba tổng số cho IF / ELSE.

Là một điểm khác biệt giữa C và C ++, kết quả của một biểu thức dấu phẩy trong C ++ nói chung có thể được sử dụng như một giá trị ... FWIW.


7

Vì các phần tử mảng được lưu trữ trực tiếp với nhau trong bộ nhớ, thay vì một cái gì đó như thế này:

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

Bạn có thể làm một cái gì đó như thế này:

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

Rõ ràng cả hai điều trên đều không được đánh gôn, để dễ đọc, nhưng sử dụng con trỏ rõ ràng có thể giúp bạn tiết kiệm rất nhiều không gian.


Đừng quên bạn có thể cắt bỏ tất cả khoảng trắng đó! (Mẹo khác nhau hoàn toàn, nhưng nên được đề cập)
stokastic

@stokastic Các ví dụ không có nghĩa là chơi gôn, chỉ để chứng minh cách sử dụng kỹ thuật.
Diễn viên đóng thế

6
tại sao không for(int* i=array; i<array+25*25; i++)? Sau đó, bạn chỉ phải theo dõi một biến.
Lucas

6

Khá rõ ràng, nhưng bạn đang sử dụng rất nhiều thư viện tiêu chuẩn, using namespace std;có thể lưu một vài ký tự.


5
Nếu bạn chỉ sử dụng một tên duy nhất, nhưng điều đó khá thường xuyên, using std::name;có thể ngắn hơn, mặc dù.
celtschk

10
Điều này chỉ lưu các ký tự nếu bạn sử dụng std::năm lần trở lên.
nyuszika7h

6

Nó rất hữu ích để nhớ là a[i]giống như *(a+i).

Thay thế a[0]với *ahai tiết kiệm nhân vật. Ngoài ra, a[i][0]tương đương *a[i]a[0][i]thu nhỏ lại i[*a]. Vì vậy, nếu bạn khó mã hóa một 0chỉ mục trong mảng của mình, một cách tốt hơn có thể tồn tại.


5

Thay vì viết quyền hạn lớn 10, hãy sử dụng ký hiệu điện tử . Ví dụ, a=1000000000dài hơn a=1e9. Điều này có thể được mở rộng cho các số khác như a=1e9+24là tốt hơn a=1000000024.


1
Lưu ý rằng điều này không chính xác tương đương, cần truyền sang các kiểu số nguyên trước khi sử dụng. Ví dụ 1e9/xkhông giống như 1000000000/xhoặc int(1e9)/x.
dùng202729

5

Bạn có thể sử dụng toán tử ternary ?:mà không có bất kỳ biểu thức nào trong khối thực (nó tiết kiệm một byte)

#include <iostream>

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

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

Kiểm tra nó ở đây


5
Đây dường như là một phần mở rộng GNU và không phải trong tiêu chuẩn C ++. https://gcc.gnu.org/onlinesocs/gcc-4.4.4/gcc/Cond điều
kiện.html

r? foo (): 0; // if (r) foo () cái này là ok ;;;;; nhưng đối với điều này r ?: foo (); tôi không biết điều đó
RosLuP

5

Tiêu đề ngắn hơn

Đây là GCC cụ thể, nó có thể mở rộng cho các trình biên dịch khác.

Tiêu đề được biên dịch sẵn.

Trong G ++ bits/stdc++.hlà tiêu đề được biên dịch trước bao gồm tất cả các tiêu đề khác. Nếu bạn cần import2 cái khác nhau, bạn có thể sử dụng cái này.

Tiêu đề ngắn hơn.

Đây là tất cả các tiêu đề được liệt kê trên http://en.cppreference.com/w/cpp/header :

sắp xếp theo thứ tự tăng dần của chiều dài.

Một số trong số chúng đã dài hơn bits/stdc++.hvà một số trong chúng yêu cầu hỗ trợ C ++ 17. Một số người khác không được TIO G ++ hỗ trợ (vì lý do tôi không biết). Lọc chúng ra chúng ta có:

Nó có thể xảy ra rằng một số trong số họ có thể được thay thế bằng những cái ngắn hơn. Chỉ cần tìm kiếm nhị phân cho dù cái bạn cần có thể được thay thế. Đặc biệt:

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

4

#importthay vì #includecung cấp cho bạn thêm một byte.

Ngoài ra, ký tự khoảng trắng giữa #importvà tiêu đề không nhất thiết phải là:

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

Và nếu bạn cần thứ gì đó từ stdlibtiêu đề, bạn có thể nhập bất kỳ tiêu đề nào với bộ chứa STL (thích hợp hơn sethoặc map) thay vì cstdlib.


3

Các phép toán số học trên Booleans:

Mặc dù

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

tốt hơn

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

nó không tốt bằng

a*=(b>0)-.5

Ngoài ra, sử dụng #define trên bất cứ thứ gì được sử dụng nhiều. Nó thường ngắn hơn so với việc sử dụng các hàm, vì tên loại không cần thiết.

Kết hợp mọi thứ càng nhiều càng tốt:

a+=a--;

giống như

a=2*a-1;

Trong khi các ví dụ của bạn là chính xác, hãy cẩn thận khi gọi hành vi không xác định khi sử dụng x như một giá trị và x++như một giá trị . hành vi và điểm trình tự không xác định
trần mèo

Có thể a + = a--; có hành vi không xác định
RosLuP

3

Sử dụng lambdas chung làm mẫu giá rẻ

Đối với các loại khác int, sử dụng chúng làm đối số chức năng có thể tốn kém. Tuy nhiên, lambdas chung đã được giới thiệu (trong C ++ 14?) Và cho phép bất kỳ lambda nào trở thành một mẫu - sử dụng autocho các loại đối số có thể lưu byte. So sánh:

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

Lambdas Generic cũng rất thuận tiện cho việc chấp nhận lặp - có lẽ là cách tốt nhất để chấp nhận đầu vào mảng trong C ++ là [](auto a, auto z), nơi azđược thông qua như là begin()end()của mảng / vector / danh sách / etc.


2

Trong nỗ lực đầu tiên của tôi tại mã golf cho nhiệm vụ "Trừ các số tiếp theo" tôi đã bắt đầu từ hàm (58 byte)

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

sau đó an toàn 5 byte khi chuyển sang lambda và di chuyển khởi tạo ra khỏi for(53)

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

và cuối cùng sau khi chuyển từ forsang whiletôi đã nhận được 51 byte:

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

Mã kiểm tra không được mã hóa là một cái gì đó như:

#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;
}

CẬP NHẬT:

Trên thực tế forcó thể đạt đến độ dài tương tự như while:

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

2

Tôi đoán là sẽ đến bữa tiệc muộn ...

Nếu bạn muốn biến một biểu thức thành -1 và 1 thay vì 0 và 1, thay vì biểu thức này:

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

làm cái này:

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

Nó có thể lưu một số byte tùy thuộc vào việc sử dụng.


Thay vì int x=(a*10>5)*2-1;, bạn không thể làm int x=a*10>5?1:-1;, cái nào ngắn hơn 1 byte?
girobuz

2

Nếu bạn muốn hoán đổi hai biến số nguyên a và b thì

a^=b^=a^=b;

có thể được sử dụng, tiết kiệm 5 ký tự so với cách tiêu chuẩn

a+=b;
b=a-b;
a-=b;

1
Về cách tiêu chuẩn đó. ,ttại các int được tạo trước đó và sau đó t=a;a=b;b=t;sẽ ngắn hơn 3 byte so với a+=b;b=a-b;a-=b;. Tuy nhiên, bạn a^=b^=a^=b;thậm chí còn ngắn hơn thế, nên +1 từ tôi. Tôi không biết C ++, nhưng nó thực sự hoạt động . Là một người chơi mã Java, tôi buồn, nó dường như không hoạt động ở đó . :(
Kevin Cruijssen

1
@KevinCruijssen Vâng, tôi nên đã đề cập đến C ++, tôi không biết nhiều về java, nhưng a^=b;b^=a;a^=b;đang hoạt động tốt trong java.
joker007

1
Không cần phải đề cập rõ ràng về C ++. Tất cả những lời khuyên này là dành cho C ++. :) Là một nhà phát triển Java, tôi chỉ tò mò liệu có thể làm điều gì đó tương tự trong Java, nhưng dường như là không. a^=b;b^=a;a^=b;thực sự hoạt động, nhưng dài hơn ,t+ t=a;a=b;b=t;. Xin lỗi về việc đề cập đến Java, vì nó không có chủ đề ở đây. Nhưng mẹo hay cho codegolfers C ++!
Kevin Cruijssen

2

Sử dụng nội dung GCC thay vì nhập

Nếu bạn đang sử dụng trình biên dịch GCC, đôi khi sẽ giúp sử dụng các hàm dựng sẵn của chúng, chẳng hạn như __builtin_putshoặc __builtin_clz. Ví dụ,

44 byte:

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

50 byte:

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

1

Nếu bạn đang sử dụng C ++ 11 hoặc mới hơn (luôn luôn là trường hợp hiện tại), hãy sử dụng auto cho các loại phức tạp, nếu có thể.

Ví dụ: 54 byte thay vì 66

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

Ngoài ra, vì hiệu suất không thành vấn đề, đối với một số thách thức, std::listcó thể chỉ thực hiện công việc với một vài byte ít hơn:

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

1

Các hàm <algorithm>thường yêu cầu truyền a.begin(),a.end()rất dài, thay vào đó bạn có thể sử dụng &a[0],&*end(a)để lưu 3 byte nếu avectorhoặc string.

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

0

Đừng sử dụng string(""), sử dụng "". Nó tiết kiệm 8 byte.


Nó không chính xác tương đương. Ví dụ "" + 'a'char* + char, đó là con trỏ Ngoài ra, trong khi std::string("") + 'a'std::string + char- nối chuỗi. string()sẽ làm việc
dùng202729
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.